52
52
53
53
#include " swift/Basic/BlotSetVector.h"
54
54
#include " swift/SIL/SILFunction.h"
55
+ #include " swift/SIL/SILModule.h"
55
56
#include " swift/SILOptimizer/Analysis/Analysis.h"
56
57
#include " llvm/ADT/SmallSet.h"
57
58
#include " llvm/ADT/iterator.h"
@@ -80,40 +81,15 @@ inline bool isNonEscapingClosure(CanSILFunctionType funcTy) {
80
81
return llvm::any_of (funcTy->getParameters (), isInoutAliasable);
81
82
}
82
83
83
- class ClosureScopeData ;
84
+ class ClosureGraph ;
84
85
85
86
class 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 ;
111
88
112
- private:
113
89
SILModule *M;
114
90
115
91
// The analysis data. nullptr if it has never been computed.
116
- std::unique_ptr<ClosureScopeData> scopeData ;
92
+ std::unique_ptr<ClosureGraph> scopeGraph ;
117
93
118
94
public:
119
95
ClosureScopeAnalysis (SILModule *M);
@@ -125,13 +101,20 @@ class ClosureScopeAnalysis : public SILAnalysis {
125
101
126
102
SILModule *getModule () const { return M; }
127
103
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);
130
108
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
+ }
135
118
136
119
// / Invalidate all information in this analysis.
137
120
virtual void invalidate () override ;
@@ -159,25 +142,50 @@ class ClosureScopeAnalysis : public SILAnalysis {
159
142
}
160
143
161
144
protected:
162
- ClosureScopeData *getOrComputeScopeData ();
145
+ ClosureScopeAnalysis (const ClosureScopeAnalysis &) = delete ;
146
+ ClosureScopeAnalysis &operator =(const ClosureScopeAnalysis &) = delete ;
147
+
148
+ ClosureGraph *getOrComputeGraph ();
163
149
};
164
150
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;
169
158
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;
171
162
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;
173
168
174
169
public:
175
- TopDownClosureFunctionOrder (ClosureScopeAnalysis *CSA ) : CSA(CSA ) {}
170
+ ClosureFunctionOrder (ClosureScopeAnalysis *csa ) : csa(csa ) {}
176
171
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 ;
181
189
};
182
190
183
191
} // end namespace swift
0 commit comments