Go Wiki: AVX512

Go 1.11リリースでは、AVX-512サポートが導入されました。
このページでは、新機能の使用方法と重要なエンコーダーの詳細について説明します。

用語

ほとんどの用語は、Intel Software Developer’s manualからのものです。
サフィックスは、AT&Tにも近いGoアセンブラ構文に由来しており、サイズサフィックスも使用します。

あいまいさを避けるために、いくつかの用語がリストされています(たとえば、オペコードは異なる意味を持つ場合があります)。

用語 説明
オペランド 「命令引数」と同じです。
オペコード 命令グループを参照する名前。たとえば、VADDPDはオペコードです。
VEXとEVEXの両方でエンコードされた形式とすべてのオペランドの組み合わせを指します。
AVX-512のGoアセンブラオペコードのほとんどはIntelマニュアルのエントリと一致していますが、追加のサイズサフィックスが使用される場合を除きます。
(例:VCVTTPD2DQYVCVTTPD2DQです)。
オペコードサフィックス 一部のオペコードのプロパティをオーバーライドするサフィックス。「.」の後(ドット)にリストされます。
たとえば、VADDPD.Zには「Z」オペコードサフィックスがあります。
複数のドットで区切られたオペコードサフィックスが存在する可能性があります。
サイズサフィックス オペランドだけでは推測できない場合に、命令オペランドのサイズを指定するサフィックス。
たとえば、VCVTSS2USILには「L」サイズサフィックスがあります。
オプマスク {k1}表記の両方と、Kレジスタオペランドを持つ命令の説明に使用されます。
EVEXプレフィックスのマスキングサポートに関連しています。
レジスタブロック レジスタ範囲をエンコードするマルチソースオペランド。
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レジスタを使用します。

{k1}オペランドにK0レジスタを使用することはコンパイル時エラーです(詳細はマニュアルを参照してください)。

EVEXブロードキャスト/丸め/SAEサポート

オペコードサフィックスを介して有効化された埋め込みブロードキャスト、丸め、SAE。

{er}が有効なreg-reg FP命令の場合、丸めオペコードサフィックスを指定できます。

丸めモードの詳細については、MXCSR.RC情報を参照してください。

{sae}が有効なreg-reg FP命令の場合、例外抑制をSAEオペコードサフィックスで指定できます。

m32bcst/m64bcstオペランドを持つreg-mem命令の場合、BCSTオペコードサフィックスを使用してブロードキャストを有効にできます。

ゼロイングオペコードサフィックスは、これらのいずれかと組み合わせることができます。
たとえば、VMAXPD.SAE.Z Z3, Z2, Z1ZSAEの両方のオペコードサフィックスを使用します。
ゼロイングオペコードサフィックスは最後に置く必要があります。そうでない場合、コンパイルエラーになります。

レジスタブロック(マルチソース)オペランド

レジスタブロックは、レジスタ範囲構文を使用して指定されます。

最初の(低い)レジスタのみを指定すれば十分ですが、Goアセンブラでは、可読性の理由から両端を含む明示的な範囲が必要です。

たとえば、+3範囲を持つ命令は、VP4DPWSSD Z25, [Z0-Z3], (AX)のように使用できます。
範囲[Z0-Z3]は、「Z0、Z1、Z2、Z3のレジスタブロック」のように読み取られます。
無効な範囲はコンパイルエラーになります。

EVEXプレフィックスを持つAVX1およびAVX2命令

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が必要です。
つまり、VADDPDavx512fで使用できる場合でも、avx512vlを使用しないとXおよびY引数は使用できません。

ファイル名は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の場合に{reg, reg/mem}{reg/mem, reg}の両方の形式を持つ命令(VMOVUPSなど)で発生する可能性があります。

これはコードの動作に影響を与えず、コードを大きくしたり効率を低下させたりしません。
新しいエンコーディング選択スキームは、Intel XEDから借用されています。

以下のいずれかが当てはまる場合、EVEXエンコーディングが使用されます。

その他のすべてのケースでは、VEXエンコーディングが使用されます。
つまり、可能な限りVEXが使用され、必要な場合にのみEVEXが使用されます。

EVEXでエンコードされた命令では、可能な限り圧縮disp8が適用されます。
これには、場合によっては異なるN乗数を持つブロードキャストdisp8も含まれます。

経験豊富な読者は、avx_optabs.goを検査して、任意の命令のN乗数について学ぶことができます。

たとえば、VADDPDには次のものがあります。

多数の例は、Goアセンブラのテストスイートにあります。

各ファイルは、特定のAVX-512拡張機能でサポートされているすべての命令形式のいくつかの例を提供しています。
すべての例には、生成されたマシンコードも含まれています。

Intel® Optimization Manualから採用された「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の一部です。