5252
5353#include " swift/Basic/BlotSetVector.h"
5454#include " swift/SIL/SILFunction.h"
55+ #include " swift/SIL/SILModule.h"
5556#include " swift/SILOptimizer/Analysis/Analysis.h"
5657#include " llvm/ADT/SmallSet.h"
5758#include " llvm/ADT/iterator.h"
@@ -80,40 +81,15 @@ inline bool isNonEscapingClosure(CanSILFunctionType funcTy) {
8081 return llvm::any_of (funcTy->getParameters (), isInoutAliasable);
8182}
8283
83- class ClosureScopeData ;
84+ class ClosureGraph ;
8485
8586class ClosureScopeAnalysis : public SILAnalysis {
86- friend class ClosureScopeData ;
87-
88- // Get a closure's scope function from its index. This functor is compatible
89- // with OptionalTransformRange. Unfortunately it exposes the internals of the
90- // analysis data.
91- struct IndexLookupFunc {
92- // A reference to all closure parent scopes ordered by their index.
93- const std::vector<SILFunction *> &indexedScopes;
94-
95- IndexLookupFunc (const std::vector<SILFunction *> &indexedScopes)
96- : indexedScopes(indexedScopes) {}
97-
98- Optional<SILFunction *> operator ()(int idx) const {
99- if (auto funcPtr = indexedScopes[idx]) {
100- return funcPtr;
101- }
102- return None;
103- }
104- };
105- using IndexRange = iterator_range<int *>;
106-
107- public:
108- // A range of SILFunction scopes converted from their scope indices and
109- // filtered to remove any erased functions.
110- using ScopeRange = OptionalTransformRange<IndexRange, IndexLookupFunc, int *>;
87+ friend class ClosureGraph ;
11188
112- private:
11389 SILModule *M;
11490
11591 // The analysis data. nullptr if it has never been computed.
116- std::unique_ptr<ClosureScopeData> scopeData ;
92+ std::unique_ptr<ClosureGraph> scopeGraph ;
11793
11894public:
11995 ClosureScopeAnalysis (SILModule *M);
@@ -125,13 +101,20 @@ class ClosureScopeAnalysis : public SILAnalysis {
125101
126102 SILModule *getModule () const { return M; }
127103
128- // Return true if the given function is the parent scope for any closures.
129- bool isClosureScope (SILFunction *scopeFunc);
104+ // / Visit the parent scopes of \p closure if it has any. If \p visitor returns
105+ // / false, exit early and return false. Otherwise return true.
106+ bool visitClosureScopes (SILFunction *closure,
107+ std::function<bool (SILFunction *scopeFunc)> visitor);
130108
131- // Return a range of scopes for the given closure. The elements of the
132- // returned range have type `SILFunction *` and are non-null. Returns an
133- // empty range for a SILFunction that is not a closure or is a dead closure.
134- ScopeRange getClosureScopes (SILFunction *closureFunc);
109+ // / Visit the closures directly referenced by \p scopeFunc.
110+ bool visitClosures (SILFunction *scopeFunc,
111+ std::function<bool (SILFunction *closure)> visitor);
112+
113+ // / Return true if this function is a reachable closure.
114+ bool isReachableClosure (SILFunction *function) {
115+ // This visitor returns false immediately on the first scope.
116+ return !visitClosureScopes (function, [](SILFunction *) { return false ; });
117+ }
135118
136119 // / Invalidate all information in this analysis.
137120 virtual void invalidate () override ;
@@ -159,25 +142,50 @@ class ClosureScopeAnalysis : public SILAnalysis {
159142 }
160143
161144protected:
162- ClosureScopeData *getOrComputeScopeData ();
145+ ClosureScopeAnalysis (const ClosureScopeAnalysis &) = delete ;
146+ ClosureScopeAnalysis &operator =(const ClosureScopeAnalysis &) = delete ;
147+
148+ ClosureGraph *getOrComputeGraph ();
163149};
164150
165- // ClosureScopeAnalysis utility for visiting functions top down in closure scope
166- // order.
167- class TopDownClosureFunctionOrder {
168- ClosureScopeAnalysis *CSA;
151+ // ClosureScopeAnalysis utility for visiting functions top-down or bottom-up in
152+ // closure scope order.
153+ class ClosureFunctionOrder {
154+ class ClosureDFS ;
155+ friend class ClosureDFS ;
156+
157+ ClosureScopeAnalysis *csa;
169158
170- llvm::SmallSet<SILFunction *, 16 > visited;
159+ // All functions in this module in top-down order (RPO) following the closure
160+ // scope graph. Functions that define a closure occur before the closure.
161+ std::vector<SILFunction *> topDownFunctions;
171162
172- BlotSetVector<SILFunction *> closureWorklist;
163+ // If the closure scope graph has any cycles, record each function at the
164+ // head of a cycle. This does not include all the functions in the
165+ // strongly-connected component. This is extremely rare. It is always a local
166+ // function that refers to itself either directly or indirectly.
167+ SmallPtrSet<SILFunction *, 4 > closureCycleHeads;
173168
174169public:
175- TopDownClosureFunctionOrder (ClosureScopeAnalysis *CSA ) : CSA(CSA ) {}
170+ ClosureFunctionOrder (ClosureScopeAnalysis *csa ) : csa(csa ) {}
176171
177- // Visit all functions in a module, visiting each closure scope function
178- // before
179- // the closure function itself.
180- void visitFunctions (llvm::function_ref<void (SILFunction *)> visitor);
172+ void compute ();
173+
174+ ArrayRef<SILFunction *> getTopDownFunctions () const {
175+ assert (!topDownFunctions.empty ()
176+ || llvm::empty (csa->getModule ()->getFunctions ()));
177+ return topDownFunctions;
178+ }
179+
180+ bool isHeadOfClosureCycle (SILFunction *function) const {
181+ return closureCycleHeads.contains (function);
182+ }
183+
184+ SWIFT_ASSERT_ONLY_DECL (void dump ());
185+
186+ protected:
187+ ClosureFunctionOrder (const ClosureFunctionOrder &) = delete;
188+ ClosureFunctionOrder &operator =(const ClosureFunctionOrder &) = delete ;
181189};
182190
183191} // end namespace swift
0 commit comments