11
11
// ===----------------------------------------------------------------------===//
12
12
13
13
#define DEBUG_TYPE " capture-prop"
14
+ #include " swift/AST/GenericEnvironment.h"
14
15
#include " swift/SILOptimizer/PassManager/Passes.h"
16
+ #include " swift/SILOptimizer/Utils/Generics.h"
15
17
#include " swift/SILOptimizer/Utils/SpecializationMangler.h"
16
18
#include " swift/Demangling/Demangle.h"
17
19
#include " swift/SIL/Mangle.h"
18
20
#include " swift/SIL/SILCloner.h"
19
21
#include " swift/SIL/SILInstruction.h"
22
+ #include " swift/SIL/TypeSubstCloner.h"
20
23
#include " swift/SILOptimizer/Analysis/ColdBlockInfo.h"
21
24
#include " swift/SILOptimizer/Analysis/DominanceAnalysis.h"
22
25
#include " swift/SILOptimizer/PassManager/Transforms.h"
@@ -99,16 +102,17 @@ namespace {
99
102
// / caller, so the cloned function will have a mix of locations from different
100
103
// / functions.
101
104
class CapturePropagationCloner
102
- : public SILClonerWithScopes <CapturePropagationCloner> {
103
- using SuperTy = SILClonerWithScopes <CapturePropagationCloner>;
105
+ : public TypeSubstCloner <CapturePropagationCloner> {
106
+ using SuperTy = TypeSubstCloner <CapturePropagationCloner>;
104
107
friend class SILVisitor <CapturePropagationCloner>;
105
108
friend class SILCloner <CapturePropagationCloner>;
106
109
107
110
SILFunction *OrigF;
108
111
bool IsCloningConstant;
109
112
public:
110
- CapturePropagationCloner (SILFunction *OrigF, SILFunction *NewF)
111
- : SuperTy(*NewF), OrigF(OrigF), IsCloningConstant(false ) {}
113
+ CapturePropagationCloner (SILFunction *OrigF, SILFunction *NewF,
114
+ SubstitutionList Subs)
115
+ : SuperTy(*NewF, *OrigF, Subs), OrigF(OrigF), IsCloningConstant(false ) {}
112
116
113
117
void cloneBlocks (OperandValueArrayRef Args);
114
118
@@ -219,6 +223,20 @@ void CapturePropagationCloner::cloneBlocks(
219
223
}
220
224
}
221
225
226
+ CanSILFunctionType getPartialApplyInterfaceResultType (PartialApplyInst *PAI) {
227
+ SILFunction *OrigF = PAI->getReferencedFunction ();
228
+ // The new partial_apply will no longer take any arguments--they are all
229
+ // expressed as literals. So its callee signature will be the same as its
230
+ // return signature.
231
+ auto FTy = PAI->getType ().castTo <SILFunctionType>();
232
+ CanGenericSignature CanGenericSig;
233
+ assert (!PAI->hasSubstitutions () || !hasArchetypes (PAI->getSubstitutions ()));
234
+ FTy = cast<SILFunctionType>(
235
+ OrigF->mapTypeOutOfContext (FTy)->getCanonicalType ());
236
+ auto NewFTy = FTy;
237
+ return NewFTy;
238
+ }
239
+
222
240
// / Given a partial_apply instruction, create a specialized callee by removing
223
241
// / all constant arguments and adding constant literals to the specialized
224
242
// / function body.
@@ -243,12 +261,16 @@ SILFunction *CapturePropagation::specializeConstClosure(PartialApplyInst *PAI,
243
261
// The new partial_apply will no longer take any arguments--they are all
244
262
// expressed as literals. So its callee signature will be the same as its
245
263
// return signature.
246
- CanSILFunctionType NewFTy =
247
- Lowering::adjustFunctionType (PAI->getType ().castTo <SILFunctionType>(),
248
- SILFunctionType::Representation::Thin);
264
+ auto NewFTy = getPartialApplyInterfaceResultType (PAI);
265
+ NewFTy = Lowering::adjustFunctionType (NewFTy,
266
+ SILFunctionType::Representation::Thin);
267
+
268
+ GenericEnvironment *GenericEnv = nullptr ;
269
+ if (NewFTy->getGenericSignature ())
270
+ GenericEnv = OrigF->getGenericEnvironment ();
249
271
SILFunction *NewF = OrigF->getModule ().createFunction (
250
272
SILLinkage::Shared, Name, NewFTy,
251
- OrigF-> getGenericEnvironment () , OrigF->getLocation (), OrigF->isBare (),
273
+ GenericEnv , OrigF->getLocation (), OrigF->isBare (),
252
274
OrigF->isTransparent (), Fragile, OrigF->isThunk (),
253
275
OrigF->getClassVisibility (), OrigF->getInlineStrategy (),
254
276
OrigF->getEffectsKind (),
@@ -259,18 +281,28 @@ SILFunction *CapturePropagation::specializeConstClosure(PartialApplyInst *PAI,
259
281
DEBUG (llvm::dbgs () << " Specialize callee as " ;
260
282
NewF->printName (llvm::dbgs ()); llvm::dbgs () << " " << NewFTy << " \n " );
261
283
262
- CapturePropagationCloner cloner (OrigF, NewF);
284
+ DEBUG (if (PAI->hasSubstitutions ()) {
285
+ llvm::dbgs () << " CapturePropagation of generic partial_apply:\n " ;
286
+ PAI->dumpInContext ();
287
+ });
288
+ CapturePropagationCloner cloner (OrigF, NewF, PAI->getSubstitutions ());
263
289
cloner.cloneBlocks (PAI->getArguments ());
264
290
assert (OrigF->getDebugScope ()->Parent != NewF->getDebugScope ()->Parent );
265
291
return NewF;
266
292
}
267
293
268
294
void CapturePropagation::rewritePartialApply (PartialApplyInst *OrigPAI,
269
295
SILFunction *SpecialF) {
296
+ DEBUG (llvm::dbgs () << " \n Rewriting a partial apply:\n " ;
297
+ OrigPAI->dumpInContext (); llvm::dbgs () << " with special function: "
298
+ << SpecialF->getName () << " \n " ;
299
+ llvm::dbgs () << " \n The function being rewritten is:\n " ;
300
+ OrigPAI->getFunction ()->dump ());
301
+
270
302
SILBuilderWithScope Builder (OrigPAI);
271
303
auto FuncRef = Builder.createFunctionRef (OrigPAI->getLoc (), SpecialF);
272
- auto *T2TF = Builder.createThinToThickFunction (OrigPAI->getLoc (),
273
- FuncRef, OrigPAI->getType ());
304
+ auto *T2TF = Builder.createThinToThickFunction (OrigPAI->getLoc (), FuncRef,
305
+ OrigPAI->getType ());
274
306
OrigPAI->replaceAllUsesWith (T2TF);
275
307
recursivelyDeleteTriviallyDeadInstructions (OrigPAI, true );
276
308
DEBUG (llvm::dbgs () << " Rewrote caller:\n " << *T2TF);
@@ -311,12 +343,13 @@ static bool onlyContainsReturnOrThrowOfArg(SILBasicBlock *BB) {
311
343
312
344
// / Checks if \p Orig is a thunk which calls another function but without
313
345
// / passing the trailing \p numDeadParams dead parameters.
314
- static SILFunction *getSpecializedWithDeadParams (SILFunction *Orig,
315
- int numDeadParams) {
346
+ static SILFunction *getSpecializedWithDeadParams (
347
+ PartialApplyInst *PAI, SILFunction *Orig, int numDeadParams,
348
+ std::pair<SILFunction *, SILFunction *> &GenericSpecialized) {
316
349
SILBasicBlock &EntryBB = *Orig->begin ();
317
350
unsigned NumArgs = EntryBB.getNumArguments ();
318
351
SILModule &M = Orig->getModule ();
319
-
352
+
320
353
// Check if all dead parameters have trivial types. We don't support non-
321
354
// trivial types because it's very hard to find places where we can release
322
355
// those parameters (as a replacement for the removed partial_apply).
@@ -328,20 +361,20 @@ static SILFunction *getSpecializedWithDeadParams(SILFunction *Orig,
328
361
}
329
362
SILFunction *Specialized = nullptr ;
330
363
SILValue RetValue;
331
-
364
+
332
365
// Check all instruction of the entry block.
333
366
for (SILInstruction &I : EntryBB) {
334
367
if (auto FAS = FullApplySite::isa (&I)) {
335
-
336
368
// Check if this is the call of the specialized function.
337
- // As the original function is not generic, also the specialized function
338
- // must be not generic.
339
- if (FAS.hasSubstitutions ())
369
+ // If the original partial_apply didn't have substitutions,
370
+ // also the specialized function must be not generic.
371
+ if (!PAI-> hasSubstitutions () && FAS.hasSubstitutions ())
340
372
return nullptr ;
373
+
341
374
// Is it the only call?
342
375
if (Specialized)
343
376
return nullptr ;
344
-
377
+
345
378
Specialized = FAS.getReferencedFunction ();
346
379
if (!Specialized)
347
380
return nullptr ;
@@ -376,29 +409,55 @@ static SILFunction *getSpecializedWithDeadParams(SILFunction *Orig,
376
409
if (I.mayHaveSideEffects () || isa<TermInst>(&I))
377
410
return nullptr ;
378
411
}
412
+
413
+ GenericSpecialized = std::make_pair (nullptr , nullptr );
414
+
415
+ if (PAI->hasSubstitutions ()) {
416
+ if (Specialized->isExternalDeclaration ())
417
+ return nullptr ;
418
+ // Perform a generic specialization of the Specialized function.
419
+ ReabstractionInfo ReInfo (ApplySite (), Specialized, PAI->getSubstitutions (),
420
+ /* ConvertIndirectToDirect */ false );
421
+ GenericFuncSpecializer FuncSpecializer (Specialized,
422
+ ReInfo.getClonerParamSubstitutions (),
423
+ Specialized->isFragile (), ReInfo);
424
+
425
+ SILFunction *GenericSpecializedFunc = FuncSpecializer.trySpecialization ();
426
+ if (!GenericSpecializedFunc)
427
+ return nullptr ;
428
+ GenericSpecialized = std::make_pair (GenericSpecializedFunc, Specialized);
429
+ return GenericSpecializedFunc;
430
+ }
379
431
return Specialized;
380
432
}
381
433
382
434
bool CapturePropagation::optimizePartialApply (PartialApplyInst *PAI) {
383
- // Check if the partial_apply has generic substitutions.
384
- // FIXME: We could handle generic thunks if it's worthwhile.
385
- if (PAI->hasSubstitutions ())
386
- return false ;
387
-
388
435
SILFunction *SubstF = PAI->getReferencedFunction ();
389
436
if (!SubstF)
390
437
return false ;
391
438
if (SubstF->isExternalDeclaration ())
392
439
return false ;
393
440
394
- assert (!SubstF->getLoweredFunctionType ()->isPolymorphic () &&
395
- " cannot specialize generic partial apply" );
441
+ if (PAI->hasSubstitutions () && hasArchetypes (PAI->getSubstitutions ())) {
442
+ DEBUG (llvm::dbgs ()
443
+ << " CapturePropagation: cannot handle partial specialization "
444
+ " of partial_apply:\n " ;
445
+ PAI->dumpInContext ());
446
+ return false ;
447
+ }
448
+
396
449
397
450
// First possibility: Is it a partial_apply where all partially applied
398
451
// arguments are dead?
399
- if (SILFunction *NewFunc = getSpecializedWithDeadParams (SubstF,
400
- PAI->getNumArguments ())) {
452
+ std::pair<SILFunction *, SILFunction *> GenericSpecialized;
453
+ if (auto *NewFunc = getSpecializedWithDeadParams (
454
+ PAI, SubstF, PAI->getNumArguments (), GenericSpecialized)) {
401
455
rewritePartialApply (PAI, NewFunc);
456
+ if (GenericSpecialized.first ) {
457
+ // Notify the pass manager about the new function.
458
+ notifyPassManagerOfFunction (GenericSpecialized.first ,
459
+ GenericSpecialized.second );
460
+ }
402
461
return true ;
403
462
}
404
463
@@ -411,7 +470,8 @@ bool CapturePropagation::optimizePartialApply(PartialApplyInst *PAI) {
411
470
return false ;
412
471
413
472
DEBUG (llvm::dbgs () << " Specializing closure for constant arguments:\n "
414
- << " " << SubstF->getName () << " \n " << *PAI);
473
+ << " " << SubstF->getName () << " \n "
474
+ << *PAI);
415
475
++NumCapturesPropagated;
416
476
SILFunction *NewF = specializeConstClosure (PAI, SubstF);
417
477
rewritePartialApply (PAI, NewF);
0 commit comments