Skip to content

Commit 3ac2932

Browse files
committed
[ConstraintElim] Add facts implied by intrinsics if they are used by other constraints
1 parent bc9c2be commit 3ac2932

File tree

4 files changed

+98
-54
lines changed

4 files changed

+98
-54
lines changed

llvm/include/llvm/Analysis/ConstraintSystem.h

Lines changed: 37 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,19 @@ class ConstraintSystem {
3535
return 0;
3636
}
3737

38-
static int64_t getLastCoefficient(ArrayRef<Entry> Row, uint16_t Id) {
39-
if (Row.empty())
38+
struct ConstraintRow {
39+
SmallVector<Entry, 8> Entries;
40+
bool IsWellDefined;
41+
42+
ConstraintRow(SmallVector<Entry, 8> Entries, bool IsWellDefined)
43+
: Entries(std::move(Entries)), IsWellDefined(IsWellDefined) {}
44+
};
45+
46+
static int64_t getLastCoefficient(const ConstraintRow &Row, uint16_t Id) {
47+
if (Row.Entries.empty())
4048
return 0;
41-
if (Row.back().Id == Id)
42-
return Row.back().Coefficient;
49+
if (Row.Entries.back().Id == Id)
50+
return Row.Entries.back().Coefficient;
4351
return 0;
4452
}
4553

@@ -48,12 +56,16 @@ class ConstraintSystem {
4856
/// Current linear constraints in the system.
4957
/// An entry of the form c0, c1, ... cn represents the following constraint:
5058
/// c0 >= v0 * c1 + .... + v{n-1} * cn
51-
SmallVector<SmallVector<Entry, 8>, 4> Constraints;
59+
SmallVector<ConstraintRow, 4> Constraints;
5260

5361
/// A map of variables (IR values) to their corresponding index in the
5462
/// constraint system.
5563
DenseMap<Value *, unsigned> Value2Index;
5664

65+
/// A map of index to the count of the corresponding variable used by
66+
/// well-defined constraints.
67+
DenseMap<unsigned, unsigned> WellDefinedVariableRefCount;
68+
5769
// Eliminate constraints from the system using Fourier–Motzkin elimination.
5870
bool eliminateUsingFM();
5971

@@ -74,22 +86,27 @@ class ConstraintSystem {
7486
ConstraintSystem(const DenseMap<Value *, unsigned> &Value2Index)
7587
: NumVariables(Value2Index.size()), Value2Index(Value2Index) {}
7688

77-
bool addVariableRow(ArrayRef<int64_t> R) {
89+
bool addVariableRow(ArrayRef<int64_t> R, bool IsWellDefined = true) {
7890
assert(Constraints.empty() || R.size() == NumVariables);
7991
// If all variable coefficients are 0, the constraint does not provide any
8092
// usable information.
8193
if (all_of(ArrayRef(R).drop_front(1), [](int64_t C) { return C == 0; }))
8294
return false;
8395

84-
SmallVector<Entry, 4> NewRow;
96+
SmallVector<Entry, 8> NewRow;
8597
for (const auto &[Idx, C] : enumerate(R)) {
8698
if (C == 0)
8799
continue;
88100
NewRow.emplace_back(C, Idx);
89101
}
90102
if (Constraints.empty())
91103
NumVariables = R.size();
92-
Constraints.push_back(std::move(NewRow));
104+
Constraints.emplace_back(std::move(NewRow), IsWellDefined);
105+
if (IsWellDefined) {
106+
for (auto &Entry : Constraints.back().Entries)
107+
if (Entry.Id != 0)
108+
++WellDefinedVariableRefCount[Entry.Id];
109+
}
93110
return true;
94111
}
95112

@@ -98,14 +115,14 @@ class ConstraintSystem {
98115
return Value2Index;
99116
}
100117

101-
bool addVariableRowFill(ArrayRef<int64_t> R) {
118+
bool addVariableRowFill(ArrayRef<int64_t> R, bool IsWellDefined = true) {
102119
// If all variable coefficients are 0, the constraint does not provide any
103120
// usable information.
104121
if (all_of(ArrayRef(R).drop_front(1), [](int64_t C) { return C == 0; }))
105122
return false;
106123

107124
NumVariables = std::max(R.size(), NumVariables);
108-
return addVariableRow(R);
125+
return addVariableRow(R, IsWellDefined);
109126
}
110127

111128
/// Returns true if there may be a solution for the constraints in the system.
@@ -147,12 +164,20 @@ class ConstraintSystem {
147164
SmallVector<int64_t> getLastConstraint() const {
148165
assert(!Constraints.empty() && "Constraint system is empty");
149166
SmallVector<int64_t> Result(NumVariables, 0);
150-
for (auto &Entry : Constraints.back())
167+
for (auto &Entry : Constraints.back().Entries)
151168
Result[Entry.Id] = Entry.Coefficient;
152169
return Result;
153170
}
154171

155-
void popLastConstraint() { Constraints.pop_back(); }
172+
void popLastConstraint() {
173+
if (Constraints.back().IsWellDefined) {
174+
for (auto &Entry : Constraints.back().Entries)
175+
if (Entry.Id != 0)
176+
--WellDefinedVariableRefCount[Entry.Id];
177+
}
178+
Constraints.pop_back();
179+
}
180+
156181
void popLastNVariables(unsigned N) {
157182
assert(NumVariables > N);
158183
NumVariables -= N;

llvm/lib/Analysis/ConstraintSystem.cpp

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,12 @@ bool ConstraintSystem::eliminateUsingFM() {
3333

3434
// First, either remove the variable in place if it is 0 or add the row to
3535
// RemainingRows and remove it from the system.
36-
SmallVector<SmallVector<Entry, 8>, 4> RemainingRows;
36+
SmallVector<ConstraintRow, 4> RemainingRows;
3737
for (unsigned R1 = 0; R1 < Constraints.size();) {
38-
SmallVector<Entry, 8> &Row1 = Constraints[R1];
38+
ConstraintRow &Row1 = Constraints[R1];
3939
if (getLastCoefficient(Row1, LastIdx) == 0) {
40-
if (Row1.size() > 0 && Row1.back().Id == LastIdx)
41-
Row1.pop_back();
40+
if (Row1.Entries.size() > 0 && Row1.Entries.back().Id == LastIdx)
41+
Row1.Entries.pop_back();
4242
R1++;
4343
} else {
4444
std::swap(Constraints[R1], Constraints.back());
@@ -74,8 +74,8 @@ bool ConstraintSystem::eliminateUsingFM() {
7474
SmallVector<Entry, 8> NR;
7575
unsigned IdxUpper = 0;
7676
unsigned IdxLower = 0;
77-
auto &LowerRow = RemainingRows[LowerR];
78-
auto &UpperRow = RemainingRows[UpperR];
77+
auto &LowerRow = RemainingRows[LowerR].Entries;
78+
auto &UpperRow = RemainingRows[UpperR].Entries;
7979
while (true) {
8080
if (IdxUpper >= UpperRow.size() || IdxLower >= LowerRow.size())
8181
break;
@@ -112,7 +112,7 @@ bool ConstraintSystem::eliminateUsingFM() {
112112
}
113113
if (NR.empty())
114114
continue;
115-
Constraints.push_back(std::move(NR));
115+
Constraints.emplace_back(std::move(NR), /*IsWellDefined*/ true);
116116
// Give up if the new system gets too big.
117117
if (Constraints.size() > 500)
118118
return false;
@@ -124,6 +124,10 @@ bool ConstraintSystem::eliminateUsingFM() {
124124
}
125125

126126
bool ConstraintSystem::mayHaveSolutionImpl() {
127+
// Make sure that all variables in the system are well defined.
128+
assert(all_of(Constraints,
129+
[](const ConstraintRow &Row) { return Row.IsWellDefined; }));
130+
127131
while (!Constraints.empty() && NumVariables > 1) {
128132
if (!eliminateUsingFM())
129133
return true;
@@ -133,10 +137,10 @@ bool ConstraintSystem::mayHaveSolutionImpl() {
133137
return true;
134138

135139
return all_of(Constraints, [](auto &R) {
136-
if (R.empty())
140+
if (R.Entries.empty())
137141
return true;
138-
if (R[0].Id == 0)
139-
return R[0].Coefficient >= 0;
142+
if (R.Entries[0].Id == 0)
143+
return R.Entries[0].Coefficient >= 0;
140144
return true;
141145
});
142146
}
@@ -161,7 +165,7 @@ void ConstraintSystem::dump() const {
161165
if (Constraints.empty())
162166
return;
163167
SmallVector<std::string> Names = getVarNamesList();
164-
for (const auto &Row : Constraints) {
168+
for (const auto &[Row, IsWellDefined] : Constraints) {
165169
SmallVector<std::string, 16> Parts;
166170
for (unsigned I = 0, S = Row.size(); I < S; ++I) {
167171
if (Row[I].Id >= NumVariables)
@@ -204,6 +208,15 @@ bool ConstraintSystem::isConditionImplied(SmallVector<int64_t, 8> R) const {
204208
return false;
205209

206210
auto NewSystem = *this;
207-
NewSystem.addVariableRow(R);
211+
NewSystem.addVariableRow(R, /*IsWellDefined*/ true);
212+
// Remove invalid constraints whose variables may be poison.
213+
erase_if(NewSystem.Constraints, [&](ConstraintRow &R) {
214+
if (!R.IsWellDefined) {
215+
R.IsWellDefined = all_of(R.Entries, [&](const Entry &E) {
216+
return E.Id == 0 || NewSystem.WellDefinedVariableRefCount[E.Id] > 0;
217+
});
218+
}
219+
return !R.IsWellDefined;
220+
});
208221
return !NewSystem.mayHaveSolution();
209222
}

llvm/lib/Transforms/Scalar/ConstraintElimination.cpp

Lines changed: 35 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,8 @@ class ConstraintInfo {
306306
bool doesHold(CmpInst::Predicate Pred, Value *A, Value *B) const;
307307

308308
void addFact(CmpInst::Predicate Pred, Value *A, Value *B, unsigned NumIn,
309-
unsigned NumOut, SmallVectorImpl<StackEntry> &DFSInStack);
309+
unsigned NumOut, SmallVectorImpl<StackEntry> &DFSInStack,
310+
bool IsWellDefined);
310311

311312
/// Turn a comparison of the form \p Op0 \p Pred \p Op1 into a vector of
312313
/// constraints, using indices from the corresponding constraint system.
@@ -329,7 +330,8 @@ class ConstraintInfo {
329330
/// system if \p Pred is signed/unsigned.
330331
void transferToOtherSystem(CmpInst::Predicate Pred, Value *A, Value *B,
331332
unsigned NumIn, unsigned NumOut,
332-
SmallVectorImpl<StackEntry> &DFSInStack);
333+
SmallVectorImpl<StackEntry> &DFSInStack,
334+
bool IsWellDefined);
333335
};
334336

335337
/// Represents a (Coefficient * Variable) entry after IR decomposition.
@@ -819,7 +821,8 @@ bool ConstraintInfo::doesHold(CmpInst::Predicate Pred, Value *A,
819821

820822
void ConstraintInfo::transferToOtherSystem(
821823
CmpInst::Predicate Pred, Value *A, Value *B, unsigned NumIn,
822-
unsigned NumOut, SmallVectorImpl<StackEntry> &DFSInStack) {
824+
unsigned NumOut, SmallVectorImpl<StackEntry> &DFSInStack,
825+
bool IsWellDefined) {
823826
auto IsKnownNonNegative = [this](Value *V) {
824827
return doesHold(CmpInst::ICMP_SGE, V, ConstantInt::get(V->getType(), 0)) ||
825828
isKnownNonNegative(V, DL, /*Depth=*/MaxAnalysisRecursionDepth - 1);
@@ -839,37 +842,40 @@ void ConstraintInfo::transferToOtherSystem(
839842
// If B is a signed positive constant, then A >=s 0 and A <s (or <=s) B.
840843
if (IsKnownNonNegative(B)) {
841844
addFact(CmpInst::ICMP_SGE, A, ConstantInt::get(B->getType(), 0), NumIn,
842-
NumOut, DFSInStack);
845+
NumOut, DFSInStack, IsWellDefined);
843846
addFact(CmpInst::getSignedPredicate(Pred), A, B, NumIn, NumOut,
844-
DFSInStack);
847+
DFSInStack, IsWellDefined);
845848
}
846849
break;
847850
case CmpInst::ICMP_UGE:
848851
case CmpInst::ICMP_UGT:
849852
// If A is a signed positive constant, then B >=s 0 and A >s (or >=s) B.
850853
if (IsKnownNonNegative(A)) {
851854
addFact(CmpInst::ICMP_SGE, B, ConstantInt::get(B->getType(), 0), NumIn,
852-
NumOut, DFSInStack);
855+
NumOut, DFSInStack, IsWellDefined);
853856
addFact(CmpInst::getSignedPredicate(Pred), A, B, NumIn, NumOut,
854-
DFSInStack);
857+
DFSInStack, IsWellDefined);
855858
}
856859
break;
857860
case CmpInst::ICMP_SLT:
858861
if (IsKnownNonNegative(A))
859-
addFact(CmpInst::ICMP_ULT, A, B, NumIn, NumOut, DFSInStack);
862+
addFact(CmpInst::ICMP_ULT, A, B, NumIn, NumOut, DFSInStack,
863+
IsWellDefined);
860864
break;
861865
case CmpInst::ICMP_SGT: {
862866
if (doesHold(CmpInst::ICMP_SGE, B, ConstantInt::get(B->getType(), -1)))
863867
addFact(CmpInst::ICMP_UGE, A, ConstantInt::get(B->getType(), 0), NumIn,
864-
NumOut, DFSInStack);
868+
NumOut, DFSInStack, IsWellDefined);
865869
if (IsKnownNonNegative(B))
866-
addFact(CmpInst::ICMP_UGT, A, B, NumIn, NumOut, DFSInStack);
870+
addFact(CmpInst::ICMP_UGT, A, B, NumIn, NumOut, DFSInStack,
871+
IsWellDefined);
867872

868873
break;
869874
}
870875
case CmpInst::ICMP_SGE:
871876
if (IsKnownNonNegative(B))
872-
addFact(CmpInst::ICMP_UGE, A, B, NumIn, NumOut, DFSInStack);
877+
addFact(CmpInst::ICMP_UGE, A, B, NumIn, NumOut, DFSInStack,
878+
IsWellDefined);
873879
break;
874880
}
875881
}
@@ -1068,10 +1074,6 @@ void State::addInfoFor(BasicBlock &BB) {
10681074
// TODO: handle llvm.abs as well
10691075
WorkList.push_back(
10701076
FactOrCheck::getCheck(DT.getNode(&BB), cast<CallInst>(&I)));
1071-
// TODO: Check if it is possible to instead only added the min/max facts
1072-
// when simplifying uses of the min/max intrinsics.
1073-
if (!isGuaranteedNotToBePoison(&I))
1074-
break;
10751077
[[fallthrough]];
10761078
case Intrinsic::abs:
10771079
WorkList.push_back(FactOrCheck::getInstFact(DT.getNode(&BB), &I));
@@ -1464,7 +1466,8 @@ static bool checkOrAndOpImpliedByOther(
14641466

14651467
// Optimistically add fact from first condition.
14661468
unsigned OldSize = DFSInStack.size();
1467-
Info.addFact(Pred, A, B, CB.NumIn, CB.NumOut, DFSInStack);
1469+
Info.addFact(Pred, A, B, CB.NumIn, CB.NumOut, DFSInStack,
1470+
/*IsWellDefined*/ true);
14681471
if (OldSize == DFSInStack.size())
14691472
return false;
14701473

@@ -1496,7 +1499,8 @@ static bool checkOrAndOpImpliedByOther(
14961499

14971500
void ConstraintInfo::addFact(CmpInst::Predicate Pred, Value *A, Value *B,
14981501
unsigned NumIn, unsigned NumOut,
1499-
SmallVectorImpl<StackEntry> &DFSInStack) {
1502+
SmallVectorImpl<StackEntry> &DFSInStack,
1503+
bool IsWellDefined) {
15001504
// If the constraint has a pre-condition, skip the constraint if it does not
15011505
// hold.
15021506
SmallVector<Value *> NewVariables;
@@ -1513,7 +1517,7 @@ void ConstraintInfo::addFact(CmpInst::Predicate Pred, Value *A, Value *B,
15131517
if (R.Coefficients.empty())
15141518
return;
15151519

1516-
Added |= CSToUse.addVariableRowFill(R.Coefficients);
1520+
Added |= CSToUse.addVariableRowFill(R.Coefficients, IsWellDefined);
15171521

15181522
// If R has been added to the system, add the new variables and queue it for
15191523
// removal once it goes out-of-scope.
@@ -1539,7 +1543,7 @@ void ConstraintInfo::addFact(CmpInst::Predicate Pred, Value *A, Value *B,
15391543
ConstraintTy VarPos(SmallVector<int64_t, 8>(Value2Index.size() + 1, 0),
15401544
false, false, false);
15411545
VarPos.Coefficients[Value2Index[V]] = -1;
1542-
CSToUse.addVariableRow(VarPos.Coefficients);
1546+
CSToUse.addVariableRow(VarPos.Coefficients, IsWellDefined);
15431547
DFSInStack.emplace_back(NumIn, NumOut, R.IsSigned,
15441548
SmallVector<Value *, 2>());
15451549
}
@@ -1549,7 +1553,7 @@ void ConstraintInfo::addFact(CmpInst::Predicate Pred, Value *A, Value *B,
15491553
// Also add the inverted constraint for equality constraints.
15501554
for (auto &Coeff : R.Coefficients)
15511555
Coeff *= -1;
1552-
CSToUse.addVariableRowFill(R.Coefficients);
1556+
CSToUse.addVariableRowFill(R.Coefficients, IsWellDefined);
15531557

15541558
DFSInStack.emplace_back(NumIn, NumOut, R.IsSigned,
15551559
SmallVector<Value *, 2>());
@@ -1724,7 +1728,8 @@ static bool eliminateConstraints(Function &F, DominatorTree &DT, LoopInfo &LI,
17241728
continue;
17251729
}
17261730

1727-
auto AddFact = [&](CmpInst::Predicate Pred, Value *A, Value *B) {
1731+
auto AddFact = [&](CmpInst::Predicate Pred, Value *A, Value *B,
1732+
bool IsWellDefined) {
17281733
LLVM_DEBUG(dbgs() << "Processing fact to add to the system: ";
17291734
dumpUnpackedICmp(dbgs(), Pred, A, B); dbgs() << "\n");
17301735
if (Info.getCS(CmpInst::isSigned(Pred)).size() > MaxRows) {
@@ -1734,11 +1739,12 @@ static bool eliminateConstraints(Function &F, DominatorTree &DT, LoopInfo &LI,
17341739
return;
17351740
}
17361741

1737-
Info.addFact(Pred, A, B, CB.NumIn, CB.NumOut, DFSInStack);
1742+
Info.addFact(Pred, A, B, CB.NumIn, CB.NumOut, DFSInStack, IsWellDefined);
17381743
if (ReproducerModule && DFSInStack.size() > ReproducerCondStack.size())
17391744
ReproducerCondStack.emplace_back(Pred, A, B);
17401745

1741-
Info.transferToOtherSystem(Pred, A, B, CB.NumIn, CB.NumOut, DFSInStack);
1746+
Info.transferToOtherSystem(Pred, A, B, CB.NumIn, CB.NumOut, DFSInStack,
1747+
IsWellDefined);
17421748
if (ReproducerModule && DFSInStack.size() > ReproducerCondStack.size()) {
17431749
// Add dummy entries to ReproducerCondStack to keep it in sync with
17441750
// DFSInStack.
@@ -1756,14 +1762,16 @@ static bool eliminateConstraints(Function &F, DominatorTree &DT, LoopInfo &LI,
17561762
Value *X;
17571763
if (match(CB.Inst, m_Intrinsic<Intrinsic::abs>(m_Value(X)))) {
17581764
// TODO: Add CB.Inst >= 0 fact.
1759-
AddFact(CmpInst::ICMP_SGE, CB.Inst, X);
1765+
bool IsWellDefined = isGuaranteedNotToBePoison(CB.Inst);
1766+
AddFact(CmpInst::ICMP_SGE, CB.Inst, X, IsWellDefined);
17601767
continue;
17611768
}
17621769

17631770
if (auto *MinMax = dyn_cast<MinMaxIntrinsic>(CB.Inst)) {
17641771
Pred = ICmpInst::getNonStrictPredicate(MinMax->getPredicate());
1765-
AddFact(Pred, MinMax, MinMax->getLHS());
1766-
AddFact(Pred, MinMax, MinMax->getRHS());
1772+
bool IsWellDefined = isGuaranteedNotToBePoison(CB.Inst);
1773+
AddFact(Pred, MinMax, MinMax->getLHS(), IsWellDefined);
1774+
AddFact(Pred, MinMax, MinMax->getRHS(), IsWellDefined);
17671775
continue;
17681776
}
17691777
}
@@ -1791,7 +1799,7 @@ static bool eliminateConstraints(Function &F, DominatorTree &DT, LoopInfo &LI,
17911799
(void)Matched;
17921800
assert(Matched && "Must have an assume intrinsic with a icmp operand");
17931801
}
1794-
AddFact(Pred, A, B);
1802+
AddFact(Pred, A, B, /*IsWellDefined*/ true);
17951803
}
17961804

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

0 commit comments

Comments
 (0)