SSEの命令に_mm_andnot_si128()というのがあります。この命令を使うと、(Bitboardの)notしたあとandを取りたいときに1命令で処理することが出来ます。なかなか凄い命令です。ところが、従来、
drop_to = rank2_9_bb & ~ occupied; // 先手の香が打てる場所は敵の駒がない2から9筋
のように書いたときに、&と~とが個別に呼び出されるので、_mm_andnot_si128()を使うコードが生成されません。
そこで、上の場合、andnotという関数を用意して
drop_to = andnot(rank2_9,occupied);
のように書く必要がありました。これは、可読性がすこぶる悪いです。ソースコードがぐちゃぐちゃになっていきますね。
それなら「&~」を自動的に置換するようなプリプロセッサでも作ればいいじゃん、みたいな発想になるのは老害というものです。いまどきそんなの流行りません。
いまは、
「C++のExpression Templateでそれ出来るよ」
であります。
Bitboardクラスの演算子オーバーロードで_mm_andnot_si128()を使う
http://d.hatena.ne.jp/merom686/20151126/1448507504
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
class Bitboard { __m128i m128i_; struct Not { const __m128i not_m128i_; //~b0 & b1 Bitboard operator&(const Bitboard& b) const { return Bitboard{ _mm_andnot_si128(not_m128i_, b.m128i_) }; } //通常のnot operator Bitboard() const { __m128i temp; const __m128i mask = _mm_cmpeq_epi64(temp, temp); return Bitboard{ _mm_xor_si128(not_m128i_, mask) }; } explicit Not(const Bitboard& b) : not_m128i_(b.m128i_) {} }; public: //ここでは計算せずNot構造体を返す Bitboard::Not operator~() const { return Bitboard::Not{ *this }; } //b0 & ~b1 Bitboard operator&(const Bitboard::Not& not_b) const { return Bitboard{ _mm_andnot_si128(not_b.not_m128i_, m128i_) }; } Bitboard operator&(const Bitboard& b) const { return Bitboard{ _mm_and_si128(m128i_, b.m128i_) }; } uint64_t operator[](const size_t i) const { return m128i_.m128i_u64[i]; } constexpr explicit Bitboard(const __m128i& i) : m128i_(i) {} }; |
個人的には、この素晴らしい発明に、2015年コンピューター将棋技術大賞(?)を差し上げたいところです。C++はまさに秘境でありますな。
Expression Templateについては以下の記事を参考にどうぞ。
Expression Template(Faith and Brave – C++で遊ぼう)
http://faithandbrave.hateblo.jp/entry/20081003/1223026720
結果を auto で受け取らないように注意ですね。
ああ、そういう問題がありますね…。
&のうしろが ~なら &は _mm_andnot_si128 になり、
&のうしろが ~でないなら &は _mm_and_si128 になるのかだぜ☆(^~^)
それで &一発の読みやすさがそのままに
~、& 2連発分だったのが _mm_andnot_si128 一発になるのかなんだぜ☆
こんなことやってるのか☆www(^▽^)