日別アーカイブ: 2008年10月13日

Intel AVX

Intel の新しい拡張命令セットです。基本的には SSE と同じようなもの。

Intel AVX

その特徴は

・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 のように
内部でスカラー単位に分割して依存を管理しているのかもしれません。

関連エントリ
AMD SSE5 Shader のような新しい命令
SSE についてのメモ(2) SSE4など