问题描述
嗨,我正在尝试使用这些标志在没有任何avx512指令的情况下进行构建:
-march=native -mno-avx512f
。
但是我仍然得到一个二进制文件
生成了AVX512(vmovss
)指令(我正在使用elfx86exts进行检查)。
知道如何禁用这些功能吗?
解决方法
-march=native -mno-avx512f
是正确的选项,vmovss
仅需要AVX1。
有 个vmovss
的AVX512F EVEX编码,但是除非涉及的寄存器为xmm16..31
,否则GAS不会使用它。当您使用-mno-avx512f
禁用AVX512F时,或者不首先使用-march=skylake
或-march=znver2
之类的功能来启用GCC时,GCC不会使用这些寄存器发出asm。
如果仍然不确定,请检查实际的反汇编+机器代码,以查看该指令以什么前缀开头:
-
C5
或C4
字节:2或3字节VEX前缀的开头,AVX1编码。 -
62
字节:EVEX前缀的开头,AVX512F编码
示例:
.intel_syntax noprefix
vmovss xmm15,[rdi]
vmovss xmm15,[r11]
vmovss xmm16,[rdi]
用gcc -c avx.s
组装,用objdump -drwC -Mintel avx.o
分解:
0000000000000000 <.text>:
0: c5 7a 10 3f vmovss xmm15,DWORD PTR [rdi] # AVX1
4: c4 41 7a 10 3b vmovss xmm15,DWORD PTR [r11] # AVX1
9: 62 e1 7e 08 10 07 vmovss xmm16,DWORD PTR [rdi] # AVX512F
在10
操作码之前的2和3字节VEX,以及4字节EVEX前缀。 (ModRM字节也不同; xmm0和xmm16的区别仅在于前缀的额外寄存器位,而不是modrm)。
GAS在可能的情况下使用vmovss
的AVX1 VEX编码和其他指令。因此,您可以指望使用非AVX512F格式的指令随时使用非AVX512F格式。可能。这就是GNU工具链(由GCC使用)如何使-mno-avx512f
起作用。
即使EVEX编码较短,这也适用 。例如当[reg + constant]
可以使用AVX512缩放后的disp8(按元素宽度缩放),但AVX1编码需要32位位移(以字节为单位)时。
f: c5 7a 10 bf 00 01 00 00 vmovss xmm15,DWORD PTR [rdi+0x100] # AVX1 [reg+disp32]
17: 62 e1 7e 08 10 47 40 vmovss xmm16,DWORD PTR [rdi+0x100] # AVX512 [reg + disp8*4]
1e: c5 78 28 bf 00 01 00 00 vmovaps xmm15,XMMWORD PTR [rdi+0x100] # AVX1 [reg+disp32]
26: 62 e1 7c 08 28 47 10 vmovaps xmm16,XMMWORD PTR [rdi+0x100] # AVX512 [reg + disp8*16]
请注意机器代码编码的最后一个字节或最后4个字节:对于AVX1编码,它是32位的小尾数0x100字节位移,但是对于AVX512,它是8x的0x40 dword或0x10 dqwords位移。编码。
但是使用{evex} vmovaps xmm0,[rdi+256]
的asm源覆盖,即使对于“低”寄存器,我们也可以获得紧凑的编码:
62 f1 7c 08 28 47 10 vmovaps xmm0,XMMWORD PTR [rdi+0x100]
GCC当然不会使用-mno-avx512f
这样做。
不幸的是,当您执行启用AVX512F时,例如,GCC和clang也会错过该优化。使用__m128 load(__m128 *p){ return p[16]; }
(Godbolt)编译-O3 -march=skylake-avx512
时。使用二进制模式,或者只是注意编译器输出的asm源代码行上缺少{evex}
标签。
我在用例中发现一个错误。.已编译的单元之一依赖于openvino SDK,后者明确添加了-mavx512f标志。