Go Wiki:AVX512

Go 1.11 版本推出 AVX-512 支援。
此頁面說明如何使用新功能,以及一些重要的編碼器詳細資料。

術語

大多數術語來自 Intel 軟體開發人員手冊
後綴源自 Go 組譯器語法,它接近 AT&T,AT&T 也使用大小後綴。

列出一些術語以避免歧義(例如,opcode 可能有不同的含義)。

術語 說明
運算元 與「指令參數」相同。
opcode 指指令群組的名稱。例如,VADDPD 是 opcode。
它同時指 VEX 和 EVEX 編碼形式以及所有運算元組合。
大多數 AVX-512 的 Go 組譯器 opcode 與 Intel 手冊條目相符,但有例外情況
使用額外大小後綴(例如,VCVTTPD2DQYVCVTTPD2DQ)。
opcode 後綴 覆寫某些 opcode 屬性的後綴。列在「.」之後(點)。
例如,VADDPD.Z 有「Z」opcode 後綴。
可以有多個以點分隔的 opcode 後綴。
大小後綴 如果無法僅從運算元推斷出指令運算元大小,則指定指令運算元大小的後綴。
例如,VCVTSS2USIL 有「L」大小後綴。
opmask 用於 {k1} 表示法和描述具有 K 暫存器運算元的指令。
與 EVEX 前綴中的遮罩支援相關。
暫存器區塊 編碼暫存器範圍的多來源運算元。
Intel 手冊使用 +n 表示法表示暫存器區塊。
例如,+3 是 4 個暫存器的暫存器區塊。
FP 浮點

新暫存器

啟用 EVEX 的指令可以存取額外的 16 個 X(128 位元組 xmm)和 Y(256 位元組 ymm)暫存器,加上 64 位元模式中的 32 個新 Z(512 位元組 zmm)暫存器。32 位元模式僅取得 Z0-Z7

新的 opmask 暫存器命名為 K0-K7
它們可用於遮罩和特殊 opmask 指令(如 KADDB)。

遮罩支援

支援遮罩的指令可以省略 K 暫存器運算元。
在這種情況下,K0 暫存器是隱含的(「全 1」)且執行合併遮罩。
這實際上是「沒有遮罩」。

K1-K7 暫存器可用於覆寫預設 opmask。
K 暫存器應放置在目的地運算元正前方。

可以使用 Z opcode 後綴來啟用歸零遮罩。歸零遮罩需要指定 K0 以外的遮罩暫存器。

例如,VADDPD.Z (AX), Z30, K3, Z10 使用歸零遮罩和明確的 K 暫存器。

對於 {k1} 運算元使用 K0 暫存器會產生編譯時期錯誤(有關詳細資訊,請參閱 手冊)。

EVEX 廣播/捨入/SAE 支援

透過 opcode 後綴啟用嵌入式廣播、捨入和 SAE。

對於啟用 {er} 的 reg-reg FP 指令,可以指定捨入 opcode 後綴

如需瞭解更多有關捨入模式的資訊,請參閱 MXCSR.RC 資訊

對於啟用 {sae} 的 reg-reg FP 指令,可以使用 SAE opcode 字尾指定例外抑制。

對於具有 m32bcst/m64bcst 參數的 reg-mem 指令,可以使用 BCST opcode 字尾開啟廣播。

零化 opcode 字尾可以與這些中的任何一個結合使用。
例如,VMAXPD.SAE.Z Z3, Z2, Z1 同時使用 ZSAE opcode 字尾。
重要的是將零化 opcode 字尾放在最後,否則會出現編譯錯誤。

暫存器區塊(多來源)參數

暫存器區塊使用暫存器範圍語法指定。

僅指定第一個(低)暫存器就足夠了,但 Go 組合器出於可讀性原因需要明確指定兩端的範圍。

例如,具有 +3 範圍的指令可以使用,例如 VP4DPWSSD Z25, [Z0-Z3], (AX)
範圍 [Z0-Z3] 讀取為「Z0、Z1、Z2、Z3 的暫存器區塊」。
無效範圍會導致編譯錯誤。

