使用英特尔内在函数SSSE3的替代方案时,性能会下降

Har*_*son 5 sse intel intel-atom simd sse3

我正在开发一个性能关键型应用程序,它必须移植到Intel Atom处理器,它只支持MMX,SSE,SSE2和SSE3.我以前的应用程序支持SSSE3以及AVX,现在我想将它降级到Intel Atom处理器(MMX,SSE,SSE2,SSE3).

当我更换ssse3指令时,特别是_mm_hadd_epi16使用此代码,会严重降低性能

RegTemp1 = _mm_setr_epi16(RegtempRes1.m128i_i16[0], RegtempRes1.m128i_i16[2], 
                          RegtempRes1.m128i_i16[4], RegtempRes1.m128i_i16[6],
                          Regfilter.m128i_i16[0],   Regfilter.m128i_i16[2],
                          Regfilter.m128i_i16[4],   Regfilter.m128i_i16[6]);

RegTemp2 = _mm_setr_epi16(RegtempRes1.m128i_i16[1], RegtempRes1.m128i_i16[3],
                          RegtempRes1.m128i_i16[5], RegtempRes1.m128i_i16[7],
                          Regfilter.m128i_i16[1],   Regfilter.m128i_i16[3],
                          Regfilter.m128i_i16[5], Regfilter.m128i_i16[7]);

RegtempRes1 = _mm_add_epi16(RegTemp1, RegTemp2);
Run Code Online (Sandbox Code Playgroud)

这是我能够为这个特定指令提出的最佳转换.但这种变化严重影响了整个计划的表现.

任何人都可以在MMX,SSE,SSE2和SSE3指令中建议更好的性能效率替代_mm_hadd_epi16指令.提前致谢.

Mar*_*han 8

_mm_hadd_epi16(a, b) 可以使用以下代码进行模拟:

/* (b3, a3, b2, a2, b1, a1, b0, a0) */
__m128i ab0 = _mm_unpacklo_epi16(a, b);
/* (b7, a7, b6, a6, b5, a5, b4, a4) */
__m128i ba0 = _mm_unpackhi_epi16(a, b);

/* (b5, b1, a5, a1, b4, b0, a4, a0) */
__m128i ab1 = _mm_unpacklo_epi16(ab0, ba0);
/* (b7, b3, a7, a3, b6, b2, a6, a2) */
__m128i ba1 = _mm_unpackhi_epi16(ab0, ba0);

/* (b6, b4, b2, b0, a6, a4, a2, a0) */
__m128i ab2 = _mm_unpacklo_epi16(ab1, ba1);
/* (b7, b5, b3, b1, a7, a5, a3, a1) */
__m128i ba2 = _mm_unpackhi_epi16(ab1, ba1);


/* (b6+b7, b4+b5, b2+b3, b0+b1, a6+a7, a4+a5, a2+a3, a0+a1) */
__m128i c = _mm_add_epi16(ab2, ba2);
Run Code Online (Sandbox Code Playgroud)

  • 谢谢你的回答,这是性能数字,我刚刚在我的应用程序上测试过.1)使用_mm_hadd_epi16需要255毫秒.2)使用我之前的代码,性能为356毫秒.3)在对指令使用更改后,有一个增益,最多需要262毫秒.通过查看结果我们可以确认您的逻辑远比我的好,我想知道是否有办法通过利用SSE3及以下指令集来击败SSSE3指令性能. (4认同)

Z b*_*son 3

如果您的目标是获取 8 个 16 位值的水平总和,您可以使用 SSE2 执行此操作,如下所示:

__m128i sum1  = _mm_shuffle_epi32(a,0x0E);             // 4 high elements
__m128i sum2  = _mm_add_epi16(a,sum1);                 // 4 sums
__m128i sum3  = _mm_shuffle_epi32(sum2,0x01);          // 2 high elements
__m128i sum4  = _mm_add_epi16(sum2,sum3);              // 2 sums
__m128i sum5  = _mm_shufflelo_epi16(sum4,0x01);        // 1 high element
__m128i sum6  = _mm_add_epi16(sum4,sum5);              // 1 sum
int16_t sum7  = _mm_cvtsi128_si32(sum6);               // 16 bit sum
Run Code Online (Sandbox Code Playgroud)

  • 感谢您向我提供输入,我仍在我的应用程序中测试您的更改,一旦完成,我会让您知道结果。 (3认同)