21
21
#include " swift/SIL/SILFunction.h"
22
22
#include " swift/SIL/SILInstruction.h"
23
23
#include " swift/SILOptimizer/PassManager/Transforms.h"
24
+ #include " swift/SILOptimizer/Utils/BasicBlockOptUtils.h"
25
+ #include " swift/SILOptimizer/Utils/ConstantFolding.h"
26
+ #include " swift/SILOptimizer/Utils/Devirtualize.h"
24
27
#include " swift/SILOptimizer/Utils/Generics.h"
25
28
#include " swift/SILOptimizer/Utils/InstOptUtils.h"
26
29
#include " swift/SILOptimizer/Utils/SILOptFunctionBuilder.h"
30
+ #include " swift/SILOptimizer/Utils/SILInliner.h"
27
31
#include " llvm/ADT/SmallVector.h"
28
32
29
33
using namespace swift ;
30
34
31
35
namespace {
32
36
33
- class GenericSpecializer : public SILFunctionTransform {
34
-
35
- bool specializeAppliesInFunction (SILFunction &F);
36
-
37
- // / The entry point to the transformation.
38
- void run () override {
39
- SILFunction &F = *getFunction ();
40
-
41
- LLVM_DEBUG (llvm::dbgs () << " ***** GenericSpecializer on function:"
42
- << F.getName () << " *****\n " );
43
-
44
- if (specializeAppliesInFunction (F))
45
- invalidateAnalysis (SILAnalysis::InvalidationKind::Everything);
46
- }
47
-
48
- };
49
-
50
- } // end anonymous namespace
51
-
52
- bool GenericSpecializer::specializeAppliesInFunction (SILFunction &F) {
53
- SILOptFunctionBuilder FunctionBuilder (*this );
37
+ static bool specializeAppliesInFunction (SILFunction &F,
38
+ SILTransform *transform,
39
+ bool isMandatory) {
40
+ SILOptFunctionBuilder FunctionBuilder (*transform);
54
41
DeadInstructionSet DeadApplies;
55
42
llvm::SmallSetVector<SILInstruction *, 8 > Applies;
56
43
OptRemark::Emitter ORE (DEBUG_TYPE, F);
@@ -97,14 +84,17 @@ bool GenericSpecializer::specializeAppliesInFunction(SILFunction &F) {
97
84
SILFunction *Callee = Apply.getReferencedFunctionOrNull ();
98
85
assert (Callee && " Expected to have a known callee" );
99
86
100
- if (!Apply.canOptimize () || !Callee->shouldOptimize ())
87
+ if (!Apply.canOptimize ())
88
+ continue ;
89
+
90
+ if (!isMandatory && !Callee->shouldOptimize ())
101
91
continue ;
102
92
103
93
// We have a call that can potentially be specialized, so
104
94
// attempt to do so.
105
95
llvm::SmallVector<SILFunction *, 2 > NewFunctions;
106
96
trySpecializeApplyOfGeneric (FunctionBuilder, Apply, DeadApplies,
107
- NewFunctions, ORE);
97
+ NewFunctions, ORE, isMandatory );
108
98
109
99
// Remove all the now-dead applies. We must do this immediately
110
100
// rather than defer it in order to avoid problems with cloning
@@ -120,18 +110,181 @@ bool GenericSpecializer::specializeAppliesInFunction(SILFunction &F) {
120
110
Changed = true ;
121
111
}
122
112
123
- // If calling the specialization utility resulted in new functions
124
- // (as opposed to returning a previous specialization), we need to notify
125
- // the pass manager so that the new functions get optimized.
126
- for (SILFunction *NewF : reverse (NewFunctions)) {
127
- addFunctionToPassManagerWorklist (NewF, Callee);
113
+ if (auto *sft = dyn_cast<SILFunctionTransform>(transform)) {
114
+ // If calling the specialization utility resulted in new functions
115
+ // (as opposed to returning a previous specialization), we need to notify
116
+ // the pass manager so that the new functions get optimized.
117
+ for (SILFunction *NewF : reverse (NewFunctions)) {
118
+ sft->addFunctionToPassManagerWorklist (NewF, Callee);
119
+ }
128
120
}
129
121
}
130
122
}
131
123
132
124
return Changed;
133
125
}
134
126
127
+ // / The generic specializer, used in the optimization pipeline.
128
+ class GenericSpecializer : public SILFunctionTransform {
129
+
130
+ // / The entry point to the transformation.
131
+ void run () override {
132
+ SILFunction &F = *getFunction ();
133
+
134
+ LLVM_DEBUG (llvm::dbgs () << " ***** GenericSpecializer on function:"
135
+ << F.getName () << " *****\n " );
136
+
137
+ if (specializeAppliesInFunction (F, this , /* isMandatory*/ false )) {
138
+ invalidateAnalysis (SILAnalysis::InvalidationKind::Everything);
139
+ }
140
+ }
141
+ };
142
+
143
+ // / The mandatory specializer, which runs in the mandatory pipeline.
144
+ // /
145
+ // / It specializes functions, called from performance-annotated functions
146
+ // / (@_noLocks, @_noAllocation).
147
+ class MandatoryGenericSpecializer : public SILModuleTransform {
148
+
149
+ void run () override ;
150
+
151
+ bool optimize (SILFunction *func, ClassHierarchyAnalysis *cha);
152
+
153
+ bool optimizeInst (SILInstruction *inst, SILOptFunctionBuilder &funcBuilder,
154
+ InstructionDeleter &deleter, ClassHierarchyAnalysis *cha);
155
+ };
156
+
157
+
158
+ void MandatoryGenericSpecializer::run () {
159
+ SILModule *module = getModule ();
160
+
161
+ if (!module->getOptions ().EnablePerformanceAnnotations )
162
+ return ;
163
+
164
+ ClassHierarchyAnalysis *cha = getAnalysis<ClassHierarchyAnalysis>();
165
+
166
+ llvm::SmallVector<SILFunction *, 8 > workList;
167
+ llvm::SmallPtrSet<SILFunction *, 16 > visited;
168
+
169
+ // Look for performance-annotated functions.
170
+ for (SILFunction &function : *module) {
171
+ if (function.getPerfConstraints () != PerformanceConstraints::None) {
172
+ workList.push_back (&function);
173
+ visited.insert (&function);
174
+ }
175
+ }
176
+
177
+ while (!workList.empty ()) {
178
+ SILFunction *func = workList.pop_back_val ();
179
+ module->linkFunction (func, SILModule::LinkingMode::LinkAll);
180
+ if (!func->isDefinition ())
181
+ continue ;
182
+
183
+ // Perform generic specialization and other related optimzations.
184
+ bool changed = optimize (func, cha);
185
+
186
+ if (changed)
187
+ invalidateAnalysis (func, SILAnalysis::InvalidationKind::Everything);
188
+
189
+ // Continue specializing called functions.
190
+ for (SILBasicBlock &block : *func) {
191
+ for (SILInstruction &inst : block) {
192
+ if (auto as = ApplySite::isa (&inst)) {
193
+ if (SILFunction *callee = as.getReferencedFunctionOrNull ()) {
194
+ if (visited.insert (callee).second )
195
+ workList.push_back (callee);
196
+ }
197
+ }
198
+ }
199
+ }
200
+ }
201
+ }
202
+
203
+ // / Specialize generic calls in \p func and do some other related optimizations:
204
+ // / devirtualization and constant-folding of the Builtin.canBeClass.
205
+ bool MandatoryGenericSpecializer::optimize (SILFunction *func,
206
+ ClassHierarchyAnalysis *cha) {
207
+ bool changed = false ;
208
+ SILOptFunctionBuilder funcBuilder (*this );
209
+ InstructionDeleter deleter;
210
+ ReachingReturnBlocks rrBlocks (func);
211
+ NonErrorHandlingBlocks neBlocks (func);
212
+
213
+ // If this is a just specialized function, try to optimize copy_addr, etc.
214
+ // instructions.
215
+ if (optimizeMemoryAccesses (*func)) {
216
+ eliminateDeadAllocations (*func);
217
+ changed = true ;
218
+ }
219
+
220
+ // Visiting blocks in reverse order avoids revisiting instructions after block
221
+ // splitting, which would be quadratic.
222
+ for (SILBasicBlock &block : llvm::reverse (*func)) {
223
+ // Only consider blocks which are not on a "throw" path.
224
+ if (!rrBlocks.reachesReturn (&block) || !neBlocks.isNonErrorHandling (&block))
225
+ continue ;
226
+
227
+ for (SILInstruction *inst : deleter.updatingReverseRange (&block)) {
228
+ changed |= optimizeInst (inst, funcBuilder, deleter, cha);
229
+ }
230
+ }
231
+ deleter.cleanupDeadInstructions ();
232
+
233
+ if (specializeAppliesInFunction (*func, this , /* isMandatory*/ true ))
234
+ changed = true ;
235
+
236
+ return changed;
237
+ }
238
+
239
+ bool MandatoryGenericSpecializer::
240
+ optimizeInst (SILInstruction *inst, SILOptFunctionBuilder &funcBuilder,
241
+ InstructionDeleter &deleter, ClassHierarchyAnalysis *cha) {
242
+ if (auto as = ApplySite::isa (inst)) {
243
+ // Specialization opens opportunities to devirtualize method calls.
244
+ ApplySite newAS = tryDevirtualizeApply (as, cha).first ;
245
+ if (!newAS)
246
+ return false ;
247
+ deleter.forceDelete (as.getInstruction ());
248
+ auto newFAS = FullApplySite::isa (newAS.getInstruction ());
249
+ if (!newFAS)
250
+ return true ;
251
+
252
+ SILFunction *callee = newFAS.getReferencedFunctionOrNull ();
253
+ if (!callee || callee->isTransparent () == IsNotTransparent)
254
+ return true ;
255
+
256
+ // If the de-virtualized callee is a transparent function, inline it.
257
+ SILInliner::inlineFullApply (newFAS, SILInliner::InlineKind::MandatoryInline,
258
+ funcBuilder, deleter);
259
+ return true ;
260
+ }
261
+ if (auto *bi = dyn_cast<BuiltinInst>(inst)) {
262
+ // Constant-fold the Builtin.canBeClass. This is essential for Array code.
263
+ if (bi->getBuiltinInfo ().ID != BuiltinValueKind::CanBeObjCClass)
264
+ return false ;
265
+
266
+ SILBuilderWithScope builder (bi);
267
+ IntegerLiteralInst *lit = optimizeBuiltinCanBeObjCClass (bi, builder);
268
+ if (!lit)
269
+ return false ;
270
+
271
+ bi->replaceAllUsesWith (lit);
272
+ ConstantFolder constFolder (funcBuilder, getOptions ().AssertConfig ,
273
+ /* EnableDiagnostics*/ false );
274
+ constFolder.addToWorklist (lit);
275
+ constFolder.processWorkList ();
276
+ deleter.forceDelete (bi);
277
+ return true ;
278
+ }
279
+ return false ;
280
+ }
281
+
282
+ } // end anonymous namespace
283
+
135
284
SILTransform *swift::createGenericSpecializer () {
136
285
return new GenericSpecializer ();
137
286
}
287
+
288
+ SILTransform *swift::createMandatoryGenericSpecializer () {
289
+ return new MandatoryGenericSpecializer ();
290
+ }
0 commit comments