[InstCombine] Fold `(X | C2) ^ C1 --> (X & ~C2) ^ (C1^C2)`
authorRoman Lebedev <lebedev.ri@gmail.com>
Sat, 2 Apr 2022 20:54:33 +0000 (23:54 +0300)
committerRoman Lebedev <lebedev.ri@gmail.com>
Sat, 2 Apr 2022 21:12:56 +0000 (00:12 +0300)
commit308ca349cbc5fa891b08c525084fc86017bdc498
treed463abf6a3080237166bad68f210ffa8c0804e5f
parent3ae08dac8f1031a5874572bf6f0a50097e1fbd25
[InstCombine] Fold `(X | C2) ^ C1 --> (X & ~C2) ^ (C1^C2)`

These two are equivalent,
and i *think* the `and` form is more-ish canonical.

General proof: https://alive2.llvm.org/ce/z/RrF5s6

If constant on the (outer) `xor` is an `undef`,
the whole lane is dead: https://alive2.llvm.org/ce/z/mu4Sh2

However, if the constant on the (inner) `or` is an `undef`,
we must sanitize it first: https://alive2.llvm.org/ce/z/MHYJL7
I guess, producing a zero `and`-mask is optimal in that case.

alive-tv is happy about the entirety of `xor-of-or.ll`.
llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
llvm/test/Transforms/InstCombine/and.ll
llvm/test/Transforms/InstCombine/apint-and.ll
llvm/test/Transforms/InstCombine/demorgan.ll
llvm/test/Transforms/InstCombine/or-xor.ll
llvm/test/Transforms/InstCombine/xor-of-or.ll
llvm/test/Transforms/InstCombine/xor.ll