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,16 @@ 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
+ // / If a generic specialization was performed for a generic capture,
347
+ // / GenericSpecialized contains a tuple:
348
+ // / (new specialized function, old function)
349
+ static SILFunction *getSpecializedWithDeadParams (
350
+ PartialApplyInst *PAI, SILFunction *Orig, int numDeadParams,
351
+ std::pair<SILFunction *, SILFunction *> &GenericSpecialized) {
316
352
SILBasicBlock &EntryBB = *Orig->begin ();
317
353
unsigned NumArgs = EntryBB.getNumArguments ();
318
354
SILModule &M = Orig->getModule ();
319
-
355
+
320
356
// Check if all dead parameters have trivial types. We don't support non-
321
357
// trivial types because it's very hard to find places where we can release
322
358
// those parameters (as a replacement for the removed partial_apply).
@@ -328,20 +364,20 @@ static SILFunction *getSpecializedWithDeadParams(SILFunction *Orig,
328
364
}
329
365
SILFunction *Specialized = nullptr ;
330
366
SILValue RetValue;
331
-
367
+
332
368
// Check all instruction of the entry block.
333
369
for (SILInstruction &I : EntryBB) {
334
370
if (auto FAS = FullApplySite::isa (&I)) {
335
-
336
371
// 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 ())
372
+ // If the original partial_apply didn't have substitutions,
373
+ // also the specialized function must be not generic.
374
+ if (!PAI-> hasSubstitutions () && FAS.hasSubstitutions ())
340
375
return nullptr ;
376
+
341
377
// Is it the only call?
342
378
if (Specialized)
343
379
return nullptr ;
344
-
380
+
345
381
Specialized = FAS.getReferencedFunction ();
346
382
if (!Specialized)
347
383
return nullptr ;
@@ -376,29 +412,54 @@ static SILFunction *getSpecializedWithDeadParams(SILFunction *Orig,
376
412
if (I.mayHaveSideEffects () || isa<TermInst>(&I))
377
413
return nullptr ;
378
414
}
415
+
416
+ GenericSpecialized = std::make_pair (nullptr , nullptr );
417
+
418
+ if (PAI->hasSubstitutions ()) {
419
+ if (Specialized->isExternalDeclaration ())
420
+ return nullptr ;
421
+ // Perform a generic specialization of the Specialized function.
422
+ ReabstractionInfo ReInfo (ApplySite (), Specialized, PAI->getSubstitutions (),
423
+ /* ConvertIndirectToDirect */ false );
424
+ GenericFuncSpecializer FuncSpecializer (Specialized,
425
+ ReInfo.getClonerParamSubstitutions (),
426
+ Specialized->isFragile (), ReInfo);
427
+
428
+ SILFunction *GenericSpecializedFunc = FuncSpecializer.trySpecialization ();
429
+ if (!GenericSpecializedFunc)
430
+ return nullptr ;
431
+ GenericSpecialized = std::make_pair (GenericSpecializedFunc, Specialized);
432
+ return GenericSpecializedFunc;
433
+ }
379
434
return Specialized;
380
435
}
381
436
382
437
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
438
SILFunction *SubstF = PAI->getReferencedFunction ();
389
439
if (!SubstF)
390
440
return false ;
391
441
if (SubstF->isExternalDeclaration ())
392
442
return false ;
393
443
394
- assert (!SubstF->getLoweredFunctionType ()->isPolymorphic () &&
395
- " cannot specialize generic partial apply" );
444
+ if (PAI->hasSubstitutions () && hasArchetypes (PAI->getSubstitutions ())) {
445
+ DEBUG (llvm::dbgs ()
446
+ << " CapturePropagation: cannot handle partial specialization "
447
+ " of partial_apply:\n " ;
448
+ PAI->dumpInContext ());
449
+ return false ;
450
+ }
451
+
396
452
397
453
// First possibility: Is it a partial_apply where all partially applied
398
454
// arguments are dead?
399
- if (SILFunction *NewFunc = getSpecializedWithDeadParams (SubstF,
400
- PAI->getNumArguments ())) {
455
+ std::pair<SILFunction *, SILFunction *> GenericSpecialized;
456
+ if (auto *NewFunc = getSpecializedWithDeadParams (
457
+ PAI, SubstF, PAI->getNumArguments (), GenericSpecialized)) {
401
458
rewritePartialApply (PAI, NewFunc);
459
+ if (GenericSpecialized.first ) {
460
+ // Notify the pass manager about the new function.
461
+ notifyAddFunction (GenericSpecialized.first , GenericSpecialized.second );
462
+ }
402
463
return true ;
403
464
}
404
465
@@ -411,7 +472,8 @@ bool CapturePropagation::optimizePartialApply(PartialApplyInst *PAI) {
411
472
return false ;
412
473
413
474
DEBUG (llvm::dbgs () << " Specializing closure for constant arguments:\n "
414
- << " " << SubstF->getName () << " \n " << *PAI);
475
+ << " " << SubstF->getName () << " \n "
476
+ << *PAI);
415
477
++NumCapturesPropagated;
416
478
SILFunction *NewF = specializeConstClosure (PAI, SubstF);
417
479
rewritePartialApply (PAI, NewF);
0 commit comments