c – 在AVX2中重现_mm256_sllv_epi16和_mm256_sllv_epi8

c – 在AVX2中重现_mm256_sllv_epi16和_mm256_sllv_epi8,第1张

概述我很惊讶地看到_mm256_sllv_epi16 / 8(__ m256i v1,__ m256i v2)和_mm256_srlv_epi16 / 8(__ m256i v1,__ m256i v2)不在 Intel Intrinsics Guide中,我找不到任何解决方案来仅用AVX2重新创建AVX512内在函数. 该函数左移所有16/8位打包int由v2中相应数据元素的计数值. epi16的示 我很惊讶地看到_mm256_sllv_epi16 / 8(__ m256i v1,__ m256i v2)和_mm256_srlv_epi16 / 8(__ m256i v1,__ m256i v2)不在 Intel Intrinsics Guide中,我找不到任何解决方案来仅用AVX2重新创建AVX512内在函数.

该函数左移所有16/8位打包int由v2中相应数据元素的计数值.

epi16的示例:

__m256i v1 = _mm256_set1_epi16(0b1111111111111111);__m256i v2 = _mm256_setr_epi16(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15);v1 = _mm256_sllv_epi16(v1,v2);

然后v1等于 – > (1111111111111111,
                     1111111111111110,
                     1111111111111100,
                     1111111111111000,
                     …………….,
                     千万亿);

解决方法 在_mm256_sllv_epi8情况下,使用pshufb指令作为一个小的查找表,用乘法替换移位并不太困难.也可以通过乘法和其他一些指令来模拟_mm256_srlv_epi8的正确移位,请参阅下面的代码.我希望至少_mm256_sllv_epi8比Nyan的 solution更有效率.

或多或少相同的想法可用于模拟_mm256_sllv_epi16,但在这种情况下,选择正确的乘数(参见下面的代码)则不那么简单.

下面的解决方案_mm256_sllv_epi16_emu不一定比Nyan的solution更快,也更好.
性能取决于周围的代码和使用的cpu.
然而,这里的解决方案可能是有意义的,至少在较旧的计算机系统上.
例如,vpsllvd指令在Nyan的解决方案中使用了两次.此指令在英特尔Skylake系统或更新版本上很快.
在Intel broaDWell或Haswell上,此指令很慢,因为它解码为3个微 *** 作.这里的解决方案避免了这种缓慢的指令.

如果已知移位计数小于或等于15,则可以使用mask_lt_15跳过两行代码.

缺少内在的_mm256_srlv_epi16留给读者练习.

