Skip to content

Commit 15dd685

Browse files
committed
ConstraintSystem: replace data structure with Matrix
ConstraintSystem currently stores constraints in a vector-of-vectors, performing inefficient memory operations on it, as part of its operation. Replace this data structure with the newly-minted Matrix, using MatrixView to eliminate row-swaps and truncation of the underlying storage. Since Matrix requires knowing an upper bounds on the number of columns ahead-of-time, add a cl::opt to ConstraintElimination upper-bounding this, and change addVariableRowFill to not add constraints whose length exceeds this upper bound.
1 parent 47c8510 commit 15dd685

File tree

3 files changed

+79
-44
lines changed

3 files changed

+79
-44
lines changed

llvm/include/llvm/Analysis/ConstraintSystem.h

Lines changed: 48 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -9,22 +9,19 @@
99
#ifndef LLVM_ANALYSIS_CONSTRAINTSYSTEM_H
1010
#define LLVM_ANALYSIS_CONSTRAINTSYSTEM_H
1111

12-
#include "llvm/ADT/APInt.h"
13-
#include "llvm/ADT/ArrayRef.h"
1412
#include "llvm/ADT/DenseMap.h"
15-
#include "llvm/ADT/SmallVector.h"
13+
#include "llvm/ADT/Matrix.h"
1614
#include "llvm/Support/MathExtras.h"
1715

