如何获得intel Architecture SIMD __m128的标志

时间:2018-01-21 02:53:33

标签: c++ simd

由于“_mm_sign_ps”不存在,因为我能够找到:给定一个带有四个浮点值的__m128值,哪条SIMD指令或SIMD指令列表将其转换为__m128值,其中四个浮点值 - 点值包含:

+1,如果四个原始值为正且大于零。 0,如果四的原始值为零。 -1,如果四个原始值为负且小于零。

2 个答案:

答案 0 :(得分:3)

SSE真的不太匹配。首先,比较函数不会导致±1.0f,而是在条件为真时设置所有位,或者如果条件为假则不设置任何位。此外,您要求进行三向比较,如果值为“零”,则结果为“零”(“零”在引号中,因为您实际上没有指定是否需要正零或负零; IEEE 754有两个)。如果您可以重新设置问题以更好地匹配SSE提供的内容,那么您将 更好。

那说:

__m128 foo (__m128 value) {
  const __m128 zero = _mm_set_ps1 (0.0f);

  __m128 positives = _mm_and_ps(_mm_cmpgt_ps (value, zero), _mm_set_ps1(1.0f));
  __m128 negatives = _mm_and_ps(_mm_cmplt_ps (value, zero), _mm_set_ps1(-1.0f));

  return _mm_or_ps(positives, negatives);
}

我不知道您计划使用它的目的是什么,但如果您对按位操作感到满意,那么很有可能您可以弄清楚如何使用单_mm_cmpgt_ps,{ {1}},_mm_cmpge_ps_mm_cmplt_ps

答案 1 :(得分:1)

SSE没有自然/有效地以这种方式为浮动/双重工作。您希望对-1.0f / 0.0f / 1.0f sgn(x)值做什么?

您应该优化在寄存器中实际具有这些FP值的步骤,并直接使用比较掩码结果。您提出的问题是an X-Y problem的标志。是的,你实际上可以实现这一点,但通常你不应该。

例如,您可以使用布尔AND或比较+ AND来获取符号位的掩码,然后可以使用布尔XOR(_mm_xor_ps())来翻转设置了这些位的另一个向量中的符号位,以及保持在相应元素中未设置符号位的元素保持不变。

(FP否定就像翻转符号位一样简单,因为IEEE-754二进制格式使用符号/幅度表示。)

但请注意-0.0,因为它设置了符号位。如果你想根据相应的元素归零而忽略其他元素,你可以使用几个布尔运算,然后使用_mm_cmpeq_ps的结果屏蔽结果0.0。 (0.0和-0.0都适用。)

例如:

// SSE2  v * sgn(src), except we treat src=NaN as src=0

__m128 mul_by_signum(__m128 v, __m128 src)
{
    __m128 signbits = _mm_and_ps(src, _mm_set1_ps(-0.0));  // epi32(1<<31)
    __m128 flipped = _mm_xor_ps(v, signbits);

    __m128 nonzero = _mm_cmpne_ps(src, _mm_setzero_ps());
    return _mm_and_ps(flipped, nonzero);
}

对于整数,有SSSE3 psignb/w/d,它将保留/归零/否定目标中的元素,具体取决于源为正/零/负。目的地为_mm_set1_epi32(1),它会为您提供1/0 / -1元素的向量。

您无法在FP数据上使用它,因为FP使用符号/幅度而不是2的补码。并且因为它检查整数零,所以-0.0看起来像一个负数。

顺便说一下,你没有提到你想要为NaN FP输入做些什么。不要忘记FP比较有4种可能的结果:高于/等于/低于,或者如果一个或两个操作数是NaN则无序。 (因此,为了与零进行比较,您可以有正,零,负或NaN)。