Skip to content

Commit d934758

Browse files
committed
[6.2] Fix an inliner crash when inlining begin_apply with scoped lifetime dependence
1 parent 5d24373 commit d934758

File tree

5 files changed

+170
-3
lines changed

5 files changed

+170
-3
lines changed

SwiftCompilerSources/Sources/Optimizer/FunctionPasses/LifetimeDependenceInsertion.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,9 +145,13 @@ extension LifetimeDependentApply {
145145
case .inherit:
146146
continue
147147
case .scope:
148+
// FIXME: For yields with a scoped lifetime dependence, dependence on parameter operands is redundant,
149+
// since we introduce dependence on the begin_apply's token as well.
150+
// This can lead to duplicate lifetime dependence diagnostics in some cases.
151+
// However this is neccessary for safety when begin_apply gets inlined which will delete the dependence on the token.
148152
for yieldedValue in beginApply.yieldedValues {
149153
let targetKind = yieldedValue.type.isAddress ? TargetKind.yieldAddress : TargetKind.yield
150-
info.sources.push(LifetimeSource(targetKind: targetKind, convention: .inherit, value: operand.value))
154+
info.sources.push(LifetimeSource(targetKind: targetKind, convention: dep, value: operand.value))
151155
}
152156
}
153157
}

include/swift/SIL/SILInstruction.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8903,10 +8903,10 @@ class MarkDependenceAddrInst
89038903

