Skip to content

Commit cf1732c

Browse files
committed
[Constraint graph] Reinstate the adjacencies of constraint graph nodes.
Reinstate the list of adjacencies in each constraint graph node, effectively reverting dfdd352. Exclude one-way constraints from this computation; we'll handle them separately.
1 parent 1857a37 commit cf1732c

File tree

2 files changed

+247
-26
lines changed

2 files changed

+247
-26
lines changed

lib/Sema/ConstraintGraph.cpp

Lines changed: 205 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,74 @@ void ConstraintGraphNode::removeConstraint(Constraint *constraint) {
128128
Constraints.pop_back();
129129
}
130130

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

261-
void ConstraintGraph::addConstraint(Constraint *constraint) {
262-
// For the nodes corresponding to each type variable...
329+
/// Enumerate the adjacency edges for the given constraint.
330+
static void enumerateAdjacencies(
331+
Constraint *constraint,
332+
llvm::function_ref<void(TypeVariableType *, TypeVariableType *)> visitor) {
333+
// Don't record adjacencies for one-way constraints.
334+
if (constraint->isOneWayConstraint())
335+
return;
336+
337+
// O(N^2) update for all of the adjacent type variables.
263338
auto referencedTypeVars = constraint->getTypeVariables();
264339
for (auto typeVar : referencedTypeVars) {
265-
// Find the node for this type variable.
266-
auto &node = (*this)[typeVar];
340+
for (auto otherTypeVar : referencedTypeVars) {
341+
if (typeVar == otherTypeVar)
342+
continue;
343+
344+
visitor(typeVar, otherTypeVar);
345+
}
346+
}
347+
}
267348

268-
// Note the constraint within the node for that type variable.
269-
node.addConstraint(constraint);
349+
void ConstraintGraph::addConstraint(Constraint *constraint) {
350+
// Record the change, if there are active scopes.
351+
if (ActiveScope) {
352+
Changes.push_back(Change::addedConstraint(constraint));
270353
}
271354

272-
// If the constraint doesn't reference any type variables, it's orphaned;
273-
// track it as such.
274-
if (referencedTypeVars.empty()) {
355+
if (constraint->getTypeVariables().empty()) {
356+
// A constraint that doesn't reference any type variables is orphaned;
357+
// track it as such.
275358
OrphanedConstraints.push_back(constraint);
359+
return;
276360
}
277361

278-
// Record the change, if there are active scopes.
279-
if (ActiveScope)
280-
Changes.push_back(Change::addedConstraint(constraint));
362+
// Record this constraint in each type variable.
363+
for (auto typeVar : constraint->getTypeVariables()) {
364+
(*this)[typeVar].addConstraint(constraint);
365+
}
366+
367+
// Record adjacencies.
368+
enumerateAdjacencies(constraint,
369+
[&](TypeVariableType *lhs, TypeVariableType *rhs) {
370+
assert(lhs != rhs);
371+
(*this)[lhs].addAdjacency(rhs);
372+
});
281373
}
282374

283375
void ConstraintGraph::removeConstraint(Constraint *constraint) {
284-
// For the nodes corresponding to each type variable...
285-
auto referencedTypeVars = constraint->getTypeVariables();
286-
for (auto typeVar : referencedTypeVars) {
287-
// Find the node for this type variable.
288-
auto &node = (*this)[typeVar];
289-
290-
// Remove the constraint.
291-
node.removeConstraint(constraint);
292-
}
376+
// Record the change, if there are active scopes.
377+
if (ActiveScope)
378+
Changes.push_back(Change::removedConstraint(constraint));
293379

294-
// If this is an orphaned constraint, remove it from the list.
295-
if (referencedTypeVars.empty()) {
380+
if (constraint->getTypeVariables().empty()) {
381+
// A constraint that doesn't reference any type variables is orphaned;
382+
// remove it from the list of orphaned constraints.
296383
auto known = std::find(OrphanedConstraints.begin(),
297384
OrphanedConstraints.end(),
298385
constraint);
299386
assert(known != OrphanedConstraints.end() && "missing orphaned constraint");
300387
*known = OrphanedConstraints.back();
301388
OrphanedConstraints.pop_back();
389+
return;
302390
}
303391

304-
// Record the change, if there are active scopes.
305-
if (ActiveScope)
306-
Changes.push_back(Change::removedConstraint(constraint));
392+
// Remove the constraint from each type variable.
393+
for (auto typeVar : constraint->getTypeVariables()) {
394+
(*this)[typeVar].removeConstraint(constraint);
395+
}
396+
397+
// Remove all adjacencies for all type variables.
398+
enumerateAdjacencies(constraint,
399+
[&](TypeVariableType *lhs, TypeVariableType *rhs) {
400+
assert(lhs != rhs);
401+
(*this)[lhs].removeAdjacency(rhs);
402+
});
307403
}
308404

309405
void ConstraintGraph::mergeNodes(TypeVariableType *typeVar1,
@@ -1228,6 +1324,28 @@ void ConstraintGraphNode::print(llvm::raw_ostream &out, unsigned indent) {
12281324
}
12291325
}
12301326

1327+
if (!Adjacencies.empty()) {
1328+
out.indent(indent + 2);
1329+
out << "Adjacencies:";
1330+
SmallVector<TypeVariableType *, 4> sortedAdjacencies(Adjacencies.begin(),
1331+
Adjacencies.end());
1332+
std::sort(sortedAdjacencies.begin(), sortedAdjacencies.end(),
1333+
[](TypeVariableType *lhs, TypeVariableType *rhs) {
1334+
return lhs->getID() < rhs->getID();
1335+
});
1336+
for (auto adj : sortedAdjacencies) {
1337+
out << ' ';
1338+
adj->print(out);
1339+
1340+
auto &info = AdjacencyInfo[adj];
1341+
auto degree = info.NumConstraints;
1342+
if (degree > 1) {
1343+
out << " (" << degree << ")";
1344+
}
1345+
}
1346+
out << "\n";
1347+
}
1348+
12311349
// Print fixed bindings.
12321350
if (!FixedBindings.empty()) {
12331351
out.indent(indent + 2);
@@ -1396,6 +1514,67 @@ void ConstraintGraphNode::verify(ConstraintGraph &cg) {
13961514
requireSameValue(info.first, Constraints[info.second],
13971515
"constraint map provides wrong index into vector");
13981516
}
1517+
1518+
// Verify that the adjacency map/vector haven't gotten out of sync.
1519+
requireSameValue(Adjacencies.size(), AdjacencyInfo.size(),
1520+
"adjacency vector and map have different sizes");
1521+
for (auto info : AdjacencyInfo) {
1522+
require(info.second.Index < Adjacencies.size(),
1523+
"adjacency index out-of-range");
1524+
requireSameValue(info.first, Adjacencies[info.second.Index],
1525+
"adjacency map provides wrong index into vector");
1526+
require(!info.second.empty(),
1527+
"adjacency information should have been removed");
1528+
require(info.second.NumConstraints <= Constraints.size(),
1529+
"adjacency information has higher degree than # of constraints");
1530+
}
1531+
1532+
// Based on the constraints we have, build up a representation of what
1533+
// we expect the adjacencies to look like.
1534+
llvm::DenseMap<TypeVariableType *, unsigned> expectedAdjacencies;
1535+
for (auto constraint : Constraints) {
1536+
if (constraint->isOneWayConstraint())
1537+
continue;
1538+
1539+
for (auto adjTypeVar : constraint->getTypeVariables()) {
1540+
if (adjTypeVar == TypeVar)
1541+
continue;
1542+
1543+
++expectedAdjacencies[adjTypeVar];
1544+
}
1545+
}
1546+
1547+
// Make sure that the adjacencies we expect are the adjacencies we have.
1548+
for (auto adj : expectedAdjacencies) {
1549+
auto knownAdj = AdjacencyInfo.find(adj.first);
1550+
requireWithContext(knownAdj != AdjacencyInfo.end(),
1551+
"missing adjacency information for type variable",
1552+
[&] {
1553+
llvm::dbgs() << " type variable=" << adj.first->getString() << 'n';
1554+
});
1555+
1556+
requireWithContext(adj.second == knownAdj->second.NumConstraints,
1557+
"wrong number of adjacencies for type variable",
1558+
[&] {
1559+
llvm::dbgs() << " type variable=" << adj.first->getString()
1560+
<< " (" << adj.second << " vs. "
1561+
<< knownAdj->second.NumConstraints
1562+
<< ")\n";
1563+
});
1564+
}
1565+
1566+
if (AdjacencyInfo.size() != expectedAdjacencies.size()) {
1567+
// The adjacency information has something extra in it. Find the
1568+
// extraneous type variable.
1569+
for (auto adj : AdjacencyInfo) {
1570+
requireWithContext(AdjacencyInfo.count(adj.first) > 0,
1571+
"extraneous adjacency info for type variable",
1572+
[&] {
1573+
llvm::dbgs() << " type variable=" << adj.first->getString() << '\n';
1574+
});
1575+
}
1576+
}
1577+
13991578
#undef requireSameValue
14001579
#undef requireWithContext
14011580
#undef require

lib/Sema/ConstraintGraph.h

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,20 @@ class ConstraintSystem;
4545

4646
/// A single node in the constraint graph, which represents a type variable.
4747
class ConstraintGraphNode {
48+
/// Describes information about an adjacency between two type variables.
49+
struct Adjacency {
50+
/// Index into the vector of adjacent type variables, \c Adjacencies.
51+
unsigned Index;
52+
53+
/// The number of constraints that link this type variable to the
54+
/// enclosing node.
55+
unsigned NumConstraints;
56+
57+
bool empty() const {
58+
return NumConstraints == 0;
59+
}
60+
};
61+
4862
public:
4963
explicit ConstraintGraphNode(TypeVariableType *typeVar) : TypeVar(typeVar) { }
5064

@@ -60,6 +74,11 @@ class ConstraintGraphNode {
6074
/// various other nodes.
6175
ArrayRef<Constraint *> getConstraints() const { return Constraints; }
6276

77+
/// Retrieve the set of type variables to which this node is adjacent.
78+
ArrayRef<TypeVariableType *> getAdjacencies() const {
79+
return Adjacencies;
80+
}
81+
6382
/// Retrieve the set of type variables that are adjacent due to fixed
6483
/// bindings.
6584
ArrayRef<TypeVariableType *> getFixedBindings() const {
@@ -84,6 +103,21 @@ class ConstraintGraphNode {
84103
/// remove the corresponding adjacencies.
85104
void removeConstraint(Constraint *constraint);
86105

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+
87121
/// Add the given type variables to this node's equivalence class.
88122
void addToEquivalenceClass(ArrayRef<TypeVariableType *> typeVars);
89123

@@ -105,6 +139,14 @@ class ConstraintGraphNode {
105139
/// to the index within the vector of constraints.
106140
llvm::SmallDenseMap<Constraint *, unsigned, 2> ConstraintIndex;
107141

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;
149+
108150
/// The set of type variables that occur within the fixed binding of
109151
/// this type variable.
110152
SmallVector<TypeVariableType *, 2> FixedBindings;

0 commit comments

Comments
 (0)