From: Sanjay Patel Date: Fri, 25 Sep 2015 23:21:38 +0000 (+0000) Subject: [InstCombine] match De Morgan's Law hidden by zext ops (PR22723) X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=358e4088417ffbb59a269825daf6543742fa8eef;p=oota-llvm.git [InstCombine] match De Morgan's Law hidden by zext ops (PR22723) This is a fix for PR22723: https://llvm.org/bugs/show_bug.cgi?id=22723 My first attempt at this was to change what I thought was the root problem: xor (zext i1 X to i32), 1 --> zext (xor i1 X, true) to i32 ...but we create the opposite pattern in InstCombiner::visitZExt(), so infinite loop! My next idea was to fix the matchIfNot() implementation in PatternMatch, but that would mean potentially returning a different size for the match than what was input. I think this would require all users of m_Not to check the size of the returned match, so I abandoned that idea. I settled on just fixing the exact case presented in the PR. This patch does allow the 2 functions in PR22723 to compile identically (x86): bool test(bool x, bool y) { return !x | !y; } bool test(bool x, bool y) { return !x || !y; } ... andb %sil, %dil xorb $1, %dil movb %dil, %al retq Differential Revision: http://reviews.llvm.org/D12705 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@248634 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp index 5459c8955a1..d6e87b61177 100644 --- a/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ b/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -1208,6 +1208,11 @@ static Instruction *matchDeMorgansLaws(BinaryOperator &I, auto Opcode = I.getOpcode(); assert((Opcode == Instruction::And || Opcode == Instruction::Or) && "Trying to match De Morgan's Laws with something other than and/or"); + // Flip the logic operation. + if (Opcode == Instruction::And) + Opcode = Instruction::Or; + else + Opcode = Instruction::And; Value *Op0 = I.getOperand(0); Value *Op1 = I.getOperand(1); @@ -1215,16 +1220,31 @@ static Instruction *matchDeMorgansLaws(BinaryOperator &I, if (Value *Op0NotVal = dyn_castNotVal(Op0)) if (Value *Op1NotVal = dyn_castNotVal(Op1)) if (Op0->hasOneUse() && Op1->hasOneUse()) { - // Flip the logic operation. - if (Opcode == Instruction::And) - Opcode = Instruction::Or; - else - Opcode = Instruction::And; Value *LogicOp = Builder->CreateBinOp(Opcode, Op0NotVal, Op1NotVal, I.getName() + ".demorgan"); return BinaryOperator::CreateNot(LogicOp); } + // De Morgan's Law in disguise: + // (zext(bool A) ^ 1) & (zext(bool B) ^ 1) -> zext(~(A | B)) + // (zext(bool A) ^ 1) | (zext(bool B) ^ 1) -> zext(~(A & B)) + Value *A = nullptr; + Value *B = nullptr; + ConstantInt *C1 = nullptr; + if (match(Op0, m_OneUse(m_Xor(m_ZExt(m_Value(A)), m_ConstantInt(C1)))) && + match(Op1, m_OneUse(m_Xor(m_ZExt(m_Value(B)), m_Specific(C1))))) { + // TODO: This check could be loosened to handle different type sizes. + // Alternatively, we could fix the definition of m_Not to recognize a not + // operation hidden by a zext? + if (A->getType()->isIntegerTy(1) && B->getType()->isIntegerTy(1) && + C1->isOne()) { + Value *LogicOp = Builder->CreateBinOp(Opcode, A, B, + I.getName() + ".demorgan"); + Value *Not = Builder->CreateNot(LogicOp); + return CastInst::CreateZExtOrBitCast(Not, I.getType()); + } + } + return nullptr; } diff --git a/test/Transforms/InstCombine/demorgan-zext.ll b/test/Transforms/InstCombine/demorgan-zext.ll index 0587ca7cfa7..da41fac3e35 100644 --- a/test/Transforms/InstCombine/demorgan-zext.ll +++ b/test/Transforms/InstCombine/demorgan-zext.ll @@ -11,12 +11,10 @@ define i32 @demorgan_or(i1 %X, i1 %Y) { ret i32 %or ; CHECK-LABEL: demorgan_or( -; CHECK-NEXT: = zext -; CHECK-NEXT: = zext -; CHECK-NEXT: = xor -; CHECK-NEXT: = xor -; CHECK-NEXT: = or -; CHECK-NEXT: ret +; CHECK-NEXT: %[[AND:.*]] = and i1 %X, %Y +; CHECK-NEXT: %[[ZEXT:.*]] = zext i1 %[[AND]] to i32 +; CHECK-NEXT: %[[XOR:.*]] = xor i32 %[[ZEXT]], 1 +; CHECK-NEXT: ret i32 %[[XOR]] } define i32 @demorgan_and(i1 %X, i1 %Y) { @@ -28,11 +26,9 @@ define i32 @demorgan_and(i1 %X, i1 %Y) { ret i32 %and ; CHECK-LABEL: demorgan_and( -; CHECK-NEXT: = zext -; CHECK-NEXT: = zext -; CHECK-NEXT: = xor -; CHECK-NEXT: = xor -; CHECK-NEXT: = and -; CHECK-NEXT: ret +; CHECK-NEXT: %[[OR:.*]] = or i1 %X, %Y +; CHECK-NEXT: %[[ZEXT:.*]] = zext i1 %[[OR]] to i32 +; CHECK-NEXT: %[[XOR:.*]] = xor i32 %[[ZEXT]], 1 +; CHECK-NEXT: ret i32 %[[XOR]] }