Skip to content

Commit 7758857

Browse files
authored
Merge pull request #26369 from DougGregor/constraint-graph-connected-components-subgraph
[Constraint graph] Restrict connected components to requested type variables
2 parents 61261fc + 14ca9d1 commit 7758857

File tree

1 file changed

+51
-82
lines changed

1 file changed

+51
-82
lines changed

lib/Sema/ConstraintGraph.cpp

Lines changed: 51 additions & 82 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,80 +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-
typeVars.clear();
530-
531-
// Initialize the components with component == # of type variables,
532-
// a sentinel value indicating that we have yet to assign a component to
533-
// that particular type variable.
534-
unsigned numTypeVariables = TypeVariables.size();
535-
components.assign(numTypeVariables, numTypeVariables);
512+
llvm::SmallDenseMap<TypeVariableType *, unsigned> componentsMap;
536513

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

552522
// Record this component.
553523
unsigned component = numComponents++;
554524

555-
// 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.
556527
depthFirstSearch(
557-
*this, nodeAndIndex.first, nodeAndIndex.second,
558-
/*visitFixedBindings=*/true,
559-
[&](unsigned nodeIndex) {
528+
*this, typeVar,
529+
[&](TypeVariableType *typeVar) {
560530
// If we have already seen this node, we're done.
561-
unsigned &nodeComponent = components[nodeIndex];
562-
if (nodeComponent == component)
531+
if (componentsMap.count(typeVar) > 0) {
532+
assert(componentsMap[typeVar] == component && "Wrong component?");
563533
return false;
534+
}
564535

565-
assert(nodeComponent == components.size() &&
566-
"Already in a component?");
567-
nodeComponent = component;
536+
componentsMap[typeVar] = component;
568537
return true;
569538
},
570539
[&](Constraint *constraint) {
@@ -575,43 +544,43 @@ unsigned ConstraintGraph::computeConnectedComponents(
575544
// Figure out which components have unbound type variables; these
576545
// are the only components and type variables we want to report.
577546
SmallVector<bool, 4> componentHasUnboundTypeVar(numComponents, false);
578-
for (unsigned i = 0; i != numTypeVariables; ++i) {
547+
for (auto typeVar : typeVars) {
579548
// If this type variable has a fixed type, skip it.
580-
if (CS.getFixedType(TypeVariables[i]))
581-
continue;
582-
583-
// If this type variable isn't in the subset of type variables we care
584-
// about, skip it.
585-
if (typeVarSubset.count(TypeVariables[i]) == 0)
549+
if (CS.getFixedType(typeVar))
586550
continue;
587551

588-
componentHasUnboundTypeVar[components[i]] = true;
552+
assert(componentsMap.count(typeVar) > 0);
553+
componentHasUnboundTypeVar[componentsMap[typeVar]] = true;
589554
}
590555

591556
// Renumber the old components to the new components.
592557
SmallVector<unsigned, 4> componentRenumbering(numComponents, 0);
593558
numComponents = 0;
594-
for (unsigned i = 0, n = componentHasUnboundTypeVar.size(); i != n; ++i) {
559+
for (unsigned i : indices(componentRenumbering)) {
595560
// Skip components that have no unbound type variables.
596561
if (!componentHasUnboundTypeVar[i])
597562
continue;
598563

599564
componentRenumbering[i] = numComponents++;
600565
}
601566

602-
// Copy over the type variables in the live components and remap
603-
// component numbers.
604-
unsigned outIndex = 0;
605-
for (unsigned i = 0, n = TypeVariables.size(); i != n; ++i) {
606-
// Skip type variables in dead components.
607-
if (!componentHasUnboundTypeVar[components[i]])
608-
continue;
609-
610-
typeVars.push_back(TypeVariables[i]);
611-
components[outIndex] = componentRenumbering[components[i]];
612-
++outIndex;
613-
}
614-
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());
615584

616585
return numComponents + getOrphanedConstraints().size();
617586
}

0 commit comments

Comments
 (0)