@@ -261,14 +261,18 @@ class StackAllocationPromoter {
261
261
// / AllocStackInst.
262
262
BlockToInstMap lastStoreInBlock;
263
263
264
+ // / Records blocks in which the value in asi is moved out.
265
+ // / i.e There was a load [take] of the asi with no following store.
266
+ BasicBlockSet deadValueBlock;
264
267
public:
265
268
// / C'tor.
266
269
StackAllocationPromoter (AllocStackInst *inputASI, DominanceInfo *inputDomInfo,
267
270
DomTreeLevelMap &inputDomTreeLevels,
268
271
SILBuilderContext &inputCtx,
269
272
InstructionDeleter &deleter)
270
273
: asi(inputASI), dsi(nullptr ), domInfo(inputDomInfo),
271
- domTreeLevels (inputDomTreeLevels), ctx(inputCtx), deleter(deleter) {
274
+ domTreeLevels (inputDomTreeLevels), ctx(inputCtx), deleter(deleter),
275
+ deadValueBlock(inputASI->getFunction ()) {
272
276
// Scan the users in search of a deallocation instruction.
273
277
for (auto *use : asi->getUses ()) {
274
278
if (auto *foundDealloc = dyn_cast<DeallocStackInst>(use->getUser ())) {
@@ -330,12 +334,14 @@ class StackAllocationPromoter {
330
334
StoreInst *StackAllocationPromoter::promoteAllocationInBlock (
331
335
SILBasicBlock *blockPromotingWithin) {
332
336
LLVM_DEBUG (llvm::dbgs () << " *** Promoting ASI in block: " << *asi);
333
-
334
337
// RunningVal is the current value in the stack location.
335
338
// We don't know the value of the alloca until we find the first store.
336
339
SILValue runningVal = SILValue ();
337
340
// Keep track of the last StoreInst that we found.
338
341
StoreInst *lastStore = nullptr ;
342
+ // Keep track if value in asi becomes dead via load [take] or destroy_addr in
343
+ // this block
344
+ bool deadAsi = false ;
339
345
340
346
// For all instructions in the block.
341
347
for (auto bbi = blockPromotingWithin->begin (),
@@ -346,6 +352,10 @@ StoreInst *StackAllocationPromoter::promoteAllocationInBlock(
346
352
347
353
if (isLoadFromStack (inst, asi)) {
348
354
auto *li = cast<LoadInst>(inst);
355
+ // The value in asi was moved out, set deadAsi to true
356
+ if (li->getOwnershipQualifier () == LoadOwnershipQualifier::Take) {
357
+ deadAsi = true ;
358
+ }
349
359
if (runningVal) {
350
360
// If we are loading from the AllocStackInst and we already know the
351
361
// content of the Alloca then use it.
@@ -371,6 +381,9 @@ StoreInst *StackAllocationPromoter::promoteAllocationInBlock(
371
381
if (si->getDest () != asi)
372
382
continue ;
373
383
384
+ // Found a store to asi, set deadAsi to false.
385
+ deadAsi = false ;
386
+
374
387
// If we see a store [assign], always convert it to a store [init]. This
375
388
// simplifies further processing.
376
389
if (si->getOwnershipQualifier () == StoreOwnershipQualifier::Assign) {
@@ -416,28 +429,28 @@ StoreInst *StackAllocationPromoter::promoteAllocationInBlock(
416
429
417
430
// Replace destroys with a release of the value.
418
431
if (auto *dai = dyn_cast<DestroyAddrInst>(inst)) {
419
- if (dai->getOperand () == asi && runningVal) {
420
- replaceDestroy (dai, runningVal, ctx, deleter);
432
+ if (dai->getOperand () == asi) {
433
+ if (runningVal) {
434
+ replaceDestroy (dai, runningVal, ctx, deleter);
435
+ }
436
+ // The value in asi was destroyed, set deadAsi to true
437
+ deadAsi = true ;
421
438
}
422
439
continue ;
423
440
}
424
441
425
- if (auto *dvi = dyn_cast<DestroyValueInst>(inst)) {
426
- if (dvi->getOperand () == runningVal) {
427
- // Reset LastStore.
428
- // So that we don't end up passing dead values as phi args in
429
- // StackAllocationPromoter::fixBranchesAndUses
430
- lastStore = nullptr ;
431
- }
432
- }
433
-
434
442
// Stop on deallocation.
435
443
if (auto *dsi = dyn_cast<DeallocStackInst>(inst)) {
436
444
if (dsi->getOperand () == asi)
437
445
break ;
438
446
}
439
447
}
440
448
449
+ // If the asi was dead in this block, insert into deadValueBlock in OSSA.
450
+ if (deadAsi && asi->getFunction ()->hasOwnership () &&
451
+ !asi->getType ().isTrivial (*asi->getFunction ())) {
452
+ deadValueBlock.insert (blockPromotingWithin);
453
+ }
441
454
if (lastStore) {
442
455
assert (lastStore->getOwnershipQualifier () !=
443
456
StoreOwnershipQualifier::Assign &&
@@ -461,11 +474,17 @@ void StackAllocationPromoter::addBlockArguments(BlockSetVector &phiBlocks) {
461
474
SILValue StackAllocationPromoter::getLiveOutValue (BlockSetVector &phiBlocks,
462
475
SILBasicBlock *startBlock) {
463
476
LLVM_DEBUG (llvm::dbgs () << " *** Searching for a value definition.\n " );
477
+ auto *func = asi->getFunction ();
478
+
464
479
// Walk the Dom tree in search of a defining value:
465
480
for (DomTreeNode *domNode = domInfo->getNode (startBlock); domNode;
466
481
domNode = domNode->getIDom ()) {
467
482
SILBasicBlock *domBlock = domNode->getBlock ();
468
483
484
+ // If the value in asi is moved out, then return undef
485
+ if (deadValueBlock.contains (domBlock)) {
486
+ return SILUndef::get (asi->getElementType (), *func);
487
+ }
469
488
// If there is a store (that must come after the phi), use its value.
470
489
BlockToInstMap::iterator it = lastStoreInBlock.find (domBlock);
471
490
if (it != lastStoreInBlock.end ())
@@ -487,7 +506,7 @@ SILValue StackAllocationPromoter::getLiveOutValue(BlockSetVector &phiBlocks,
487
506
LLVM_DEBUG (llvm::dbgs () << " *** Walking up the iDOM.\n " );
488
507
}
489
508
LLVM_DEBUG (llvm::dbgs () << " *** Could not find a Def. Using Undef.\n " );
490
- return SILUndef::get (asi->getElementType (), *asi-> getFunction () );
509
+ return SILUndef::get (asi->getElementType (), *func );
491
510
}
492
511
493
512
SILValue StackAllocationPromoter::getLiveInValue (BlockSetVector &phiBlocks,
@@ -596,14 +615,22 @@ void StackAllocationPromoter::fixBranchesAndUses(BlockSetVector &phiBlocks) {
596
615
}
597
616
}
598
617
599
- // If the owned phi arg we added did not have any uses, create end_lifetime to
600
- // end its lifetime. In asserts mode, make sure we have only undef incoming
601
- // values for such phi args.
602
- for (auto *block : phiBlocks) {
603
- auto *phiArg =
604
- cast<SILPhiArgument>(block->getArgument (block->getNumArguments () - 1 ));
605
- if (phiArg->use_empty ()) {
606
- erasePhiArgument (block, block->getNumArguments () - 1 );
618
+ // Fix ownership of newly created non-trivial phis
619
+ if (asi->getFunction ()->hasOwnership () &&
620
+ !asi->getType ().isTrivial (*asi->getFunction ())) {
621
+ // Go over all the proactively added phis and create end_lifetime at
622
+ // leaking blocks
623
+ SmallVector<SILBasicBlock *, 4 > consumingBlocks;
624
+ for (auto *block : phiBlocks) {
625
+ auto *phiArg = cast<SILPhiArgument>(
626
+ block->getArgument (block->getNumArguments () - 1 ));
627
+ if (phiArg->use_empty ()) {
628
+ auto *insertPt = phiArg->getNextInstruction ();
629
+ SILBuilderWithScope builder (insertPt);
630
+ builder.createEndLifetime (
631
+ RegularLocation::getAutoGeneratedLocation (insertPt->getLoc ()),
632
+ phiArg);
633
+ }
607
634
}
608
635
}
609
636
}
@@ -1049,6 +1076,10 @@ bool MemoryToRegisters::promoteSingleAllocation(AllocStackInst *alloc) {
1049
1076
LLVM_DEBUG (llvm::dbgs () << " *** Memory to register looking at: " << *alloc);
1050
1077
++NumAllocStackFound;
1051
1078
1079
+ if (f.hasOwnership () && alloc->hasDynamicLifetime ()) {
1080
+ return false ;
1081
+ }
1082
+
1052
1083
// Don't handle captured AllocStacks.
1053
1084
bool inSingleBlock = false ;
1054
1085
if (isCaptured (alloc, inSingleBlock)) {
@@ -1058,9 +1089,8 @@ bool MemoryToRegisters::promoteSingleAllocation(AllocStackInst *alloc) {
1058
1089
1059
1090
// Remove write-only AllocStacks.
1060
1091
if (isWriteOnlyAllocation (alloc)) {
1061
- deleter.forceDeleteWithUsers (alloc);
1062
-
1063
1092
LLVM_DEBUG (llvm::dbgs () << " *** Deleting store-only AllocStack: " << *alloc);
1093
+ deleter.forceDeleteWithUsers (alloc);
1064
1094
return true ;
1065
1095
}
1066
1096
0 commit comments