式のつぶし方
主にやってたのこれなのですが、結構いろいろあって、コンパイラ屋さん大変だなぁ、と思ったりしてました(小並感)。
4種類ほど紹介します。
自明な bit 演算
(and 0 A) -> 0, (and 0xFFFFFFFFFFFFFFFF A) -> A, (and A A) -> A, (xor A A) -> 0, (and (not A) A) -> 0, (or (not A) A) -> 0xFFFFFFFFFFFFFFFF, (not (not A)) -> A, (not (or (not A) B) -> (or A B), (xor (not A) (not B)) -> (xor A B) etc. etc...
0/非0 の判定
定数は畳み込むので
(if0 0 A B) -> A
は即判断化ですが、逆はそうでもない。ので、(if0 C A B) に関して、基本Cの全bitを追いかけて、ひとつでも確実に1になるbitがあるなら B 。わからないときはあきらめてそのまま。
(if0 x A B)
Aが選択されるのは x = 0 の場合のみ。なので、(if0 x A[x/0], B)。さらに A[x/0] == B[x/0] なら B。
不必要な bit 演算の削除
(shr1 (xor 1 (or 1 x)))
みたいな式は、最後の shr1 が末尾の bit 操作をおとしてしまうので、xor も or も実は不必要。