具有 EVEX 前綴的 AVX1 和 AVX2 指令

以前存在的、可以使用 EVEX 前綴編碼的 opcode 現在可以存取 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
也就是說,如果 VADDPDavx512f 中可用,您無法在沒有 avx512vl 的情況下使用 XY 參數。

檔名遵循 GNU as (gas) 慣例。
avx512extmap.csv 可以讓命名方案更明顯。

帶有大小字尾的指令

有些操作碼與 Intel 手冊條目不符。
提供此部分以方便搜尋。

Intel 操作碼 Go 組合器操作碼
VCVTPD2DQ VCVTPD2DQXVCVTPD2DQY
VCVTPD2PS VCVTPD2PSXVCVTPD2PSY
VCVTTPD2DQ VCVTTPD2DQXVCVTTPD2DQY
VCVTQQ2PS VCVTQQ2PSXVCVTQQ2PSY
VCVTUQQ2PS VCVTUQQ2PSXVCVTUQQ2PSY
VCVTPD2UDQ VCVTPD2UDQXVCVTPD2UDQY
VCVTTPD2UDQ VCVTTPD2UDQXVCVTTPD2UDQY
VFPCLASSPD VFPCLASSPDXVFPCLASSPDYVFPCLASSPDZ
VFPCLASSPS VFPCLASSPSXVFPCLASSPSYVFPCLASSPSZ
VCVTSD2SI VCVTSD2SIVCVTSD2SIQ
VCVTTSD2SI VCVTSD2SIVCVTSD2SIQ
VCVTTSS2SI VCVTSD2SIVCVTSD2SIQ
VCVTSS2SI VCVTSD2SIVCVTSD2SIQ
VCVTSD2USI VCVTSD2USILVCVTSD2USIQ
VCVTSS2USI VCVTSS2USILVCVTSS2USIQ
VCVTTSD2USI VCVTTSD2USILVCVTTSD2USIQ
VCVTTSS2USI VCVTTSS2USILVCVTTSS2USIQ
VCVTUSI2SD VCVTUSI2SDLVCVTUSI2SDQ
VCVTUSI2SS VCVTUSI2SSLVCVTUSI2SSQ
VCVTSI2SD VCVTSI2SDLVCVTSI2SDQ
VCVTSI2SS VCVTSI2SSLVCVTSI2SSQ
ANDN ANDNLANDNQ
BEXTR BEXTRLBEXTRQ
BLSI BLSILBLSIQ
BLSMSK BLSMSKLBLSMSKQ
BLSR BLSRLBLSRQ
BZHI BZHILBZHIQ
MULX MULXLMULXQ
PDEP PDEPLPDEPQ
PEXT PEXTLPEXTQ
RORX RORXLRORXQ
SARX SARXLSARXQ
SHLX SHLXLSHLXQ
SHRX SHRXLSHRXQ

編碼器詳細資料

由於編碼器表格順序略有不同,因此使用較舊編碼器進行位元比較可能會導致 VEX 編碼指令失敗。

此差異可能會發生在同時具有 {reg, reg/mem}{reg/mem, reg} 形式的指令中,例如 reg-reg 案例。其中一個此類指令為 VMOVUPS

這不會影響程式碼行為,也不會讓程式碼變大/效率降低。
新的編碼選擇機制取自 Intel XED

在下列任何情況下都會使用 EVEX 編碼

在所有其他情況下,都會使用 VEX 編碼。
這表示只要有可能,就會使用 VEX,而只有在需要時才會使用 EVEX。

對於 EVEX 編碼指令,只要有可能,就會套用壓縮 disp8。
這也包含廣播 disp8,它有時具有不同的 N 倍數。

經驗豐富的讀者可以檢查 avx_optabs.go,以瞭解任何指令的 N 倍數。

例如,VADDPD 具有以下倍數

範例

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