« はじめに | メイン | 並列スワップ »

2008年02月23日

x86 SIMD Technique:: 比較

    

SIMD の比較は、単にマスクを生成してくれるだけだ。
比較して分岐するなどは出来ない。
生成されたマスクを使って何とかするしかない。
これはいつも分岐で書いていると、どう書けばいいのかさっぱりわからない問題だ。
でも、これが使えると分岐を消して並列で処理できるようになる。

比較的わかりやすいであろう、theora のフィルタのソースコードの一部を以下に書いた。
MMX を使っている。

まずは条件に一致するものを 0 にするコード

// if( R <= -2L || R >= 2L ) R = 0;
mask_L2 = _mm_cmpgt_pi16( limit_x2_p, R ); // 2L >   R ? FF : 00
R = _mm_and_si64( R, mask_L2 );            // 2L >   R ? R : 0
mask_mL2 = _mm_cmpgt_pi16( R, limit_x2_m );//  R > -2L ? FF : 00
R = _mm_and_si64( R, mask_mL2 );           //  R > -2L ? R : 0

マスクを作って and をとって 0 にしているので、if 文の条件が逆転しているのさえわかれば、特に難しいことはない。

次に条件に一致する時に加算するコード。

// if( R < -L ) R2 = R + 2L;
mask_mL_R = _mm_cmpgt_pi16( limit_m, R );      // -L > R ? FF : 00 ( マスクを作る )
tmp_2L = _mm_and_si64( limit_x2_p, mask_mL_R );// -L > R ? 2L : 0
R2 = _mm_add_pi16( R, tmp_2L );                // -L > R ? R + 2L : R

条件に一致する加算する方をマスクし、加算されないものを 0 にしてから加算する。
こうすることで条件に一致するものだけ加算できる

だいたいこの2つがわかれば、比較は他にも応用できる。

追記:
指摘された内容を以下に加筆。
上の判定は、 R + 32767-2L が 32767- 4L 以下ならば R <= -2L || R >= 2L の条件に当てはまるということになる。
値域を整数の上限にまで移動させてしまえば範囲外の比較が一回で済む。
整数の範囲内の計算で範囲がほぼ固定の場合は 値域を整数の上限か下限にもっていってしまえば 比較一回で範囲外か範囲内かがわかるようになります。
だから、値域を移動させるための加算が一回、比較が一回、マスクが一回の形。
計3命令で実現できるかな。



投稿者 Takenori : 2008年02月23日 20:49




comments powered by Disqus
Total : Today : Yesterday : なかのひと