Skip to content

Commit 14ca9d1

Browse files
committed
[Constraint graph] Make connected components never touch all type variables.
Simplify the connected-components computation slightly and make sure that it never performs work outside of the subgraph described by the input set of type variables.
1 parent 6be6401 commit 14ca9d1

File tree

1 file changed

+50
-87
lines changed

1 file changed

+50
-87
lines changed

lib/Sema/ConstraintGraph.cpp

Lines changed: 50 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -431,10 +431,7 @@ llvm::TinyPtrVector<Constraint *> ConstraintGraph::gatherConstraints(
431431
/// Perform a depth-first search.
432432
///
433433
/// \param cg The constraint graph.
434-
/// \param node The current constraint graph node.
435-
/// \param nodeIndex The index of the current constraint graph node.
436-
/// \param visitFixedBindings Whether to visit the nodes by following
437-
/// fixed bindings.
434+
/// \param typeVar The type variable we're searching from.
438435
/// \param preVisitNode Called before traversing a node. Must return \c
439436
/// false when the node has already been visited.
440437
/// \param visitConstraint Called before considering a constraint. If it
@@ -443,31 +440,28 @@ llvm::TinyPtrVector<Constraint *> ConstraintGraph::gatherConstraints(
443440
/// internally to avoid duplicated work.
444441
static void depthFirstSearch(
445442
ConstraintGraph &cg,
446-
ConstraintGraphNode &node,
447-
unsigned nodeIndex,
448-
bool visitFixedBindings,
449-
llvm::function_ref<bool(unsigned)> preVisitNode,
443+
TypeVariableType *typeVar,
444+
llvm::function_ref<bool(TypeVariableType *)> preVisitNode,
450445
llvm::function_ref<bool(Constraint *)> visitConstraint,
451446
llvm::DenseSet<Constraint *> &visitedConstraints) {
452447
// Visit this node. If we've already seen it, bail out.
453-
if (!preVisitNode(nodeIndex))
448+
if (!preVisitNode(typeVar))
454449
return;
455450

456451
// Local function to visit adjacent type variables.
457452
auto visitAdjacencies = [&](ArrayRef<TypeVariableType *> adjTypeVars) {
458453
for (auto adj : adjTypeVars) {
459-
if (adj == node.getTypeVariable())
454+
if (adj == typeVar)
460455
continue;
461456

462-
auto adjNodeAndIndex = cg.lookupNode(adj);
463-
464457
// Recurse into this node.
465-
depthFirstSearch(cg, adjNodeAndIndex.first, adjNodeAndIndex.second,
466-
visitFixedBindings, preVisitNode, visitConstraint,
458+
depthFirstSearch(cg, adj, preVisitNode, visitConstraint,
467459
visitedConstraints);
468460
}
469461
};
470462

463+
auto &node = cg[typeVar];
464+
471465
// Walk all of the constraints associated with this node to find related
472466
// nodes.
473467
for (auto constraint : node.getConstraints()) {
@@ -480,9 +474,8 @@ static void depthFirstSearch(
480474
}
481475

482476
// Visit all of the other nodes in the equivalence class.
483-
auto nodeTypeVar = node.getTypeVariable();
484-
auto repTypeVar = cg.getConstraintSystem().getRepresentative(nodeTypeVar);
485-
if (nodeTypeVar == repTypeVar) {
477+
auto repTypeVar = cg.getConstraintSystem().getRepresentative(typeVar);
478+
if (typeVar == repTypeVar) {
486479
// We are the representative, so visit all of the other type variables
487480
// in this equivalence class.
488481
visitAdjacencies(node.getEquivalenceClass());
@@ -491,77 +484,56 @@ static void depthFirstSearch(
491484
visitAdjacencies(repTypeVar);
492485
}
493486

494-
if (visitFixedBindings) {
495-
// Walk any type variables related via fixed bindings.
496-
visitAdjacencies(node.getFixedBindings());
497-
}
487+
// Walk any type variables related via fixed bindings.
488+
visitAdjacencies(node.getFixedBindings());
498489
}
499490

500491
/// Perform a depth-first search.
501492
///
502493
/// \param cg The constraint graph.
503-
/// \param node The current constraint graph node.
504-
/// \param nodeIndex The index of the current constraint graph node.
505-
/// \param visitFixedBindings Whether to visit the nodes by following
506-
/// fixed bindings.
494+
/// \param typeVar The type variable we're searching from.
507495
/// \param preVisitNode Called before traversing a node. Must return \c
508496
/// false when the node has already been visited.
509497
/// \param visitConstraint Called before considering a constraint. If it
510498
/// returns \c false, that constraint will be skipped.
511499
static void depthFirstSearch(
512500
ConstraintGraph &cg,
513-
ConstraintGraphNode &node,
514-
unsigned nodeIndex,
515-
bool visitFixedBindings,
516-
llvm::function_ref<bool(unsigned)> preVisitNode,
501+
TypeVariableType *typeVar,
502+
llvm::function_ref<bool(TypeVariableType *)> preVisitNode,
517503
llvm::function_ref<bool(Constraint *)> visitConstraint) {
518504
llvm::DenseSet<Constraint *> visitedConstraints;
519-
depthFirstSearch(cg, node, nodeIndex, visitFixedBindings, preVisitNode,
520-
visitConstraint, visitedConstraints);
505+
depthFirstSearch(cg, typeVar, preVisitNode, visitConstraint,
506+
visitedConstraints);
521507
}
522508

523509
unsigned ConstraintGraph::computeConnectedComponents(
524510
std::vector<TypeVariableType *> &typeVars,
525511
std::vector<unsigned> &components) {
526-
// Track those type variables that the caller cares about.
527-
llvm::SmallPtrSet<TypeVariableType *, 4> typeVarSubset(typeVars.begin(),
528-
typeVars.end());
529-
530-
// Initialize the components with component == # of type variables,
531-
// a sentinel value indicating that we have yet to assign a component to
532-
// that particular type variable.
533-
unsigned numTypeVariables = TypeVariables.size();
534-
components.assign(numTypeVariables, numTypeVariables);
512+
llvm::SmallDenseMap<TypeVariableType *, unsigned> componentsMap;
535513

536514
// Perform a depth-first search from each type variable to identify
537515
// what component it is in.
538-
llvm::DenseSet<Constraint *> visitedConstraints;
539516
unsigned numComponents = 0;
540517
for (auto typeVar : typeVars) {
541-
// Look up the node for this type variable.
542-
auto nodeAndIndex = lookupNode(typeVar);
543-
544-
// If we're already assigned a component for this node, skip it.
545-
unsigned &curComponent = components[nodeAndIndex.second];
546-
if (curComponent != numTypeVariables)
518+
// If we've already assigned a component to this type variable, we're done.
519+
if (componentsMap.count(typeVar) > 0)
547520
continue;
548521

549522
// Record this component.
550523
unsigned component = numComponents++;
551524

552-
// Note that this node is part of this component, then visit it.
525+
// Perform a depth-first search to mark those type variables that are
526+
// in the same component as this type variable.
553527
depthFirstSearch(
554-
*this, nodeAndIndex.first, nodeAndIndex.second,
555-
/*visitFixedBindings=*/true,
556-
[&](unsigned nodeIndex) {
528+
*this, typeVar,
529+
[&](TypeVariableType *typeVar) {
557530
// If we have already seen this node, we're done.
558-
unsigned &nodeComponent = components[nodeIndex];
559-
if (nodeComponent == component)
531+
if (componentsMap.count(typeVar) > 0) {
532+
assert(componentsMap[typeVar] == component && "Wrong component?");
560533
return false;
534+
}
561535

562-
assert(nodeComponent == components.size() &&
563-
"Already in a component?");
564-
nodeComponent = component;
536+
componentsMap[typeVar] = component;
565537
return true;
566538
},
567539
[&](Constraint *constraint) {
@@ -572,52 +544,43 @@ unsigned ConstraintGraph::computeConnectedComponents(
572544
// Figure out which components have unbound type variables; these
573545
// are the only components and type variables we want to report.
574546
SmallVector<bool, 4> componentHasUnboundTypeVar(numComponents, false);
575-
for (unsigned i = 0; i != numTypeVariables; ++i) {
576-
// If we didn't look at this type variable, there's nothing to do.
577-
if (components[i] == numTypeVariables)
578-
continue;
579-
547+
for (auto typeVar : typeVars) {
580548
// If this type variable has a fixed type, skip it.
581-
if (CS.getFixedType(TypeVariables[i]))
549+
if (CS.getFixedType(typeVar))
582550
continue;
583551

584-
// If this type variable isn't in the subset of type variables we care
585-
// about, skip it.
586-
if (typeVarSubset.count(TypeVariables[i]) == 0)
587-
continue;
588-
589-
componentHasUnboundTypeVar[components[i]] = true;
552+
assert(componentsMap.count(typeVar) > 0);
553+
componentHasUnboundTypeVar[componentsMap[typeVar]] = true;
590554
}
591555

592556
// Renumber the old components to the new components.
593557
SmallVector<unsigned, 4> componentRenumbering(numComponents, 0);
594558
numComponents = 0;
595-
for (unsigned i = 0, n = componentHasUnboundTypeVar.size(); i != n; ++i) {
559+
for (unsigned i : indices(componentRenumbering)) {
596560
// Skip components that have no unbound type variables.
597561
if (!componentHasUnboundTypeVar[i])
598562
continue;
599563

600564
componentRenumbering[i] = numComponents++;
601565
}
602566

603-
// Copy over the type variables in the live components and remap
604-
// component numbers.
605-
typeVars.clear();
606-
unsigned outIndex = 0;
607-
for (unsigned i = 0, n = TypeVariables.size(); i != n; ++i) {
608-
// If we didn't look at this type variable, there's nothing to do.
609-
if (components[i] == numTypeVariables)
610-
continue;
611-
612-
// Skip type variables in dead components.
613-
if (!componentHasUnboundTypeVar[components[i]])
614-
continue;
615-
616-
typeVars.push_back(TypeVariables[i]);
617-
components[outIndex] = componentRenumbering[components[i]];
618-
++outIndex;
619-
}
620-
components.erase(components.begin() + outIndex, components.end());
567+
// Remove type variables in dead components and provide component
568+
// numbers for those that remain.
569+
typeVars.erase(
570+
std::remove_if(
571+
typeVars.begin(), typeVars.end(),
572+
[&](TypeVariableType *typeVar) {
573+
assert(componentsMap.count(typeVar) > 0);
574+
unsigned component = componentsMap[typeVar];
575+
// Remove type variables in dead components.
576+
if (!componentHasUnboundTypeVar[component])
577+
return true;
578+
579+
// Record the (renumbered) component.
580+
components.push_back(componentRenumbering[component]);
581+
return false;
582+
}),
583+
typeVars.end());
621584

622585
return numComponents + getOrphanedConstraints().size();
623586
}

0 commit comments

Comments
 (0)