@@ -616,6 +616,11 @@ class GenericSignatureBuilder::ExplicitRequirement {
616
616
617
617
return true ;
618
618
}
619
+
620
+ friend bool operator !=(const ExplicitRequirement &lhs,
621
+ const ExplicitRequirement &rhs) {
622
+ return !(lhs == rhs);
623
+ }
619
624
};
620
625
621
626
namespace llvm {
@@ -690,8 +695,13 @@ struct GenericSignatureBuilder::Implementation {
690
695
// / Whether there were any errors.
691
696
bool HadAnyError = false ;
692
697
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;
695
705
696
706
#ifndef NDEBUG
697
707
// / Whether we've already computed redundant requiremnts.
@@ -5624,8 +5634,8 @@ class RedundantRequirementGraph {
5624
5634
5625
5635
SmallVector<Vertex, 2 > vertices;
5626
5636
5627
- ComponentID nextComponent = 0 ;
5628
- VertexID nextIndex = 0 ;
5637
+ ComponentID componentCount = 0 ;
5638
+ VertexID vertexCount = 0 ;
5629
5639
5630
5640
SmallVector<VertexID, 2 > stack;
5631
5641
@@ -5784,11 +5794,11 @@ class RedundantRequirementGraph {
5784
5794
void strongConnect (VertexID v) {
5785
5795
// Set the depth index for v to the smallest unused index.
5786
5796
assert (vertices[v].index == Vertex::UndefinedIndex);
5787
- vertices[v].index = nextIndex ;
5797
+ vertices[v].index = vertexCount ;
5788
5798
assert (vertices[v].lowLink == Vertex::UndefinedIndex);
5789
- vertices[v].lowLink = nextIndex ;
5799
+ vertices[v].lowLink = vertexCount ;
5790
5800
5791
- nextIndex ++;
5801
+ vertexCount ++;
5792
5802
5793
5803
stack.push_back (v);
5794
5804
assert (!vertices[v].onStack );
@@ -5826,40 +5836,60 @@ class RedundantRequirementGraph {
5826
5836
vertices[w].onStack = false ;
5827
5837
assert (vertices[w].component == Vertex::UndefinedComponent);
5828
5838
5829
- vertices[w].component = nextComponent ;
5839
+ vertices[w].component = componentCount ;
5830
5840
} while (v != w);
5831
5841
5832
- nextComponent ++;
5842
+ componentCount ++;
5833
5843
}
5834
5844
}
5835
5845
5836
5846
public:
5847
+ using RedundantRequirementMap =
5848
+ llvm::DenseMap<ExplicitRequirement,
5849
+ llvm::SmallDenseSet<ExplicitRequirement, 2 >>;
5850
+
5837
5851
void computeRedundantRequirements (SourceManager &SM,
5838
- llvm::DenseSet<ExplicitRequirement> &redundant) {
5852
+ RedundantRequirementMap &redundant) {
5839
5853
// First, compute SCCs.
5840
5854
computeSCCs ();
5841
5855
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);
5845
5863
5846
- // Visit all vertices and count inter-component edges.
5864
+ // Visit all vertices and build the adjacency sets for the connected
5865
+ // component graph.
5847
5866
for (const auto &vertex : vertices) {
5848
5867
assert (vertex.component != Vertex::UndefinedComponent);
5849
5868
for (auto successor : vertex.successors ) {
5850
5869
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
+ }
5853
5874
}
5854
5875
}
5855
5876
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.
5857
5885
SmallVector<Optional<ExplicitRequirement>, 2 > bestExplicitReq;
5858
- bestExplicitReq.resize (nextComponent );
5886
+ bestExplicitReq.resize (componentCount );
5859
5887
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 .
5861
5889
for (const auto &vertex : vertices) {
5862
- if (inboundComponentEdges[vertex.component ] == 0 ) {
5890
+ if (isRootComponent (vertex.component )) {
5891
+ rootComponents.insert (vertex.component );
5892
+
5863
5893
// If this vertex is part of a root SCC, see if the requirement is
5864
5894
// better than the one we have so far.
5865
5895
auto &best = bestExplicitReq[vertex.component ];
@@ -5868,26 +5898,61 @@ class RedundantRequirementGraph {
5868
5898
}
5869
5899
}
5870
5900
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);
5879
5904
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 );
5882
5934
} else {
5883
- // We have a non-root SCC. This requirement is always
5884
- // redundant.
5885
5935
assert (!bestExplicitReq[vertex.component ].hasValue () &&
5886
5936
" Recorded best requirement for non-root SCC?" );
5887
5937
}
5888
5938
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
+ }
5891
5956
}
5892
5957
}
5893
5958
0 commit comments