Skip to content

Commit dfdd352

Browse files
committed
[Constraint graph] Eliminate adjacency information in the graph nodes.
Each constraint graph node maintained adjacency information that was fairly expensive---a vector of type variables and a dense map of extra adjacency information---and that was continuously maintained. Remove this adjacency information, instead recomputing it by walking the constraints (to get their type variables) and having a separate (smaller) list of type variables that are adjacent due to fixed bindings. This simplifies the constraint graph code and reduces per-node memory overhead.
1 parent 54bdd7b commit dfdd352

File tree

2 files changed

+24
-240
lines changed

2 files changed

+24
-240
lines changed

lib/Sema/ConstraintGraph.cpp

Lines changed: 18 additions & 194 deletions
Original file line numberDiff line numberDiff line change
@@ -83,18 +83,6 @@ ConstraintGraph::lookupNode(TypeVariableType *typeVar) {
8383
return { *nodePtr, index };
8484
}
8585

86-
llvm::TinyPtrVector<TypeVariableType *>
87-
ConstraintGraphNode::getFixedAdjacencies() const {
88-
llvm::TinyPtrVector<TypeVariableType *> results;
89-
for (auto adj : getAdjacencies()) {
90-
auto adjInfo = AdjacencyInfo.find(adj);
91-
assert(adjInfo != AdjacencyInfo.end());
92-
if (adjInfo->second.FixedBinding)
93-
results.push_back(adj);
94-
}
95-
return results;
96-
}
97-
9886
ArrayRef<TypeVariableType *> ConstraintGraphNode::getEquivalenceClass() const{
9987
assert(TypeVar == TypeVar->getImpl().getRepresentative(nullptr) &&
10088
"Can't request equivalence class from non-representative type var");
@@ -140,74 +128,6 @@ void ConstraintGraphNode::removeConstraint(Constraint *constraint) {
140128
Constraints.pop_back();
141129
}
142130

143-
ConstraintGraphNode::Adjacency &
144-
ConstraintGraphNode::getAdjacency(TypeVariableType *typeVar) {
145-
assert(typeVar != TypeVar && "Cannot be adjacent to oneself");
146-
147-
// Look for existing adjacency information.
148-
auto pos = AdjacencyInfo.find(typeVar);
149-
150-
if (pos != AdjacencyInfo.end())
151-
return pos->second;
152-
153-
// If we weren't already adjacent to this type variable, add it to the
154-
// list of adjacencies.
155-
pos = AdjacencyInfo.insert(
156-
{ typeVar, { static_cast<unsigned>(Adjacencies.size()), 0, 0 } })
157-
.first;
158-
Adjacencies.push_back(typeVar);
159-
return pos->second;
160-
}
161-
162-
void ConstraintGraphNode::modifyAdjacency(
163-
TypeVariableType *typeVar,
164-
llvm::function_ref<void(Adjacency& adj)> modify) {
165-
// Find the adjacency information.
166-
auto pos = AdjacencyInfo.find(typeVar);
167-
assert(pos != AdjacencyInfo.end() && "Type variables not adjacent");
168-
assert(Adjacencies[pos->second.Index] == typeVar && "Mismatched adjacency");
169-
170-
// Perform the modification .
171-
modify(pos->second);
172-
173-
// If the adjacency is not empty, leave the information in there.
174-
if (!pos->second.empty())
175-
return;
176-
177-
// Remove this adjacency from the mapping.
178-
unsigned index = pos->second.Index;
179-
AdjacencyInfo.erase(pos);
180-
181-
// If this adjacency is last in the vector, just pop it off.
182-
unsigned lastIndex = Adjacencies.size()-1;
183-
if (index == lastIndex) {
184-
Adjacencies.pop_back();
185-
return;
186-
}
187-
188-
// This adjacency is somewhere in the middle; swap it with the last
189-
// adjacency so we can remove the adjacency from the vector in O(1) time
190-
// rather than O(n) time.
191-
auto lastTypeVar = Adjacencies[lastIndex];
192-
Adjacencies[index] = lastTypeVar;
193-
AdjacencyInfo[lastTypeVar].Index = index;
194-
Adjacencies.pop_back();
195-
}
196-
197-
void ConstraintGraphNode::addAdjacency(TypeVariableType *typeVar) {
198-
auto &adjacency = getAdjacency(typeVar);
199-
200-
// Bump the degree of the adjacency.
201-
++adjacency.NumConstraints;
202-
}
203-
204-
void ConstraintGraphNode::removeAdjacency(TypeVariableType *typeVar) {
205-
modifyAdjacency(typeVar, [](Adjacency &adj) {
206-
assert(adj.NumConstraints > 0 && "No adjacency to remove?");
207-
--adj.NumConstraints;
208-
});
209-
}
210-
211131
void ConstraintGraphNode::addToEquivalenceClass(
212132
ArrayRef<TypeVariableType *> typeVars) {
213133
assert(TypeVar == TypeVar->getImpl().getRepresentative(nullptr) &&
@@ -218,17 +138,11 @@ void ConstraintGraphNode::addToEquivalenceClass(
218138
}
219139

220140
void ConstraintGraphNode::addFixedBinding(TypeVariableType *typeVar) {
221-
auto &adjacency = getAdjacency(typeVar);
222-
223-
assert(!adjacency.FixedBinding && "Already marked as a fixed binding?");
224-
adjacency.FixedBinding = true;
141+
FixedBindings.push_back(typeVar);
225142
}
226143

227144
void ConstraintGraphNode::removeFixedBinding(TypeVariableType *typeVar) {
228-
modifyAdjacency(typeVar, [](Adjacency &adj) {
229-
assert(adj.FixedBinding && "Not a fixed binding?");
230-
adj.FixedBinding = false;
231-
});
145+
FixedBindings.pop_back();
232146
}
233147

234148
#pragma mark Graph scope management
@@ -353,16 +267,6 @@ void ConstraintGraph::addConstraint(Constraint *constraint) {
353267

354268
// Note the constraint within the node for that type variable.
355269
node.addConstraint(constraint);
356-
357-
// Record the adjacent type variables.
358-
// This is O(N^2) in the number of referenced type variables, because
359-
// we're updating all of the adjacent type variables eagerly.
360-
for (auto otherTypeVar : referencedTypeVars) {
361-
if (typeVar == otherTypeVar)
362-
continue;
363-
364-
node.addAdjacency(otherTypeVar);
365-
}
366270
}
367271

368272
// If the constraint doesn't reference any type variables, it's orphaned;
@@ -385,16 +289,6 @@ void ConstraintGraph::removeConstraint(Constraint *constraint) {
385289

386290
// Remove the constraint.
387291
node.removeConstraint(constraint);
388-
389-
// Remove the adjacencies for all adjacent type variables.
390-
// This is O(N^2) in the number of referenced type variables, because
391-
// we're updating all of the adjacent type variables eagerly.
392-
for (auto otherTypeVar : referencedTypeVars) {
393-
if (typeVar == otherTypeVar)
394-
continue;
395-
396-
node.removeAdjacency(otherTypeVar);
397-
}
398292
}
399293

400294
// If this is an orphaned constraint, remove it from the list.
@@ -487,7 +381,6 @@ void ConstraintGraph::gatherConstraints(
487381
auto equivClass = reprNode.getEquivalenceClass();
488382
llvm::SmallPtrSet<TypeVariableType *, 4> typeVars;
489383

490-
491384
/// Add constraints for the given adjacent type variable.
492385
auto addAdjacentConstraints = [&](TypeVariableType *adjTypeVar) {
493386
auto adjTypeVarsToVisit =
@@ -520,7 +413,7 @@ void ConstraintGraph::gatherConstraints(
520413

521414
// For any type variable mentioned in a fixed binding, add adjacent
522415
// constraints.
523-
for (auto adjTypeVar : node.getFixedAdjacencies()) {
416+
for (auto adjTypeVar : node.getFixedBindings()) {
524417
addAdjacentConstraints(adjTypeVar);
525418
}
526419
}
@@ -593,7 +486,7 @@ static void depthFirstSearch(
593486

594487
if (visitFixedBindings) {
595488
// Walk any type variables related via fixed bindings.
596-
visitAdjacencies(node.getFixedAdjacencies());
489+
visitAdjacencies(node.getFixedBindings());
597490
}
598491
}
599492

@@ -882,35 +775,24 @@ void ConstraintGraphNode::print(llvm::raw_ostream &out, unsigned indent) {
882775
}
883776
}
884777

885-
// Print adjacencies.
886-
if (!Adjacencies.empty()) {
778+
// Print fixed bindings.
779+
if (!FixedBindings.empty()) {
887780
out.indent(indent + 2);
888-
out << "Adjacencies:";
889-
SmallVector<TypeVariableType *, 4> sortedAdjacencies(Adjacencies.begin(),
890-
Adjacencies.end());
891-
std::sort(sortedAdjacencies.begin(), sortedAdjacencies.end(),
781+
out << "Fixed bindings: ";
782+
SmallVector<TypeVariableType *, 4> sortedFixedBindings(
783+
FixedBindings.begin(), FixedBindings.end());
784+
std::sort(sortedFixedBindings.begin(), sortedFixedBindings.end(),
892785
[&](TypeVariableType *typeVar1, TypeVariableType *typeVar2) {
893786
return typeVar1->getID() < typeVar2->getID();
894787
});
895788

896-
for (auto adj : sortedAdjacencies) {
897-
out << ' ';
898-
adj->print(out);
899-
900-
auto &info = AdjacencyInfo[adj];
901-
auto degree = info.NumConstraints;
902-
if (degree > 1 || info.FixedBinding) {
903-
out << " (";
904-
if (degree > 1) {
905-
out << degree;
906-
if (info.FixedBinding)
907-
out << ", fixed";
908-
} else {
909-
out << "fixed";
910-
}
911-
out << ")";
912-
}
913-
}
789+
interleave(sortedFixedBindings,
790+
[&](TypeVariableType *typeVar) {
791+
out << "$T" << typeVar->getID();
792+
},
793+
[&]() {
794+
out << ", ";
795+
});
914796
out << "\n";
915797
}
916798

@@ -997,7 +879,7 @@ static void _require(bool condition, const Twine &complaint,
997879
extraContext();
998880

999881
// Print the graph.
1000-
// FIXME: Highlight the offending node/constraint/adjacency/etc.
882+
// FIXME: Highlight the offending node/constraint/etc.
1001883
cg.print(llvm::dbgs());
1002884

1003885
abort();
@@ -1039,64 +921,6 @@ void ConstraintGraphNode::verify(ConstraintGraph &cg) {
1039921
requireSameValue(info.first, Constraints[info.second],
1040922
"constraint map provides wrong index into vector");
1041923
}
1042-
1043-
// Verify that the adjacency map/vector haven't gotten out of sync.
1044-
requireSameValue(Adjacencies.size(), AdjacencyInfo.size(),
1045-
"adjacency vector and map have different sizes");
1046-
for (auto info : AdjacencyInfo) {
1047-
require(info.second.Index < Adjacencies.size(),
1048-
"adjacency index out-of-range");
1049-
requireSameValue(info.first, Adjacencies[info.second.Index],
1050-
"adjacency map provides wrong index into vector");
1051-
require(!info.second.empty(),
1052-
"adjacency information should have been removed");
1053-
require(info.second.NumConstraints <= Constraints.size(),
1054-
"adjacency information has higher degree than # of constraints");
1055-
}
1056-
1057-
// Based on the constraints we have, build up a representation of what
1058-
// we expect the adjacencies to look like.
1059-
llvm::DenseMap<TypeVariableType *, unsigned> expectedAdjacencies;
1060-
for (auto constraint : Constraints) {
1061-
for (auto adjTypeVar : constraint->getTypeVariables()) {
1062-
if (adjTypeVar == TypeVar)
1063-
continue;
1064-
1065-
++expectedAdjacencies[adjTypeVar];
1066-
}
1067-
}
1068-
1069-
// Make sure that the adjacencies we expect are the adjacencies we have.
1070-
for (auto adj : expectedAdjacencies) {
1071-
auto knownAdj = AdjacencyInfo.find(adj.first);
1072-
requireWithContext(knownAdj != AdjacencyInfo.end(),
1073-
"missing adjacency information for type variable",
1074-
[&] {
1075-
llvm::dbgs() << " type variable=" << adj.first->getString() << 'n';
1076-
});
1077-
1078-
requireWithContext(adj.second == knownAdj->second.NumConstraints,
1079-
"wrong number of adjacencies for type variable",
1080-
[&] {
1081-
llvm::dbgs() << " type variable=" << adj.first->getString()
1082-
<< " (" << adj.second << " vs. "
1083-
<< knownAdj->second.NumConstraints
1084-
<< ")\n";
1085-
});
1086-
}
1087-
1088-
if (AdjacencyInfo.size() != expectedAdjacencies.size()) {
1089-
// The adjacency information has something extra in it. Find the
1090-
// extraneous type variable.
1091-
for (auto adj : AdjacencyInfo) {
1092-
requireWithContext(AdjacencyInfo.count(adj.first) > 0,
1093-
"extraneous adjacency info for type variable",
1094-
[&] {
1095-
llvm::dbgs() << " type variable=" << adj.first->getString() << '\n';
1096-
});
1097-
}
1098-
}
1099-
1100924
#undef requireSameValue
1101925
#undef requireWithContext
1102926
#undef require

lib/Sema/ConstraintGraph.h

Lines changed: 6 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -44,23 +44,6 @@ class ConstraintSystem;
4444

4545
/// A single node in the constraint graph, which represents a type variable.
4646
class ConstraintGraphNode {
47-
/// Describes information about an adjacency between two type variables.
48-
struct Adjacency {
49-
/// Index into the vector of adjacent type variables, \c Adjacencies.
50-
unsigned Index : 31;
51-
52-
/// Whether a fixed type binding relates the two type variables.
53-
unsigned FixedBinding : 1;
54-
55-
/// The number of constraints that link this type variable to the
56-
/// enclosing node.
57-
unsigned NumConstraints;
58-
59-
bool empty() const {
60-
return !FixedBinding && !NumConstraints;
61-
}
62-
};
63-
6447
public:
6548
explicit ConstraintGraphNode(TypeVariableType *typeVar) : TypeVar(typeVar) { }
6649

@@ -76,14 +59,11 @@ class ConstraintGraphNode {
7659
/// various other nodes.
7760
ArrayRef<Constraint *> getConstraints() const { return Constraints; }
7861

79-
/// Retrieve the set of type variables to which this node is adjacent.
80-
ArrayRef<TypeVariableType *> getAdjacencies() const {
81-
return Adjacencies;
82-
}
83-
8462
/// Retrieve the set of type variables that are adjacent due to fixed
8563
/// bindings.
86-
llvm::TinyPtrVector<TypeVariableType *> getFixedAdjacencies() const;
64+
ArrayRef<TypeVariableType *> getFixedBindings() const {
65+
return FixedBindings;
66+
}
8767

8868
/// Retrieve all of the type variables in the same equivalence class
8969
/// as this type variable.
@@ -103,21 +83,6 @@ class ConstraintGraphNode {
10383
/// remove the corresponding adjacencies.
10484
void removeConstraint(Constraint *constraint);
10585

106-
/// Retrieve adjacency information for the given type variable.
107-
Adjacency &getAdjacency(TypeVariableType *typeVar);
108-
109-
/// Modify the adjacency information for the given type variable
110-
/// directly. If the adjacency becomes empty afterward, it will be
111-
/// removed.
112-
void modifyAdjacency(TypeVariableType *typeVar,
113-
llvm::function_ref<void(Adjacency &adj)> modify);
114-
115-
/// Add an adjacency to the list of adjacencies.
116-
void addAdjacency(TypeVariableType *typeVar);
117-
118-
/// Remove an adjacency from the list of adjacencies.
119-
void removeAdjacency(TypeVariableType *typeVar);
120-
12186
/// Add the given type variables to this node's equivalence class.
12287
void addToEquivalenceClass(ArrayRef<TypeVariableType *> typeVars);
12388

@@ -139,13 +104,9 @@ class ConstraintGraphNode {
139104
/// to the index within the vector of constraints.
140105
llvm::SmallDenseMap<Constraint *, unsigned, 2> ConstraintIndex;
141106

142-
/// The set of adjacent type variables, in a stable order.
143-
SmallVector<TypeVariableType *, 2> Adjacencies;
144-
145-
/// A mapping from each of the type variables adjacent to this
146-
/// type variable to the index of the adjacency information in
147-
/// \c Adjacencies.
148-
llvm::SmallDenseMap<TypeVariableType *, Adjacency, 2> AdjacencyInfo;
107+
/// The set of type variables that occur within the fixed binding of
108+
/// this type variable.
109+
SmallVector<TypeVariableType *, 2> FixedBindings;
149110

150111
/// All of the type variables in the same equivalence class as this
151112
/// representative type variable.
@@ -321,7 +282,6 @@ class ConstraintGraph {
321282
/// caution.
322283
void unbindTypeVariable(TypeVariableType *typeVar, Type fixedType);
323284

324-
325285
/// Perform edge contraction on the constraint graph, merging equivalence
326286
/// classes until a fixed point is reached.
327287
bool contractEdges();

0 commit comments

Comments
 (0)