Assembly lscpu和cpuid说我有AVX2,但vpsllvw不工作
如果我运行Assembly lscpu和cpuid说我有AVX2,但vpsllvw不工作,assembly,x86-64,avx2,cpuid,Assembly,X86 64,Avx2,Cpuid,如果我运行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
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。需要AVX512AVX2每个元素只有dword/qword变量计数移位。(并且只有dword用于算术右移。vpsravq
也需要AVX512。)旋转也需要AVX-512:vprord
/vprorvd
等等
这个问题的初始版本是关于可追溯到MMX/SSE2的指令的AVX形式(对所有元素使用相同的计数,从寄存器或内存位置的底部开始,或作为立即数)。这就是下面这部分的内容
对于将来有其他vpsllw/vpslld/vpsllq问题的读者(或VPSLLDQ洗牌),可能您使用了一种形式的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立即计数表加载和移位内存源。这个限制似乎完全是任意的,并且没有机器代码编码的原因来解释为什么它会成为一个问题。它使用ModRM中的r/m
字段对只读源操作数()进行编码,这与EVEX表单相同,因此似乎是任意决定将内存源设置为非法而不是允许它。(其中r
字段为额外的操作码位,VEX VVV字段为目标寄存器。)
可能是在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的可能性。另外,
0x29c67af&(1Oh等一下,您没有使用xmm[mem],immediate
表单,您使用的是xmm,xmm[mem]
form,计数来自内存,使用NASM的速记法,如果第一个源代码与目标代码相同,则可以省略第一个源代码。是的,AVX1也可以。您的问题中仍然没有包含一个出错的代码。因此,让我们知道,我做了一个大蠢事:我一直在说vpsllw,这很好,vpsllvw是专业的问题。而且它似乎是用62
编码的(不确定如何包含它,我只是用x(地址)
从gdb抓取了它)但是vpsllvw
显然是AVX512,不是吗?哦,我的天哪,我正在看,我甚至没有注意到只有dword和qword版本在AVX2上可用,我已经打印了一半(或者至少在我的头脑中计划了)在OP澄清它不是即时形式之前,它肯定是未来读者可能遇到的一个坑,所以我还是写了出来。