Skip to content

Commit 904266c

Browse files
committed
[SILInliner] Mark alloc_stacks lexical.
When inlining a function to which an alloc_stack is passed (via any convention that's not all of mutating, exclusive, and inout), mark the alloc_stack as lexical. Otherwise, destroy_addrs could be hoisted through the inlined function in a way inconsistent with how they were hoisted through the callee prior to inlining.
1 parent 896a464 commit 904266c

File tree

4 files changed

+52
-9
lines changed

4 files changed

+52
-9
lines changed

lib/SILOptimizer/Utils/SILInliner.cpp

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
#include "swift/SILOptimizer/Utils/SILInliner.h"
1616
#include "swift/AST/Builtins.h"
1717
#include "swift/AST/DiagnosticsSIL.h"
18+
#include "swift/Basic/Defer.h"
19+
#include "swift/SIL/MemAccessUtils.h"
1820
#include "swift/SIL/PrettyStackTrace.h"
1921
#include "swift/SIL/SILDebugScope.h"
2022
#include "swift/SIL/SILInstruction.h"
@@ -433,17 +435,44 @@ void SILInlineCloner::cloneInline(ArrayRef<SILValue> AppliedArgs) {
433435
auto calleeConv = getCalleeFunction()->getConventions();
434436
for (auto p : llvm::enumerate(AppliedArgs)) {
435437
SILValue callArg = p.value();
438+
SWIFT_DEFER { entryArgs.push_back(callArg); };
436439
unsigned idx = p.index();
437440
if (idx >= calleeConv.getSILArgIndexOfFirstParam()) {
438-
// Insert begin/end borrow for guaranteed arguments.
439-
if (calleeConv.getParamInfoForSILArg(idx).isGuaranteed()) {
440-
if (SILValue newValue = borrowFunctionArgument(callArg, Apply)) {
441-
callArg = newValue;
442-
borrowedArgs[idx] = true;
441+
auto paramInfo = calleeConv.getParamInfoForSILArg(idx);
442+
if (callArg->getType().isAddress()) {
443+
// If lexical lifetimes are enabled, any alloc_stacks in the caller that
444+
// are passed to the callee being inlined (except mutating exclusive
445+
// accesses) need to be promoted to be lexical. Otherwise,
446+
// destroy_addrs could be hoisted through the body of the newly inlined
447+
// function without regard to the deinit barriers it contains.
448+
//
449+
// TODO: [begin_borrow_addr] Instead of marking the alloc_stack as a
450+
// whole lexical, just mark the inlined range lexical via
451+
// begin_borrow_addr [lexical]/end_borrow_addr just as is done
452+
// with values.
453+
auto &module = Apply.getFunction()->getModule();
454+
auto enableLexicalLifetimes =
455+
module.getASTContext().SILOpts.supportsLexicalLifetimes(module);
456+
if (!enableLexicalLifetimes)
457+
continue;
458+
459+
// Exclusive mutating accesses don't entail a lexical scope.
460+
if (paramInfo.getConvention() == ParameterConvention::Indirect_Inout)
461+
continue;
462+
463+
auto storage = AccessStorageWithBase::compute(callArg);
464+
if (auto *asi = dyn_cast<AllocStackInst>(storage.base))
465+
asi->setIsLexical();
466+
} else {
467+
// Insert begin/end borrow for guaranteed arguments.
468+
if (paramInfo.isGuaranteed()) {
469+
if (SILValue newValue = borrowFunctionArgument(callArg, Apply)) {
470+
callArg = newValue;
471+
borrowedArgs[idx] = true;
472+
}
443473
}
444474
}
445475
}
446-
entryArgs.push_back(callArg);
447476
}
448477

449478
// Create the return block and set ReturnToBB for use in visitTerminator

test/SILGen/copy_operator.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ class Klass {}
3737
// CHECK-SIL-LABEL: sil @$s8moveonly7useCopyyAA5KlassCADF : $@convention(thin) (@guaranteed Klass) -> @owned Klass {
3838
// CHECK-SIL: bb0([[ARG:%.*]] : $Klass):
3939
// CHECK-SIL-NEXT: debug_value
40-
// CHECK-SIL-NEXT: [[INPUT:%.*]] = alloc_stack $Klass
40+
// CHECK-SIL-NEXT: [[INPUT:%.*]] = alloc_stack [lexical] $Klass
4141
// CHECK-SIL-NEXT: store [[ARG]] to [[INPUT]]
4242
// CHECK-SIL-NEXT: [[VALUE:%[0-9][0-9]*]] = load [[INPUT]]{{.*}}
4343
// CHECK-SIL-NEXT: strong_retain [[VALUE]]
@@ -78,7 +78,7 @@ public func useCopy(_ k: Klass) -> Klass {
7878
// CHECK-SIL-LABEL: sil @$s8moveonly7useCopyyxxRlzClF : $@convention(thin) <T where T : AnyObject> (@guaranteed T) -> @owned T {
7979
// CHECK-SIL: bb0([[ARG:%.*]] :
8080
// CHECK-SIL-NEXT: debug_value
81-
// CHECK-SIL-NEXT: [[INPUT_TO_BE_ELIMINATED:%.*]] = alloc_stack $T
81+
// CHECK-SIL-NEXT: [[INPUT_TO_BE_ELIMINATED:%.*]] = alloc_stack [lexical] $T
8282
// CHECK-SIL-NEXT: store [[ARG]] to [[INPUT]] : $*T
8383
// CHECK-SIL-NEXT: [[VALUE:%.*]] = load [[INPUT]] : $*T
8484
// CHECK-SIL-NEXT: strong_retain [[VALUE]]

test/SILOptimizer/inline_lifetime.sil

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,20 @@ bb0(%instance : $*T):
130130
return %retval : $()
131131
}
132132

133+
// CHECK-LABEL: sil [ossa] @caller_allocstack_callee_inguaranteed : $@convention(thin) <T> () -> () {
134+
// CHECK: alloc_stack [lexical]
135+
// CHECK-LABEL: } // end sil function 'caller_allocstack_callee_inguaranteed'
136+
sil [ossa] @caller_allocstack_callee_inguaranteed : $@convention(thin) <T> () -> () {
137+
bb0:
138+
%addr = alloc_stack $T
139+
apply undef<T>(%addr) : $@convention(thin) <τ_0_0> () -> @out τ_0_0
140+
%callee_inguaranteed = function_ref @callee_inguaranteed : $@convention(thin) <T> (@in_guaranteed T) -> ()
141+
%retval = apply %callee_inguaranteed<T>(%addr) : $@convention(thin) <T> (@in_guaranteed T) -> ()
142+
destroy_addr %addr : $*T
143+
dealloc_stack %addr : $*T
144+
return %retval : $()
145+
}
146+
133147
////////////////////////////////////////////////////////////////////////////////
134148
// begin_apply
135149
////////////////////////////////////////////////////////////////////////////////

test/SILOptimizer/specialize_dynamic_self.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ extension P {
1111

1212
class C<T> : P {
1313
// CHECK-LABEL: sil shared [noinline] @$s23specialize_dynamic_self1CC11returnsSelfACyxGXDyFSi_Tg5 : $@convention(method) (@guaranteed C<Int>) -> @owned C<Int>
14-
// CHECK: [[RESULT:%.*]] = alloc_stack $C<Int>
14+
// CHECK: [[RESULT:%.*]] = alloc_stack [lexical] $C<Int>
1515
// CHECK: [[FN:%.*]] = function_ref @$s23specialize_dynamic_self1PPAAE7method1yyF : $@convention(method) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> ()
1616
// CHECK: apply [[FN]]<@dynamic_self C<Int>>([[RESULT]]) : $@convention(method) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> ()
1717
// CHECK: return %0 : $C<Int>

0 commit comments

Comments
 (0)