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