Pin*_*oyd 5 c x86-64 intrinsics avx avx2
对于研究问题,我需要使用 AVX2/AVX 指令实现非常高效的 4 位乘法(仅需要低 4 位)。
我目前的做法是:
__m256i _mm256_mullo_epi4(const __m256i a, const __m256i b) {
__m256i mask_f_0 = _mm256_set1_epi16(0x000f);
__m256i tmp_mul_0 = _mm256_and_si256(_mm256_mullo_epi16(a, b), mask_f_0);
__m256i tmp_mul_1 = _mm256_and_si256(_mm256_mullo_epi16(_mm256_srli_epi16(a, 4), _mm256_srli_epi16(b, 4)), mask_f_0);
__m256i tmp_mul_2 = _mm256_and_si256(_mm256_mullo_epi16(_mm256_srli_epi16(a, 8), _mm256_srli_epi16(b, 8)), mask_f_0);
__m256i tmp_mul_3 = _mm256_and_si256(_mm256_mullo_epi16(_mm256_srli_epi16(a, 12), _mm256_srli_epi16(b, 12)), mask_f_0);
__m256i tmp1 = _mm256_xor_si256(tmp_mul_0, _mm256_slli_epi16(tmp_mul_1, 4));
__m256i tmp2 = _mm256_xor_si256(tmp1, _mm256_slli_epi16(tmp_mul_2, 8));
__m256i tmp = _mm256_xor_si256(tmp2, _mm256_slli_epi16(tmp_mul_3, 12));
return tmp;
}
Run Code Online (Sandbox Code Playgroud)
此实现利用相对昂贵的_mm256_mullo_epi16指令 4 次来limb单独计算每个 4 位。这可以以某种方式更快地完成吗?更准确地说:是否可以减少所需指令的数量?
我没有看到一种明显的方法来减少乘法次数,例如,屏蔽两个输入的足够字节以通过一次乘法获得两个单独的乘积。Evenvpmaddubsw很难利用,因为它需要一个操作数作为带符号的 8 位值(并且需要大量移位才能将半字节置于正确的位置)。
但是,您可以减少移动量,但需要进行更多屏蔽:
伪代码:
(a*b) & 0xf = 0,0,0,ab
(a>>4)*(b&0xf0) = *,*,ab,0
(a>>8)*(b&0xf00) = *,ab,0,0
(a>>12)*(b&0xf000) = ab,0,0,0
Run Code Online (Sandbox Code Playgroud)
使用内在函数(未经测试):
__m256i _mm256_mullo_epi4(const __m256i a, const __m256i b) {
__m256i mask_000f = _mm256_set1_epi16(0x000f);
__m256i mask_00f0 = _mm256_set1_epi16(0x00f0);
__m256i mask_0f00 = _mm256_set1_epi16(0x0f00);
__m256i mask_f000 = _mm256_set1_epi16(0xf000);
__m256i tmp_mul_0 = _mm256_and_si256(_mm256_mullo_epi16(a, b), mask_000f);
__m256i tmp_mul_1 = _mm256_and_si256(_mm256_mullo_epi16(_mm256_srli_epi16(a, 4), _mm256_and_si256(b, mask_00f0)), mask_00f0);
__m256i tmp_mul_2 = _mm256_and_si256(_mm256_mullo_epi16(_mm256_srli_epi16(a, 8), _mm256_and_si256(b, mask_0f00)), mask_0f00);
__m256i tmp_mul_3 = _mm256_mullo_epi16(_mm256_srli_epi16(a, 12), _mm256_and_si256(b, mask_f000));
__m256i tmp1 = _mm256_xor_si256(tmp_mul_0, tmp_mul_1);
__m256i tmp2 = _mm256_xor_si256(tmp_mul_2, tmp_mul_3);
__m256i tmp = _mm256_xor_si256(tmp1, tmp2);
return tmp;
}
Run Code Online (Sandbox Code Playgroud)
与 4 次乘法、9 次移位和 7 位操作相比,这需要 4 次乘法和 3 次移位,但需要 9 次位操作(从技术上讲,屏蔽tmp_mul_3是不必要的,编译器可能能够将其优化掉)。
所以总共是 16 个微指令,而不是 19 个。
| 归档时间: |
|
| 查看次数: |
155 次 |
| 最近记录: |