Skip to content

Commit 4a5bcbd

Browse files
committed
[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
1 parent 5b3f41c commit 4a5bcbd

File tree

2 files changed

+86
-59
lines changed

2 files changed

+86
-59
lines changed

llvm/lib/Transforms/Scalar/ConstraintElimination.cpp

Lines changed: 82 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,16 @@ static Instruction *getContextInstForUse(Use &U) {
8383
}
8484

8585
namespace {
86+
/// Struct to express a condition of the form %Op0 Pred %Op1.
87+
struct ConditionTy {
88+
CmpInst::Predicate Pred;
89+
Value *Op0;
90+
Value *Op1;
91+
92+
ConditionTy(CmpInst::Predicate Pred, Value *Op0, Value *Op1)
93+
: Pred(Pred), Op0(Op0), Op1(Op1) {}
94+
};
95+
8696
/// Represents either
8797
/// * a condition that holds on entry to a block (=condition fact)
8898
/// * an assume (=assume fact)
@@ -101,37 +111,45 @@ struct FactOrCheck {
101111
union {
102112
Instruction *Inst;
103113
Use *U;
114+
ConditionTy Cond;
104115
};
105116

106117
unsigned NumIn;
107118
unsigned NumOut;
108119
EntryTy Ty;
109-
bool Not;
110120

111-
FactOrCheck(EntryTy Ty, DomTreeNode *DTN, Instruction *Inst, bool Not)
121+
FactOrCheck(EntryTy Ty, DomTreeNode *DTN, Instruction *Inst)
112122
: Inst(Inst), NumIn(DTN->getDFSNumIn()), NumOut(DTN->getDFSNumOut()),
113-
Ty(Ty), Not(Not) {}
123+
Ty(Ty) {}
114124

115125
FactOrCheck(DomTreeNode *DTN, Use *U)
116126
: U(U), NumIn(DTN->getDFSNumIn()), NumOut(DTN->getDFSNumOut()),
117-
Ty(EntryTy::UseCheck), Not(false) {}
127+
Ty(EntryTy::UseCheck) {}
118128

119-
static FactOrCheck getConditionFact(DomTreeNode *DTN, CmpInst *Inst,
120-
bool Not = false) {
121-
return FactOrCheck(EntryTy::ConditionFact, DTN, Inst, Not);
129+
FactOrCheck(DomTreeNode *DTN, CmpInst::Predicate Pred, Value *Op0, Value *Op1)
130+
: Cond(Pred, Op0, Op1), NumIn(DTN->getDFSNumIn()),
131+
NumOut(DTN->getDFSNumOut()), Ty(EntryTy::ConditionFact) {}
132+
133+
static FactOrCheck getConditionFact(DomTreeNode *DTN, CmpInst::Predicate Pred,
134+
Value *Op0, Value *Op1) {
135+
return FactOrCheck(DTN, Pred, Op0, Op1);
136+
}
137+
138+
static FactOrCheck getInstFact(DomTreeNode *DTN, Instruction *Inst) {
139+
return FactOrCheck(EntryTy::InstFact, DTN, Inst);
122140
}
123141

124-
static FactOrCheck getInstFact(DomTreeNode *DTN, Instruction *Inst,
125-
bool Not = false) {
126-
return FactOrCheck(EntryTy::InstFact, DTN, Inst, Not);
142+
static FactOrCheck getFact(DomTreeNode *DTN, CmpInst::Predicate Pred,
143+
Value *Op0, Value *Op1) {
144+
return FactOrCheck(DTN, Pred, Op0, Op1);
127145
}
128146

129147
static FactOrCheck getCheck(DomTreeNode *DTN, Use *U) {
130148
return FactOrCheck(DTN, U);
131149
}
132150

133151
static FactOrCheck getCheck(DomTreeNode *DTN, CallInst *CI) {
134-
return FactOrCheck(EntryTy::InstCheck, DTN, CI, false);
152+
return FactOrCheck(EntryTy::InstCheck, DTN, CI);
135153
}
136154

137155
bool isCheck() const {
@@ -188,19 +206,9 @@ struct StackEntry {
188206
ValuesToRelease(ValuesToRelease) {}
189207
};
190208

191-
/// Struct to express a pre-condition of the form %Op0 Pred %Op1.
192-
struct PreconditionTy {
193-
CmpInst::Predicate Pred;
194-
Value *Op0;
195-
Value *Op1;
196-
197-
PreconditionTy(CmpInst::Predicate Pred, Value *Op0, Value *Op1)
198-
: Pred(Pred), Op0(Op0), Op1(Op1) {}
199-
};
200-
201209
struct ConstraintTy {
202210
SmallVector<int64_t, 8> Coefficients;
203-
SmallVector<PreconditionTy, 2> Preconditions;
211+
SmallVector<ConditionTy, 2> Preconditions;
204212

205213
SmallVector<SmallVector<int64_t, 8>> ExtraInfo;
206214

@@ -346,17 +354,17 @@ struct Decomposition {
346354
} // namespace
347355

348356
static Decomposition decompose(Value *V,
349-
SmallVectorImpl<PreconditionTy> &Preconditions,
357+
SmallVectorImpl<ConditionTy> &Preconditions,
350358
bool IsSigned, const DataLayout &DL);
351359

352360
static bool canUseSExt(ConstantInt *CI) {
353361
const APInt &Val = CI->getValue();
354362
return Val.sgt(MinSignedConstraintValue) && Val.slt(MaxConstraintValue);
355363
}
356364

357-
static Decomposition
358-
decomposeGEP(GEPOperator &GEP, SmallVectorImpl<PreconditionTy> &Preconditions,
359-
bool IsSigned, const DataLayout &DL) {
365+
static Decomposition decomposeGEP(GEPOperator &GEP,
366+
SmallVectorImpl<ConditionTy> &Preconditions,
367+
bool IsSigned, const DataLayout &DL) {
360368
// Do not reason about pointers where the index size is larger than 64 bits,
361369
// as the coefficients used to encode constraints are 64 bit integers.
362370
if (DL.getIndexTypeSizeInBits(GEP.getPointerOperand()->getType()) > 64)
@@ -417,7 +425,7 @@ decomposeGEP(GEPOperator &GEP, SmallVectorImpl<PreconditionTy> &Preconditions,
417425
// Variable } where Coefficient * Variable. The sum of the constant offset and
418426
// pairs equals \p V.
419427
static Decomposition decompose(Value *V,
420-
SmallVectorImpl<PreconditionTy> &Preconditions,
428+
SmallVectorImpl<ConditionTy> &Preconditions,
421429
bool IsSigned, const DataLayout &DL) {
422430

423431
auto MergeResults = [&Preconditions, IsSigned, &DL](Value *A, Value *B,
@@ -560,7 +568,7 @@ ConstraintInfo::getConstraint(CmpInst::Predicate Pred, Value *Op0, Value *Op1,
560568
Pred != CmpInst::ICMP_SLE && Pred != CmpInst::ICMP_SLT)
561569
return {};
562570

563-
SmallVector<PreconditionTy, 4> Preconditions;
571+
SmallVector<ConditionTy, 4> Preconditions;
564572
bool IsSigned = CmpInst::isSigned(Pred);
565573
auto &Value2Index = getValue2Index(IsSigned);
566574
auto ADec = decompose(Op0->stripPointerCastsSameRepresentation(),
@@ -670,7 +678,7 @@ ConstraintTy ConstraintInfo::getConstraintForSolving(CmpInst::Predicate Pred,
670678

671679
bool ConstraintTy::isValid(const ConstraintInfo &Info) const {
672680
return Coefficients.size() > 0 &&
673-
all_of(Preconditions, [&Info](const PreconditionTy &C) {
681+
all_of(Preconditions, [&Info](const ConditionTy &C) {
674682
return Info.doesHold(C.Pred, C.Op0, C.Op1);
675683
});
676684
}
@@ -805,15 +813,16 @@ void State::addInfoFor(BasicBlock &BB) {
805813
continue;
806814
}
807815

808-
Value *Cond;
816+
Value *A, *B;
817+
CmpInst::Predicate Pred;
809818
// For now, just handle assumes with a single compare as condition.
810-
if (match(&I, m_Intrinsic<Intrinsic::assume>(m_Value(Cond))) &&
811-
isa<ICmpInst>(Cond)) {
819+
if (match(&I, m_Intrinsic<Intrinsic::assume>(
820+
m_ICmp(Pred, m_Value(A), m_Value(B))))) {
812821
if (GuaranteedToExecute) {
813822
// The assume is guaranteed to execute when BB is entered, hence Cond
814823
// holds on entry to BB.
815824
WorkList.emplace_back(FactOrCheck::getConditionFact(
816-
DT.getNode(I.getParent()), cast<CmpInst>(Cond)));
825+
DT.getNode(I.getParent()), Pred, A, B));
817826
} else {
818827
WorkList.emplace_back(
819828
FactOrCheck::getInstFact(DT.getNode(I.getParent()), &I));
@@ -853,8 +862,11 @@ void State::addInfoFor(BasicBlock &BB) {
853862
while (!CondWorkList.empty()) {
854863
Value *Cur = CondWorkList.pop_back_val();
855864
if (auto *Cmp = dyn_cast<ICmpInst>(Cur)) {
856-
WorkList.emplace_back(
857-
FactOrCheck::getConditionFact(DT.getNode(Successor), Cmp, IsOr));
865+
WorkList.emplace_back(FactOrCheck::getConditionFact(
866+
DT.getNode(Successor),
867+
IsOr ? CmpInst::getInversePredicate(Cmp->getPredicate())
868+
: Cmp->getPredicate(),
869+
Cmp->getOperand(0), Cmp->getOperand(1)));
858870
continue;
859871
}
860872
if (IsOr && match(Cur, m_LogicalOr(m_Value(Op0), m_Value(Op1)))) {
@@ -876,11 +888,14 @@ void State::addInfoFor(BasicBlock &BB) {
876888
if (!CmpI)
877889
return;
878890
if (canAddSuccessor(BB, Br->getSuccessor(0)))
879-
WorkList.emplace_back(
880-
FactOrCheck::getConditionFact(DT.getNode(Br->getSuccessor(0)), CmpI));
891+
WorkList.emplace_back(FactOrCheck::getConditionFact(
892+
DT.getNode(Br->getSuccessor(0)), CmpI->getPredicate(),
893+
CmpI->getOperand(0), CmpI->getOperand(1)));
881894
if (canAddSuccessor(BB, Br->getSuccessor(1)))
882895
WorkList.emplace_back(FactOrCheck::getConditionFact(
883-
DT.getNode(Br->getSuccessor(1)), CmpI, true));
896+
DT.getNode(Br->getSuccessor(1)),
897+
CmpInst::getInversePredicate(CmpI->getPredicate()), CmpI->getOperand(0),
898+
CmpI->getOperand(1)));
884899
}
885900

886901
namespace {
@@ -1312,8 +1327,9 @@ static bool eliminateConstraints(Function &F, DominatorTree &DT,
13121327
// transfer logic.
13131328
stable_sort(S.WorkList, [](const FactOrCheck &A, const FactOrCheck &B) {
13141329
auto HasNoConstOp = [](const FactOrCheck &B) {
1315-
return !isa<ConstantInt>(B.Inst->getOperand(0)) &&
1316-
!isa<ConstantInt>(B.Inst->getOperand(1));
1330+
Value *V0 = B.isConditionFact() ? B.Cond.Op0 : B.Inst->getOperand(0);
1331+
Value *V1 = B.isConditionFact() ? B.Cond.Op1 : B.Inst->getOperand(1);
1332+
return !isa<ConstantInt>(V0) && !isa<ConstantInt>(V1);
13171333
};
13181334
// If both entries have the same In numbers, conditional facts come first.
13191335
// Otherwise use the relative order in the basic block.
@@ -1386,7 +1402,6 @@ static bool eliminateConstraints(Function &F, DominatorTree &DT,
13861402
continue;
13871403
}
13881404

1389-
LLVM_DEBUG(dbgs() << "fact to add to the system: " << *CB.Inst << "\n");
13901405
auto AddFact = [&](CmpInst::Predicate Pred, Value *A, Value *B) {
13911406
if (Info.getCS(CmpInst::isSigned(Pred)).size() > MaxRows) {
13921407
LLVM_DEBUG(
@@ -1395,6 +1410,14 @@ static bool eliminateConstraints(Function &F, DominatorTree &DT,
13951410
return;
13961411
}
13971412

1413+
LLVM_DEBUG({
1414+
dbgs() << "Processing fact to add to the system: " << Pred << " ";
1415+
A->printAsOperand(dbgs());
1416+
dbgs() << ", ";
1417+
B->printAsOperand(dbgs(), false);
1418+
dbgs() << "\n";
1419+
});
1420+
13981421
Info.addFact(Pred, A, B, CB.NumIn, CB.NumOut, DFSInStack);
13991422
if (ReproducerModule && DFSInStack.size() > ReproducerCondStack.size())
14001423
ReproducerCondStack.emplace_back(Pred, A, B);
@@ -1413,23 +1436,27 @@ static bool eliminateConstraints(Function &F, DominatorTree &DT,
14131436
};
14141437

14151438
ICmpInst::Predicate Pred;
1416-
if (auto *MinMax = dyn_cast<MinMaxIntrinsic>(CB.Inst)) {
1417-
Pred = ICmpInst::getNonStrictPredicate(MinMax->getPredicate());
1418-
AddFact(Pred, MinMax, MinMax->getLHS());
1419-
AddFact(Pred, MinMax, MinMax->getRHS());
1420-
continue;
1439+
if (!CB.isConditionFact()) {
1440+
if (auto *MinMax = dyn_cast<MinMaxIntrinsic>(CB.Inst)) {
1441+
Pred = ICmpInst::getNonStrictPredicate(MinMax->getPredicate());
1442+
AddFact(Pred, MinMax, MinMax->getLHS());
1443+
AddFact(Pred, MinMax, MinMax->getRHS());
1444+
continue;
1445+
}
14211446
}
14221447

1423-
Value *A, *B;
1424-
Value *Cmp = CB.Inst;
1425-
match(Cmp, m_Intrinsic<Intrinsic::assume>(m_Value(Cmp)));
1426-
if (match(Cmp, m_ICmp(Pred, m_Value(A), m_Value(B)))) {
1427-
// Use the inverse predicate if required.
1428-
if (CB.Not)
1429-
Pred = CmpInst::getInversePredicate(Pred);
1430-
1431-
AddFact(Pred, A, B);
1448+
Value *A = nullptr, *B = nullptr;
1449+
if (CB.isConditionFact()) {
1450+
Pred = CB.Cond.Pred;
1451+
A = CB.Cond.Op0;
1452+
B = CB.Cond.Op1;
1453+
} else {
1454+
bool Matched = match(CB.Inst, m_Intrinsic<Intrinsic::assume>(
1455+
m_ICmp(Pred, m_Value(A), m_Value(B))));
1456+
(void)Matched;
1457+
assert(Matched && "Must have an assume intrinsic with a icmp operand");
14321458
}
1459+
AddFact(Pred, A, B);
14331460
}
14341461

14351462
if (ReproducerModule && !ReproducerModule->functions().empty()) {

llvm/test/Transforms/ConstraintElimination/debug.ll

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@
33
; REQUIRES: asserts
44

55
define i1 @test_and_ule(i4 %x, i4 %y, i4 %z) {
6-
; CHECK: Processing fact to add to the system: %c.1 = icmp ule i4 %x, %y
6+
; CHECK: Processing fact to add to the system: ule i4 %x, %y
77
; CHECK-NEXT: Adding 'ule %x, %y'
88
; CHECK-NEXT: constraint: %x + -1 * %y <= 0
99

10-
; CHECK: Processing fact to add to the system: %c.2 = icmp ule i4 %y, %z
10+
; CHECK: Processing fact to add to the system: ule i4 %y, %z
1111
; CHECK-NEXT: Adding 'ule %y, %z'
1212
; CHECK-NEXT: constraint: %y + -1 * %z <= 0
1313

@@ -33,11 +33,11 @@ exit:
3333
}
3434

3535
define i1 @test_and_ugt(i4 %x, i4 %y, i4 %z) {
36-
; CHECK: Processing fact to add to the system: %c.1 = icmp ugt i4 %x, %y
36+
; CHECK: Processing fact to add to the system: ugt i4 %x, %y
3737
; CHECK-NEXT: Adding 'ugt %x, %y'
3838
; CHECK-NEXT: constraint: -1 * %x + %y <= -1
3939

40-
; CHECK: Processing fact to add to the system: %c.2 = icmp ugt i4 %y, %z
40+
; CHECK: Processing fact to add to the system: ugt i4 %y, %z
4141
; CHECK-NEXT: Adding 'ugt %y, %z'
4242
; CHECK-NEXT: constraint: -1 * %y + %z <= -1
4343

0 commit comments

Comments
 (0)