SSE/AVX - VMULPD 为小整数输入生成全零?

SSE/AVX - VMULPD produces all zeros for small integer inputs?

我正在使用 X64dbg 测试 SSE/AVX 汇编指令,以便在使用它们编写代码之前更好地了解它们的行为。我已经能够以这种方式毫无问题地测试 vmovapd、vbroadcastsd、vsubpd 和 vaddpd 指令。

我加载了 YMM 寄存器如下:

YMM0: 0000000000000004000000000000000400000000000000040000000000000004
YMM1: 0000000000000002000000000000000200000000000000020000000000000002
YMM2: 0101010101010101010101010101010101010101010101010101010101010101

然后,我执行这条指令:

VMULPD ymm2, ymm1, ymm0

我正在尝试将 YMM0 与 YMM1 相乘,并将结果存储在 YMM2 中,但是在我执行此指令后,YMM2 包含以下内容:

0000000000000000000000000000000000000000000000000000000000000000

但我希望这样:

0000000000000008000000000000000800000000000000080000000000000008
(That's four 8's from 4.0 * 2.0)

根据第 798 页的 Intel 64 and IA-32 Software Developer's Manual,这应该有效:

VMULPD ymm1, ymm2, ymm3/m256

Multiply packed double-precision floating-point values 
in ymm3/m256 with ymm2 and store result in ymm1.

那么我在这里错过了什么?

您加载的值表示异常(非常小)doubles。他们的产品下溢到 +0.0,即使没有启用 FTZ / DAZ(刷新为零/非正规零)。

顺便说一句,将 0 写入 ymm2 不是 "does nothing"。 VMULPD 的目标操作数是只写的,因此看到它从您加载的调试标记变为全零证明它确实做了一些事情。


如果您正在寻找 64 位压缩整数乘法,那就太难了。 AVX2 没有打包的 64 位乘法。它确实具有 32x32 -> 64 位乘法 (vpmuludq) 和打包 32x32 -> 32 位(VPMULLD 在许多 CPU 上为 2 微指令)。使用 AVX2 向量化 64x64 -> 64 位乘法 可能 有利可图,参见

AVX512 有 64x64 -> 64 位乘法。

如果您的整数(及其乘积)可以用 double 精确表示,那么使用压缩转换到 double 并在其上使用 vmulpd 可能是值得的,因为硬件具有出色的 add / mul / FMA with packed double 吞吐量。 (Haswell/Skylake:每个时钟 2 个向量,vpmulld 好很多


有趣的事实:

IEEE float/double 有一个有趣的 属性(除了符号位)作为整数进行比较 "works"。这就是指数有偏差的原因,因此将 1 加到二进制表示中的整数会产生下一个可表示的值。 (在 SSE 上实施 nextafterf 很有趣;I looked at it a while ago 但从来没有抽出时间发送补丁。)

另请参阅 https://www.h-schmidt.net/FloatConverter/IEEE754.html for int -> float binary representation. (for single-precision, but https://en.wikipedia.org/wiki/Double-precision_floating-point_formatIEEE binary64 与 binary32 的工作原理相同。)