AVX2 1x mm256i 32bit 到 2x mm256i 64bit

Posted

技术标签:

【中文标题】AVX2 1x mm256i 32bit 到 2x mm256i 64bit【英文标题】:AVX2 1x mm256i 32bit to 2x mm256i 64bit 【发布时间】:2014-08-07 02:26:52 【问题描述】:

有没有一种正常的方法可以将 1x __m256i 的 32 位整数转换为 2x __m256i 的 64 位整数。我正在平均数据,我的 32 位整数溢出。所以我想把累加器寄存器分成两个64位寄存器。

【问题讨论】:

【参考方案1】:

作为构建块,您正在寻找 VPMULDQ 指令或 _mm256_mul_epi32 内在函数。

这是 32x32 -> 64 乘法,但与您想要的略有不同。在这种情况下,源ymm 寄存器每个都包含四个 32 位值,并输出到四个 64 位值的单个寄存器。

根据英特尔的文档:

DEST[63:0] ← SRC1[31:0] * SRC2[31:0]
DEST[127:64] ← SRC1[95:64] * SRC2[95:64]
DEST[191:128] ← SRC1[159:128] * SRC2[159:128]
DEST[255:192] ← SRC1[223:192] * SRC2[223:192]

所以要获得 8x32 * 8x32 -> 两个 4x64 寄存器,您需要拆分工作:

void mul32to64(__m256i a, __m256i b, __m256i *reshi, __m256i *reslo)

    *reshi = _mm256_mul_epi32(
        _mm256_cvtepi32_epi64(_mm256_extracti128_si256(a, 1)),
        _mm256_cvtepi32_epi64(_mm256_extracti128_si256(b, 1)));

    *reslo = _mm256_mul_epi32(
        _mm256_cvtepi32_epi64(_mm256_castsi256_si128(a)),
        _mm256_cvtepi32_epi64(_mm256_castsi256_si128(b)));

【讨论】:

这不是有点矫枉过正吗?有一个扩展整数的指令。除非我忽略了某些东西,_mm256_cvtepu32_epi64 表示未签名,_mm256_cvtepi32_epi64 表示已签名? 谢谢,显然对 SSE 太累了。【参考方案2】:

我最终使用了 _mm256_unpackhi_epi32 和 _mm256_unpacklo_epi32,参数 b 的值为 0。这是一个仅执行平均的示例。

#define DATA_SIZE 16

__declspec(align(16)) static int buf[] = 
    1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16
;


__m256i zero =  0 ; 
__m256i accumulated =  0 ;

for (int idx = 0; idx < DATA_SIZE; idx = idx + 8)

    //load data from buf
    __m256i int32data = _mm256_load_si256((__m256i*)(buf + idx)); 

    __m256i data2 = _mm256_unpackhi_epi32(int32data, zero); //extract 4 ints
    __m256i data3 = _mm256_unpacklo_epi32(int32data, zero); //extract 4 more

    accumulated = _mm256_add_epi64(accumulated, data2); //accumulate first 4
    accumulated = _mm256_add_epi64(accumulated, data3); //accumulate 2nd 4


__m256i averageVec;
_mm256_store_si256(&averageVec, accumulated); //unload accumulated vector

//calculate the average
long long average = (averageVec.m256i_i64[0] + averageVec.m256i_i64[1]
    + averageVec.m256i_i64[2] + averageVec.m256i_i64[3])
    / DATA_SIZE;

printf("Average is: %d\n", average);

【讨论】:

请注意,您的平均计算是不可移植的 - 它仅适用于 Visual C(因此仅适用于 Windows),这可能适合您的应用程序,但如果您应该注意这一点对编写跨平台代码感兴趣。 你的意思是我使用的是 long long 而不是 __int64? 确实应该是标准类型的可移植性(int64_t - long long__int64 都不是可移植的),但我指的是使用 .m256i_i64[n],是微软主义。

以上是关于AVX2 1x mm256i 32bit 到 2x mm256i 64bit的主要内容,如果未能解决你的问题,请参考以下文章

将 2x4 64b 结构的第一行加载到 AVX2 的 256b 寄存器中的最快方法是啥?

转置 8x8 64 位矩阵

如何使用 avx2 将 24 位 rgb 转换为 32 位?

从 JSON 转换数组中的列 [关闭]

256 位块的 CRC 计算

如何在 AVX2 中将 32 位无符号整数转换为 16 位无符号整数?