assembly - 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
我知道这不是很多可用的信息,但这是我能想到的。
处理器是英特尔酷睿 i5-7200U
解决方案
原来只有dword和qword版本在AVX2中,vpsllvw
是AVX512。
解决方案
vpsllVw
需要 AVX512。 AVX2 只有 dword / qword per-element-variable-count shifts。 (并且只有 dword 用于算术右移。 vpsravq
也需要 AVX512。)旋转也需要 AVX-512: vprord
/vprorvd
等等。
这个问题的初始版本是关于vpsllw
,可以追溯到 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 立即计数形式的加载和移位内存源。该限制似乎完全是任意的,并且没有机器代码编码的原因会成为问题。它使用r/m
ModRM 中的字段来编码只读源操作数(该指令手动输入的操作数编码表上的“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。
推荐阅读
- java - 如果我初始化一个已经在 JAVA 中初始化的 Class 对象会发生什么?
- terraform - 展平复合地图的输出内容
- python - Excel列数据需要转换成双引号括起来的值列表,然后通过排除开始括号写入json文件
- php - 在 codeigniter 中加入超过 2 个数据库表错误:1066
- azure - 如何在通过 webhook 调用 azure 自动化 runnbook 的 azure 函数中获取响应
- linux - 使用linux命令列出给定小时内目录中的文件
- unix - 使用 SFTP 以二进制模式将大型机文件下载到 Unix
- haskell - 箭头 (->) 作为 haskell 数据构造函数
- javascript - 无法使用 javascript 从输入中计算面积
- c# - Unity我正在尝试制作一个布尔来触发步行和跑步动画,但它们重叠