Index: include/llvm/Analysis/ValueTracking.h =================================================================== --- include/llvm/Analysis/ValueTracking.h +++ include/llvm/Analysis/ValueTracking.h @@ -429,16 +429,18 @@ /// E.g. if RangeMD is !{i32 0, i32 10, i32 15, i32 20} then return [0, 20). ConstantRange getConstantRangeFromMetadata(MDNode &RangeMD); - /// Return true if RHS is known to be implied by LHS. A & B must be i1 - /// (boolean) values or a vector of such values. Note that the truth table for - /// implication is the same as <=u on i1 values (but not <=s!). The truth - /// table for both is: + /// Return true if RHS is known to be implied by LHS. The implication may be + /// either true or false depending on what is returned in ImpliedTrue. + /// A & B must be i1 (boolean) values or a vector of such values. Note that + /// the truth table for implication is the same as <=u on i1 values (but not + /// <=s!). The truth table for both is: /// | T | F (B) /// T | T | F /// F | T | T /// (A) - bool isImpliedCondition(Value *LHS, Value *RHS, const DataLayout &DL, - unsigned Depth = 0, AssumptionCache *AC = nullptr, + bool isImpliedCondition(Value *LHS, Value *RHS, bool &ImpliedTrue, + const DataLayout &DL, unsigned Depth = 0, + AssumptionCache *AC = nullptr, const Instruction *CxtI = nullptr, const DominatorTree *DT = nullptr); } // end namespace llvm Index: lib/Analysis/InstructionSimplify.cpp =================================================================== --- lib/Analysis/InstructionSimplify.cpp +++ lib/Analysis/InstructionSimplify.cpp @@ -2131,14 +2131,16 @@ if (match(RHS, m_Zero())) return LHS; break; - case ICmpInst::ICMP_UGE: + case ICmpInst::ICMP_UGE: { // X >=u 1 -> X if (match(RHS, m_One())) return LHS; - if (isImpliedCondition(RHS, LHS, Q.DL)) + bool ImpliedTrue; + if (isImpliedCondition(RHS, LHS, ImpliedTrue, Q.DL) && ImpliedTrue) return getTrue(ITy); break; - case ICmpInst::ICMP_SGE: + } + case ICmpInst::ICMP_SGE: { /// For signed comparison, the values for an i1 are 0 and -1 /// respectively. This maps into a truth table of: /// LHS | RHS | LHS >=s RHS | LHS implies RHS @@ -2146,9 +2148,11 @@ /// 0 | 1 | 1 (0 >= -1) | 1 /// 1 | 0 | 0 (-1 >= 0) | 0 /// 1 | 1 | 1 (-1 >= -1) | 1 - if (isImpliedCondition(LHS, RHS, Q.DL)) + bool ImpliedTrue; + if (isImpliedCondition(LHS, RHS, ImpliedTrue, Q.DL) && ImpliedTrue) return getTrue(ITy); break; + } case ICmpInst::ICMP_SLT: // X X if (match(RHS, m_Zero())) @@ -2159,11 +2163,13 @@ if (match(RHS, m_One())) return LHS; break; - case ICmpInst::ICMP_ULE: - if (isImpliedCondition(LHS, RHS, Q.DL)) + case ICmpInst::ICMP_ULE: { + bool ImpliedTrue; + if (isImpliedCondition(LHS, RHS, ImpliedTrue, Q.DL) && ImpliedTrue) return getTrue(ITy); break; } + } } // If we are comparing with zero then try hard since this is a common case. Index: lib/Analysis/ValueTracking.cpp =================================================================== --- lib/Analysis/ValueTracking.cpp +++ lib/Analysis/ValueTracking.cpp @@ -3769,9 +3769,47 @@ } } -bool llvm::isImpliedCondition(Value *LHS, Value *RHS, const DataLayout &DL, - unsigned Depth, AssumptionCache *AC, - const Instruction *CxtI, +/// Return true if "icmp2 Pred op2 op1" is known to be implied by "icmp1 Pred +/// op1 op2". The implication may be either true or false depending on the +/// value of ImpliedTrue. +static bool isImpliedCondSwappedOperands(CmpInst::Predicate PredA, Value *ALHS, + Value *ARHS, CmpInst::Predicate PredB, + Value *BLHS, Value *BRHS, + bool &ImpliedTrue) { + // The below logic assumes the swapped operands match. + if (ALHS != BRHS || ARHS != BLHS) + return false; + + // If the predicates match we can infer the second condition is false because + // if, for example, A > B is true, then B > A must be false. + if (PredA == PredB) { + switch (PredA) { + default: + break; + case CmpInst::ICMP_UGT: + case CmpInst::ICMP_ULT: + case CmpInst::ICMP_SGT: + case CmpInst::ICMP_SLT: + ImpliedTrue = false; + return true; + } + } + + // If the swapped predicates match, then we know the first condition implies + // the second is true. + if (PredA == ICmpInst::getSwappedPredicate(PredB)) { + ImpliedTrue = true; + return true; + } + + // FIXME: Lots of additional implications can be inferred. For example, A == + // B implies A > B and A < B are false. + return false; +} + +bool llvm::isImpliedCondition(Value *LHS, Value *RHS, bool &ImpliedTrue, + const DataLayout &DL, unsigned Depth, + AssumptionCache *AC, const Instruction *CxtI, const DominatorTree *DT) { assert(LHS->getType() == RHS->getType() && "mismatched type"); Type *OpTy = LHS->getType(); @@ -3793,9 +3831,16 @@ !match(RHS, m_ICmp(BPred, m_Value(BLHS), m_Value(BRHS)))) return false; - if (APred == BPred) + // Infer condition based on swapped operands. + if (isImpliedCondSwappedOperands(APred, ALHS, ARHS, BPred, BLHS, BRHS, + ImpliedTrue)) + return true; + + if (APred == BPred) { + ImpliedTrue = true; return isImpliedCondOperands(APred, ALHS, ARHS, BLHS, BRHS, DL, Depth, AC, CxtI, DT); + } return false; } Index: lib/Transforms/Scalar/JumpThreading.cpp =================================================================== --- lib/Transforms/Scalar/JumpThreading.cpp +++ lib/Transforms/Scalar/JumpThreading.cpp @@ -928,12 +928,16 @@ if (!PBI || !PBI->isConditional() || PBI->getSuccessor(0) != CurrentBB) return false; - if (isImpliedCondition(PBI->getCondition(), Cond, DL)) { + bool ImpliedTrue; + if (isImpliedCondition(PBI->getCondition(), Cond, ImpliedTrue, DL) && + ImpliedTrue) { BI->getSuccessor(1)->removePredecessor(BB); BranchInst::Create(BI->getSuccessor(0), BI); BI->eraseFromParent(); return true; } + // FIXME: If ImpliedTrue == false we should unconditionally branch to the + // false edge. CurrentBB = CurrentPred; CurrentPred = CurrentBB->getSinglePredecessor(); } Index: lib/Transforms/Utils/SimplifyCFG.cpp =================================================================== --- lib/Transforms/Utils/SimplifyCFG.cpp +++ lib/Transforms/Utils/SimplifyCFG.cpp @@ -2722,13 +2722,17 @@ // If BI is reached from the true path of PBI and PBI's condition implies // BI's condition, we know the direction of the BI branch. + bool ImpliedTrue; if (PBI->getSuccessor(0) == BI->getParent() && - isImpliedCondition(PBI->getCondition(), BI->getCondition(), DL) && + isImpliedCondition(PBI->getCondition(), BI->getCondition(), ImpliedTrue, + DL) && PBI->getSuccessor(0) != PBI->getSuccessor(1) && BB->getSinglePredecessor()) { // Turn this into a branch on constant. auto *OldCond = BI->getCondition(); - BI->setCondition(ConstantInt::getTrue(BB->getContext())); + ConstantInt *CI = ImpliedTrue ? ConstantInt::getTrue(BB->getContext()) + : ConstantInt::getFalse(BB->getContext()); + BI->setCondition(CI); RecursivelyDeleteTriviallyDeadInstructions(OldCond); return true; // Nuke the branch on constant. } Index: test/Transforms/SimplifyCFG/implied-cond-swapped.ll =================================================================== --- /dev/null +++ test/Transforms/SimplifyCFG/implied-cond-swapped.ll @@ -0,0 +1,68 @@ +; RUN: opt %s -S -simplifycfg | FileCheck %s + +; Test same condition with swapped operands. +; void test_swapped_ops(unsigned a, unsigned b) { +; if (a > b) { +; if (b > a) <- always false +; dead(); +; alive(); +; } +; } +; +; CHECK-LABEL: @test_swapped_ops +; CHECK-NOT: call void @dead() +; CHECK: call void @alive() +; CHECK: ret +define void @test_swapped_ops(i32 %a, i32 %b) { +entry: + %cmp = icmp ugt i32 %a, %b + br i1 %cmp, label %if.then, label %if.end3 + +if.then: + %cmp1 = icmp ugt i32 %b, %a + br i1 %cmp1, label %if.then2, label %if.end + +if.then2: + call void @dead() + br label %if.end + +if.end: + call void @alive() + br label %if.end3 + +if.end3: + ret void +} + +; void test_swapped_pred(unsigned a, unsigned b) { +; if (a > b) { +; alive(); +; if (b < a) <- always true; remove branch +; alive(); +; } +; } +; +; CHECK-LABEL: @test_swapped_pred +; CHECK: call void @alive() +; CHECK-NEXT: call void @alive() +; CHECK: ret +define void @test_swapped_pred(i32 %a, i32 %b) { +entry: + %cmp = icmp ugt i32 %a, %b + br i1 %cmp, label %if.then, label %if.end3 + +if.then: + call void @alive() + %cmp1 = icmp ult i32 %b, %a + br i1 %cmp1, label %if.then2, label %if.end3 + +if.then2: + call void @alive() + br label %if.end3 + +if.end3: + ret void +} + +declare void @dead() +declare void @alive()