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

时间:2014-08-07 02:26:53

标签: c simd avx2

是否有正常的方法将1x __m256i(32位整数)转换为2x __m256i,填充64位整数。我平均数据,我的32位整数溢出。所以我想将累加器寄存器分成两个64位寄存器。

2 个答案:

答案 0 :(得分:2)

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

这是32x32 - > 64乘法,但与你想要的略有不同。在这种情况下,源ymm寄存器每个包含4个32位值,并输出到4个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)));
}

答案 1 :(得分:0)

我最终使用_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);