25
25
#include " swift/SIL/SILArgument.h"
26
26
#include " swift/SIL/SILBuilder.h"
27
27
#include " swift/SIL/SILCloner.h"
28
+ #include " swift/SILOptimizer/Analysis/DeadEndBlocksAnalysis.h"
29
+ #include " swift/SILOptimizer/Analysis/LoopAnalysis.h"
28
30
#include " swift/SILOptimizer/PassManager/Passes.h"
29
31
#include " swift/SILOptimizer/PassManager/Transforms.h"
30
32
#include " swift/SILOptimizer/Utils/InstOptUtils.h"
@@ -601,7 +603,9 @@ static void hoistMarkUnresolvedNonCopyableValueInsts(
601
603
602
604
// / rewriteAllocBoxAsAllocStack - Replace uses of the alloc_box with a
603
605
// / 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) {
605
609
LLVM_DEBUG (llvm::dbgs () << " *** Promoting alloc_box to stack: " << *ABI);
606
610
607
611
SILValue HeapBox = ABI;
@@ -693,9 +697,31 @@ static bool rewriteAllocBoxAsAllocStack(AllocBoxInst *ABI) {
693
697
ABI->getBoxType (), ABI->getModule ().Types , 0 ));
694
698
auto Loc = CleanupLocation (ABI->getLoc ());
695
699
700
+ auto *deb = deba.get (ABI->getFunction ());
696
701
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
+ }
697
723
SILBuilderWithScope Builder (LastRelease);
698
- if (!isa<DeallocBoxInst>(LastRelease) && !Lowering.isTrivial ()) {
724
+ if (!dbi && !Lowering.isTrivial ()) {
699
725
// If we have a mark_unresolved_non_copyable_value use of our stack box,
700
726
// we want to destroy that.
701
727
SILValue valueToDestroy = StackBox;
@@ -709,7 +735,6 @@ static bool rewriteAllocBoxAsAllocStack(AllocBoxInst *ABI) {
709
735
// instruction we found that isn't an explicit dealloc_box.
710
736
Builder.emitDestroyAddrAndFold (Loc, valueToDestroy);
711
737
}
712
- auto *dbi = dyn_cast<DeallocBoxInst>(LastRelease);
713
738
if (dbi && dbi->isDeadEnd ()) {
714
739
// Don't bother to create dealloc_stack instructions in dead-ends.
715
740
continue ;
@@ -1265,7 +1290,9 @@ static void rewriteApplySites(AllocBoxToStackState &pass) {
1265
1290
1266
1291
// / Clone closure bodies and rewrite partial applies. Returns the number of
1267
1292
// / alloc_box allocations promoted.
1268
- static unsigned rewritePromotedBoxes (AllocBoxToStackState &pass) {
1293
+ static unsigned rewritePromotedBoxes (AllocBoxToStackState &pass,
1294
+ DeadEndBlocksAnalysis &deba,
1295
+ SILLoopAnalysis &la) {
1269
1296
// First we'll rewrite any ApplySite that we can to remove
1270
1297
// the box container pointer from the operands.
1271
1298
rewriteApplySites (pass);
@@ -1274,7 +1301,7 @@ static unsigned rewritePromotedBoxes(AllocBoxToStackState &pass) {
1274
1301
auto rend = pass.Promotable .rend ();
1275
1302
for (auto I = pass.Promotable .rbegin (); I != rend; ++I) {
1276
1303
auto *ABI = *I;
1277
- if (rewriteAllocBoxAsAllocStack (ABI)) {
1304
+ if (rewriteAllocBoxAsAllocStack (ABI, deba, la )) {
1278
1305
++Count;
1279
1306
ABI->eraseFromParent ();
1280
1307
}
@@ -1299,7 +1326,9 @@ class AllocBoxToStack : public SILFunctionTransform {
1299
1326
}
1300
1327
1301
1328
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);
1303
1332
NumStackPromoted += Count;
1304
1333
if (Count) {
1305
1334
if (StackNesting::fixNesting (getFunction ()) == StackNesting::Changes::CFG)
0 commit comments