-march=native -mno-avx512f是正确的选项,vmovss只需要 AVX1。
这里是一个AVX512F EVEX编码vmovss,但除非涉及到的寄存器GAS不会使用它xmm16..31。使用这些寄存器时禁用AVX512F与GCC不会发出ASM -mno-avx512f,或与类似首位不启用-march=skylake或-march=znver2。
如果您仍然不确定,请检查实际的反汇编 + 机器代码以查看指令以什么前缀开头:
C5或C4字节:2 或 3 字节 VEX 前缀的开始,AVX1 编码。62字节:EVEX 前缀的开始,AVX512F 编码.intel_syntax noprefix
vmovss xmm15, [rdi]
vmovss xmm15, [r11]
vmovss xmm16, [rdi]
Run Code Online (Sandbox Code Playgroud)
组装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
Run Code Online (Sandbox Code Playgroud)
10操作码前的 2 和 3 字节 VEX,以及 4 字节 EVEX 前缀。(ModRM 字节也不同;xmm0 和 xmm16 仅在来自前缀的额外寄存器位上有所不同,而不是 modrm)。
GASvmovss在可能的情况下使用 AVX1 VEX 编码和其他指令。 因此,您可以指望具有非 AVX512F 形式的指令尽可能使用非 AVX512F 形式。这就是 GNU 工具链(由 GCC 使用)的-mno-avx512f工作方式。
即使 EVEX 编码较短,这也适用。例如,当 a[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]
Run Code Online (Sandbox Code Playgroud)
请注意机器代码编码的最后一个字节或最后 4 个字节:它是 AVX1 编码的 32 位小端 0x100 字节位移,但 AVX512 编码的 8 位位移是 0x40 dwords 或 0x10 dqwords。
但是使用 asm-source 覆盖,{evex} vmovaps xmm0, [rdi+256]即使对于“低”寄存器,我们也可以获得紧凑的编码:
62 f1 7c 08 28 47 10 vmovaps xmm0,XMMWORD PTR [rdi+0x100]
Run Code Online (Sandbox Code Playgroud)
GCC 当然不会用-mno-avx512f.
不幸的是GCC和铛也错过优化时,你就在编译时启用AVX512F,如__m128 load(__m128 *p){ return p[16]; }用-O3 -march=skylake-avx512 (Godbolt)。使用二进制模式,或者只是注意在{evex}编译器输出的 asm 源代码行上缺少标记。