Skip to content

Commit

Permalink
[Constraint graph] Make connected components more self-contained.
Browse files Browse the repository at this point in the history
Have the constraint graph's connected-component implementation be more
self-contained, producing a vector containing each of the actual
components (where each is defined by a list of type variables and a list
of constraints). This simplifies the contract with the client
(SplitterStep) and eliminates a bunch of separate mapping steps to
interpret the results.

It also lets us enrich the Component data structure in the future.
  • Loading branch information
DougGregor committed Aug 7, 2019
1 parent 805b02d commit 4c04ced
Show file tree
Hide file tree
Showing 5 changed files with 214 additions and 178 deletions.
75 changes: 15 additions & 60 deletions lib/Sema/CSStep.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,25 +96,31 @@ void SplitterStep::computeFollowupSteps(
CG.optimize();

// Compute the connected components of the constraint graph.
// FIXME: We're seeding typeVars with TypeVariables so that the
// connected-components algorithm only considers those type variables within
// our component. There are clearly better ways to do this.
std::vector<TypeVariableType *> typeVars(CS.TypeVariables);
std::vector<unsigned> components;
unsigned numComponents = CG.computeConnectedComponents(typeVars, components);
auto components = CG.computeConnectedComponents(CS.TypeVariables);
unsigned numComponents =
components.size() + CG.getOrphanedConstraints().size();
if (numComponents < 2) {
componentSteps.push_back(llvm::make_unique<ComponentStep>(
CS, 0, /*single=*/true, &CS.InactiveConstraints, Solutions));
CS, 0, &CS.InactiveConstraints, Solutions));
return;
}

Components.resize(numComponents);
PartialSolutions = std::unique_ptr<SmallVector<Solution, 4>[]>(
new SmallVector<Solution, 4>[numComponents]);

for (unsigned i = 0, n = numComponents; i != n; ++i) {
// Add components.
for (unsigned i : indices(components)) {
componentSteps.push_back(llvm::make_unique<ComponentStep>(
CS, i, /*single=*/false, &Components[i], PartialSolutions[i]));
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()) {
Expand All @@ -129,57 +135,6 @@ void SplitterStep::computeFollowupSteps(
CG.printConnectedComponents(CS.TypeVariables, log);
}

// Map type variables and constraints into appropriate steps.
llvm::DenseMap<TypeVariableType *, unsigned> typeVarComponent;
llvm::DenseMap<Constraint *, unsigned> constraintComponent;
for (unsigned i = 0, n = typeVars.size(); i != n; ++i) {
auto *typeVar = typeVars[i];
// Record the component of this type variable.
typeVarComponent[typeVar] = components[i];

for (auto *constraint : CG[typeVar].getConstraints())
constraintComponent[constraint] = components[i];
}

// Add the orphaned components to the mapping from constraints to components.
unsigned firstOrphanedComponent =
numComponents - CG.getOrphanedConstraints().size();
{
unsigned component = firstOrphanedComponent;
for (auto *constraint : CG.getOrphanedConstraints()) {
// Register this orphan constraint both as associated with
// a given component as a regular constrant, as well as an
// "orphan" constraint, so it can be proccessed correctly.
constraintComponent[constraint] = component;
componentSteps[component]->recordOrphan(constraint);
++component;
}
}

for (auto *typeVar : CS.TypeVariables) {
auto known = typeVarComponent.find(typeVar);
// If current type variable is associated with
// a certain component step, record it as being so.
if (known != typeVarComponent.end()) {
componentSteps[known->second]->record(typeVar);
continue;
}
}

// Transfer all of the constraints from the work list to
// the appropriate component.
auto &workList = CS.InactiveConstraints;
while (!workList.empty()) {
auto *constraint = &workList.front();
workList.pop_front();
assert(constraintComponent.count(constraint) > 0 && "Missed a constraint");
componentSteps[constraintComponent[constraint]]->record(constraint);
}

// Remove all of the orphaned constraints; they'll be re-introduced
// by each component independently.
OrphanedConstraints = CG.takeOrphanedConstraints();

// 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
Expand Down
45 changes: 34 additions & 11 deletions lib/Sema/CSStep.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#define SWIFT_SEMA_CSSTEP_H

#include "Constraint.h"
#include "ConstraintGraph.h"
#include "ConstraintSystem.h"
#include "swift/AST/Types.h"
#include "llvm/ADT/ArrayRef.h"
Expand Down Expand Up @@ -336,7 +337,7 @@ class ComponentStep final : public SolverStep {
std::unique_ptr<Scope> ComponentScope = nullptr;

/// Type variables and constraints "in scope" of this step.
std::vector<TypeVariableType *> TypeVars;
TinyPtrVector<TypeVariableType *> TypeVars;
/// Constraints "in scope" of this step.
ConstraintList *Constraints;

Expand All @@ -349,29 +350,51 @@ class ComponentStep final : public SolverStep {
Constraint *OrphanedConstraint = nullptr;

public:
ComponentStep(ConstraintSystem &cs, unsigned index, bool single,
/// Create a single component step.
ComponentStep(ConstraintSystem &cs, unsigned index,
ConstraintList *constraints,
SmallVectorImpl<Solution> &solutions)
: SolverStep(cs, solutions), Index(index), IsSingle(single),
: SolverStep(cs, solutions), Index(index), IsSingle(true),
OriginalScore(getCurrentScore()), OriginalBestScore(getBestScore()),
Constraints(constraints) {}

/// Record a type variable as associated with this step.
void record(TypeVariableType *typeVar) { TypeVars.push_back(typeVar); }
/// Create a component step from a constraint graph component.
ComponentStep(ConstraintSystem &cs, unsigned index,
ConstraintList *constraints,
ConstraintGraph::Component &&component,
SmallVectorImpl<Solution> &solutions)
: SolverStep(cs, solutions), Index(index), IsSingle(false),
OriginalScore(getCurrentScore()), OriginalBestScore(getBestScore()),
Constraints(constraints) {
TypeVars = std::move(component.typeVars);

for (auto constraint : component.constraints) {
constraints->erase(constraint);
record(constraint);
}
}

/// 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) {
Constraints->push_back(constraint);
if (constraint->getKind() == ConstraintKind::Disjunction)
++NumDisjunctions;
}

/// Record a constraint as associated with this step but which doesn't
/// have any free type variables associated with it.
void recordOrphan(Constraint *constraint) {
assert(!OrphanedConstraint);
OrphanedConstraint = constraint;
}
public:

StepResult take(bool prevFailed) override;

Expand Down
Loading

0 comments on commit 4c04ced

Please sign in to comment.