89048904
/// Shared API for MarkDependenceInst and MarkDependenceAddrInst.
89058905
class MarkDependenceInstruction {
8906-
const SILInstruction *inst = nullptr;
8906+
SILInstruction *inst = nullptr;
89078907

89088908
public:
8909-
explicit MarkDependenceInstruction(const SILInstruction *inst) {
8909+
explicit MarkDependenceInstruction(SILInstruction *inst) {
89108910
switch (inst->getKind()) {
89118911
case SILInstructionKind::MarkDependenceInst:
89128912
case SILInstructionKind::MarkDependenceAddrInst:
@@ -8967,6 +8967,11 @@ class MarkDependenceInstruction {
89678967
}
89688968
return false;
89698969
}
8970+
8971+
SILInstruction *operator->() { return inst; }
8972+
SILInstruction *operator->() const { return inst; }
8973+
SILInstruction *operator*() { return inst; }
8974+
SILInstruction *operator*() const { return inst; }
89708975
};
89718976

89728977
/// Promote an Objective-C block that is on the stack to the heap, or simply

lib/SILOptimizer/Utils/SILInliner.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,32 @@ class BeginApplySite {
128128
collectAbortApply(abortApply);
129129
endBorrowInsertPts.push_back(&*std::next(abortApply->getIterator()));
130130
}
131+
132+
// We may have a mark_dependence/mark_dependence_addr on the coroutine's
133+
// token. This is needed to represent lifetime dependence on values created
134+
// within the coroutine. Delete such mark_dependence instructions since the
135+
// dependencies on values created within the coroutine will be exposed after
136+
// inlining.
137+
if (BeginApply->getCalleeFunction()
138+
->getLoweredFunctionType()
139+
->hasLifetimeDependencies()) {
140+
SmallVector<SILInstruction *> toDelete;
141+
for (auto *tokenUser : BeginApply->getTokenResult()->getUsers()) {
142+
auto mdi = MarkDependenceInstruction(tokenUser);
143+
if (!mdi) {
144+
continue;
145+
}
146+
assert(mdi.isNonEscaping());
147+
if (auto *valueMDI = dyn_cast<MarkDependenceInst>(*mdi)) {
148+
valueMDI->replaceAllUsesWith(valueMDI->getValue());
149+
}
150+
toDelete.push_back(*mdi);
151+
}
152+
153+
for (auto *inst : toDelete) {
154+
inst->eraseFromParent();
155+
}
156+
}
131157
}
132158

133159
// Split the basic block before the end/abort_apply. We will insert code
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
// RUN: %target-sil-opt %s \
2+
// RUN: -early-inline \
3+
// RUN: -sil-print-types \
4+
// RUN: -enable-experimental-feature Lifetimes | %FileCheck %s
5+
6+
// REQUIRES: swift_in_compiler
7+
// REQUIRES: swift_feature_Lifetimes
8+
9+
import Swift
10+
import Builtin
11+
12+
struct Wrapper : ~Copyable {
13+
}
14+
15+
struct NE : ~Escapable {
16+
}
17+
18+
struct MyBox : ~Copyable {
19+
}
20+
21+
sil @$s4test7WrapperVACycfC : $@convention(method) (@thin Wrapper.Type) -> @owned Wrapper
22+
sil @$s4test2NEVyAcA7WrapperVhcfC : $@convention(method) (@guaranteed Wrapper, @thin NE.Type) -> @lifetime(borrow 0) @owned NE
23+
sil @$s4test5MyBoxVACycfC : $@convention(method) (@thin MyBox.Type) -> @owned MyBox
24+
sil @$s4test3useyyAA2NEVF : $@convention(thin) (@guaranteed NE) -> ()
25+
26+
sil hidden [ossa] @$s4test5MyBoxV5valueAA2NEVvr : $@yield_once @convention(method) (@guaranteed MyBox) -> @lifetime(borrow 0) @yields @guaranteed NE {
27+
bb0(%0 : @guaranteed $MyBox):
28+
%1 = copy_value %0
29+
%2 = mark_unresolved_non_copyable_value [no_consume_or_assign] %1
30+
%4 = alloc_box ${ let Wrapper }, let, name "w"
31+
%5 = begin_borrow [lexical] [var_decl] %4
32+
%6 = project_box %5, 0
33+
%7 = metatype $@thin Wrapper.Type
34+
%8 = function_ref @$s4test7WrapperVACycfC : $@convention(method) (@thin Wrapper.Type) -> @owned Wrapper
35+
%9 = apply %8(%7) : $@convention(method) (@thin Wrapper.Type) -> @owned Wrapper
36+
store %9 to [init] %6
37+
%11 = metatype $@thin NE.Type
38+
%12 = mark_unresolved_non_copyable_value [no_consume_or_assign] %6
39+
%13 = load_borrow %12
40+
%14 = function_ref @$s4test2NEVyAcA7WrapperVhcfC : $@convention(method) (@guaranteed Wrapper, @thin NE.Type) -> @lifetime(borrow 0) @owned NE
41+
%15 = apply %14(%13, %11) : $@convention(method) (@guaranteed Wrapper, @thin NE.Type) -> @lifetime(borrow 0) @owned NE
42+
%16 = mark_dependence [nonescaping] %15 on %5
43+
end_borrow %13
44+
yield %16, resume bb1, unwind bb2
45+
46+
bb1:
47+
destroy_value %16
48+
end_borrow %5
49+
destroy_value %4
50+
destroy_value %2
51+
%23 = tuple ()
52+
return %23
53+
54+
bb2:
55+
destroy_value %16
56+
end_borrow %5
57+
destroy_value %4
58+
destroy_value %2
59+
unwind
60+
}
61+
62+
// Reduced SIL for validation-test/SILOptimizer/rdar151568816.swift
63+
64+
// CHECK-LABEL: sil hidden [ossa] @$s4test3fooyyF :
65+
// CHECK: [[W:%.*]] = alloc_box ${ let Wrapper }, let, name "w"
66+
// CHECK: [[B:%.*]] = begin_borrow [lexical] [var_decl] [[W]] : ${ let Wrapper }
67+
// CHECK: [[INITFN:%.*]] = function_ref @$s4test2NEVyAcA7WrapperVhcfC : $@convention(method) (@guaranteed Wrapper, @thin NE.Type) -> @lifetime(borrow 0) @owned NE
68+
// CHECK: [[NE:%.*]] = apply [[INITFN]]({{.*}}) : $@convention(method) (@guaranteed Wrapper, @thin NE.Type) -> @lifetime(borrow 0) @owned NE
69+
// CHECK: [[MDI:%.*]] = mark_dependence [nonescaping] [[NE]] : $NE on [[B]] : ${ let Wrapper }
70+
// CHECK-LABEL: } // end sil function '$s4test3fooyyF'
71+
sil hidden [ossa] @$s4test3fooyyF : $@convention(thin) () -> () {
72+
bb0:
73+
%0 = alloc_box ${ let MyBox }, let, name "box"
74+
%1 = begin_borrow [lexical] [var_decl] %0
75+
%2 = project_box %1, 0
76+
%3 = metatype $@thin MyBox.Type
77+
%4 = function_ref @$s4test5MyBoxVACycfC : $@convention(method) (@thin MyBox.Type) -> @owned MyBox
78+
%5 = apply %4(%3) : $@convention(method) (@thin MyBox.Type) -> @owned MyBox
79+
store %5 to [init] %2
80+
%7 = mark_unresolved_non_copyable_value [no_consume_or_assign] %2
81+
%8 = load_borrow %7
82+
%9 = function_ref @$s4test5MyBoxV5valueAA2NEVvr : $@yield_once @convention(method) (@guaranteed MyBox) -> @lifetime(borrow 0) @yields @guaranteed NE
83+
(%10, %11) = begin_apply %9(%8) : $@yield_once @convention(method) (@guaranteed MyBox) -> @lifetime(borrow 0) @yields @guaranteed NE
84+
%12 = mark_dependence [nonescaping] %10 on %11
85+
%13 = mark_dependence [nonescaping] %12 on %1
86+
%14 = copy_value %13
87+
%15 = move_value [var_decl] %14
88+
%17 = begin_borrow %15
89+
%18 = function_ref @$s4test3useyyAA2NEVF : $@convention(thin) (@guaranteed NE) -> ()
90+
%19 = apply %18(%17) : $@convention(thin) (@guaranteed NE) -> ()
91+
end_borrow %17
92+
destroy_value %15
93+
%22 = end_apply %11 as $()
94+
end_borrow %8
95+
end_borrow %1
96+
destroy_value %0
97+
%26 = tuple ()
98+
return %26
99+
}
100+
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// RUN: %target-swift-frontend %s -enable-experimental-feature Lifetimes -emit-sil
2+
3+
// REQUIRES: swift_in_compiler
4+
// REQUIRES: swift_feature_Lifetimes
5+
6+
// Ensure we don't crash
7+
8+
struct Wrapper : ~Copyable {
9+
}
10+
11+
struct NE : ~Escapable {
12+
@_lifetime(borrow w)
13+
init(_ w: borrowing Wrapper) {}
14+
}
15+
16+
struct MyBox : ~Copyable {
17+
public var value: NE {
18+
_read {
19+
let w = Wrapper()
20+
yield NE(w)
21+
}
22+
}
23+
}
24+
25+
func use(_ n: borrowing NE) {}
26+
27+
func foo() {
28+
let box = MyBox()
29+
let value = box.value
30+
use(value)
31+
}
32+

0 commit comments

Comments
 (0)