SSEを用いたbsr/bsf命令の実現に向けて その5
packed u16の下位8bitにbsr/bsfしたときの結果らしきものが代入できました。
では、これをpacked u16となして最小値を探せば良いのです。
最小値を探す命令は、_mm_minpos_epu16(PHMINPOSUW)を使います。
残念なことに最大値を探す命令(PHMAXPOSUW?)はありません。PHMINPOSUWの末尾のUWがUnsigned Word(u16)の意味で、これはu16専用です。u8用ですとかs32用ですとか、そういうものは一切ありません。最小値をpacked u16に対して探す命令が1つあるだけです。命令を追加する余裕がなかったのでしょうか。よくわかりません。
最小値を探す命令を使うので、(b),(c),(d)以外の部分をmaskします。ここで言うmaskとは(最小値にこそ意味があるので)、他の部分を1でbitwise orをして1にしてしまうことを意味します。
あとPHMINPOSUWは、bit8..15に、最小値を見つけたその位置が返るようですので、この値は必要ありませんのでmaskするなり何なりしてやる必要があります。
以上、私のSSEによるbsr/bsfのアイデアをだらだらと書いてみました。
念のため擬似コードを書いておきます。
// integer→float変換 #define Bitboard_Cvt(b,b1) (b).m0 = _mm_cvtepi32_ps( (b1).m ) // 最小値の場所を探す #define Bitboard_MinPos(b,b1) (b).m = _mm_minpos_epu16( (b1).m ) // SSE used bitscan method by LS3600 Bitboard_Cvt(bb,b1); bb >>= 7; bb += (u128)0xB70000009C000000810000; // 0x81 + 27 = 0x9c , 0x81 + 27*2 = 0xB7 bb |= (u128)0xffffffffff00ffffff00ffffff00ffff; // 0のpacked byteを潰しておく必要がある。 Bitboard_MinPos(bb,bb); BoardPos position = bb.m.m128i_u8[0]; // bsf/bsr相当の値が得られた
実際は、上のコードは全く速くはないでしょう。integer→floatの変換がいかにも時間がかかりそうですし、m128i_u8[0]で下位byteを取り出す部分が、直接レジスタ間のコピーで済まないのでメモリを経由させる必要があります。
もう少しSSEの命令が充実してくれば使えるかも知れないので、こういうアイデアもあるんだよということで一応書いておきます。何か条件が変われば使えるかも知れませんし、別のことに応用できるかも知れませんし…。
つづく