Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/132.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 使用SSE获取_m128i向量中的最小短值?_C++_Sse_Simd_Sse4 - Fatal编程技术网

C++ 使用SSE获取_m128i向量中的最小短值?

C++ 使用SSE获取_m128i向量中的最小短值?,c++,sse,simd,sse4,C++,Sse,Simd,Sse4,这个问题看起来很类似,但是是简短的最小值,而不是整数+最大值。这就是我想到的: 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)); _

这个问题看起来很类似,但是是简短的最小值,而不是整数+最大值。这就是我想到的:

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));
}
该函数的作用基本上与中x的上下部分的答案相同。因此,我知道最小值在_m128i变量max2的位置0或4处。尽管它比下面显示的无SIMD函数
水平最小向量(\uuu m128i x)
快得多,但我担心最后一行的
\u mm\u extract\u 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;
}
重量水平最小向量平面(\uuuuum128ix){
权重结果[8]uuu属性_uuu((对齐(16));
_mm_-store_-si128((_-m128i*)结果,x);
权重myMin=结果[0];
对于(int l=1;l<8;l++){
如果(myMin>result[l]){
myMin=结果[l];
}
}
返回myMin;
}

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

x <s y = (x ^ signbit) <u (y ^ signbit)
x <u y = (x ^ signbit) <s (y ^ signbit)
然后我们可以使用
\u mm\u minpos\u epu16
来处理水平最小值,总的来说,得到

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

-0x8000
^0x8000
和符号扩展(
extract
zero extensions)合并为一个。

为什么要将16个短路的水平最小值作为临界值?@Zboson对u m128i x取最小值的次数将超过10万次。在这10万次中的每一次,总共有24-64个SIMD加法+最大值来创建_um128i x中的短值。您只是在寻找
\u mm\u minpos\u epu16
?@harold我认为mm\u minpos\u epu16是MS特有的。如果您想在中找到签名的最小帮助机会,我将使用_mm_set1_epi16(0x8000)尝试out.XOR。谢谢。@Royi您只需使用
psrad
pminsd
pandn
就可以在0和1之间夹紧。所有整数的延迟都很低,它们都可以转到eg Nehalem上的不同执行端口。当然,这可能会在较新的处理器上引入一些旁路延迟。。
__m128i xs = _mm_xor_si128(x, _mm_set1_epi16(0x8000));
return _mm_extract_epi16(_mm_minpos_epu16(xs), 0) - 0x8000;