1

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

4

2 回答 2

2

作为构建块,您正在寻找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)));
}
于 2014-08-07T03:55:45.540 回答
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);
于 2014-08-14T08:23:41.013 回答