Skip to content

Commit 6a970a8

Browse files
committed
[Constraint solver] Reimplement connected components using constraints.
The constraint graph maintains a fairly heavyweight list of adjacencies that is only used in two operations: connected components and gathering related constraints. Switch connected components over to primarily use the set of constraints (which are necessary for many reasons), reducing the need for the adjacencies list.
1 parent 123f4b9 commit 6a970a8

File tree

2 files changed

+72
-31
lines changed

2 files changed

+72
-31
lines changed

lib/Sema/ConstraintGraph.cpp

Lines changed: 67 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,18 @@ 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+
8698
ArrayRef<TypeVariableType *> ConstraintGraphNode::getEquivalenceClass() const{
8799
assert(TypeVar == TypeVar->getImpl().getRepresentative(nullptr) &&
88100
"Can't request equivalence class from non-representative type var");
@@ -525,40 +537,62 @@ void ConstraintGraph::gatherConstraints(
525537
#pragma mark Algorithms
526538

527539
/// Depth-first search for connected components
528-
static void connectedComponentsDFS(ConstraintGraph &cg,
529-
ConstraintGraphNode &node,
530-
unsigned component,
531-
std::vector<unsigned> &components) {
532-
// Local function that recurses on the given set of type variables.
533-
auto visitAdjacencies = [&](ArrayRef<TypeVariableType *> typeVars) {
534-
for (auto adj : typeVars) {
535-
auto nodeAndIndex = cg.lookupNode(adj);
536-
// If we've already seen this node in this component, we're done.
537-
unsigned &curComponent = components[nodeAndIndex.second];
538-
if (curComponent == component)
540+
static void connectedComponentsDFS(
541+
ConstraintGraph &cg,
542+
ConstraintGraphNode &node,
543+
unsigned nodeIndex,
544+
unsigned component,
545+
std::vector<unsigned> &components,
546+
llvm::DenseSet<Constraint *> &visitedConstraints) {
547+
// If we have already seen this node, we're done.
548+
unsigned &nodeComponent = components[nodeIndex];
549+
if (nodeComponent == component)
550+
return;
551+
552+
assert(nodeComponent == components.size() && "Already in a component?");
553+
nodeComponent = component;
554+
555+
// Local function to visit adjacent type variables.
556+
auto visitAdjacencies = [&](ArrayRef<TypeVariableType *> adjTypeVars) {
557+
for (auto adj : adjTypeVars) {
558+
if (adj == node.getTypeVariable())
539559
continue;
540560

541-
// Mark this node as part of this connected component, then recurse.
542-
assert(curComponent == components.size() && "Already in a component?");
543-
curComponent = component;
544-
connectedComponentsDFS(cg, nodeAndIndex.first, component, components);
561+
auto adjNodeAndIndex = cg.lookupNode(adj);
562+
563+
// Visit the next node.
564+
connectedComponentsDFS(cg, adjNodeAndIndex.first, adjNodeAndIndex.second,
565+
component, components, visitedConstraints);
545566
}
546567
};
547568

548-
// Recurse to mark adjacent nodes as part of this connected component.
549-
visitAdjacencies(node.getAdjacencies());
550-
551-
// Figure out the representative for this type variable.
552-
auto &cs = cg.getConstraintSystem();
553-
auto typeVarRep = cs.getRepresentative(node.getTypeVariable());
554-
if (typeVarRep == node.getTypeVariable()) {
555-
// This type variable is the representative of its set; visit all of the
556-
// other type variables in the same equivalence class.
557-
visitAdjacencies(node.getEquivalenceClass().slice(1));
558-
} else {
559-
// Otherwise, visit the representative of the set.
560-
visitAdjacencies(typeVarRep);
569+
// Walk all of the constraints associated with this node to find related
570+
// nodes.
571+
for (auto constraint : node.getConstraints()) {
572+
// If we've already seen this constraint, skip it.
573+
if (!visitedConstraints.insert(constraint).second)
574+
continue;
575+
576+
visitAdjacencies(constraint->getTypeVariables());
577+
}
578+
579+
// Walk any type variables related via fixed bindings.
580+
visitAdjacencies(node.getFixedAdjacencies());
581+
582+
// Visit all of the other nodes in the equivalence class.
583+
auto nodeTypeVar = node.getTypeVariable();
584+
auto repTypeVar = cg.getConstraintSystem().getRepresentative(nodeTypeVar);
585+
if (nodeTypeVar != repTypeVar) {
586+
// We are not the representative; visit the representative to be sure.
587+
auto repNodeAndIndex = cg.lookupNode(repTypeVar);
588+
connectedComponentsDFS(cg, repNodeAndIndex.first, repNodeAndIndex.second,
589+
component, components, visitedConstraints);
590+
return;
561591
}
592+
593+
// We are the representative, so visit all of the other type variables
594+
// in this equivalence class.
595+
visitAdjacencies(node.getEquivalenceClass());
562596
}
563597

564598
unsigned ConstraintGraph::computeConnectedComponents(
@@ -570,12 +604,14 @@ unsigned ConstraintGraph::computeConnectedComponents(
570604
typeVars.clear();
571605

572606
// Initialize the components with component == # of type variables,
573-
// a sentinel value indicating
607+
// a sentinel value indicating that we have yet to assign a component to
608+
// that particular type variable.
574609
unsigned numTypeVariables = TypeVariables.size();
575610
components.assign(numTypeVariables, numTypeVariables);
576611

577612
// Perform a depth-first search from each type variable to identify
578613
// what component it is in.
614+
llvm::DenseSet<Constraint *> visitedConstraints;
579615
unsigned numComponents = 0;
580616
for (unsigned i = 0; i != numTypeVariables; ++i) {
581617
auto typeVar = TypeVariables[i];
@@ -592,8 +628,8 @@ unsigned ConstraintGraph::computeConnectedComponents(
592628
unsigned component = numComponents++;
593629

594630
// Note that this node is part of this component, then visit it.
595-
curComponent = component;
596-
connectedComponentsDFS(*this, nodeAndIndex.first, component, components);
631+
connectedComponentsDFS(*this, nodeAndIndex.first, nodeAndIndex.second,
632+
component, components, visitedConstraints);
597633
}
598634

599635
// Figure out which components have unbound type variables; these

lib/Sema/ConstraintGraph.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
#include "swift/Basic/LLVM.h"
2121
#include "swift/AST/Identifier.h"
22+
#include "swift/AST/Type.h"
2223
#include "llvm/ADT/ArrayRef.h"
2324
#include "llvm/ADT/DenseSet.h"
2425
#include "llvm/ADT/DenseMap.h"
@@ -80,6 +81,10 @@ class ConstraintGraphNode {
8081
return Adjacencies;
8182
}
8283

84+
/// Retrieve the set of type variables that are adjacent due to fixed
85+
/// bindings.
86+
llvm::TinyPtrVector<TypeVariableType *> getFixedAdjacencies() const;
87+
8388
/// Retrieve all of the type variables in the same equivalence class
8489
/// as this type variable.
8590
ArrayRef<TypeVariableType *> getEquivalenceClass() const;

0 commit comments

Comments
 (0)