SSE指令:字节+短

时间:2012-05-17 14:02:46

标签: x86 sse instructions

我有很长的字节数组需要添加到short(或int)类型的目标数组中。 这样的SSE指令是否存在?或者也许是他们的一套?

2 个答案:

答案 0 :(得分:6)

您需要将每个8位值向量解包到两个16位值的向量中,然后添加它们。

__m128i v = _mm_set_epi8(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0);
__m128i vl = _mm_unpacklo_epi8(v, _mm_set1_epi8(0)); // vl = { 7, 6, 5, 4, 3, 2, 1, 0 }
__m128i vh = _mm_unpackhi_epi8(v, _mm_set1_epi8(0)); // vh = { 15, 14, 13, 12, 11, 10, 9, 8 }

其中v是16 x 8位值的矢量,vlvh是8 x 16位值的两个解压缩矢量。

请注意,我假设8位值是无符号的,因此当解包为16位时,高字节设置为0(即没有符号扩展)。

如果你想总结很多这些向量并获得32位结果,那么一个有用的技巧是使用乘数为1的_mm_madd_epi16,例如

__m128i vsuml = _mm_set1_epi32(0);
__m128i vsumh = _mm_set1_epi32(0);
__m128i vsum;
int sum;

for (int i = 0; i < N; i += 16)
{
    __m128i v = _mm_load_si128(&x[i]);
    __m128i vl = _mm_unpacklo_epi8(v, _mm_set1_epi8(0));
    __m128i vh = _mm_unpackhi_epi8(v, _mm_set1_epi8(0));
    vsuml = _mm_add_epi32(vsuml, _mm_madd_epi16(vl, _mm_set1_epi16(1)));
    vsumh = _mm_add_epi32(vsumh, _mm_madd_epi16(vh, _mm_set1_epi16(1)));
}
// do horizontal sum of 4 partial sums and store in scalar int
vsum = _mm_add_epi32(vsuml, vsumh);
vsum = _mm_add_epi32(vsum, _mm_srli_si128(vsum, 8));
vsum = _mm_add_epi32(vsum, _mm_srli_si128(vsum, 4));
sum = _mm_cvtsi128_si32(vsum);

答案 1 :(得分:0)

如果您需要对字节向量进行符号扩展而不是零扩展,请使用pmovsxbw (_mm_cvtepi8_epi16)。与解压缩hi / lo指令不同,你只能从src寄存器的低半/四分之一/八分之一的pmovsx。

你可以直接从内存中调用pmovsx,尽管内在函数使得它真的很笨拙。由于shuffle吞吐量比大多数CPU上的负载吞吐量更有限,因此最好做两个load + pmovsx而不是一次load +三次shuffle。