Go Wiki: AVX512
Go 1.11のリリースでは、AVX-512のサポートが導入されました。
このページでは、新機能の使用方法と、重要なエンコーダの詳細について説明します。
用語
ほとんどの用語は、Intel Software Developer’s manualに由来しています。
接尾辞はGoアセンブラ構文に由来し、これはAT&Tに近く、サイズ接尾辞も使用します。
いくつかの用語は、曖昧さを避けるためにリストされています(例:オペコードは異なる意味を持つことがあります)。
| 用語 | 説明 |
|---|---|
| オペランド | 「命令引数」と同じ。 |
| オペコード | 命令グループを参照する名前。例えば、VADDPDはオペコードです。VEXとEVEXの両方のエンコード形式と、すべてのオペランドの組み合わせを参照します。 AVX-512のほとんどのGoアセンブラのオペコードはIntelマニュアルのエントリと一致しますが、 追加のサイズ接尾辞が使用される場合(例: VCVTTPD2DQYはVCVTTPD2DQ)は例外です。 |
| オペコード接尾辞 | いくつかのオペコードプロパティを上書きする接尾辞。「.」(ドット)の後にリストされます。 例えば、 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レジスタが暗示され(「all ones」)、マージングマスキングが実行されます。
これは実質的に「マスキングなし」です。
K1-K7レジスタは、デフォルトのオペマスクを上書きするために使用できます。
Kレジスタは宛先オペランドの直前に配置する必要があります。
ゼロ化マスキングはZオペコード接尾辞で有効にできます。ゼロ化マスキングには、K0以外のマスクレジスタを指定する必要があります。
例えば、VADDPD.Z (AX), Z30, K3, Z10はゼロ化マスキングと明示的なKレジスタを使用します。
Zオペコード接尾辞を削除すると、K3マスクによるマージングマスキングになります。K3オペランドを削除すると、アセンブラエラーが発生します。Zオペコード接尾辞とK3オペランドの両方を削除すると、K0マスクによるマージングマスキングになります。
K0レジスタを{k1}オペランドに使用すると、コンパイル時エラーになります(詳細についてはマニュアルを参照してください)。
EVEXブロードキャスト/丸め/SAEサポート
埋め込みブロードキャスト、丸め、SAEはオペコード接尾辞を介してアクティブ化されます。
{er}が有効なreg-reg FP命令の場合、丸めオペコード接尾辞を指定できます。
RU_SAEは+Infに丸めるRD_SAEは-Infに丸めるRZ_SAEはゼロに丸めるRN_SAEは最も近い値に丸める
丸めモードの詳細については、MXCSR.RC情報を参照してください。
{sae}が有効なreg-reg FP命令の場合、SAEオペコード接尾辞で例外抑制を指定できます。
m32bcst/m64bcstオペランドを持つreg-mem命令の場合、BCSTオペコード接尾辞でブロードキャストをオンにできます。
ゼロ化オペコード接尾辞は、これらのいずれかと組み合わせることができます。
例えば、VMAXPD.SAE.Z Z3, Z2, Z1はZとSAEの両方のオペコード接尾辞を使用します。
ゼロ化オペコード接尾辞を最後に置くことが重要です。そうしないとコンパイルエラーになります。
レジスタブロック(マルチソース)オペランド
レジスタブロックは、レジスタ範囲構文を使用して指定されます。
最初の(低い)レジスタを指定するだけで十分ですが、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が必要です。
つまり、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の場合に{reg, reg/mem}と{reg/mem, reg}の両方の形式を持つ命令で発生する可能性があります。そのような命令の1つがVMOVUPSです。
これはコードの動作に影響せず、大きくしたり非効率にしたりすることはありません。
新しいエンコード選択スキームは、Intel XEDから借用されています。
EVEXエンコーディングは、以下のいずれかが真の場合に使用されます。
- 命令が新しいレジスタ(上位16個の
X/Y、ZまたはKレジスタ)を使用する場合 - 命令が
BCSTなどのEVEX関連のオペコード接尾辞を使用する場合 - 命令がAVX-512でのみ利用可能なオペランドの組み合わせを使用する場合
その他のすべてのケースでは、VEXエンコーディングが使用されます。
これは、可能な限りVEXが使用され、必要な場合にEVEXが使用されることを意味します。
EVEXエンコード命令には、可能な限り圧縮されたdisp8が適用されます。
これには、N乗数が異なる場合があるブロードキャストdisp8も含まれます。
経験豊富な読者は、avx_optabs.goを調べて、任意の命令のN乗数について学ぶことができます。
例えば、VADDPDにはこれらがあります。
- 512ビット形式の場合は
N=64。ブロードキャスト時はN=8 - 256ビット形式の場合は
N=32。ブロードキャスト時はN=8 - 128ビット形式の場合は
N=16。ブロードキャスト時はN=8
例
網羅的な例は、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の一部です。