18-
#include <string>
19-
2016
namespace llvm {
2117

2218
class Value;
2319
class ConstraintSystem {
2420
struct Entry {
25-
int64_t Coefficient;
26-
uint16_t Id;
21+
int64_t Coefficient = 0;
22+
uint16_t Id = 0;
2723

24+
Entry() = default;
2825
Entry(int64_t Coefficient, uint16_t Id)
2926
: Coefficient(Coefficient), Id(Id) {}
3027
};
@@ -48,7 +45,10 @@ class ConstraintSystem {
4845
/// Current linear constraints in the system.
4946
/// An entry of the form c0, c1, ... cn represents the following constraint:
5047
/// c0 >= v0 * c1 + .... + v{n-1} * cn
51-
SmallVector<SmallVector<Entry, 8>, 4> Constraints;
48+
MatrixStorage<Entry, 64> Constraints;
49+
50+
/// Constraints is only ever manipulated via this View.
51+
JaggedArrayView<Entry, 16, 64> View;
5252

5353
/// A map of variables (IR values) to their corresponding index in the
5454
/// constraint system.
@@ -64,18 +64,41 @@ class ConstraintSystem {
6464
SmallVector<std::string> getVarNamesList() const;
6565

6666
public:
67-
ConstraintSystem() {}
68-
ConstraintSystem(ArrayRef<Value *> FunctionArgs) {
67+
// The Matrix Constraints should always be initialized with an upper-bound
68+
// number of columns. The default constructor hard-codes an upper-bound of 6,
69+
// as it is only used in unit tests, and not in the actual
70+
// ConstraintElimination Analysis.
71+
ConstraintSystem() : Constraints(6), View(Constraints) {}
72+
73+
// This constructor is used by ConstraintElimination, inside ConstraintInfo.
74+
// Unfortunately, due to calls to addFact, that adds local variables, it is
75+
// impossible to know how many local variables there are in advance.
76+
// ConstraintElimination has a fixed upper-bound on the number of columns,
77+
// configurable as a cl::opt, so use that number, and don't add the constraint
78+
// if it exceeds that number.
79+
ConstraintSystem(ArrayRef<Value *> FunctionArgs, size_t NRows, size_t NCols)
80+
: Constraints(NCols), View(Constraints) {
81+
Constraints.reserve(NRows);
6982
NumVariables += FunctionArgs.size();
7083
for (auto *Arg : FunctionArgs) {
7184
Value2Index.insert({Arg, Value2Index.size() + 1});
7285
}
7386
}
74-
ConstraintSystem(const DenseMap<Value *, unsigned> &Value2Index)
75-
: NumVariables(Value2Index.size()), Value2Index(Value2Index) {}
87+
88+
// This constructor is only used by the dump function in
89+
// ConstraintElimination.
90+
ConstraintSystem(const DenseMap<Value *, unsigned> &Value2Index,
91+
unsigned NVars)
92+
: NumVariables(Value2Index.size()),
93+
Constraints(std::max(Value2Index.size(), NVars)), View(Constraints),
94+
Value2Index(Value2Index) {}
95+
96+
ConstraintSystem(const ConstraintSystem &Other)
97+
: NumVariables(Other.NumVariables), Constraints(Other.Constraints),
98+
View(Other.View, Constraints), Value2Index(Other.Value2Index) {}
7699

77100
bool addVariableRow(ArrayRef<int64_t> R) {
78-
assert(Constraints.empty() || R.size() == NumVariables);
101+
assert(View.empty() || R.size() == NumVariables);
79102
// If all variable coefficients are 0, the constraint does not provide any
80103
// usable information.
81104
if (all_of(ArrayRef(R).drop_front(1), [](int64_t C) { return C == 0; }))
@@ -87,9 +110,15 @@ class ConstraintSystem {
87110
continue;
88111
NewRow.emplace_back(C, Idx);
89112
}
90-
if (Constraints.empty())
113+
114+
// There is no correctness issue if we don't add a constraint.
115+
if (NewRow.size() > Constraints.getNumCols())
116+
return false;
117+
118+
if (View.empty())
91119
NumVariables = R.size();
92-
Constraints.push_back(std::move(NewRow));
120+
121+
View.addRow(std::move(NewRow));
93122
return true;
94123
}
95124

@@ -145,21 +174,21 @@ class ConstraintSystem {
145174
bool isConditionImplied(SmallVector<int64_t, 8> R) const;
146175

147176
SmallVector<int64_t> getLastConstraint() const {
148-
assert(!Constraints.empty() && "Constraint system is empty");
177+
assert(!View.empty() && "Constraint system is empty");
149178
SmallVector<int64_t> Result(NumVariables, 0);
150-
for (auto &Entry : Constraints.back())
179+
for (auto &Entry : View.lastRow())
151180
Result[Entry.Id] = Entry.Coefficient;
152181
return Result;
153182
}
154183

155-
void popLastConstraint() { Constraints.pop_back(); }
184+
void popLastConstraint() { View.dropLastRow(); }
156185
void popLastNVariables(unsigned N) {
157186
assert(NumVariables > N);
158187
NumVariables -= N;
159188
}
160189

161190
/// Returns the number of rows in the constraint system.
162-
unsigned size() const { return Constraints.size(); }
191+
unsigned size() const { return View.getRowSpan(); }
163192

164193
/// Print the constraints in the system.
165194
void dump() const;

llvm/lib/Analysis/ConstraintSystem.cpp

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,12 @@
77
//===----------------------------------------------------------------------===//
88

99
#include "llvm/Analysis/ConstraintSystem.h"
10+
#include "llvm/ADT/Matrix.h"
1011
#include "llvm/ADT/SmallVector.h"
11-
#include "llvm/Support/MathExtras.h"
1212
#include "llvm/ADT/StringExtras.h"
1313
#include "llvm/IR/Value.h"
1414
#include "llvm/Support/Debug.h"
15+
#include "llvm/Support/MathExtras.h"
1516

1617
#include <string>
1718

@@ -26,37 +27,38 @@ bool ConstraintSystem::eliminateUsingFM() {
2627
// analysis."
2728
// Supercomputing'91: Proceedings of the 1991 ACM/
2829
// IEEE conference on Supercomputing. IEEE, 1991.
29-
assert(!Constraints.empty() &&
30+
assert(!View.empty() &&
3031
"should only be called for non-empty constraint systems");
3132

3233
unsigned LastIdx = NumVariables - 1;
3334

3435
// First, either remove the variable in place if it is 0 or add the row to
3536
// RemainingRows and remove it from the system.
36-
SmallVector<SmallVector<Entry, 8>, 4> RemainingRows;
37-
for (unsigned R1 = 0; R1 < Constraints.size();) {
38-
SmallVector<Entry, 8> &Row1 = Constraints[R1];
37+
MatrixStorage<Entry, 32> RemainingRows(View.getMaxColSpan());
38+
JaggedArrayView<Entry, 8, 32> RemainingRowsView{RemainingRows};
39+
for (unsigned R1 = 0; R1 < View.getRowSpan();) {
40+
auto &Row1 = View[R1];
3941
if (getLastCoefficient(Row1, LastIdx) == 0) {
4042
if (Row1.size() > 0 && Row1.back().Id == LastIdx)
4143
Row1.pop_back();
4244
R1++;
4345
} else {
44-
std::swap(Constraints[R1], Constraints.back());
45-
RemainingRows.push_back(std::move(Constraints.back()));
46-
Constraints.pop_back();
46+
View[R1].swap(View.lastRow());
47+
RemainingRowsView.addRow(View.lastRow());
48+
View.dropLastRow();
4749
}
4850
}
4951

5052
// Process rows where the variable is != 0.
51-
unsigned NumRemainingConstraints = RemainingRows.size();
53+
unsigned NumRemainingConstraints = RemainingRowsView.getRowSpan();
5254
for (unsigned R1 = 0; R1 < NumRemainingConstraints; R1++) {
5355
// FIXME do not use copy
5456
for (unsigned R2 = R1 + 1; R2 < NumRemainingConstraints; R2++) {
5557
if (R1 == R2)
5658
continue;
5759

58-
int64_t UpperLast = getLastCoefficient(RemainingRows[R2], LastIdx);
59-
int64_t LowerLast = getLastCoefficient(RemainingRows[R1], LastIdx);
60+
int64_t UpperLast = getLastCoefficient(RemainingRowsView[R2], LastIdx);
61+
int64_t LowerLast = getLastCoefficient(RemainingRowsView[R1], LastIdx);
6062
assert(
6163
UpperLast != 0 && LowerLast != 0 &&
6264
"RemainingRows should only contain rows where the variable is != 0");
@@ -74,8 +76,8 @@ bool ConstraintSystem::eliminateUsingFM() {
7476
SmallVector<Entry, 8> NR;
7577
unsigned IdxUpper = 0;
7678
unsigned IdxLower = 0;
77-
auto &LowerRow = RemainingRows[LowerR];
78-
auto &UpperRow = RemainingRows[UpperR];
79+
auto &LowerRow = RemainingRowsView[LowerR];
80+
auto &UpperRow = RemainingRowsView[UpperR];
7981
while (true) {
8082
if (IdxUpper >= UpperRow.size() || IdxLower >= LowerRow.size())
8183
break;
@@ -112,9 +114,9 @@ bool ConstraintSystem::eliminateUsingFM() {
112114
}
113115
if (NR.empty())
114116
continue;
115-
Constraints.push_back(std::move(NR));
117+
View.addRow(std::move(NR));
116118
// Give up if the new system gets too big.
117-
if (Constraints.size() > 500)
119+
if (size() > 500)
118120
return false;
119121
}
120122
}
@@ -124,15 +126,15 @@ bool ConstraintSystem::eliminateUsingFM() {
124126
}
125127

126128
bool ConstraintSystem::mayHaveSolutionImpl() {
127-
while (!Constraints.empty() && NumVariables > 1) {
129+
while (!View.empty() && NumVariables > 1) {
128130
if (!eliminateUsingFM())
129131
return true;
130132
}
131133

132-
if (Constraints.empty() || NumVariables > 1)
134+
if (View.empty() || NumVariables > 1)
133135
return true;
134136

135-
return all_of(Constraints, [](auto &R) {
137+
return all_of(View, [](auto &R) {
136138
if (R.empty())
137139
return true;
138140
if (R[0].Id == 0)
@@ -158,10 +160,10 @@ SmallVector<std::string> ConstraintSystem::getVarNamesList() const {
158160

159161
void ConstraintSystem::dump() const {
160162
#ifndef NDEBUG
161-
if (Constraints.empty())
163+
if (View.empty())
162164
return;
163165
SmallVector<std::string> Names = getVarNamesList();
164-
for (const auto &Row : Constraints) {
166+
for (const auto &Row : View) {
165167
SmallVector<std::string, 16> Parts;
166168
for (const Entry &E : Row) {
167169
if (E.Id >= NumVariables)

llvm/lib/Transforms/Scalar/ConstraintElimination.cpp

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -276,8 +276,10 @@ class ConstraintInfo {
276276
const DataLayout &DL;
277277

278278
public:
279-
ConstraintInfo(const DataLayout &DL, ArrayRef<Value *> FunctionArgs)
280-
: UnsignedCS(FunctionArgs), SignedCS(FunctionArgs), DL(DL) {
279+
ConstraintInfo(const DataLayout &DL, ArrayRef<Value *> FunctionArgs,
280+
unsigned MaxRows, unsigned MaxColumns)
281+
: UnsignedCS(FunctionArgs, MaxRows, MaxColumns),
282+
SignedCS(FunctionArgs, MaxRows, MaxColumns), DL(DL) {
281283
auto &Value2Index = getValue2Index(false);
282284
// Add Arg > -1 constraints to unsigned system for all function arguments.
283285
for (Value *Arg : FunctionArgs) {
@@ -898,7 +900,7 @@ void ConstraintInfo::transferToOtherSystem(
898900

899901
static void dumpConstraint(ArrayRef<int64_t> C,
900902
const DenseMap<Value *, unsigned> &Value2Index) {
901-
ConstraintSystem CS(Value2Index);
903+
ConstraintSystem CS(Value2Index, C.size());
902904
CS.addVariableRowFill(C);
903905
CS.dump();
904906
}
@@ -1759,7 +1761,8 @@ dryRun(Function &F, DominatorTree &DT, LoopInfo &LI, ScalarEvolution &SE) {
17591761
// EstimatedRowsA corresponds to SignedCS, and EstimatedRowsB corresponds to
17601762
// UnsignedCS.
17611763
unsigned EstimatedRowsA = 0, EstimatedRowsB = 1;
1762-
ConstraintInfo Info(F.getDataLayout(), FunctionArgs);
1764+
ConstraintInfo Info(F.getDataLayout(), FunctionArgs, EstimatedRowsB,
1765+
EstimatedColumns);
17631766

17641767
// First, collect conditions implied by branches and blocks with their
17651768
// Dominator DFS in and out numbers.
@@ -1876,7 +1879,8 @@ static bool eliminateConstraints(Function &F, DominatorTree &DT, LoopInfo &LI,
18761879
SmallVector<Value *> FunctionArgs;
18771880
for (Value &Arg : F.args())
18781881
FunctionArgs.push_back(&Arg);
1879-
ConstraintInfo Info(F.getDataLayout(), FunctionArgs);
1882+
ConstraintInfo Info(F.getDataLayout(), FunctionArgs, EstimatedRows,
1883+
EstimatedColumns);
18801884
std::unique_ptr<Module> ReproducerModule(
18811885
DumpReproducers ? new Module(F.getName(), F.getContext()) : nullptr);
18821886

0 commit comments

Comments
 (0)