Skip to content

Commit a51795f

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. (cherry picked from commit 6a970a8)
1 parent a36d1f8 commit a51795f

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)