SSE:如何将 _m128i._i32[4] 减少到 _m128i._i8
SSE: How to reduce a _m128i._i32[4] to _m128i._i8
我是 SSE 的新手 - 编码:我想将 _m128i[4] 与 int32 类型的结果存储到一个 _m128i 与 int8 类型。 (_m128i[j]._i32[k]的值都在(-127和+127)
之间
我认为伪代码如下:
result._i8 = {
vec1._i8[0], vec1._i8[4], vec1._i8[8], vec1._i8[12],
vec2._i8[0], vec2._i8[4], vec2._i8[8], vec2._i8[12],
vec3._i8[0], vec3._i8[4], vec3._i8[8], vec3._i8[12],
vec4._i8[0], vec4._i8[4], vec4._i8[8], vec4._i8[12]};
我找到的唯一方法就是这种混乱的洗牌。
__m128i mmResult, mmResult0_3, mmResult4_7, mmResult8_11, mmResult12_15;
//some calculation ...
__m128i mmShuffler0_3 = _mm_set_epi8(-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,-1,12, 8, 4, 0);
__m128i mmShuffler4_7 = _mm_set_epi8(-1, -1, -1, -1, -1, -1, -1, -1, 12, 8, 4, 0, -1, -1, -1, -1);
__m128i mmShuffler8_11 = _mm_set_epi8(-1, -1, -1, -1, 12, 8, 4, 0, -1, -1, -1, -1, -1, -1, -1, -1);
__m128i mmShuffler12_15 = _mm_set_epi8(12, 8, 4, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1);
mmResult0_3 = _mm_shuffle_epi8(mmResult0_3, mmShuffler0_3);
mmResult4_7 = _mm_shuffle_epi8(mmResult4_7, mmShuffler4_7);
mmResult8_11 = _mm_shuffle_epi8(mmResult8_11, mmShuffler8_11);
mmResult12_15 = _mm_shuffle_epi8(mmResult12_15, mmShuffler12_15);
mmResult = _mm_or_si128(_mm_or_si128(mmResult0_3, mmResult4_7), _mm_or_si128(mmResult8_11, mmResult12_15));
有没有这样做得更漂亮的?
有没有更快的方法?
您可以只使用打包操作将 32 位值减少到 8 位,例如假设你有 4 个 32 位 int
元素的向量,v0
...v3
:
__m128i v01 = _mm_packs_epi32(v0, v1); // pack v0, v1 to 16 bits
__m128i v23 = _mm_packs_epi32(v2, v3); // pack v2, v3 to 16 bits
__m128i v0123 = _mm_packs_epi16(v01, v23); // pack v0...v3 to 8 bits
示例:
#include <xmmintrin.h>
#include <stdio.h>
int main(void)
{
__m128i v0 = _mm_setr_epi32(-8, -7, -6, -5);
__m128i v1 = _mm_setr_epi32(-4, -3, -2, -1);
__m128i v2 = _mm_setr_epi32( 0, 1, 2, 3);
__m128i v3 = _mm_setr_epi32( 4, 5, 6, 7);
printf("v0 = %vld\n", v0);
printf("v1 = %vld\n", v1);
printf("v2 = %vld\n", v2);
printf("v3 = %vld\n", v3);
__m128i v01 = _mm_packs_epi32(v0, v1); // pack v0, v1 to 16 bits
__m128i v23 = _mm_packs_epi32(v2, v3); // pack v2, v3 to 16 bits
__m128i v0123 = _mm_packs_epi16(v01, v23); // pack v0...v3 to 8 bits
printf("v0123 = %vd\n", v01234);
return 0;
}
编译测试:
$ gcc -Wall pack_32_8.c && ./a.out
v0 = -8 -7 -6 -5
v1 = -4 -3 -2 -1
v2 = 0 1 2 3
v3 = 4 5 6 7
v0123 = -8 -7 -6 -5 -4 -3 -2 -1 0 1 2 3 4 5 6 7
我是 SSE 的新手 - 编码:我想将 _m128i[4] 与 int32 类型的结果存储到一个 _m128i 与 int8 类型。 (_m128i[j]._i32[k]的值都在(-127和+127)
之间我认为伪代码如下:
result._i8 = {
vec1._i8[0], vec1._i8[4], vec1._i8[8], vec1._i8[12],
vec2._i8[0], vec2._i8[4], vec2._i8[8], vec2._i8[12],
vec3._i8[0], vec3._i8[4], vec3._i8[8], vec3._i8[12],
vec4._i8[0], vec4._i8[4], vec4._i8[8], vec4._i8[12]};
我找到的唯一方法就是这种混乱的洗牌。
__m128i mmResult, mmResult0_3, mmResult4_7, mmResult8_11, mmResult12_15;
//some calculation ...
__m128i mmShuffler0_3 = _mm_set_epi8(-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,-1,12, 8, 4, 0);
__m128i mmShuffler4_7 = _mm_set_epi8(-1, -1, -1, -1, -1, -1, -1, -1, 12, 8, 4, 0, -1, -1, -1, -1);
__m128i mmShuffler8_11 = _mm_set_epi8(-1, -1, -1, -1, 12, 8, 4, 0, -1, -1, -1, -1, -1, -1, -1, -1);
__m128i mmShuffler12_15 = _mm_set_epi8(12, 8, 4, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1);
mmResult0_3 = _mm_shuffle_epi8(mmResult0_3, mmShuffler0_3);
mmResult4_7 = _mm_shuffle_epi8(mmResult4_7, mmShuffler4_7);
mmResult8_11 = _mm_shuffle_epi8(mmResult8_11, mmShuffler8_11);
mmResult12_15 = _mm_shuffle_epi8(mmResult12_15, mmShuffler12_15);
mmResult = _mm_or_si128(_mm_or_si128(mmResult0_3, mmResult4_7), _mm_or_si128(mmResult8_11, mmResult12_15));
有没有这样做得更漂亮的? 有没有更快的方法?
您可以只使用打包操作将 32 位值减少到 8 位,例如假设你有 4 个 32 位 int
元素的向量,v0
...v3
:
__m128i v01 = _mm_packs_epi32(v0, v1); // pack v0, v1 to 16 bits
__m128i v23 = _mm_packs_epi32(v2, v3); // pack v2, v3 to 16 bits
__m128i v0123 = _mm_packs_epi16(v01, v23); // pack v0...v3 to 8 bits
示例:
#include <xmmintrin.h>
#include <stdio.h>
int main(void)
{
__m128i v0 = _mm_setr_epi32(-8, -7, -6, -5);
__m128i v1 = _mm_setr_epi32(-4, -3, -2, -1);
__m128i v2 = _mm_setr_epi32( 0, 1, 2, 3);
__m128i v3 = _mm_setr_epi32( 4, 5, 6, 7);
printf("v0 = %vld\n", v0);
printf("v1 = %vld\n", v1);
printf("v2 = %vld\n", v2);
printf("v3 = %vld\n", v3);
__m128i v01 = _mm_packs_epi32(v0, v1); // pack v0, v1 to 16 bits
__m128i v23 = _mm_packs_epi32(v2, v3); // pack v2, v3 to 16 bits
__m128i v0123 = _mm_packs_epi16(v01, v23); // pack v0...v3 to 8 bits
printf("v0123 = %vd\n", v01234);
return 0;
}
编译测试:
$ gcc -Wall pack_32_8.c && ./a.out
v0 = -8 -7 -6 -5
v1 = -4 -3 -2 -1
v2 = 0 1 2 3
v3 = 4 5 6 7
v0123 = -8 -7 -6 -5 -4 -3 -2 -1 0 1 2 3 4 5 6 7