[Constraint graph] Handle orphaned constraints within connected components

Move the logic for creating connected components of orphaned
constraints into the connected-components algorithm code, rather than
making it a special part of SplitterStep.
This commit is contained in:
Doug Gregor
2019-08-07 15:34:21 -07:00
parent 5a4af23a63
commit ab38be128d
4 changed files with 32 additions and 35 deletions

View File

@@ -97,32 +97,13 @@ void SplitterStep::computeFollowupSteps(
// Compute the connected components of the constraint graph.
auto components = CG.computeConnectedComponents(CS.TypeVariables);
unsigned numComponents =
components.size() + CG.getOrphanedConstraints().size();
unsigned numComponents = components.size();
if (numComponents < 2) {
componentSteps.push_back(llvm::make_unique<ComponentStep>(
CS, 0, &CS.InactiveConstraints, Solutions));
return;
}
Components.resize(numComponents);
PartialSolutions = std::unique_ptr<SmallVector<Solution, 4>[]>(
new SmallVector<Solution, 4>[numComponents]);
// Add components.
for (unsigned i : indices(components)) {
componentSteps.push_back(llvm::make_unique<ComponentStep>(
CS, i, &Components[i], std::move(components[i]), PartialSolutions[i]));
}
// Add components for the orphaned constraints.
OrphanedConstraints = CG.takeOrphanedConstraints();
for (unsigned i : range(components.size(), numComponents)) {
auto orphaned = OrphanedConstraints[i - components.size()];
componentSteps.push_back(llvm::make_unique<ComponentStep>(
CS, i, &Components[i], orphaned, PartialSolutions[i]));
}
if (isDebugMode()) {
auto &log = getDebugLogger();
// Verify that the constraint graph is valid.
@@ -135,6 +116,19 @@ void SplitterStep::computeFollowupSteps(
CG.printConnectedComponents(CS.TypeVariables, log);
}
// Take the orphaned constraints, because they'll go into a component now.
OrphanedConstraints = CG.takeOrphanedConstraints();
Components.resize(numComponents);
PartialSolutions = std::unique_ptr<SmallVector<Solution, 4>[]>(
new SmallVector<Solution, 4>[numComponents]);
// Add components.
for (unsigned i : indices(components)) {
componentSteps.push_back(llvm::make_unique<ComponentStep>(
CS, i, &Components[i], std::move(components[i]), PartialSolutions[i]));
}
// Create component ordering based on the information associated
// with constraints in each step - e.g. number of disjunctions,
// since components are going to be executed in LIFO order, we'd

View File

@@ -366,6 +366,13 @@ public:
: SolverStep(cs, solutions), Index(index), IsSingle(false),
OriginalScore(getCurrentScore()), OriginalBestScore(getBestScore()),
Constraints(constraints) {
if (component.isOrphaned()) {
assert(component.constraints.size() == 1);
OrphanedConstraint = component.constraints.front();
} else {
assert(component.typeVars.size() > 0);
}
TypeVars = std::move(component.typeVars);
for (auto constraint : component.constraints) {
@@ -374,18 +381,6 @@ public:
}
}
/// Create a component step for an orphaned constraint.
ComponentStep(ConstraintSystem &cs, unsigned index,
ConstraintList *constraints,
Constraint *orphaned,
SmallVectorImpl<Solution> &solutions)
: SolverStep(cs, solutions), Index(index), IsSingle(false),
OriginalScore(getCurrentScore()), OriginalBestScore(getBestScore()),
Constraints(constraints), OrphanedConstraint(orphaned) {
constraints->erase(orphaned);
record(orphaned);
}
private:
/// Record a constraint as associated with this step.
void record(Constraint *constraint) {
@@ -418,7 +413,8 @@ private:
getDebugLogger() << "(solving component #" << Index << '\n';
ComponentScope = llvm::make_unique<Scope>(*this);
// If this component has oprhaned constraint attached,
// If this component has orphaned constraint attached,
// let's return it to the graph.
CS.CG.setOrphanedConstraint(OrphanedConstraint);
}

View File

@@ -540,6 +540,8 @@ namespace {
// Assign each type variable to its appropriate component.
SmallVector<Component, 1> components;
components.reserve(
validComponents.size() + cg.getOrphanedConstraints().size());
llvm::SmallDenseMap<TypeVariableType *, unsigned> componentIdxMap;
for (auto typeVar : typeVars) {
// Find the representative. If we aren't creating a type variable
@@ -577,6 +579,12 @@ namespace {
components[componentIdxMap[rep]].constraints.push_back(&constraint);
}
// Gather orphaned constraints; each gets its own component.
for (auto orphaned : cg.getOrphanedConstraints()) {
components.push_back({ });
components.back().constraints.push_back(orphaned);
}
return components;
}
@@ -635,7 +643,6 @@ ConstraintGraph::computeConnectedComponents(
// Perform connected components via a union-find algorithm on all of the
// constraints adjacent to these type variables.
ConnectedComponents cc(*this, typeVars);
return cc.getComponents();
}

View File

@@ -213,7 +213,7 @@ public:
TinyPtrVector<Constraint *> constraints;
/// Whether this component represents an orphaned constraint.
bool isOrphanedConstraint() const {
bool isOrphaned() const {
return typeVars.empty();
}
};