将8个16位SSE寄存器转换成8位数据
Convert 8 16 bit SSE register to 8bit data
假设我有一个包含 16 位数据的 SSE 数组:
{1,2,3,4,5,6,7,8}
现在我需要通过在前 8 个字节中仅存储 16 位数据的低字节来将此 SSE 数组转换为 8 位数据,例如:
{1,2,3,4,5,6,7,8,0,0,0,0,0,0,0,0}.
是否有任何SSE指令可以执行此操作?
如@harold says in the comments above, you can do this quite easily with pshufb
aka _mm_shuffle_epi8
,例如
#include <stdio.h>
#include <tmmintrin.h>
static __m128i pack_16_to_8(const __m128i v)
{
const __m128i vperm = _mm_setr_epi8(0, 2, 4, 6, 8, 10, 12, 14, -1, -1, -1, -1, -1, -1, -1, -1);
return _mm_shuffle_epi8(v, vperm);
}
int main(void)
{
const __m128i v = _mm_setr_epi16(1, 2, 3, 4, 5, 6, 7, 8);
printf("%vhd -> %vd\n", v, pack_16_to_8(v));
return 0;
}
编译并运行:
$ gcc -Wall -mssse3 pack_16_to_8.c && ./a.out
1 2 3 4 5 6 7 8 -> 1 2 3 4 5 6 7 8 0 0 0 0 0 0 0 0
Paul К 的补充:
SSE2 扩展包含命令 PACKSSWB(_mm_packs_epi16) and PACKUSWB (_mm_packus_epi16)。这些命令专门用于将 16 位向量转换为 8 位向量。如果这些值超过 8 位无符号整数 (0..255) 的范围,它们会执行 16 位(有符号和无符号)值的饱和。
#include <iostream>
#include <emmintrin.h>
template<class T> inline void Print(const __m128i & v)
{
T b[sizeof(v) / sizeof(T)];
_mm_storeu_si128((__m128i*)b, v);
for (int i = 0; i < sizeof(v) / sizeof(T); i++)
std::cout << int(b[i]) << " ";
std::cout << std::endl;
}
int main()
{
__m128i v16 = _mm_setr_epi16(1, 2, 3, 4, 5, 6, 7, 8);
Print<uint8_t>(_mm_packs_epi16(v16, _mm_setzero_si128()));
Print<uint8_t>(_mm_packus_epi16(v16, _mm_setzero_si128()));
return 0;
}
输出:
1 2 3 4 5 6 7 8 0 0 0 0 0 0 0 0
1 2 3 4 5 6 7 8 0 0 0 0 0 0 0 0
假设我有一个包含 16 位数据的 SSE 数组:
{1,2,3,4,5,6,7,8}
现在我需要通过在前 8 个字节中仅存储 16 位数据的低字节来将此 SSE 数组转换为 8 位数据,例如:
{1,2,3,4,5,6,7,8,0,0,0,0,0,0,0,0}.
是否有任何SSE指令可以执行此操作?
如@harold says in the comments above, you can do this quite easily with pshufb
aka _mm_shuffle_epi8
,例如
#include <stdio.h>
#include <tmmintrin.h>
static __m128i pack_16_to_8(const __m128i v)
{
const __m128i vperm = _mm_setr_epi8(0, 2, 4, 6, 8, 10, 12, 14, -1, -1, -1, -1, -1, -1, -1, -1);
return _mm_shuffle_epi8(v, vperm);
}
int main(void)
{
const __m128i v = _mm_setr_epi16(1, 2, 3, 4, 5, 6, 7, 8);
printf("%vhd -> %vd\n", v, pack_16_to_8(v));
return 0;
}
编译并运行:
$ gcc -Wall -mssse3 pack_16_to_8.c && ./a.out
1 2 3 4 5 6 7 8 -> 1 2 3 4 5 6 7 8 0 0 0 0 0 0 0 0
Paul К 的补充:
SSE2 扩展包含命令 PACKSSWB(_mm_packs_epi16) and PACKUSWB (_mm_packus_epi16)。这些命令专门用于将 16 位向量转换为 8 位向量。如果这些值超过 8 位无符号整数 (0..255) 的范围,它们会执行 16 位(有符号和无符号)值的饱和。
#include <iostream>
#include <emmintrin.h>
template<class T> inline void Print(const __m128i & v)
{
T b[sizeof(v) / sizeof(T)];
_mm_storeu_si128((__m128i*)b, v);
for (int i = 0; i < sizeof(v) / sizeof(T); i++)
std::cout << int(b[i]) << " ";
std::cout << std::endl;
}
int main()
{
__m128i v16 = _mm_setr_epi16(1, 2, 3, 4, 5, 6, 7, 8);
Print<uint8_t>(_mm_packs_epi16(v16, _mm_setzero_si128()));
Print<uint8_t>(_mm_packus_epi16(v16, _mm_setzero_si128()));
return 0;
}
输出:
1 2 3 4 5 6 7 8 0 0 0 0 0 0 0 0
1 2 3 4 5 6 7 8 0 0 0 0 0 0 0 0