这个问题看起来类似于 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 操作
。有没有更好的方法来实现这一点,以更好地加快速度?我使用的是 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;
}
最佳答案
有符号和无符号比较几乎相同,只是在无符号比较中设置了最高位的范围被视为大于未设置最高位的范围,而在有符号比较中被视为较小。这意味着有符号和无符号比较可以通过以下规则相互转换:
x <s y = (x ^ signbit) <u (y ^ signbit)
x <u y = (x ^ signbit) <s (y ^ signbit)
此属性直接传输到 min
和 max
,因此:
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
和符号扩展(提取
零扩展)合二为一。
关于c++ - 使用 SSE 获取 __m128i vector 中的最小短值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28561983/