Skip to content

Commit 60c1755

Browse files
committed
GSB: Generalize redundant requirement algorithm to record which requirement implied a redundant requirement
Recall the meaning of an explicit requirement here: - If the requirement is part of a root SCC, it is redundant unless it is the 'best' requirement from that root SCC. - If the requirement is part of a non-root SCC, it is always redundant. Instead of computing the set of redundant requirements, we build a mapping. The value in the mapping stores the set of root requirements that imply the given redundant requirement. This mapping is computed by traversing the graph from each root, recording which components can be reached from each root. For now, I'm using this to fix rdar://problem/65263302. After fixing that bug, this will also allow us to radically simplify the various callers of checkConstraintList().
1 parent adc3938 commit 60c1755

File tree

1 file changed

+99
-34
lines changed

1 file changed

+99
-34
lines changed

lib/AST/GenericSignatureBuilder.cpp

Lines changed: 99 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -616,6 +616,11 @@ class GenericSignatureBuilder::ExplicitRequirement {
616616

617617
return true;
618618
}
619+
620+
friend bool operator!=(const ExplicitRequirement &lhs,
621+
const ExplicitRequirement &rhs) {
622+
return !(lhs == rhs);
623+
}
619624
};
620625

621626
namespace llvm {
@@ -690,8 +695,13 @@ struct GenericSignatureBuilder::Implementation {
690695
/// Whether there were any errors.
691696
bool HadAnyError = false;
692697

693-
/// The set of computed redundant explicit requirements.
694-
llvm::DenseSet<ExplicitRequirement> RedundantRequirements;
698+
/// A mapping of redundant explicit requirements to the best root requirement
699+
/// that implies them.
700+
using RedundantRequirementMap =
701+
llvm::DenseMap<ExplicitRequirement,
702+
llvm::SmallDenseSet<ExplicitRequirement, 2>>;
703+
704+
RedundantRequirementMap RedundantRequirements;
695705

696706
#ifndef NDEBUG
697707
/// Whether we've already computed redundant requiremnts.
@@ -5624,8 +5634,8 @@ class RedundantRequirementGraph {
56245634

56255635
SmallVector<Vertex, 2> vertices;
56265636

5627-
ComponentID nextComponent = 0;
5628-
VertexID nextIndex = 0;
5637+
ComponentID componentCount = 0;
5638+
VertexID vertexCount = 0;
56295639

56305640
SmallVector<VertexID, 2> stack;
56315641

@@ -5784,11 +5794,11 @@ class RedundantRequirementGraph {
57845794
void strongConnect(VertexID v) {
57855795
// Set the depth index for v to the smallest unused index.
57865796
assert(vertices[v].index == Vertex::UndefinedIndex);
5787-
vertices[v].index = nextIndex;
5797+
vertices[v].index = vertexCount;
57885798
assert(vertices[v].lowLink == Vertex::UndefinedIndex);
5789-
vertices[v].lowLink = nextIndex;
5799+
vertices[v].lowLink = vertexCount;
57905800

5791-
nextIndex++;
5801+
vertexCount++;
57925802

57935803
stack.push_back(v);
57945804
assert(!vertices[v].onStack);
@@ -5826,40 +5836,60 @@ class RedundantRequirementGraph {
58265836
vertices[w].onStack = false;
58275837
assert(vertices[w].component == Vertex::UndefinedComponent);
58285838

5829-
vertices[w].component = nextComponent;
5839+
vertices[w].component = componentCount;
58305840
} while (v != w);
58315841

5832-
nextComponent++;
5842+
componentCount++;
58335843
}
58345844
}
58355845

58365846
public:
5847+
using RedundantRequirementMap =
5848+
llvm::DenseMap<ExplicitRequirement,
5849+
llvm::SmallDenseSet<ExplicitRequirement, 2>>;
5850+
58375851
void computeRedundantRequirements(SourceManager &SM,
5838-
llvm::DenseSet<ExplicitRequirement> &redundant) {
5852+
RedundantRequirementMap &redundant) {
58395853
// First, compute SCCs.
58405854
computeSCCs();
58415855

5842-
// The number of edges from other connected components to this one.
5843-
SmallVector<unsigned, 2> inboundComponentEdges;
5844-
inboundComponentEdges.resize(nextComponent);
5856+
// The set of edges pointing to each connected component.
5857+
SmallVector<SmallVector<ComponentID, 2>, 2> inboundComponentEdges;
5858+
inboundComponentEdges.resize(componentCount);
5859+
5860+
// The set of edges originating from this connected component.
5861+
SmallVector<SmallVector<ComponentID, 2>, 2> outboundComponentEdges;
5862+
outboundComponentEdges.resize(componentCount);
58455863

5846-
// Visit all vertices and count inter-component edges.
5864+
// Visit all vertices and build the adjacency sets for the connected
5865+
// component graph.
58475866
for (const auto &vertex : vertices) {
58485867
assert(vertex.component != Vertex::UndefinedComponent);
58495868
for (auto successor : vertex.successors) {
58505869
ComponentID otherComponent = vertices[successor].component;
5851-
if (vertex.component != otherComponent)
5852-
++inboundComponentEdges[otherComponent];
5870+
if (vertex.component != otherComponent) {
5871+
inboundComponentEdges[otherComponent].push_back(vertex.component);
5872+
outboundComponentEdges[vertex.component].push_back(otherComponent);
5873+
}
58535874
}
58545875
}
58555876

5856-
// The best explicit requirement for each root SCC.
5877+
auto isRootComponent = [&](ComponentID component) -> bool {
5878+
return inboundComponentEdges[component].empty();
5879+
};
5880+
5881+
// The set of root components.
5882+
llvm::SmallDenseSet<ComponentID, 2> rootComponents;
5883+
5884+
// The best explicit requirement for each root component.
58575885
SmallVector<Optional<ExplicitRequirement>, 2> bestExplicitReq;
5858-
bestExplicitReq.resize(nextComponent);
5886+
bestExplicitReq.resize(componentCount);
58595887

5860-
// Visit all vertices and find the best requirement for each root SCC.
5888+
// Visit all vertices and find the best requirement for each root component.
58615889
for (const auto &vertex : vertices) {
5862-
if (inboundComponentEdges[vertex.component] == 0) {
5890+
if (isRootComponent(vertex.component)) {
5891+
rootComponents.insert(vertex.component);
5892+
58635893
// If this vertex is part of a root SCC, see if the requirement is
58645894
// better than the one we have so far.
58655895
auto &best = bestExplicitReq[vertex.component];
@@ -5868,26 +5898,61 @@ class RedundantRequirementGraph {
58685898
}
58695899
}
58705900

5871-
// Compute the set of redundant requirements.
5872-
for (const auto &vertex : vertices) {
5873-
if (inboundComponentEdges[vertex.component] == 0) {
5874-
// We have a root SCC. This requirement is redundant unless
5875-
// it is the best requirement for this SCC.
5876-
auto best = bestExplicitReq[vertex.component];
5877-
assert(best.hasValue() &&
5878-
"Did not record best requirement for root SCC?");
5901+
// The set of root components that each component is reachable from.
5902+
SmallVector<llvm::SmallDenseSet<ComponentID, 2>, 2> reachableFromRoot;
5903+
reachableFromRoot.resize(componentCount);
58795904

5880-
if (vertex.req == *best)
5881-
continue;
5905+
// Traverse the graph of connected components starting from the roots.
5906+
for (auto rootComponent : rootComponents) {
5907+
SmallVector<ComponentID, 2> worklist;
5908+
5909+
auto addToWorklist = [&](ComponentID nextComponent) {
5910+
if (!reachableFromRoot[nextComponent].count(rootComponent))
5911+
worklist.push_back(nextComponent);
5912+
};
5913+
5914+
addToWorklist(rootComponent);
5915+
5916+
while (!worklist.empty()) {
5917+
auto component = worklist.back();
5918+
worklist.pop_back();
5919+
5920+
reachableFromRoot[component].insert(rootComponent);
5921+
5922+
for (auto nextComponent : outboundComponentEdges[component])
5923+
addToWorklist(nextComponent);
5924+
}
5925+
}
5926+
5927+
// Compute the mapping of redundant requirements to the best root
5928+
// requirement that implies them.
5929+
for (const auto &vertex : vertices) {
5930+
if (isRootComponent(vertex.component)) {
5931+
// A root component is reachable from itself, and itself only.
5932+
assert(reachableFromRoot[vertex.component].size() == 1);
5933+
assert(reachableFromRoot[vertex.component].count(vertex.component) == 1);
58825934
} else {
5883-
// We have a non-root SCC. This requirement is always
5884-
// redundant.
58855935
assert(!bestExplicitReq[vertex.component].hasValue() &&
58865936
"Recorded best requirement for non-root SCC?");
58875937
}
58885938

5889-
auto inserted = redundant.insert(vertex.req);
5890-
assert(inserted.second && "Saw the same vertex twice?");
5939+
// We have a non-root component. This requirement is always
5940+
// redundant.
5941+
auto reachableFromRootSet = reachableFromRoot[vertex.component];
5942+
assert(reachableFromRootSet.size() > 0);
5943+
5944+
for (auto rootComponent : reachableFromRootSet) {
5945+
assert(isRootComponent(rootComponent));
5946+
5947+
auto best = bestExplicitReq[rootComponent];
5948+
assert(best.hasValue() &&
5949+
"Did not record best requirement for root SCC?");
5950+
5951+
assert(vertex.req != *best || vertex.component == rootComponent);
5952+
if (vertex.req != *best) {
5953+
redundant[vertex.req].insert(*best);
5954+
}
5955+
}
58915956
}
58925957
}
58935958

0 commit comments

Comments
 (0)