/*     gcc -O3 -m64 -Wall -mavx2 -march=broaDWell shift_v_epi8.c     */#include <immintrin.h>#include <stdio.h>int print_epi8(__m256i  a);int print_epi16(__m256i  a);__m256i _mm256_sllv_epi8(__m256i a,__m256i count) {    __m256i mask_hi        = _mm256_set1_epi32(0xFF00FF00);    __m256i multiplIEr_lut = _mm256_set_epi8(0,128,64,32,16,1);    __m256i count_sat      = _mm256_min_epu8(count,_mm256_set1_epi8(8));     /* AVX shift counts are not masked. So a_i << n_i = 0 for n_i >= 8. count_sat is always less than 9.*/     __m256i multiplIEr     = _mm256_shuffle_epi8(multiplIEr_lut,count_sat);  /* Select the right multiplication factor in the lookup table.                                      */    __m256i x_lo           = _mm256_mullo_epi16(a,multiplIEr);               /* Unfortunately _mm256_mullo_epi8 doesn't exist. Split the 16 bit elements in a high and low part. */    __m256i multiplIEr_hi  = _mm256_srli_epi16(multiplIEr,8);                /* The multiplIEr of the high bits.                                                                 */    __m256i a_hi           = _mm256_and_si256(a,mask_hi);                    /* Mask off the low bits.                                                                           */    __m256i x_hi           = _mm256_mullo_epi16(a_hi,multiplIEr_hi);    __m256i x              = _mm256_blendv_epi8(x_lo,x_hi,mask_hi);         /* Merge the high and low part.                                                                     */            return x;}__m256i _mm256_srlv_epi8(__m256i a,128);    __m256i count_sat      = _mm256_min_epu8(count,_mm256_set1_epi8(8));     /* AVX shift counts are not masked. So a_i >> n_i = 0 for n_i >= 8. count_sat is always less than 9.*/     __m256i multiplIEr     = _mm256_shuffle_epi8(multiplIEr_lut,count_sat);  /* Select the right multiplication factor in the lookup table.                                      */    __m256i a_lo           = _mm256_andnot_si256(mask_hi,a);                 /* Mask off the high bits.                                                                          */    __m256i multiplIEr_lo  = _mm256_andnot_si256(mask_hi,multiplIEr);        /* The multiplIEr of the low bits.                                                                  */    __m256i x_lo           = _mm256_mullo_epi16(a_lo,multiplIEr_lo);         /* Shift @R_301_6823@ a_lo by multiplying.                                                                  */            x_lo           = _mm256_srli_epi16(x_lo,7);                      /* Shift right by 7 to get the low bits at the right position.                                      */    __m256i multiplIEr_hi  = _mm256_and_si256(mask_hi,multiplIEr);           /* The multiplIEr of the high bits.                                                                 */    __m256i x_hi           = _mm256_mulhi_epu16(a,multiplIEr_hi);            /* Variable shift @R_301_6823@ a_hi by multiplying. Use a instead of a_hi because the a_lo bits don't interfere */            x_hi           = _mm256_slli_epi16(x_hi,1);                      /* Shift @R_301_6823@ by 1 to get the high bits at the right position.                                      */    __m256i x              = _mm256_blendv_epi8(x_lo,mask_hi);         /* Merge the high and low part.                                                                     */            return x;}__m256i _mm256_sllv_epi16_emu(__m256i a,__m256i count) {    __m256i multiplIEr_lut = _mm256_set_epi8(0,1);    __m256i byte_shuf_mask = _mm256_set_epi8(14,0);    __m256i mask_lt_15     = _mm256_cmpgt_epi16(_mm256_set1_epi16(16),count);            a              = _mm256_and_si256(mask_lt_15,a);                    /* Set a to zero if count > 15.                                                                      */            count          = _mm256_shuffle_epi8(count,byte_shuf_mask);         /* Duplicate bytes from the even postions to bytes at the even and odd positions.                    */            count          = _mm256_sub_epi8(count,_mm256_set1_epi16(0x0800));   /* Subtract 8 at the even byte positions. Note that the vpshufb instruction selects a zero byte if the shuffle control mask is negative.     */    __m256i multiplIEr     = _mm256_shuffle_epi8(multiplIEr_lut,count);         /* Select the right multiplication factor in the lookup table. Within the 16 bit elements,only the upper byte or the lower byte is nonzero. */    __m256i x              = _mm256_mullo_epi16(a,multiplIEr);                              return x;}int main(){    printf("Emulating _mm256_sllv_epi8:\n");    __m256i a     = _mm256_set_epi8(32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,15,1);    __m256i count = _mm256_set_epi8(7,0);    __m256i x     = _mm256_sllv_epi8(a,count);    printf("a     = \n"); print_epi8(a    );    printf("count = \n"); print_epi8(count);    printf("x     = \n"); print_epi8(x    );    printf("\n\n");     printf("Emulating _mm256_srlv_epi8:\n");            a     = _mm256_set_epi8(223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254);            count = _mm256_set_epi8(7,0);            x     = _mm256_srlv_epi8(a,count);    printf("a     = \n"); print_epi8(a    );    printf("count = \n"); print_epi8(count);    printf("x     = \n"); print_epi8(x    );    printf("\n\n");     printf("Emulating _mm256_sllv_epi16:\n");            a     = _mm256_set_epi16(1601,1501,1401,1301,1200,1100,1000,900,800,700,600,500,400,300,200,100);            count = _mm256_set_epi16(17,0);            x     = _mm256_sllv_epi16_emu(a,count);    printf("a     = \n"); print_epi16(a    );    printf("count = \n"); print_epi16(count);    printf("x     = \n"); print_epi16(x    );    printf("\n\n");     return 0;}int print_epi8(__m256i  a){  char v[32];  int i;  _mm256_storeu_si256((__m256i *)v,a);  for (i = 0; i<32; i++) printf("%4hhu",v[i]);  printf("\n");  return 0;}int print_epi16(__m256i  a){  unsigned short int  v[16];  int i;  _mm256_storeu_si256((__m256i *)v,a);  for (i = 0; i<16; i++) printf("%6hu",v[i]);  printf("\n");  return 0;}

输出是:

Emulating _mm256_sllv_epi8:a     =    1   2   3   4   5   6   7   8   9  10  11  12  13  14  15  16  17  18  19  20  21  22  23  24  25  26  27  28  29  30  31  32count =    0   1   2   3   4   5   6   7   8   9  10  11   0   1   2   3   4   5   6   7   8   9  10  11   0   1   2   3   4   5   6   7x     =    1   4  12  32  80 192 192   0   0   0   0   0  13  28  60 128  16  64 192   0   0   0   0   0  25  52 108 224 208 192 192   0Emulating _mm256_srlv_epi8:a     =  254 253 252 251 250 249 248 247 246 245 244 243 242 241 240 239 238 237 236 235 234 233 232 231 230 229 228 227 226 225 224 223count =    0   1   2   3   4   5   6   7   8   9  10  11   0   1   2   3   4   5   6   7   8   9  10  11   0   1   2   3   4   5   6   7x     =  254 126  63  31  15   7   3   1   0   0   0   0 242 120  60  29  14   7   3   1   0   0   0   0 230 114  57  28  14   7   3   1Emulating _mm256_sllv_epi16:a     =    100   200   300   400   500   600   700   800   900  1000  1100  1200  1301  1401  1501  1601count =      0     1     2     3     4     5     6     7     8     9    10    11    13    15    16    17x     =    100   400  1200  3200  8000 19200 44800 36864 33792 53248 12288 32768 40960 32768     0     0

确实缺少一些AVX2指令.但请注意,通过模拟“缺失的”AVX2指令来填补这些空白并不总是一个好主意.有时它是更有效地重新设计代码,以避免这些模拟指令.例如,通过使用更宽的向量元素(_epi32而不是_epi16),具有原生支持.

总结

以上是内存溢出为你收集整理的c – 在AVX2中重现_mm256_sllv_epi16和_mm256_sllv_epi8全部内容,希望文章能够帮你解决c – 在AVX2中重现_mm256_sllv_epi16和_mm256_sllv_epi8所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/1212063.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-04
下一篇 2022-06-04

发表评论

登录后才能评论

评论列表(0条)

保存