1

我正在对 A/D 以 16 位值 A1B1A2B2 的顺序 12 位样本形式返回的数据进行插值...兼容的)。我的插值器采用 4 个连续值作为输入,它们作为 uint16 加载,然后作为浮点处理:

        //channel 1 input samples - 32 bit aligned
        UINT16 a3 = linedata[pos - 6] & 0x0FFF;     
        UINT16 a2 = linedata[pos - 4] & 0x0FFF;
        UINT16 a1 = linedata[pos - 2] & 0x0FFF;
        UINT16 a0 = linedata[pos]     & 0x0FFF;

        //channel 2 input samples
        UINT16 b3 = linedata[pos - 5] & 0x0FFF;
        UINT16 b2 = linedata[pos - 3] & 0x0FFF;
        UINT16 b1 = linedata[pos - 1] & 0x0FFF;
        UINT16 b0 = linedata[pos + 1] & 0x0FFF;

为了矢量化,我一次运行 4 对 AB 样本(如果插值接近,它们可能会重叠),旨在填充 256 位 AVX 寄存器,对应于 0、1、2 和 3 插值的 8 个唯一样本像这样的系数:

记忆

虽然处理和保存很简单,但我想不出一种有效的方法来解压缩 16 位样本,然后将它们混洗到向量中。我最终不得不将它们加载到包含相同输出样本的 4 对 A/B 系数的向量中,然后执行多个 shuffle/permute 循环以转换为最终形状:

//load all 8 coefficients for each sample pair at once
__m128i zero2 = _mm_lddqu_si128((__m128i const*)&(linedata[pos - 6]));
__m128i zero2_2 = _mm_lddqu_si128((__m128i const*)&(linedata[pos2 - 6]));
__m128i zero2_3 = _mm_lddqu_si128((__m128i const*) & (linedata[pos3 - 6]));
__m128i zero2_4 = _mm_lddqu_si128((__m128i const*) & (linedata[pos4 - 6]));

//now convert u16 to to 32 bit ints
__m256i zero3 = _mm256_cvtepu16_epi32(zero2);
__m256i zero3_2 = _mm256_cvtepu16_epi32(zero2_2);
__m256i zero3_3 = _mm256_cvtepu16_epi32(zero2_3);
__m256i zero3_4 = _mm256_cvtepu16_epi32(zero2_4);

//and off the upper 4 bits to be safe since we have 12 bit values
zero3 = _mm256_and_si256(zero3, constant_mask);
zero3_2 = _mm256_and_si256(zero3_2, constant_mask);
zero3_3 = _mm256_and_si256(zero3_3, constant_mask);
zero3_4 = _mm256_and_si256(zero3_4, constant_mask);

//convert to float32
__m256 A = _mm256_cvtepi32_ps(zero3);
__m256 B = _mm256_cvtepi32_ps(zero3_2);
__m256 C = _mm256_cvtepi32_ps(zero3_3);
__m256 D = _mm256_cvtepi32_ps(zero3_4);

//shuffle and then permute into separate vectors
__m256 tempshuffle1 = _mm256_shuffle_ps(C, A, _MM_SHUFFLE(3, 2, 3, 2));
__m256 tempshuffle2 = _mm256_shuffle_ps(D, B, _MM_SHUFFLE(3, 2, 3, 2));
__m256 temppermute1 = _mm256_permutevar8x32_ps(tempshuffle1, _mm256_set_epi32(7, 6, 3, 2, 5, 4, 1, 0));
__m256 temppermute2 = _mm256_permutevar8x32_ps(tempshuffle2, _mm256_set_epi32(7, 6, 3, 2, 5, 4, 1, 0));
__m256 zero = _mm256_shuffle_ps(temppermute2, temppermute1, _MM_SHUFFLE(3, 2, 3, 2));
__m256 two = _mm256_shuffle_ps(temppermute2, temppermute1, _MM_SHUFFLE(1, 0, 1, 0));

__m256 tempshuffle3 = _mm256_shuffle_ps(C, A, _MM_SHUFFLE(1, 0, 1, 0));
__m256 tempshuffle4 = _mm256_shuffle_ps(D, B, _MM_SHUFFLE(1, 0, 1, 0));
__m256 temppermute3 = _mm256_permutevar8x32_ps(tempshuffle3, _mm256_set_epi32(7, 6, 3, 2, 5, 4, 1, 0));
__m256 temppermute4 = _mm256_permutevar8x32_ps(tempshuffle4, _mm256_set_epi32(7, 6, 3, 2, 5, 4, 1, 0));
__m256 one = _mm256_shuffle_ps(temppermute4, temppermute3, _MM_SHUFFLE(3, 2, 3, 2));
__m256 three = _mm256_shuffle_ps(temppermute4, temppermute3, _MM_SHUFFLE(1, 0, 1, 0));

//zero, one, two and three vectors now contain values to be interpolated with from 8 independent samples (4 pairs)

这最终的速度大约是 c 版本的 3 倍,但是查看程序集,上面编译的内容比实际处理和写出数据的代码组合的时间要长。是否有更有效的策略可用于将数据加载和改组到向量中?

4

0 回答 0