优化从AVX2寄存器中提取64位值

mar*_*n s 5 c sse avx avx2

我尝试从__m256i寄存器中提取64位.我当前提取功能的示例:

             byte     31                    16 15                    0
byte_result_vec        000D  000C  000B  000A   000H  000G  000F  000E

_mm256_packs_epi32 ->  0D0C  0B0A  0D0C  0B0A   0H0G  0F0E  0H0G  0F0E

_mm256_packus_epi16 -> DCBA  DCBA  DCBA  DCBA   HGFE  HGFE  HGFE  HGFE
                                         ^^^^                     ^^^^
_mm256_castsi256_si128   -> HGFE  HGFE  HGFE  HGFE

_mm256_extracti128_si256 -> DCBA  DCBA  DCBA  DCBA

_mm_cvtsi128_si32(byte_result_vec1) ->  ABCD

_mm_cvtsi128_si32(byte_result_vec2) ->  EFGH
Run Code Online (Sandbox Code Playgroud)

下面的代码将4x8位移到寄存器位置0-3,而不是提取32位.

        byte_result_vec = _mm256_packs_epi32(byte_result_vec, byte_result_vec);
        byte_result_vec = _mm256_packus_epi16(byte_result_vec, byte_result_vec);
        __m128i byte_result_vec1 = _mm256_castsi256_si128(byte_result_vec);
        __m128i byte_result_vec2 = _mm256_extracti128_si256(byte_result_vec,1);
        const int res1 = _mm_cvtsi128_si32(byte_result_vec1);
        const int res2 = _mm_cvtsi128_si32(byte_result_vec2);
        result_array[j]       = res1;
        result_array[j+1]     = res2;
Run Code Online (Sandbox Code Playgroud)

代码工作正常,但速度很慢.看起来将res1和res2复制到result_array需要花费最多的时间.有没有办法优化它?

Mar*_*han 5

可能这个变种会更快

/* byte_result_vec        000H  000G  000F  000E   000D  000C  000B  000A */
const __m256i shuffle_mask = _mm256_setr_epi8(0,  4,  8, 12, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 4, 8, 12, -1, -1, -1, -1, -1, -1, -1, -1);
/* abcdefgh               0000  0000  HGFE  0000   0000  0000  0000  DCBA */
const __m256i abcdefgh = _mm256_shuffle_epi8(byte_result_vec, shuffle_mask);
/* abcd                                            0000  0000  0000  DCBA */
const __m128i abcd = _mm256_castsi256_si128(abcdefgh);
/* efgh                                            0000  0000  HGFE  0000 */
const __m128i efgh = _mm256_extracti128_si256(abcdefgh, 1);
_mm_storel_epi64((__m128i*)&result_array[j], _mm_or_si128(abcd, efgh));
Run Code Online (Sandbox Code Playgroud)

  • 英特尔CPU传统上具有单独的寄存器文件和整数和浮点寄存器的数据路径.因此,`VEXTRACTI128`可以在SIMD内核的整数部分实现并连接到整数SIMD寄存器文件,并且在浮点部分连接到`VEXTRACTF128`并连接到FP SIMD寄存器文件.因此,如果将"VEXTRACTI128"用于由浮点运算产生的数据(因此寄存器驻留在FP文件中),则可能存在几个周期的延迟,以在SIMD核心的各部分之间移动数据. (3认同)