From: Chris Lattner Date: Mon, 26 Oct 2009 01:06:31 +0000 (+0000) Subject: Implement PR3266 & PR5276, folding: X-Git-Url: http://plrg.eecs.uci.edu/git/?a=commitdiff_plain;h=863928fc39c7f1ab86779415eb704b2f2474b995;p=oota-llvm.git Implement PR3266 & PR5276, folding: not (or (icmp, icmp)) -> and(icmp, icmp) git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@85085 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Transforms/Scalar/InstructionCombining.cpp b/lib/Transforms/Scalar/InstructionCombining.cpp index 81423b740b6..0285fb53773 100644 --- a/lib/Transforms/Scalar/InstructionCombining.cpp +++ b/lib/Transforms/Scalar/InstructionCombining.cpp @@ -631,9 +631,32 @@ static inline Value *dyn_castFNegVal(Value *V) { return 0; } -static inline Value *dyn_castNotVal(Value *V) { +/// isFreeToInvert - Return true if the specified value is free to invert (apply +/// ~ to). This happens in cases where the ~ can be eliminated. +static inline bool isFreeToInvert(Value *V) { + // ~(~(X)) -> X. if (BinaryOperator::isNot(V)) - return BinaryOperator::getNotArgument(V); + return true; + + // Constants can be considered to be not'ed values. + if (isa(V)) + return true; + + // Compares can be inverted if they have a single use. + if (CmpInst *CI = dyn_cast(V)) + return CI->hasOneUse(); + + return false; +} + +static inline Value *dyn_castNotVal(Value *V) { + // If this is not(not(x)) don't return that this is a not: we want the two + // not's to be folded first. + if (BinaryOperator::isNot(V)) { + Value *Operand = BinaryOperator::getNotArgument(V); + if (!isFreeToInvert(Operand)) + return Operand; + } // Constants can be considered to be not'ed values... if (ConstantInt *C = dyn_cast(V)) @@ -641,6 +664,8 @@ static inline Value *dyn_castNotVal(Value *V) { return 0; } + + // dyn_castFoldableMul - If this value is a multiply that can be folded into // other computations (because it has a constant operand), return the // non-constant operand of the multiply, and set CST to point to the multiplier. @@ -4166,7 +4191,7 @@ Instruction *InstCombiner::visitAnd(BinaryOperator &I) { if (Instruction *CastOp = dyn_cast(CI->getOperand(0))) { if ((isa(CI) || isa(CI)) && CastOp->getNumOperands() == 2) - if (ConstantInt *AndCI = dyn_cast(CastOp->getOperand(1))) { + if (ConstantInt *AndCI =dyn_cast(CastOp->getOperand(1))){ if (CastOp->getOpcode() == Instruction::And) { // Change: and (cast (and X, C1) to T), C2 // into : and (cast X to T), trunc_or_bitcast(C1)&C2 @@ -5064,12 +5089,13 @@ Instruction *InstCombiner::visitXor(BinaryOperator &I) { // Is this a ~ operation? if (Value *NotOp = dyn_castNotVal(&I)) { - // ~(~X & Y) --> (X | ~Y) - De Morgan's Law - // ~(~X | Y) === (X & ~Y) - De Morgan's Law if (BinaryOperator *Op0I = dyn_cast(NotOp)) { if (Op0I->getOpcode() == Instruction::And || Op0I->getOpcode() == Instruction::Or) { - if (dyn_castNotVal(Op0I->getOperand(1))) Op0I->swapOperands(); + // ~(~X & Y) --> (X | ~Y) - De Morgan's Law + // ~(~X | Y) === (X & ~Y) - De Morgan's Law + if (dyn_castNotVal(Op0I->getOperand(1))) + Op0I->swapOperands(); if (Value *Op0NotVal = dyn_castNotVal(Op0I->getOperand(0))) { Value *NotY = Builder->CreateNot(Op0I->getOperand(1), @@ -5078,6 +5104,19 @@ Instruction *InstCombiner::visitXor(BinaryOperator &I) { return BinaryOperator::CreateOr(Op0NotVal, NotY); return BinaryOperator::CreateAnd(Op0NotVal, NotY); } + + // ~(X & Y) --> (~X | ~Y) - De Morgan's Law + // ~(X | Y) === (~X & ~Y) - De Morgan's Law + if (isFreeToInvert(Op0I->getOperand(0)) && + isFreeToInvert(Op0I->getOperand(1))) { + Value *NotX = + Builder->CreateNot(Op0I->getOperand(0), "notlhs"); + Value *NotY = + Builder->CreateNot(Op0I->getOperand(1), "notrhs"); + if (Op0I->getOpcode() == Instruction::And) + return BinaryOperator::CreateOr(NotX, NotY); + return BinaryOperator::CreateAnd(NotX, NotY); + } } } } diff --git a/test/Transforms/InstCombine/or.ll b/test/Transforms/InstCombine/or.ll index dbdd08a489a..b72480b4f9d 100644 --- a/test/Transforms/InstCombine/or.ll +++ b/test/Transforms/InstCombine/or.ll @@ -237,4 +237,19 @@ define i1 @test24(double %X, double %Y) { ; CHECK: @test24 ; CHECK: %bothcond = fcmp uno double %Y, %X ; [#uses=1] ; CHECK: ret i1 %bothcond -} \ No newline at end of file +} + +; PR3266 & PR5276 +define i1 @test25(i32 %A, i32 %B) { + %C = icmp eq i32 %A, 0 + %D = icmp eq i32 %B, 57 + %E = or i1 %C, %D + %F = xor i1 %E, -1 + ret i1 %F + +; CHECK: @test25 +; CHECK: icmp ne i32 %A, 0 +; CHECK-NEXT: icmp ne i32 %B, 57 +; CHECK-NEXT: %F = and i1 +; CHECK-NEXT: ret i1 %F +} diff --git a/test/Transforms/InstCombine/xor-demorgans.ll b/test/Transforms/InstCombine/xor-demorgans.ll deleted file mode 100644 index 3383845fb36..00000000000 --- a/test/Transforms/InstCombine/xor-demorgans.ll +++ /dev/null @@ -1,12 +0,0 @@ -; RUN: opt < %s -instcombine -S | not grep {= or} -; PR3266 -; XFAIL: * - -define i1 @foo(i32 %x, i32 %y) nounwind { -.summary: - %0 = icmp sgt i32 %x, 4 ; [#uses=1] - %1 = icmp sgt i32 %y, 0 ; [#uses=1] - %.demorgan = or i1 %1, %0 ; [#uses=1] - %2 = xor i1 %.demorgan, true ; [#uses=1] - ret i1 %2 -}