我有一个函数使用SSE来做很多事情,分析器告诉我,我用来计算水平最小和最大值的代码部分大部分时间都会消耗。
例如,我一直在最低限度地使用以下实现:
static inline int16_t hMin(__m128i buffer) {
buffer = _mm_min_epi8(buffer, _mm_shuffle_epi8(buffer, m1));
buffer = _mm_min_epi8(buffer, _mm_shuffle_epi8(buffer, m2));
buffer = _mm_min_epi8(buffer, _mm_shuffle_epi8(buffer, m3));
buffer = _mm_min_epi8(buffer, _mm_shuffle_epi8(buffer, m4));
return ((int8_t*) ((void *) &buffer))[0];
}
我需要计算16个1字节整数的最小值和最大值,如您所见.
任何好的建议都会受到高度赞赏:)
谢谢
发布于 2014-03-07 20:00:51
我建议作出两项改变:
((int8_t*) ((void *) &buffer))[0]
替换为_mm_cvtsi128_si32
。_mm_shuffle_epi8
替换为_mm_shuffle_epi32
/_mm_shufflelo_epi16
,后者在最近的AMD处理器和Intel上具有较低的延迟时间,并将节省内存加载操作:
静态内联int16_t hMin(__m128i缓冲器){__m128i=_mm_min_epi8(缓冲器,_mm_shuffle_epi32,_MM_SHUFFLE(3,2,3,2)),缓冲器=_mm_min_epi8(缓冲器,_mm_shuffle_epi32(缓冲器,_MM_SHUFFLE(1,1,1,1);缓冲器=_mm_min_epi8(缓冲器,_mm_shufflelo_epi16(缓冲器,_MM_SHUFFLE(1,1,1,1));缓冲器=_mm_min_epi8(缓冲区,_mm_srli_epi16(缓冲器,8));返回(Int8_t)_mm_cvtsi128_si32(缓冲区);}发布于 2014-03-08 10:54:57
SSE 4.1有一个指令,它可以做你想做的事情。它的名字是PHMINPOSUW
,C/C++内禀是_mm_minpos_epu16
。它仅限于16位无符号值,不能给出最大值,但这些问题可以很容易地解决。
_mm_srli_pi16
或_mm_shuffle_epi8
,然后使用_mm_min_epu8
获得以偶数字节表示的8个配对最小值,以及以奇数字节表示的XMM寄存器中的零。(这些零是由移位/洗牌指令产生的,应该保持在_mm_min_epu8
之后的位置)。_mm_minpos_epu16
在这些值中找到最小值。_mm_cvtsi128_si32
提取结果的最小值。下面是一个返回最多16个带符号字节的示例:
static inline int16_t hMax(__m128i buffer)
{
__m128i tmp1 = _mm_sub_epi8(_mm_set1_epi8(127), buffer);
__m128i tmp2 = _mm_min_epu8(tmp1, _mm_srli_epi16(tmp1, 8));
__m128i tmp3 = _mm_minpos_epu16(tmp2);
return (int8_t)(127 - _mm_cvtsi128_si32(tmp3));
}
https://stackoverflow.com/questions/22256525
复制相似问题