« 比較 | メイン | クリッピング »

2008年02月23日

x86 SIMD Technique:: 並列スワップ

    

SIMD の比較を使うことで、スワップも一度に行うことが出来る。
複数個同時にスワップが出来、分岐がなくなるので高速化に役立つ。
以下、SSE を使ったコード。

// if( x1 > x2 ) swap( x1, s2 ); を行う
__m128 swapmask = _mm_cmpgt_ps( x1, x2 );
__m128 tmp = x1;
x1 = _mm_add_ps( _mm_andnot_ps( swapmask, x1 ), _mm_and_ps( swapmask, x2 ) );  // x1 = (~mask & x1 ) + (mask & x2 );
x2 = _mm_add_ps( _mm_andnot_ps( swapmask, x2 ), _mm_and_ps( swapmask, tmp ) ); // x2 = (~mask & x2 ) + (mask & tmp );

比較を使ってマスクを作り出し、入れ替え対象のものを 0 にして、代入する値を逆のマスクで交換する値のみ残し、加算している。
MMX や SSE2 などでも同じようにしてできる。
整数の時は加算よりも or を取る方が自然かもしれない。

追記:
上の処理だと、min、max を使えばそれで出来ると指摘されたので追記。
コードは以下。

__m128 tmp = x1;
x1 = _mm_min_ps(x1, x2);
x2 = _mm_max_ps(tmp, x2);

上のソースを実際に使っているところでは、この x1 と x2 条件で uv 値もスワップしているため、min、max では実現できない。
例文のソースコードは比較条件を別のものにした方がよかったかも。

さらに追記:
xor でスワップするテクニックを使えば、さらに速くなると指摘を受けたので追記。
コードは以下。

__m128 tmp = _mm_and_ps(_mm_xor_ps(x1, x2), _mm_cmpgt_ps( x1, x2 ));
x1 = _mm_xor_ps(tmp, x1);
x2 = _mm_xor_ps(tmp, x2);

xor でスワップは最近使っていなかったのと、浮動小数点だったので抜け落ちていた。



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




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