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

时间:2014-02-21 07:30:34

标签: intel sse simd sse3 intel-atom

我正在开发一个性能关键型应用程序,必须将其移植到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);

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

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

2 个答案:

答案 0 :(得分: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);

答案 1 :(得分: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