lscpu和cpuid说我有AVX2,但vpsllvw不起作用
如果我运行lscpu或查看/proc/cpuinfo,他们都说我的处理器支持 AVX2。
$ lscpu | grep -o avx2
avx2
但是,当我vpsllvw在我的代码中使用时,它给出了 SIGILL。
bits 64
global main
section .text
main:
movdqa xmm0, [initial]
vpsllvw xmm0, [shift]
ret
section .data
align 16
initial dw 0,1,2,3,4,5,6,7
shift dw 4,0,4,0,4,0,4,0
组装与 $ nasm -g -felf64 test.asm && g++ -g -m64 test.o
我知道这不是很多信息可以使用,但这是我能想到的全部。
处理器为 Intel Core i5-7200U
解决方案
原来只有 dword 和 qword 版本在 AVX2 中,vpsllvw是 AVX512。
回答
vpsllVw需要 AVX512。 AVX2 只有 dword / qword 每元素变量计数移位。 (并且只有算术右移的双字。 vpsravq也需要 AVX512。)旋转也需要 AVX-512: vprord/vprorvd等等。
这个问题的初始版本是 about vpsllw,指令的 AVX 形式可以追溯到 MMX/SSE2(对所有元素使用相同的计数,从寄存器或内存位置的底部开始,或者作为立即数)。这就是下面的部分。
对于有其他 vpsllw / vpslld / vpsllq 问题(或 VPSLLDQ shuffles)的未来读者,也许您使用了一种vpsllw需要 AVX-512VL的形式(具有即时计数和内存源数据),而您的 CPU 没有。
- AVX1/2(VEX 前缀)允许
vpsllw xmm1, xmm2, imm8(AVX2 允许 ymm) - AVX512(EVEX 前缀)允许
vpsllw xmm1, xmm2/mem, imm8,从内存中转移数据。当然,还有 ymm/zmm 形式。 - AVX1/2 和 AVX512 允许
vpsllw xmm1, xmm2, xmm3/mem128(从内存操作数的低 64 位开始计数)。
所以vpsllw xmm1, [rdi], 1只能用 EVEX 前缀编码,默认情况下 NASM 不会停止或警告你。
(如果你想阻止自己不小心使用 CPU 功能,YASM 可以通过CPU skylake AMD指令来做到这一点(AMD 包含 x86-64 的东西;它不是一个设计良好的系统)。但 YASM 根本不支持 AVX-512最后我检查过,所以这仅适用于在那之前的东西,不适用于各种级别的 AVX-512。我认为也有一些支持使用 NASM 执行此操作,也许使用宏包。GAS 可以进行 CPU 功能检查命令行选项。)
我不知道为什么英特尔选择不以允许AVX1 / 2立即数形式的负载和移位存储器源。该限制似乎完全是任意的,并且没有机器代码编码的原因为什么会出现问题。它使用r/mModRM 中的字段来编码只读源操作数(该指令手动输入的操作数编码表上的“D”行),与 EVEX 形式相同,因此似乎是任意决定进行记忆来源非法而不是允许。(该r字段是额外的操作码位,而 VEX VVVV 字段是目标寄存器。)
在 Sandybridge 设计之前,他们在规划 AVX 时可能是某种历史原因?由于传统 SSE 转移永远无法转移内存,因此 Nehalem CPU 内部不必支持拥有用于这种 uop 的内存源。似乎是一个蹩脚的借口,并且可能并没有给他们带来多少好处,因为 Sandybridge 最终还是显着地重新设计了内部 uop 格式。
imul reg, [mem], imm存在类似形式的指令,尽管它使用 ModRM/r作为目标 reg,而不是作为额外的操作码位(这是它如何使用 VEX 进行编码)。因此,也许没有指令用/r作为额外的操作码位,并使用ModRM:r/m作为只读源操作数,可以是记忆?
普通标量的变化就像shl dword [rdi], 4使用r/m的读写操作数(与/r作为额外的操作码位),像许多单操作数指令8086等neg dword [rdi],所以解码内存操作数连同额外的操作码位来自/r东西解码器已经处理。
似乎糟糕的设计引入了任意的意外限制,使用允许内存源操作数的有点紧凑的机器代码格式破坏了成为 CISC 的意义。幸运的是,他们使用 AVX-512 解决了这个问题,但这会导致在您不打算或不期望的情况下意外使用 AVX-512 的可能性。