%not1 = xor i32 %b, -1 %not2 = xor i32 %c, -1 %and1 = and i32 %a, %not1 %and2 = and i32 %and1, %not2
>
%i1 = or i32 %b, %c %i2 = xor i32 %1, -1 %and2 = and i32 %i2, %a
Differential D112108
[InstCombine] Fold `(a & ~b) & ~c` to `a & ~(b | c)` rampitec on Oct 19 2021, 4:22 PM. Authored by
Details %not1 = xor i32 %b, -1 %not2 = xor i32 %c, -1 %and1 = and i32 %a, %not1 %and2 = and i32 %and1, %not2 >%i1 = or i32 %b, %c %i2 = xor i32 %1, -1 %and2 = and i32 %i2, %a
Diff Detail
Event Timeline
Comment Actions Please pre-commit the tests with current output, so we can confirm that we are testing all of the commuted patterns correctly. This seems like another short-coming of the reassociation pass, but I think it's ok to deal with the minimal case here. define i4 @src(i4 %a, i4 %b, i4 %c, i4 %d) { %notb = xor i4 %b, -1 %notc = xor i4 %c, -1 %and1 = and i4 %a, %notb %and2 = and i4 %and1, %d %and3 = and i4 %and2, %notc ret i4 %and3 }
Comment Actions Yes, this test does not change.
Comment Actions LGTM - I'd prefer that the NFC test changes get committed first followed by the code patch and its test changes. That way, we'll still have the expected tests/results in place even if the patch gets reverted for some reason. Comment Actions Actually it is transformed too. It does not with opt -instcombine but does with opt -reassociate -instcombine or just opt -O3. Comment Actions Thanks, that's good news. If you want to make sure that combination of transforms doesn't break invisibly, you could add a test like that for -O{1,2,3} runs to /test/Transforms/PhaseOrdering.. Comment Actions I forgot to mention it during the review, but we should always have these kinds of bitwise logic folds apply to the Demorgan'ized sibling form too (and this fold itself is just reassociation + Demorgan): Comment Actions Thanks Sanjay! I now wander if a next testcase I am looking at needs a pattern as I wanted to add to visitOr, because it also looks like a more complex case of reassociation: (c & ~(a | b)) | (b & ~(a | c)) --> ~a & (b ^ c) We currently cannot simplify it. define i32 @or_not_and(i32 %a, i32 %b, i32 %c) { %or1 = or i32 %a, %b %not1 = xor i32 %or1, -1 %and1 = and i32 %not1, %c %or2 = or i32 %a, %c %not2 = xor i32 %or2, -1 %and2 = and i32 %not2, %b %or3 = or i32 %and1, %and2 ret i32 %or3 } Comment Actions Hmm...so that's 2 of the patterns in this patch glued together. I don't see an intermediate fold that we can use to reduce it. Either you have to hard-code a big pattern match or add a generalized boolean logic solver (as its own pass). Comment Actions Having a separate boolean logic solver might be a good idea in a long run. I.e. collect operands unused ouside of a dag solved, build truth table, generate a minimal expression. But that probably needs much more thought than this initial idea. |
You can fold the one-use check into the 1st match with m_OneUse(). Could also use && for the match clauses instead of nested ifs to make the structure more like the code above here.