我想将两个 512 位 __m512i
相乘16 个无符号 32 位整数组成的 vector 在一起,并且仅从乘法的 64 位结果中取出高 32 位。尽管英特尔内在函数指南说 _mm512_mulhi_epu32
存在,它无法在我的机器上编译。
答案here声称_mm512_srli_epi64(_mm512_mul_epu32(a,b),32)
可以,但不行 - 问题似乎是 _mm512_mul_epu32
仅考虑位 0...31、64...95 等,忽略奇数位置的值。
如何最快地从 32 位 vector 乘法的结果中取出高 32 位?
最佳答案
vpmuludq
又名 _mm512_mul_epu32
采用偶数源 32 位元素(0、2、4 等)1。这使其能够在每个 64 位 block 内高效执行,将输入的低 32 位馈送到 FP 尾数乘法器。这是一个加宽,又称为全乘法,而不是高半乘法,因此它当然必须忽略一些输入(因为没有 SIMD 数学指令有两个 vector 目标。)
因此,您需要使用它两次才能获得所需的所有高半结果:一次使用偶数元素,一次使用偶数位置的奇数元素(右移两个输入 vector ) 。然后您需要交错这些 64 位元素的高半部分。
诀窍在于高效地做到这一点:AVX-512 vpermt2d
从 2 个源 vector 中选取 32 位元素可以在单个微指令中完成工作。所以这很棒,特别是在允许编译器提升洗牌控制 vector 常量负载的循环中。其他选项包括_mm512_mask_shuffle_epi32
( vpshufd
带有合并掩码)将高半部分复制到 1 个 vector 中,并合并到结果的另一个 vector 中,给定 k
中的合并控制登记。 (vpmuludq
结果之一具有您想要的高半部分,因为输入是右移的)。 vmovshdup
( _mm512_mask_movehdup_ps
) 在少 1 个字节的机器代码中执行相同的洗牌操作,无需立即执行。内在函数很不方便,因为你需要强制转换 __m512i
至__m512
与 _mm512_castsi512_ps
,但应该具有相同的性能。
或者甚至存储两次,并对第二次存储进行屏蔽,但这可能很糟糕,因为其中一个存储必须未对齐(因此 64 字节存储的缓存行交叉)。尽管如此,它确实避免了更多的 ALU uops。
更“明显”的选项(就像您对 AVX2 所做的那样)是 vpsrld
( _mm512_srli_epi64(v,32)
) 其中之一,然后 vpblendd
。但这需要 2 个独立的 ALU 微指令,并且在当前 CPU 上使用 512 位 vector 意味着只有 2 个 vector ALU 执行端口可以处理它们。另外,vpblendd
没有 AVX-512 版本;仅存在采用 k
中的控制操作数的混合。登记。 (使用shift/AND和OR合并会更糟,并且仍然需要 vector 常量)
__m512i mulhi_epu32_512(__m512i a, __m512i b)
{
__m512i evens = _mm512_mul_epu32(a,b);
__m512i odds = _mm512_mul_epu32(_mm512_srli_epi64(a,32), _mm512_srli_epi64(b,32));
return _mm512_mask_shuffle_epi32(odds, 0x5555, evens, _MM_SHUFFLE(3,3,1,1));
// _mm512_mask_movehdup_ps may be slightly more efficient, saving 1 byte of code size
}
对于独立函数,clang 将合并屏蔽的随机播放优化为 vpermi2d
使用内存中的 vector 常量,而不是 mov eax, 0x5555
/kmovw k1, eax
管他呢。当包含设置时,微指令会更少,但可能会丢失缓存。 GCC 按编写方式编译它。 https://godbolt.org/z/v4M7PK两者都显示。对于循环体(设置提升),任一方式都是单个 uop,但合并屏蔽 vpshufd
只有 1 个延迟周期,而穿越车道则有 3 个延迟周期 vpermi2d
/vpermt2d
。 ( https://uops.info/ 和 https://agner.org/optimize/ )
脚注 1:您链接的问答要么没有完全描述问题和/或解决方案,要么确实只需要 2 个数字(在 vector 的底部?),而不是 2 数字 vector 。
关于c++ - 将 32 位整数的 vector 相乘,仅取高 32 位,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64852344/