Go Wiki: AVX512
Go 1.11 版本引入了 AVX-512 支持。
本页面介绍了如何使用新功能以及一些重要的编码器细节。
术语
大部分术语来自 Intel 软件开发人员手册。
后缀源自 Go 汇编语法,该语法接近 AT&T,后者也使用大小后缀。
列出了一些术语以避免歧义(例如,“opcode”可以有不同的含义)。
术语 | 描述 |
---|---|
操作数 | 与“指令参数”相同。 |
Opcode (操作码) | 指代指令组的名称。例如,VADDPD 是一个操作码。它同时指代 VEX 和 EVEX 编码形式以及所有操作数组合。 大多数 AVX-512 的 Go 汇编操作码与 Intel 手册条目匹配,但存在例外情况 使用附加的大小后缀(例如, VCVTTPD2DQY 是 VCVTTPD2DQ )。 |
Opcode 后缀 | 覆盖某些操作码属性的后缀。跟在 "." (点) 之后列出。 例如, VADDPD.Z 有 "Z" 操作码后缀。可以有多个由点分隔的操作码后缀。 |
大小后缀 | 如果指令操作数的大小无法仅从操作数推断,则用于指定指令操作数大小的后缀。 例如, VCVTSS2USIL 有 "L" 大小后缀。 |
Opmask (操作掩码) | 同时用于 {k1} 表示法和描述具有 K 寄存器操作数的指令。与 EVEX 前缀中的掩码支持相关。 |
Register block (寄存器块) | 对多源操作数进行编码以表示寄存器范围。 Intel 手册使用 +n 表示法表示寄存器块。例如, +3 是一个包含 4 个寄存器的寄存器块。 |
FP | 浮点数 |
新寄存器
启用 EVEX 的指令可以在 64 位模式下访问另外 16 个 X
(128 位 xmm) 和 Y
(256 位 ymm) 寄存器,以及 32 个新的 Z
(512 位 zmm) 寄存器。32 位模式仅提供 Z0-Z7
。
新的操作掩码寄存器命名为 K0-K7
。
它们可用于掩码操作和特殊操作掩码指令(如 KADDB
)。
掩码支持
支持掩码的指令可以省略 K
寄存器操作数。
在这种情况下,将隐含使用 K0
寄存器(“全部为 1”)并执行合并掩码。
这实际上是“无掩码”。
K1-K7
寄存器可用于覆盖默认操作掩码。
K
寄存器应放置在目标操作数之前。
可以通过 Z
操作码后缀激活零掩码。零掩码要求指定一个 K0 以外的掩码寄存器。
例如,VADDPD.Z (AX), Z30, K3, Z10
使用零掩码和显式 K
寄存器。
- 如果删除
Z
操作码后缀,则为使用K3
掩码的合并掩码。 - 如果删除
K3
操作数,将产生汇编器错误。 - 如果同时删除
Z
操作码后缀和K3
操作数,则为使用K0
掩码的合并掩码。
对于 {k1}
操作数使用 K0
寄存器是编译时错误(有关详细信息,请参阅 手册)。
EVEX 广播/舍入/SAE 支持
通过操作码后缀激活嵌入式广播、舍入和 SAE。
对于启用 {er}
的寄存器-寄存器 FP 指令,可以指定舍入操作码后缀
RU_SAE
向 +无穷大舍入RD_SAE
向 -无穷大舍入RZ_SAE
向零舍入RN_SAE
向最近的整数舍入
要了解更多关于舍入模式的信息,请参阅 MXCSR.RC 信息。
对于启用 {sae}
的寄存器-寄存器 FP 指令,可以通过 SAE
操作码后缀指定异常抑制。
对于具有 m32bcst/m64bcst
操作数的寄存器-内存指令,可以通过 BCST
操作码后缀开启广播。
零掩码操作码后缀可以与其中任何一个结合使用。
例如,VMAXPD.SAE.Z Z3, Z2, Z1
同时使用了 Z
和 SAE
操作码后缀。
将零掩码操作码后缀放在最后很重要,否则将导致编译错误。
Register block (multi-source) operands (寄存器块(多源)操作数)
寄存器块使用寄存器范围语法指定。
指定第一个(低位)寄存器就足够了,但出于可读性考虑,Go 汇编器要求显式指定两端的范围。
例如,范围为 +3
的指令可以像这样使用:VP4DPWSSD Z25, [Z0-Z3], (AX)
。
范围 [Z0-Z3]
表示“寄存器块 Z0, Z1, Z2, Z3”。
无效的范围会导致编译错误。
AVX1 和 AVX2 指令与 EVEX 前缀
之前存在的可以用 EVEX 前缀编码的操作码,现在可以访问 AVX-512 的功能,如更宽的寄存器文件、零掩码/合并掩码等。例如,VADDPD
现在可以使用 512 位向量寄存器。
有关更多信息,请参阅 编码器细节。
支持的扩展
获取支持的扩展最新列表的最佳方法是在 测试套件 目录中执行 ls -1
。
最新列表包括
aes_avx512f
avx512_4fmaps
avx512_4vnniw
avx512_bitalg
avx512_ifma
avx512_vbmi
avx512_vbmi2
avx512_vnni
avx512_vpopcntdq
avx512bw
avx512cd
avx512dq
avx512er
avx512f
avx512pf
gfni_avx512f
vpclmulqdq_avx512f
128 位和 256 位指令还需要 avx512vl
。
也就是说,如果 VADDPD
在 avx512f
中可用,那么在没有 avx512vl
的情况下,您不能使用 X
和 Y
操作数。
文件名遵循 GNU as
(gas) 约定。
avx512extmap.csv 可以使命名方案更加清晰。
带大小后缀的指令
某些操作码与 Intel 手册条目不匹配。
本节提供搜索便利。
Intel 操作码 | Go 汇编器操作码 |
---|---|
VCVTPD2DQ |
VCVTPD2DQX , VCVTPD2DQY |
VCVTPD2PS |
VCVTPD2PSX , VCVTPD2PSY |
VCVTTPD2DQ |
VCVTTPD2DQX , VCVTTPD2DQY |
VCVTQQ2PS |
VCVTQQ2PSX , VCVTQQ2PSY |
VCVTUQQ2PS |
VCVTUQQ2PSX , VCVTUQQ2PSY |
VCVTPD2UDQ |
VCVTPD2UDQX , VCVTPD2UDQY |
VCVTTPD2UDQ |
VCVTTPD2UDQX , VCVTTPD2UDQY |
VFPCLASSPD |
VFPCLASSPDX , VFPCLASSPDY , VFPCLASSPDZ |
VFPCLASSPS |
VFPCLASSPSX , VFPCLASSPSY , VFPCLASSPSZ |
VCVTSD2SI |
VCVTSD2SI , VCVTSD2SIQ |
VCVTTSD2SI |
VCVTSD2SI , VCVTSD2SIQ |
VCVTTSS2SI |
VCVTSD2SI , VCVTSD2SIQ |
VCVTSS2SI |
VCVTSD2SI , VCVTSD2SIQ |
VCVTSD2USI |
VCVTSD2USIL , VCVTSD2USIQ |
VCVTSS2USI |
VCVTSS2USIL , VCVTSS2USIQ |
VCVTTSD2USI |
VCVTTSD2USIL , VCVTTSD2USIQ |
VCVTTSS2USI |
VCVTTSS2USIL , VCVTTSS2USIQ |
VCVTUSI2SD |
VCVTUSI2SDL , VCVTUSI2SDQ |
VCVTUSI2SS |
VCVTUSI2SSL , VCVTUSI2SSQ |
VCVTSI2SD |
VCVTSI2SDL , VCVTSI2SDQ |
VCVTSI2SS |
VCVTSI2SSL , VCVTSI2SSQ |
ANDN |
ANDNL , ANDNQ |
BEXTR |
BEXTRL , BEXTRQ |
BLSI |
BLSIL , BLSIQ |
BLSMSK |
BLSMSKL , BLSMSKQ |
BLSR |
BLSRL , BLSRQ |
BZHI |
BZHIL , BZHIQ |
MULX |
MULXL , MULXQ |
PDEP |
PDEPL , PDEPQ |
PEXT |
PEXTL , PEXTQ |
RORX |
RORXL , RORXQ |
SARX |
SARXL , SARXQ |
SHLX |
SHLXL , SHLXQ |
SHRX |
SHRXL , SHRXQ |
编码器细节
由于编码器表顺序略有不同,与旧编码器的位比较可能会因 VEX 编码的指令而失败。
这种差异可能出现在同时具有 {reg, reg/mem}
和 {reg/mem, reg}
形式的寄存器-寄存器指令中。这些指令之一是 VMOVUPS
。
这不会影响代码行为,也不会使其更大/效率更低。
新的编码选择方案借鉴了 Intel XED。
当以下任一条件成立时,将使用 EVEX 编码:
- 指令使用新寄存器(高 16 个
X
/Y
、Z
或K
寄存器) - 指令使用与 EVEX 相关的操作码后缀,如
BCST
- 指令使用仅适用于 AVX-512 的操作数组合
在所有其他情况下,使用 VEX 编码。
这意味着尽可能使用 VEX,并在需要时使用 EVEX。
对于 EVEX 编码的指令,尽可能应用压缩 disp8。
这也包括 disp8 的广播,有时具有不同的 N 乘数。
有经验的读者可以查看 avx_optabs.go 来了解任何指令的 N 乘数。
例如,VADDPD
有以下 N 乘数:
- 512 位形式的
N=64
;广播时N=8
- 256 位形式的
N=32
;广播时N=8
- 128 位形式的
N=16
;广播时N=8
示例
可以在 Go 汇编器的 测试套件 中找到大量的示例。
每个文件为特定 AVX-512 扩展中的每种支持的指令形式提供了几个示例。
每个示例还包含生成的机器码。
这是从 Intel® 优化手册 采用的“使用 AVX-512CD 进行矢量化直方图更新”示例。
for i := 0; i < 512; i++ {
histo[key[i]] += 1
}
top:
VMOVUPS 0x40(SP)(DX*4), Z4 //; vmovups zmm4, [rsp+rdx*4+0x40]
VPXORD Z1, Z1, Z1 //; vpxord zmm1, zmm1, zmm1
KMOVW K1, K2 //; kmovw k2, k1
VPCONFLICTD Z4, Z2 //; vpconflictd zmm2, zmm4
VPGATHERDD (AX)(Z4*4), K2, Z1 //; vpgatherdd zmm1{k2}, [rax+zmm4*4]
VPTESTMD histo<>(SB), Z2, K0 //; vptestmd k0, zmm2, [rip+0x185c]
KMOVW K0, CX //; kmovw ecx, k0
VPADDD Z0, Z1, Z3 //; vpaddd zmm3, zmm1, zmm0
TESTL CX, CX //; test ecx, ecx
JZ noConflicts //; jz noConflicts
VMOVUPS histo<>(SB), Z1 //; vmovups zmm1, [rip+0x1884]
VPTESTMD histo<>(SB), Z2, K0 //; vptestmd k0, zmm2, [rip+0x18ba]
VPLZCNTD Z2, Z5 //; vplzcntd zmm5, zmm2
XORB BX, BX //; xor bl, bl
KMOVW K0, CX //; kmovw ecx, k0
VPSUBD Z5, Z1, Z1 //; vpsubd zmm1, zmm1, zmm5
VPSUBD Z5, Z1, Z1 //; vpsubd zmm1, zmm1, zmm5
resolveConflicts:
VPBROADCASTD CX, Z5 //; vpbroadcastd zmm5, ecx
KMOVW CX, K2 //; kmovw k2, ecx
VPERMD Z3, Z1, K2, Z3 //; vpermd zmm3{k2}, zmm1, zmm3
VPADDD Z0, Z3, K2, Z3 //; vpaddd zmm3{k2}, zmm3, zmm0
VPTESTMD Z2, Z5, K2, K0 //; vptestmd k0{k2}, zmm5, zmm2
KMOVW K0, SI //; kmovw esi, k0
ANDL SI, CX //; and ecx, esi
JZ noConflicts //; jz noConflicts
ADDB $1, BX //; add bl, 0x1
CMPB BX, $16 //; cmp bl, 0x10
JB resolveConflicts //; jb resolveConflicts
noConflicts:
KMOVW K1, K2 //; kmovw k2, k1
VPSCATTERDD Z3, K2, (AX)(Z4*4) //; vpscatterdd [rax+zmm4*4]{k2}, zmm3
ADDL $16, DX //; add edx, 0x10
CMPL DX, $1024 //; cmp edx, 0x400
JB top //; jb top
此内容是 Go Wiki 的一部分。