Skip to content

Commit 896a464

Browse files
committed
[AllocBoxToStack] Lexical borrowees get lexical alloc_stacks.
Previously, whenever an alloc_box that was promoted to an alloc_stack, the new alloc_stack would be lexical. The result was that alloc_boxes which didn't need (or explicitly didn't want, in the case of eager move vars) received lexical alloc_stacks. Here, only add the lexical flag to the new alloc_stack instruction if any of the box's uses are `begin_borrow [lexical]`. That way, alloc_boxes end up having lexical alloc_stacks only if they were "lexical alloc_boxes".
1 parent 80ba5b5 commit 896a464

File tree

2 files changed

+58
-14
lines changed

2 files changed

+58
-14
lines changed

lib/SILOptimizer/Transforms/AllocBoxToStack.cpp

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,13 @@
1313
#define DEBUG_TYPE "allocbox-to-stack"
1414
#include "swift/AST/DiagnosticsSIL.h"
1515
#include "swift/Basic/BlotMapVector.h"
16+
#include "swift/Basic/GraphNodeWorklist.h"
1617
#include "swift/SIL/ApplySite.h"
18+
#include "swift/SIL/BasicBlockDatastructures.h"
1719
#include "swift/SIL/Dominance.h"
1820
#include "swift/SIL/SILArgument.h"
1921
#include "swift/SIL/SILBuilder.h"
2022
#include "swift/SIL/SILCloner.h"
21-
#include "swift/SIL/BasicBlockDatastructures.h"
2223
#include "swift/SILOptimizer/PassManager/Passes.h"
2324
#include "swift/SILOptimizer/PassManager/Transforms.h"
2425
#include "swift/SILOptimizer/Utils/InstOptUtils.h"
@@ -27,6 +28,7 @@
2728
#include "swift/SILOptimizer/Utils/StackNesting.h"
2829
#include "swift/SILOptimizer/Utils/ValueLifetime.h"
2930
#include "llvm/ADT/DenseMap.h"
31+
#include "llvm/ADT/STLExtras.h"
3032
#include "llvm/ADT/SmallPtrSet.h"
3133
#include "llvm/ADT/SmallSet.h"
3234
#include "llvm/ADT/SmallVector.h"
@@ -538,13 +540,35 @@ static bool rewriteAllocBoxAsAllocStack(AllocBoxInst *ABI) {
538540
SILBuilderWithScope Builder(ABI);
539541
assert(ABI->getBoxType()->getLayout()->getFields().size() == 1
540542
&& "rewriting multi-field box not implemented");
541-
auto &mod = ABI->getFunction()->getModule();
542-
bool isLexical = mod.getASTContext().SILOpts.supportsLexicalLifetimes(mod);
543-
auto *ASI = Builder.createAllocStack(
544-
ABI->getLoc(),
545-
getSILBoxFieldType(TypeExpansionContext(*ABI->getFunction()),
546-
ABI->getBoxType(), ABI->getModule().Types, 0),
547-
ABI->getVarInfo(), ABI->hasDynamicLifetime(), isLexical);
543+
auto ty = getSILBoxFieldType(TypeExpansionContext(*ABI->getFunction()),
544+
ABI->getBoxType(), ABI->getModule().Types, 0);
545+
auto isLexical = [&]() -> bool {
546+
auto &mod = ABI->getFunction()->getModule();
547+
bool lexicalLifetimesEnabled =
548+
mod.getASTContext().SILOpts.supportsLexicalLifetimes(mod);
549+
if (!lexicalLifetimesEnabled)
550+
return false;
551+
// Look for lexical borrows of the alloc_box.
552+
GraphNodeWorklist<Operand *, 4> worklist;
553+
worklist.initializeRange(ABI->getUses());
554+
while (auto *use = worklist.pop()) {
555+
// See through mark_uninitialized and non-lexical begin_borrow
556+
// instructions. It's verified that lexical begin_borrows of SILBoxType
557+
// values originate either from AllocBoxInsts or SILFunctionArguments.
558+
if (auto *mui = dyn_cast<MarkUninitializedInst>(use->getUser())) {
559+
for (auto *use : mui->getUses())
560+
worklist.insert(use);
561+
} else if (auto *bbi = dyn_cast<BeginBorrowInst>(use->getUser())) {
562+
if (bbi->isLexical())
563+
return true;
564+
for (auto *use : bbi->getUses())
565+
worklist.insert(use);
566+
}
567+
}
568+
return false;
569+
};
570+
auto *ASI = Builder.createAllocStack(ABI->getLoc(), ty, ABI->getVarInfo(),
571+
ABI->hasDynamicLifetime(), isLexical());
548572

549573
// Transfer a mark_uninitialized if we have one.
550574
SILValue StackBox = ASI;

test/SILOptimizer/allocbox_to_stack_lifetime.sil

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,13 @@ struct Bool {
1414

1515
protocol Error {}
1616

17-
// CHECK-LABEL: sil [ossa] @simple_promotion
18-
sil [ossa] @simple_promotion : $@convention(thin) (Int) -> Int {
17+
// CHECK-LABEL: sil [ossa] @promote_nonlexical
18+
// CHECK: alloc_stack $
19+
// CHECK-NOT: alloc_box
20+
// CHECK-NOT: destroy_value
21+
// CHECK: return
22+
// CHECK-LABEL: } // end sil function 'promote_nonlexical'
23+
sil [ossa] @promote_nonlexical : $@convention(thin) (Int) -> Int {
1924
bb0(%0 : $Int):
2025
%1 = alloc_box ${ var Int }
2126
%1a = project_box %1 : ${ var Int }, 0
@@ -24,9 +29,24 @@ bb0(%0 : $Int):
2429
%3 = load [trivial] %1a : $*Int
2530
destroy_value %1 : ${ var Int }
2631
return %3 : $Int
27-
// CHECK: alloc_stack [lexical]
28-
// CHECK-NOT: alloc_box
29-
// CHECK-NOT: destroy_value
30-
// CHECK: return
32+
}
33+
34+
// CHECK-LABEL: sil [ossa] @promote_lexical
35+
// CHECK: alloc_stack [lexical]
36+
// CHECK-NOT: alloc_box
37+
// CHECK-NOT: destroy_value
38+
// CHECK: return
39+
// CHECK-LABEL: } // end sil function 'promote_lexical'
40+
sil [ossa] @promote_lexical : $@convention(thin) (Int) -> Int {
41+
bb0(%0 : $Int):
42+
%1 = alloc_box ${ var Int }
43+
%b = begin_borrow [lexical] %1 : ${ var Int }
44+
%1a = project_box %b : ${ var Int }, 0
45+
store %0 to [trivial] %1a : $*Int
46+
47+
%3 = load [trivial] %1a : $*Int
48+
end_borrow %b : ${ var Int }
49+
destroy_value %1 : ${ var Int }
50+
return %3 : $Int
3151
}
3252

0 commit comments

Comments
 (0)