[llvm] 4a5bcbd - [ConstraintElim] Store conditional facts as (Predicate, Op0, Op1).
Florian Hahn via llvm-commits
llvm-commits at lists.llvm.org
Wed Aug 30 02:55:46 PDT 2023
Author: Florian Hahn
Date: 2023-08-30T10:54:28+01:00
New Revision: 4a5bcbd5602be4a9348899309a541e8d5c570645
URL: https://github.com/llvm/llvm-project/commit/4a5bcbd5602be4a9348899309a541e8d5c570645
DIFF: https://github.com/llvm/llvm-project/commit/4a5bcbd5602be4a9348899309a541e8d5c570645.diff
LOG: [ConstraintElim] Store conditional facts as (Predicate, Op0, Op1).
This allows to add facts even if no corresponding ICmp instruction
exists in the IR.
Reviewed By: nikic
Differential Revision: https://reviews.llvm.org/D158837
Added:
Modified:
llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
llvm/test/Transforms/ConstraintElimination/debug.ll
Removed:
################################################################################
diff --git a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
index d2d8f2262ee122b..3c47d36cbc0a0bc 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<int64_t, 8> Coefficients;
- SmallVector<PreconditionTy, 2> Preconditions;
+ SmallVector<ConditionTy, 2> Preconditions;
SmallVector<SmallVector<int64_t, 8>> ExtraInfo;
@@ -346,7 +354,7 @@ struct Decomposition {
} // namespace
static Decomposition decompose(Value *V,
- SmallVectorImpl<PreconditionTy> &Preconditions,
+ SmallVectorImpl<ConditionTy> &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<PreconditionTy> &Preconditions,
- bool IsSigned, const DataLayout &DL) {
+static Decomposition decomposeGEP(GEPOperator &GEP,
+ SmallVectorImpl<ConditionTy> &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<PreconditionTy> &Preconditions,
// Variable } where Coefficient * Variable. The sum of the constant offset and
// pairs equals \p V.
static Decomposition decompose(Value *V,
- SmallVectorImpl<PreconditionTy> &Preconditions,
+ SmallVectorImpl<ConditionTy> &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<PreconditionTy, 4> Preconditions;
+ SmallVector<ConditionTy, 4> 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<Intrinsic::assume>(m_Value(Cond))) &&
- isa<ICmpInst>(Cond)) {
+ if (match(&I, m_Intrinsic<Intrinsic::assume>(
+ 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<CmpInst>(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<ICmpInst>(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<ConstantInt>(B.Inst->getOperand(0)) &&
- !isa<ConstantInt>(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<ConstantInt>(V0) && !isa<ConstantInt>(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<MinMaxIntrinsic>(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<MinMaxIntrinsic>(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<Intrinsic::assume>(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<Intrinsic::assume>(
+ 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 a114db8ac6d6043..f3f0f5056135c21 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
More information about the llvm-commits
mailing list