Intel の新しい拡張命令セットです。基本的には SSE と同じようなもの。
その特徴は
・256bit になった
・積和命令
・ソース非破壊の 3オペランド命令
・命令 Prefix の圧縮
・メモリアライメント制限の緩和
など。
CPU core 数が増えて性能が向上するように、演算並列度を上げるために SIMD で
扱える bit 幅が拡張されるようです。
x64 の 64bit RAX~ レジスタのように、128bit XMM レジスタが 256bit YMM
レジスタに拡張されています。
256bit = 32bit×8 なので float×8個の演算を一度に行うことができます。
とはいえ GPU の Shader でも xyzw までで、8要素の演算には普段あまり馴染みが
ありません。むしろ 256bit = 64bit×4 と、double で一度に 4要素扱えることに
意義があるのかもしれません。
以前 SSE5 の記事を見たときに勘違いしたのが “3オペランド命令の採用” です。
てっきりソース非破壊で演算可能になったのかと思ったら積和命令のことでした。
(AMD SSE5 Shader のような新しい命令)
今度は本当です。
AVX は単なる 256bit 拡張ではなく、従来の 128bit SSE 命令も含まれています。
VEX Prefix を使った SSE 互換命令はレジスタフィールドが拡張されていて
source operand と destination operand が分離されています。
例えば ADDPS 命令の場合次の通りです。
ADDPS xmm1, xmm2/m128 // SSE VADDPS xmm1, xmm2, xmm3/m128 // AVX VADDPS ymm1, ymm2, ymm3/m256 // AVX
積和系 FMA 命令だと 4 operand です。
VFMADDPS xmm0, xmm1, xmm2/m128, xmm3 VFMADDPS xmm0, xmm1, xmm2, xmm3/m128 VFMADDPS ymm0, ymm1, ymm2/m256, ymm3 VFMADDPS ymm0, ymm1, ymm2, ymm3/m256
SSE3 の HADDPS や SSE4.1 の DPPS もありました。
HADDPS xmm1, xmm2/m128 // SSE VHADDPS xmm1, xmm2, xmm3/m128 // AVX VHADDPS ymm1, ymm2, ymm3/m256 // AVX DPPS xmm1, xmm3/m128, imm8 // SSE VDPPS xmm1, xmm2, xmm3/m128, imm8 // AVX VDPPS ymm1, ymm2, ymm3/m256, imm8 // AVX
256bit の VHADDPS も隣接 2値ごとの加算で、機能的には同じ。
問題の 256bit VDPPS ですが、8個全部の内積ではなく上位 128bit と下位 128bit
同士をそれぞれ内積した結果を返すようです。
つまり AVX の 256bit 命令とは、8個の float 演算と言うよりも 4要素の SSE 演算
自体をさらに 2つ同時に実行できると考えた方が理解しやすいようです。
残念なのが VDPPD 命令。
double×4 の内積ではなく 128bit 分 double×2 の内積を 1セット返すのみでした。
float x4 → double x4 への置き換えは簡単ではないようです。
VSHUFPS/VSHUPD も同様に上位 128bit 下位 128bit それぞれの範囲でのみ入れ替え
られます。256bit 全部入れ替えられるわけではないようです。
上位 128bit / 下位 128bit 間の転送には VINSERTF128/VEXTRACTF128 命令が使えます。
任意の xmm レジスタを ymm の上下 128bit どちらに転送するか、
または ymm のどちらの 128bit を xmm に転送するか選択できます。
ちなみに AVX では xmm レジスタへ転送を行うと上位 128bit は 0 クリアされます。
ソース非破壊だとソースを保存のための無駄な転送が減るし、3オペランドだと
演算が MOV を兼ねることが出来ます。
これらは単に命令数が減るメリットだけでなく、レジスタの部分更新が無くなるので
レジスタリネーミングの効率にも貢献するものと考えられます。
例えば MOVSS と MOVPS は AVX では次のように変化します。(m128/m256 は省略)
MOVAPS xmm1, xmm2 // SSE VMOVAPS xmm1, xmm2 // AVX VMOVAPS ymm1, ymm2 // AVX MOVSS xmm1, xmm2 // SSE VMOVSS xmm1, xmm2, xmm3 // AVX
MOVPS は単なる転送命令なので 2 operand のみ。
MOVSS は bit0~bit31 のスカラーを転送する命令です。
SSE では xmm1 の bit32~bit127 は置き換えず保持します。
AVX では dest は全書き換えが原則なので、機能互換性のため bit32~bit127 を
入力する operand が追加されています。(VINSERTF128 も同様)
MOVSS xmm1, m32 // SSE VMOVSS xmm1, m32 // AVX
メモリから読み込む場合 xmm1 の余った bit は 0 クリアされます。
AVX では xmm への転送は上位 128bit をクリアすることになっているため、
bit32~bit255 すべてが 0 になります。
AVX 対応 CPU で SSE 命令を使うと ymm の上位 128bit は非更新です。
Larrabee ではさらに SIMD が 512bit に拡張されるようです。
float だと 16個分ですが、256bit AVX の例を見ると 128bit SSE × 4 相当で
構成されている可能性があります。
また演算毎にレジスタの mask を指定できるようです。
mask の指定はおそらく入力側だと考えられます。shader のような書き込み mask だと、
AVX のルールで考えると VMOVSS のようなもの。そうでなければ GPU のように
内部でスカラー単位に分割して依存を管理しているのかもしれません。