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: " 
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