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の命令が充実してくれば使えるかも知れないので、こういうアイデアもあるんだよということで一応書いておきます。何か条件が変われば使えるかも知れませんし、別のことに応用できるかも知れませんし…。


つづく