@@ -247,6 +247,11 @@ SILValue swift::stripBorrow(SILValue V) {
247
247
return V;
248
248
}
249
249
250
+ // All instructions handled here must propagate their first operand into their
251
+ // single result.
252
+ //
253
+ // This is guaranteed to handle all function-type converstions: ThinToThick,
254
+ // ConvertFunction, and ConvertEscapeToNoEscapeInst.
250
255
SingleValueInstruction *swift::getSingleValueCopyOrCast (SILInstruction *I) {
251
256
if (auto *convert = dyn_cast<ConversionInst>(I))
252
257
return convert;
@@ -259,6 +264,7 @@ SingleValueInstruction *swift::getSingleValueCopyOrCast(SILInstruction *I) {
259
264
case SILInstructionKind::CopyBlockWithoutEscapingInst:
260
265
case SILInstructionKind::BeginBorrowInst:
261
266
case SILInstructionKind::BeginAccessInst:
267
+ case SILInstructionKind::MarkDependenceInst:
262
268
return cast<SingleValueInstruction>(I);
263
269
}
264
270
}
@@ -353,9 +359,12 @@ SILValue swift::isPartialApplyOfReabstractionThunk(PartialApplyInst *PAI) {
353
359
return Arg;
354
360
}
355
361
356
- // / Given a block used as a noescape function argument, attempt to find
357
- // / the Swift closure that invoking the block will call.
362
+ // / Given a block used as a noescape function argument, attempt to find all
363
+ // / Swift closures that invoking the block will call. The StoredClosures may not
364
+ // / actually be partial_apply instructions. They may be copied, block arguments,
365
+ // / or conversions. The caller must continue searching up the use-def chain.
358
366
static SILValue findClosureStoredIntoBlock (SILValue V) {
367
+
359
368
auto FnType = V->getType ().castTo <SILFunctionType>();
360
369
assert (FnType->getRepresentation () == SILFunctionTypeRepresentation::Block);
361
370
(void )FnType;
@@ -374,24 +383,7 @@ static SILValue findClosureStoredIntoBlock(SILValue V) {
374
383
// %block = init_block_storage_header %storage invoke %thunk
375
384
// %arg = copy_block %block
376
385
377
- InitBlockStorageHeaderInst *IBSHI = nullptr ;
378
-
379
- // Look through block copies to find the initialization of block storage.
380
- while (true ) {
381
- if (auto *CBI = dyn_cast<CopyBlockInst>(V)) {
382
- V = CBI->getOperand ();
383
- continue ;
384
- }
385
-
386
- if (auto *CBI = dyn_cast<CopyBlockWithoutEscapingInst>(V)) {
387
- V = CBI->getBlock ();
388
- continue ;
389
- }
390
-
391
- IBSHI = dyn_cast<InitBlockStorageHeaderInst>(V);
392
- break ;
393
- }
394
-
386
+ InitBlockStorageHeaderInst *IBSHI = dyn_cast<InitBlockStorageHeaderInst>(V);
395
387
if (!IBSHI)
396
388
return nullptr ;
397
389
@@ -414,45 +406,93 @@ static SILValue findClosureStoredIntoBlock(SILValue V) {
414
406
auto NoEscapeClosure = isPartialApplyOfReabstractionThunk (Sentinel);
415
407
if (WrappedNoEscape->getBase () != NoEscapeClosure)
416
408
return nullptr ;
409
+
410
+ // This is the value of the closure to be invoked. To find the partial_apply
411
+ // itself, the caller must search the use-def chain.
417
412
return NoEscapeClosure;
418
413
}
419
414
420
- // / Look through a value passed as a function argument to determine whether
421
- // / it is a closure.
415
+ // / Find all closures that may be propagated into the given function-type value.
422
416
// /
423
- // / Return the partial_apply and a flag set to true if the closure is
424
- // / indirectly captured by a reabstraction thunk.
425
- FindClosureResult swift::findClosureForAppliedArg (SILValue V) {
426
- // Look through borrows.
427
- if (auto *bbi = dyn_cast<BeginBorrowInst>(V))
428
- V = bbi->getOperand ();
429
-
430
- if (V->getType ().getOptionalObjectType ()) {
431
- auto *EI = dyn_cast<EnumInst>(V);
432
- if (!EI || !EI->hasOperand ())
433
- return FindClosureResult (nullptr , false );
434
-
435
- V = EI->getOperand ();
436
- }
417
+ // / Searches the use-def chain from the given value upward until a partial_apply
418
+ // / is reached. Populates `results` with the set of partial_apply instructions.
419
+ // /
420
+ // / `funcVal` may be either a function type or an Optional function type. This
421
+ // / might be called on a directly applied value or on a call argument, which may
422
+ // / in turn be applied within the callee.
423
+ void swift::findClosuresForFunctionValue (
424
+ SILValue funcVal, TinyPtrVector<PartialApplyInst *> &results) {
425
+
426
+ SILType funcTy = funcVal->getType ();
427
+ // Handle `Optional<@convention(block) @noescape (_)->(_)>`
428
+ if (auto optionalObjTy = funcTy.getOptionalObjectType ())
429
+ funcTy = optionalObjTy;
430
+ assert (funcTy.is <SILFunctionType>());
431
+
432
+ SmallVector<SILValue, 4 > worklist;
433
+ // Avoid exponential path exploration and prevent duplicate results.
434
+ llvm::SmallDenseSet<SILValue, 8 > visited;
435
+ auto worklistInsert = [&](SILValue V) {
436
+ if (visited.insert (V).second )
437
+ worklist.push_back (V);
438
+ };
439
+ worklistInsert (funcVal);
440
+
441
+ while (!worklist.empty ()) {
442
+ SILValue V = worklist.pop_back_val ();
443
+
444
+ if (auto *I = V->getDefiningInstruction ()) {
445
+ // Look through copies, borrows, and conversions.
446
+ //
447
+ // Handle copy_block and copy_block_without_actually_escaping before
448
+ // calling findClosureStoredIntoBlock.
449
+ if (SingleValueInstruction *SVI = getSingleValueCopyOrCast (I)) {
450
+ worklistInsert (SVI->getOperand (0 ));
451
+ continue ;
452
+ }
453
+ }
454
+ // Look through Optionals.
455
+ if (V->getType ().getOptionalObjectType ()) {
456
+ auto *EI = dyn_cast<EnumInst>(V);
457
+ if (EI && EI->hasOperand ()) {
458
+ worklistInsert (EI->getOperand ());
459
+ }
460
+ // Ignore the .None case.
461
+ continue ;
462
+ }
463
+ // Look through Phis.
464
+ //
465
+ // This should be done before calling findClosureStoredIntoBlock.
466
+ if (auto *arg = dyn_cast<SILPHIArgument>(V)) {
467
+ SmallVector<std::pair<SILBasicBlock *, SILValue>, 2 > blockArgs;
468
+ arg->getIncomingValues (blockArgs);
469
+ for (auto &blockAndArg : blockArgs)
470
+ worklistInsert (blockAndArg.second );
437
471
438
- auto fnType = V->getType ().getAs <SILFunctionType>();
439
- if (fnType->getRepresentation () == SILFunctionTypeRepresentation::Block) {
440
- V = findClosureStoredIntoBlock (V);
441
- if (!V)
442
- return FindClosureResult (nullptr , false );
443
- }
444
- auto *PAI = dyn_cast<PartialApplyInst>(stripConvertFunctions (V));
445
- if (!PAI)
446
- return FindClosureResult (nullptr , false );
447
-
448
- SILValue thunkArg = isPartialApplyOfReabstractionThunk (PAI);
449
- if (thunkArg) {
450
- // Handle reabstraction thunks recursively. This may reabstract over
451
- // @convention(block).
452
- auto result = findClosureForAppliedArg (thunkArg);
453
- return FindClosureResult (result.PAI , true );
472
+ continue ;
473
+ }
474
+ // Look through ObjC closures.
475
+ auto fnType = V->getType ().getAs <SILFunctionType>();
476
+ if (fnType
477
+ && fnType->getRepresentation () == SILFunctionTypeRepresentation::Block) {
478
+ if (SILValue storedClosure = findClosureStoredIntoBlock (V))
479
+ worklistInsert (storedClosure);
480
+
481
+ continue ;
482
+ }
483
+ if (auto *PAI = dyn_cast<PartialApplyInst>(V)) {
484
+ SILValue thunkArg = isPartialApplyOfReabstractionThunk (PAI);
485
+ if (thunkArg) {
486
+ // Handle reabstraction thunks recursively. This may reabstract over
487
+ // @convention(block).
488
+ worklistInsert (thunkArg);
489
+ continue ;
490
+ }
491
+ results.push_back (PAI);
492
+ continue ;
493
+ }
494
+ // Ignore other unrecognized values that feed this applied argument.
454
495
}
455
- return FindClosureResult (PAI, false );
456
496
}
457
497
458
498
namespace {
0 commit comments