2012/10/14
■ SSEによるbitboardの実装の検討
bitboardによる先手銀の駒を取らない移動手のコードは、
org=p->bitboard[BLACK][P_GIN]; // 銀
while ( (from=bit_pop1st(&org)) >= 0 ) {
and128(t,attack_gin_b[from],target);
mt=from+(P_GIN<<14);
while ( (to=bit_pop1st(&t)) >= 0 ) {
pin_check()
*p_move++=mt+(to<<7);
if ( (to <= 26) || (from <= 26) ) *p_move++=mt+(to<<7)+PROMOTE_BIT;
}
}
bit_pop1stはbitboardのLSBから立っているビット位置を返し、そのビットをクリアする関数である。bitboardが全てゼロのときは-1を返すようにした。
static inline int
bit_pop1st(BITBOARD *x)
{
int pos=-1;
#ifdef __x86_64__
if ( x->l64 ) {
pos=__builtin_ctzll(x->l64);
x->l64&=(x->l64-1); // reset bit
}
else if ( x->h64 ) {
pos=__builtin_ctzll(x->h64)+64;
x->h64&=(x->h64-1); // reset bit
}
#else
if ( x->l ) {
pos=__builtin_ctz(x->l);
x->l&=(x->l-1); // reset bit
}
else if ( x->m ) {
pos=__builtin_ctz(x->m)+32;
x->m&=(x->m-1); // reset bit
}
else if ( x->h ) {
pos=__builtin_ctz(x->h)+64;
x->h&=(x->h-1); // reset bit
}
#endif
return pos;
}
SSE2ではand128などの128bit論理演算が可能である。
#define zero128(r) (r).x=_mm_xor_si128((r).x,(r).x) #define and128(r,a,b) (r).x=_mm_and_si128((a).x,(b).x) #define or128(r,a,b) (r).x=_mm_or_si128((a).x,(b).x) #define xor128(r,a,b) (r).x=_mm_xor_si128((a).x,(b).x) #define andnot128(r,a,b) (r).x=_mm_andnot_si128((b).x,(a).x) #define andor128(r,a,b) (r).x=_mm_or_si128((r).x,_mm_and_si128((a).x,(b).x))
SSE4では次の比較関数も使える。Zフラグに結果が入る。
#define test128(a) (!_mm_testz_si128((a).x,(a).x)) #define andtest128(a,b) (!_mm_testz_si128((a).x,(b).x))
上記手生成コードでSIMD命令が有効となるのはand128であろう。後の命令は非SIMD命令であり、SIMDレジスタと通常レジスタの移動のオーバーヘッドがあるだろう。

