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

Intel AVX その2 転送

やはり、上位 128bit と下位 128bit を横断する命令は限られているようです。
基本的には 128bit 4要素の SSE 命令を、一度に 2個演算できるのが AVX の
256bit 命令です。

Intel AVX
Intel-AVX-Programming-Reference-319433003.pdf

上下 128bit への任意転送は 128bit 単位のものが多く、SHUFPS/SHUBPD のような
32/64bit 単位で任意に入れ替えたり転送する命令がみあたりません。
float 8個や double 4個の演算時でも、値を入れ替える場合に 128bit 転送命令を
組み合わせる必要がありそうです。

256/128bit 間の転送には VEXTRACTF128, VINSERTF128 が使えます。
上位下位どちらの 128bit を使用するか選択します。
以下 256bit レジスタの ymm.low を下位 128bit、ymm.hi を上位 128bit と表記します。

VEXTRACTF128  xmm1, ymm2, 0   // xmm1= ymm2.low
VEXTRACTF128  xmm1, ymm2, 1   // xmm1= ymm2.hi

VINSERTF128 ymm1, ymm2, xmm3, 0 // ymm1.low= xmm3,  ymm1.hi= ymm2.hi
VINSERTF128 ymm1, ymm2, xmm3, 1 // ymm1.low= ymm2.low,  ymm1.hi= xmm3

VINSERTF128 は VMOVSS 系の部分更新命令なので、合成用の追加のレジスタが増えて
います。
実際は ymm2 に dest (ymm1) と同じレジスタを指定するケースが多いかもしれません。

128bit 単位の入れ替え命令として VPERM2F128 があります。
2つのソース ymm2,ymm3 の任意の 128bit を組み合わせて ymm1 に代入できます。

VPERM2F128  ymm1, ymm2, ymm3, 0  // ymm1.low= ymm2.low,  ymm1.hi= ymm2.low
VPERM2F128  ymm1, ymm2, ymm3, 1  // ymm1.low= ymm2.hi,   ymm1.hi= ymm2.low
VPERM2F128  ymm1, ymm2, ymm3, 2  // ymm1.low= ymm3.low,  ymm1.hi= ymm2.low
VPERM2F128  ymm1, ymm2, ymm3, 3  // ymm1.low= ymm3.hi,   ymm1.hi= ymm2.low
~

VBROADCAST は、唯一 32,64,128bit の任意の値を 256bit に転送できます。
複製されます。

VBROADCASTSS   xmm1, m32   // xmm1 32bit x4= m32, 上位 128bit は 0
VBROADCASTSS   ymm1, m32   // ymm1 32bit x8= m32
VBROADCASTSD   ymm1, m64   // ymm1 64bit x4= m64
VBROADCASTF128 ymm1, m128  // ymm1 128bit x2= m128

F128 は SS, SD, PD, PS に相当し、128bit を表すようです。
(Larrabee では F256 がありそう)

これ以外の命令はほぼ 128bit SSE ×2 個分に相当します。
その他特殊な命令は次の通り。

VZEROALL
VZEROUPPER

VZEROALL は、ymm0~15 レジスタすべてをゼロクリアします。
VZEROUPPER はすべてのレジスタの上位 128bit のみクリア。
これらの命令は、レジスタの部分書き換えが発生してしまう Legacy SSE 命令の
レジスタ依存を断ち切ることが出来ます。

メモリとレジスタ間で条件付き転送が出来るようになっています。
転送単位は 32bit or 64bit で、転送するかどうか mask レジスタで指定します。
mask 値は転送データと同じサイズで、最上位 bit (符号) で判断します。
つまり負なら転送。

VMASKMOVPS  xmm1, xmm2, m128  // 32bit x4, xmm2 が mask
VMASKMOVPS  ymm1, ymm2, m256  // 32bit x8, ymm2 が mask
VMASKMOVPD  xmm1, xmm2, m128  // 64bit x2, xmm2 が mask
VMASKMOVPD  ymm1, ymm2, m256  // 64bit x4, ymm2 が mask
VMASKMOVPS  m128, xmm1, xmm2  // 32bit x4, xmm1 が mask
VMASKMOVPS  m256, ymm1, ymm2  // 32bit x8, ymm1 が mask
VMASKMOVPD  m128, xmm1, xmm2  // 64bit x2, xmm1 が mask
VMASKMOVPD  m256, ymm1, ymm2  // 64bit x4, ymm1 が mask

例えば xmm の各 32bit をシェーダーのように .x .y .z .w で表現すると

xmm2.x= -1
xmm2.y= 0
xmm2.z= -1
xmm2.w= 0

の場合

VMASKMOVPS xmm1, xmm2, m128

は次の転送を行います。

xmm1.x= m128[0]
xmm1.y= 0
xmm1.z= m128[2]
xmm1.w= 0

選択しながら読み出せるため便利ですが、mask レジスタを用意する必要があります。
命令も 3byte 長 VEX (0F38) に含まれています。

積和命令 FMA は AES と同じように別カテゴリに分かれています。
命令フィールドも 0F3A の 3byte VEX で独自のものです。

AVX は基本的に SSE をカバーしていますが SSE1~SSE4.1 までです。
SSE4.2 と AMD SSE5 は含まれていないようです。
積和命令 FMA~ FNMA~ は SSE5 と名称も機能も似通っています。
ちょうど SSE5 を VEX 拡張したかのような位置づけですが、opecode 等を見ても
関連性はありませんでした。

関連エントリ
Intel AVX