移位n位的__m128i

我有一个__m128i变量,我需要将其n位的128位值移位,即_mm_srli_si128_mm_slli_si128工作,但是在位而不是字节上。 这样做最有效的方法是什么?

这是我用SSE2进行左/右立即换档的最好方法:

 #include  #include  #define SHL128(v, n) \ ({ \ __m128i v1, v2; \ \ if ((n) >= 64) \ { \ v1 = _mm_slli_si128(v, 8); \ v1 = _mm_slli_epi64(v1, (n) - 64); \ } \ else \ { \ v1 = _mm_slli_epi64(v, n); \ v2 = _mm_slli_si128(v, 8); \ v2 = _mm_srli_epi64(v2, 64 - (n)); \ v1 = _mm_or_si128(v1, v2); \ } \ v1; \ }) #define SHR128(v, n) \ ({ \ __m128i v1, v2; \ \ if ((n) >= 64) \ { \ v1 = _mm_srli_si128(v, 8); \ v1 = _mm_srli_epi64(v1, (n) - 64); \ } \ else \ { \ v1 = _mm_srli_epi64(v, n); \ v2 = _mm_srli_si128(v, 8); \ v2 = _mm_slli_epi64(v2, 64 - (n)); \ v1 = _mm_or_si128(v1, v2); \ } \ v1; \ }) int main(void) { __m128i va = _mm_setr_epi8(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f); __m128i vb, vc; vb = SHL128(va, 4); vc = SHR128(va, 4); printf("va = %02vx\n", va); printf("vb = %02vx\n", vb); printf("vc = %02vx\n", vc); printf("\n"); vb = SHL128(va, 68); vc = SHR128(va, 68); printf("va = %02vx\n", va); printf("vb = %02vx\n", vb); printf("vc = %02vx\n", vc); return 0; } 

测试:

 $ gcc -Wall -msse2 shift128.c && ./a.out va = 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f vb = 00 10 20 30 40 50 60 70 80 90 a0 b0 c0 d0 e0 f0 vc = 10 20 30 40 50 60 70 80 90 a0 b0 c0 d0 e0 f0 00 va = 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f vb = 00 00 00 00 00 00 00 00 00 10 20 30 40 50 60 70 vc = 90 a0 b0 c0 d0 e0 f0 00 00 00 00 00 00 00 00 00 $ 

请注意,SHL128 / SHR128宏是使用gcc,clang和其他一些编译器支持的gcc扩展实现的,但如果编译器不支持此扩展,则需要对这些宏进行调整。

另请注意,测试工具中使用的SIMD类型的printf扩展适用于Apple gcc,clang ,但如果您的编译器不支持此function并且您想要测试代码,那么您需要实现自己的SIMD打印例程。

关于性能的注意事项 – 只要n是编译时常量(无论如何都需要移位内在函数),if / else分支将得到优化,因此你有2条指令用于n> = 64的情况和4条指令对于n <64的情况。