diff --git a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp index d2d8f2262ee12..3c47d36cbc0a0 100644 --- a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp +++ b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp @@ -83,6 +83,16 @@ static Instruction *getContextInstForUse(Use &U) { } namespace { +/// Struct to express a condition of the form %Op0 Pred %Op1. +struct ConditionTy { + CmpInst::Predicate Pred; + Value *Op0; + Value *Op1; + + ConditionTy(CmpInst::Predicate Pred, Value *Op0, Value *Op1) + : Pred(Pred), Op0(Op0), Op1(Op1) {} +}; + /// Represents either /// * a condition that holds on entry to a block (=condition fact) /// * an assume (=assume fact) @@ -101,29 +111,37 @@ struct FactOrCheck { union { Instruction *Inst; Use *U; + ConditionTy Cond; }; unsigned NumIn; unsigned NumOut; EntryTy Ty; - bool Not; - FactOrCheck(EntryTy Ty, DomTreeNode *DTN, Instruction *Inst, bool Not) + FactOrCheck(EntryTy Ty, DomTreeNode *DTN, Instruction *Inst) : Inst(Inst), NumIn(DTN->getDFSNumIn()), NumOut(DTN->getDFSNumOut()), - Ty(Ty), Not(Not) {} + Ty(Ty) {} FactOrCheck(DomTreeNode *DTN, Use *U) : U(U), NumIn(DTN->getDFSNumIn()), NumOut(DTN->getDFSNumOut()), - Ty(EntryTy::UseCheck), Not(false) {} + Ty(EntryTy::UseCheck) {} - static FactOrCheck getConditionFact(DomTreeNode *DTN, CmpInst *Inst, - bool Not = false) { - return FactOrCheck(EntryTy::ConditionFact, DTN, Inst, Not); + FactOrCheck(DomTreeNode *DTN, CmpInst::Predicate Pred, Value *Op0, Value *Op1) + : Cond(Pred, Op0, Op1), NumIn(DTN->getDFSNumIn()), + NumOut(DTN->getDFSNumOut()), Ty(EntryTy::ConditionFact) {} + + static FactOrCheck getConditionFact(DomTreeNode *DTN, CmpInst::Predicate Pred, + Value *Op0, Value *Op1) { + return FactOrCheck(DTN, Pred, Op0, Op1); + } + + static FactOrCheck getInstFact(DomTreeNode *DTN, Instruction *Inst) { + return FactOrCheck(EntryTy::InstFact, DTN, Inst); } - static FactOrCheck getInstFact(DomTreeNode *DTN, Instruction *Inst, - bool Not = false) { - return FactOrCheck(EntryTy::InstFact, DTN, Inst, Not); + static FactOrCheck getFact(DomTreeNode *DTN, CmpInst::Predicate Pred, + Value *Op0, Value *Op1) { + return FactOrCheck(DTN, Pred, Op0, Op1); } static FactOrCheck getCheck(DomTreeNode *DTN, Use *U) { @@ -131,7 +149,7 @@ struct FactOrCheck { } static FactOrCheck getCheck(DomTreeNode *DTN, CallInst *CI) { - return FactOrCheck(EntryTy::InstCheck, DTN, CI, false); + return FactOrCheck(EntryTy::InstCheck, DTN, CI); } bool isCheck() const { @@ -188,19 +206,9 @@ struct StackEntry { ValuesToRelease(ValuesToRelease) {} }; -/// Struct to express a pre-condition of the form %Op0 Pred %Op1. -struct PreconditionTy { - CmpInst::Predicate Pred; - Value *Op0; - Value *Op1; - - PreconditionTy(CmpInst::Predicate Pred, Value *Op0, Value *Op1) - : Pred(Pred), Op0(Op0), Op1(Op1) {} -}; - struct ConstraintTy { SmallVector Coefficients; - SmallVector Preconditions; + SmallVector Preconditions; SmallVector> ExtraInfo; @@ -346,7 +354,7 @@ struct Decomposition { } // namespace static Decomposition decompose(Value *V, - SmallVectorImpl &Preconditions, + SmallVectorImpl &Preconditions, bool IsSigned, const DataLayout &DL); static bool canUseSExt(ConstantInt *CI) { @@ -354,9 +362,9 @@ static bool canUseSExt(ConstantInt *CI) { return Val.sgt(MinSignedConstraintValue) && Val.slt(MaxConstraintValue); } -static Decomposition -decomposeGEP(GEPOperator &GEP, SmallVectorImpl &Preconditions, - bool IsSigned, const DataLayout &DL) { +static Decomposition decomposeGEP(GEPOperator &GEP, + SmallVectorImpl &Preconditions, + bool IsSigned, const DataLayout &DL) { // Do not reason about pointers where the index size is larger than 64 bits, // as the coefficients used to encode constraints are 64 bit integers. if (DL.getIndexTypeSizeInBits(GEP.getPointerOperand()->getType()) > 64) @@ -417,7 +425,7 @@ decomposeGEP(GEPOperator &GEP, SmallVectorImpl &Preconditions, // Variable } where Coefficient * Variable. The sum of the constant offset and // pairs equals \p V. static Decomposition decompose(Value *V, - SmallVectorImpl &Preconditions, + SmallVectorImpl &Preconditions, bool IsSigned, const DataLayout &DL) { auto MergeResults = [&Preconditions, IsSigned, &DL](Value *A, Value *B, @@ -560,7 +568,7 @@ ConstraintInfo::getConstraint(CmpInst::Predicate Pred, Value *Op0, Value *Op1, Pred != CmpInst::ICMP_SLE && Pred != CmpInst::ICMP_SLT) return {}; - SmallVector Preconditions; + SmallVector Preconditions; bool IsSigned = CmpInst::isSigned(Pred); auto &Value2Index = getValue2Index(IsSigned); auto ADec = decompose(Op0->stripPointerCastsSameRepresentation(), @@ -670,7 +678,7 @@ ConstraintTy ConstraintInfo::getConstraintForSolving(CmpInst::Predicate Pred, bool ConstraintTy::isValid(const ConstraintInfo &Info) const { return Coefficients.size() > 0 && - all_of(Preconditions, [&Info](const PreconditionTy &C) { + all_of(Preconditions, [&Info](const ConditionTy &C) { return Info.doesHold(C.Pred, C.Op0, C.Op1); }); } @@ -805,15 +813,16 @@ void State::addInfoFor(BasicBlock &BB) { continue; } - Value *Cond; + Value *A, *B; + CmpInst::Predicate Pred; // For now, just handle assumes with a single compare as condition. - if (match(&I, m_Intrinsic(m_Value(Cond))) && - isa(Cond)) { + if (match(&I, m_Intrinsic( + m_ICmp(Pred, m_Value(A), m_Value(B))))) { if (GuaranteedToExecute) { // The assume is guaranteed to execute when BB is entered, hence Cond // holds on entry to BB. WorkList.emplace_back(FactOrCheck::getConditionFact( - DT.getNode(I.getParent()), cast(Cond))); + DT.getNode(I.getParent()), Pred, A, B)); } else { WorkList.emplace_back( FactOrCheck::getInstFact(DT.getNode(I.getParent()), &I)); @@ -853,8 +862,11 @@ void State::addInfoFor(BasicBlock &BB) { while (!CondWorkList.empty()) { Value *Cur = CondWorkList.pop_back_val(); if (auto *Cmp = dyn_cast(Cur)) { - WorkList.emplace_back( - FactOrCheck::getConditionFact(DT.getNode(Successor), Cmp, IsOr)); + WorkList.emplace_back(FactOrCheck::getConditionFact( + DT.getNode(Successor), + IsOr ? CmpInst::getInversePredicate(Cmp->getPredicate()) + : Cmp->getPredicate(), + Cmp->getOperand(0), Cmp->getOperand(1))); continue; } if (IsOr && match(Cur, m_LogicalOr(m_Value(Op0), m_Value(Op1)))) { @@ -876,11 +888,14 @@ void State::addInfoFor(BasicBlock &BB) { if (!CmpI) return; if (canAddSuccessor(BB, Br->getSuccessor(0))) - WorkList.emplace_back( - FactOrCheck::getConditionFact(DT.getNode(Br->getSuccessor(0)), CmpI)); + WorkList.emplace_back(FactOrCheck::getConditionFact( + DT.getNode(Br->getSuccessor(0)), CmpI->getPredicate(), + CmpI->getOperand(0), CmpI->getOperand(1))); if (canAddSuccessor(BB, Br->getSuccessor(1))) WorkList.emplace_back(FactOrCheck::getConditionFact( - DT.getNode(Br->getSuccessor(1)), CmpI, true)); + DT.getNode(Br->getSuccessor(1)), + CmpInst::getInversePredicate(CmpI->getPredicate()), CmpI->getOperand(0), + CmpI->getOperand(1))); } namespace { @@ -1312,8 +1327,9 @@ static bool eliminateConstraints(Function &F, DominatorTree &DT, // transfer logic. stable_sort(S.WorkList, [](const FactOrCheck &A, const FactOrCheck &B) { auto HasNoConstOp = [](const FactOrCheck &B) { - return !isa(B.Inst->getOperand(0)) && - !isa(B.Inst->getOperand(1)); + Value *V0 = B.isConditionFact() ? B.Cond.Op0 : B.Inst->getOperand(0); + Value *V1 = B.isConditionFact() ? B.Cond.Op1 : B.Inst->getOperand(1); + return !isa(V0) && !isa(V1); }; // If both entries have the same In numbers, conditional facts come first. // Otherwise use the relative order in the basic block. @@ -1386,7 +1402,6 @@ static bool eliminateConstraints(Function &F, DominatorTree &DT, continue; } - LLVM_DEBUG(dbgs() << "fact to add to the system: " << *CB.Inst << "\n"); auto AddFact = [&](CmpInst::Predicate Pred, Value *A, Value *B) { if (Info.getCS(CmpInst::isSigned(Pred)).size() > MaxRows) { LLVM_DEBUG( @@ -1395,6 +1410,14 @@ static bool eliminateConstraints(Function &F, DominatorTree &DT, return; } + LLVM_DEBUG({ + dbgs() << "Processing fact to add to the system: " << Pred << " "; + A->printAsOperand(dbgs()); + dbgs() << ", "; + B->printAsOperand(dbgs(), false); + dbgs() << "\n"; + }); + Info.addFact(Pred, A, B, CB.NumIn, CB.NumOut, DFSInStack); if (ReproducerModule && DFSInStack.size() > ReproducerCondStack.size()) ReproducerCondStack.emplace_back(Pred, A, B); @@ -1413,23 +1436,27 @@ static bool eliminateConstraints(Function &F, DominatorTree &DT, }; ICmpInst::Predicate Pred; - if (auto *MinMax = dyn_cast(CB.Inst)) { - Pred = ICmpInst::getNonStrictPredicate(MinMax->getPredicate()); - AddFact(Pred, MinMax, MinMax->getLHS()); - AddFact(Pred, MinMax, MinMax->getRHS()); - continue; + if (!CB.isConditionFact()) { + if (auto *MinMax = dyn_cast(CB.Inst)) { + Pred = ICmpInst::getNonStrictPredicate(MinMax->getPredicate()); + AddFact(Pred, MinMax, MinMax->getLHS()); + AddFact(Pred, MinMax, MinMax->getRHS()); + continue; + } } - Value *A, *B; - Value *Cmp = CB.Inst; - match(Cmp, m_Intrinsic(m_Value(Cmp))); - if (match(Cmp, m_ICmp(Pred, m_Value(A), m_Value(B)))) { - // Use the inverse predicate if required. - if (CB.Not) - Pred = CmpInst::getInversePredicate(Pred); - - AddFact(Pred, A, B); + Value *A = nullptr, *B = nullptr; + if (CB.isConditionFact()) { + Pred = CB.Cond.Pred; + A = CB.Cond.Op0; + B = CB.Cond.Op1; + } else { + bool Matched = match(CB.Inst, m_Intrinsic( + m_ICmp(Pred, m_Value(A), m_Value(B)))); + (void)Matched; + assert(Matched && "Must have an assume intrinsic with a icmp operand"); } + AddFact(Pred, A, B); } if (ReproducerModule && !ReproducerModule->functions().empty()) { diff --git a/llvm/test/Transforms/ConstraintElimination/debug.ll b/llvm/test/Transforms/ConstraintElimination/debug.ll index a114db8ac6d60..f3f0f5056135c 100644 --- a/llvm/test/Transforms/ConstraintElimination/debug.ll +++ b/llvm/test/Transforms/ConstraintElimination/debug.ll @@ -3,11 +3,11 @@ ; REQUIRES: asserts define i1 @test_and_ule(i4 %x, i4 %y, i4 %z) { -; CHECK: Processing fact to add to the system: %c.1 = icmp ule i4 %x, %y +; CHECK: Processing fact to add to the system: ule i4 %x, %y ; CHECK-NEXT: Adding 'ule %x, %y' ; CHECK-NEXT: constraint: %x + -1 * %y <= 0 -; CHECK: Processing fact to add to the system: %c.2 = icmp ule i4 %y, %z +; CHECK: Processing fact to add to the system: ule i4 %y, %z ; CHECK-NEXT: Adding 'ule %y, %z' ; CHECK-NEXT: constraint: %y + -1 * %z <= 0 @@ -33,11 +33,11 @@ exit: } define i1 @test_and_ugt(i4 %x, i4 %y, i4 %z) { -; CHECK: Processing fact to add to the system: %c.1 = icmp ugt i4 %x, %y +; CHECK: Processing fact to add to the system: ugt i4 %x, %y ; CHECK-NEXT: Adding 'ugt %x, %y' ; CHECK-NEXT: constraint: -1 * %x + %y <= -1 -; CHECK: Processing fact to add to the system: %c.2 = icmp ugt i4 %y, %z +; CHECK: Processing fact to add to the system: ugt i4 %y, %z ; CHECK-NEXT: Adding 'ugt %y, %z' ; CHECK-NEXT: constraint: -1 * %y + %z <= -1