使用SSE获取__m128i向量中的最小短值?

时间:2015-02-17 12:52:46

标签: c++ sse simd sse4

此问题与Getting max value in a __m128i vector with SSE?类似,但是使用短路和最小值而不是整数+最大值。这就是我想出的:

typedef short int weight;

weight horizontal_min_Vec4i(__m128i x) {
    __m128i max1 = _mm_shufflehi_epi16(x, _MM_SHUFFLE(0, 0, 3, 2));
    __m128i max1b = _mm_shufflelo_epi16(x, _MM_SHUFFLE(0, 0, 3, 2));
    __m128i max2 = _mm_min_epi16(max1, max1b);
    //max2 = _mm_min_epi16(max2, x);
    max1 = _mm_shufflehi_epi16(max2, _MM_SHUFFLE(0, 0, 0, 1));
    max1b = _mm_shufflelo_epi16(max2, _MM_SHUFFLE(0, 0, 0, 1));
    __m128i max3 = _mm_min_epi16(max1, max1b);
    max2 = _mm_min_epi16(max2, max3);
    return min(_mm_extract_epi16(max2, 0), _mm_extract_epi16(max2, 4));
}

该函数基本上与https://stackoverflow.com/a/18616825/1500111中x的上部和下部的答案相同。所以,我知道最小值是在__m128i变量max2的位置0或4。虽然它比下面显示的无SIMD函数horizontal_min_Vec4i_Plain(__m128i x)快得多,但我担心瓶颈是最后一行的_mm_extract_epi16 operation。有没有更好的方法来实现这一目标,以获得更好的加速?我正在使用Haswell,因此我可以访问最新的SSE扩展。

weight horizontal_min_Vec4i_Plain(__m128i x) {
    weight result[8] __attribute__((aligned(16)));
    _mm_store_si128((__m128i *) result, x);
    weight myMin = result[0];
    for (int l = 1; l < 8; l++) {
        if (myMin > result[l]) {
            myMin = result[l];
        }
    }
    return myMin;
}

1 个答案:

答案 0 :(得分:2)

有符号和无符号比较几乎相同,只是顶部位设置的范围被视为大于未在无符号比较中设置顶部位的范围,而在有符号比较中则更小。这意味着通过以下规则可以将签名和无符号比较相互转换:

x <s y = (x ^ signbit) <u (y ^ signbit)
x <u y = (x ^ signbit) <s (y ^ signbit)

此属性会直接转移到minmax,因此:

min_s(x, y) = min_u(x ^ signbit, y ^ signbit) ^ signbit

然后我们可以使用_mm_minpos_epu16来处理水平最小值,总共得到类似

的内容
__m128i xs = _mm_xor_si128(x, _mm_set1_epi16(0x8000));
return _mm_extract_epi16(_mm_minpos_epu16(xs), 0) - 0x8000;

- 0x8000^ 0x8000,并且符号扩展名(extract零延伸)汇总为一个。