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 的一部分。