2525#include " swift/SIL/SILArgument.h"
2626#include " swift/SIL/SILBuilder.h"
2727#include " swift/SIL/SILCloner.h"
28+ #include " swift/SILOptimizer/Analysis/DeadEndBlocksAnalysis.h"
29+ #include " swift/SILOptimizer/Analysis/LoopAnalysis.h"
2830#include " swift/SILOptimizer/PassManager/Passes.h"
2931#include " swift/SILOptimizer/PassManager/Transforms.h"
3032#include " swift/SILOptimizer/Utils/InstOptUtils.h"
@@ -601,7 +603,9 @@ static void hoistMarkUnresolvedNonCopyableValueInsts(
601603
602604// / rewriteAllocBoxAsAllocStack - Replace uses of the alloc_box with a
603605// / new alloc_stack, but do not delete the alloc_box yet.
604- static bool rewriteAllocBoxAsAllocStack (AllocBoxInst *ABI) {
606+ static bool rewriteAllocBoxAsAllocStack (AllocBoxInst *ABI,
607+ DeadEndBlocksAnalysis &deba,
608+ SILLoopAnalysis &la) {
605609 LLVM_DEBUG (llvm::dbgs () << " *** Promoting alloc_box to stack: " << *ABI);
606610
607611 SILValue HeapBox = ABI;
@@ -693,9 +697,31 @@ static bool rewriteAllocBoxAsAllocStack(AllocBoxInst *ABI) {
693697 ABI->getBoxType (), ABI->getModule ().Types , 0 ));
694698 auto Loc = CleanupLocation (ABI->getLoc ());
695699
700+ auto *deb = deba.get (ABI->getFunction ());
696701 for (auto LastRelease : FinalReleases) {
702+ auto *dbi = dyn_cast<DeallocBoxInst>(LastRelease);
703+ if (!dbi && deb->isDeadEnd (LastRelease->getParent ()) &&
704+ !la.get (ABI->getFunction ())->getLoopFor (LastRelease->getParent ())) {
705+ // "Last" releases in dead-end regions may not actually destroy the box
706+ // and consequently may not actually release the stored value. That's
707+ // because values (including boxes) may be leaked along paths into
708+ // dead-end regions. Thus it is invalid to lower such final releases of
709+ // the box to destroy_addr's/dealloc_box's of the stack-promoted storage.
710+ //
711+ // There is one exception: if the alloc_box is in a dead-end loop. In
712+ // that case SIL invariants require that the final releases actually
713+ // destroy the box; otherwise, a box would leak once per loop. To check
714+ // for this, it is sufficient check that the LastRelease is in a dead-end
715+ // loop: if the alloc_box is not in that loop, then the entire loop is in
716+ // the live range, so no release within the loop would be a "final
717+ // release".
718+ //
719+ // None of this applies to dealloc_box instructions which always destroy
720+ // the box.
721+ continue ;
722+ }
697723 SILBuilderWithScope Builder (LastRelease);
698- if (!isa<DeallocBoxInst>(LastRelease) && !Lowering.isTrivial ()) {
724+ if (!dbi && !Lowering.isTrivial ()) {
699725 // If we have a mark_unresolved_non_copyable_value use of our stack box,
700726 // we want to destroy that.
701727 SILValue valueToDestroy = StackBox;
@@ -709,7 +735,6 @@ static bool rewriteAllocBoxAsAllocStack(AllocBoxInst *ABI) {
709735 // instruction we found that isn't an explicit dealloc_box.
710736 Builder.emitDestroyAddrAndFold (Loc, valueToDestroy);
711737 }
712- auto *dbi = dyn_cast<DeallocBoxInst>(LastRelease);
713738 if (dbi && dbi->isDeadEnd ()) {
714739 // Don't bother to create dealloc_stack instructions in dead-ends.
715740 continue ;
@@ -1265,7 +1290,9 @@ static void rewriteApplySites(AllocBoxToStackState &pass) {
12651290
12661291// / Clone closure bodies and rewrite partial applies. Returns the number of
12671292// / alloc_box allocations promoted.
1268- static unsigned rewritePromotedBoxes (AllocBoxToStackState &pass) {
1293+ static unsigned rewritePromotedBoxes (AllocBoxToStackState &pass,
1294+ DeadEndBlocksAnalysis &deba,
1295+ SILLoopAnalysis &la) {
12691296 // First we'll rewrite any ApplySite that we can to remove
12701297 // the box container pointer from the operands.
12711298 rewriteApplySites (pass);
@@ -1274,7 +1301,7 @@ static unsigned rewritePromotedBoxes(AllocBoxToStackState &pass) {
12741301 auto rend = pass.Promotable .rend ();
12751302 for (auto I = pass.Promotable .rbegin (); I != rend; ++I) {
12761303 auto *ABI = *I;
1277- if (rewriteAllocBoxAsAllocStack (ABI)) {
1304+ if (rewriteAllocBoxAsAllocStack (ABI, deba, la )) {
12781305 ++Count;
12791306 ABI->eraseFromParent ();
12801307 }
@@ -1299,7 +1326,9 @@ class AllocBoxToStack : public SILFunctionTransform {
12991326 }
13001327
13011328 if (!pass.Promotable .empty ()) {
1302- auto Count = rewritePromotedBoxes (pass);
1329+ auto *deba = getAnalysis<DeadEndBlocksAnalysis>();
1330+ auto *la = getAnalysis<SILLoopAnalysis>();
1331+ auto Count = rewritePromotedBoxes (pass, *deba, *la);
13031332 NumStackPromoted += Count;
13041333 if (Count) {
13051334 if (StackNesting::fixNesting (getFunction ()) == StackNesting::Changes::CFG)
0 commit comments