【问题标题】:Optimize extraction of 64 bit value from AVX2 register优化从 AVX2 寄存器中提取 64 位值
【发布时间】:2014-01-13 00:55:18
【问题描述】:

我尝试从 __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

以下代码将 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;

代码运行正常,但速度很慢。 看起来将 res1 和 res2 复制到 result_array 需要的时间最多。 有办法优化吗?

【问题讨论】:

    标签: c sse avx avx2


    【解决方案1】:

    可能这个变种会更快

    /* 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));
    

    【讨论】:

    • 我刚刚发现还有一个额外的优化机会:可以将_mm256_castsi256_si128 + _mm256_extracti128_si256 + _mm_or_si128 替换为单个_mm256_permutevar8x32_epi32 以实现另一个延迟周期。
    • 你能告诉我_mm256_castsi256_si128_mm256_castsf256_si128 之间的区别吗?第一个需要 AVX2,第二个只需要 AVX。为什么要使用_mm256_castsi256_si128
    • _mm256_castsi256_si128 是无操作的,只需要AVX。类似地,其他强制转换是无操作的,它们仅在参数/结果类型上有所不同。
    • 对不起,我问错问题了。我的意思是_mm256_extractf128_si256_mm256_extracti128_si256 之间有什么区别。我知道这些强制转换只是为了让编译器高兴。我的意思是stackoverflow.com/questions/25684454/…
    • 英特尔 CPU 传统上具有用于整数和浮点寄存器的单独寄存器文件和数据路径。因此,VEXTRACTI128 可能在 SIMD 内核的整数部分实现并连接到整数 SIMD 寄存器文件,VEXTRACTF128 - 在浮点部分实现并连接到 FP SIMD 寄存器文件。因此,如果您将 VEXTRACTI128 与浮点运算产生的数据一起使用(因此寄存器驻留在 FP 文件中),则在 SIMD 内核的各个部分之间移动数据可能会有几个周期的延迟。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-09-19
    • 2019-04-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-17
    • 2013-03-15
    相关资源
    最近更新 更多