Skip to content

Commit 814d583

Browse files
Merge pull request #39532 from nate-chandler/lexical_lifetimes/silgen_argument_lifetimes
[SILGen] Gave arguments lexical lifetimes.
2 parents c413f40 + 29faebf commit 814d583

File tree

5 files changed

+160
-80
lines changed

5 files changed

+160
-80
lines changed

lib/SILGen/Cleanup.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,14 @@ class LLVM_LIBRARY_VISIBILITY Cleanup {
133133
}
134134
};
135135

136+
struct EndBorrowCleanup final : Cleanup {
137+
SILValue borrowedValue;
138+
EndBorrowCleanup(SILValue borrowedValue);
139+
void emit(SILGenFunction &SGF, CleanupLocation l,
140+
ForUnwind_t forUnwind) override;
141+
void dump(SILGenFunction &) const override;
142+
};
143+
136144
/// A cleanup depth is generally used to denote the set of cleanups
137145
/// between the given cleanup (and not including it) and the top of
138146
/// the stack.

lib/SILGen/SILGenExpr.cpp

Lines changed: 18 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -158,34 +158,30 @@ SILGenFunction::emitManagedBeginBorrow(SILLocation loc, SILValue v,
158158
return emitManagedBorrowedRValueWithCleanup(v, bbi, lowering);
159159
}
160160

161-
namespace {
162-
163-
struct EndBorrowCleanup : Cleanup {
164-
SILValue borrowedValue;
165-
166-
EndBorrowCleanup(SILValue borrowedValue) : borrowedValue(borrowedValue) {
167-
if (auto *arg = dyn_cast<SILPhiArgument>(borrowedValue)) {
168-
if (auto *ti = arg->getSingleTerminator()) {
169-
assert(!ti->isTransformationTerminator() &&
170-
"Transforming terminators do not have end_borrow");
171-
}
161+
EndBorrowCleanup::EndBorrowCleanup(SILValue borrowedValue)
162+
: borrowedValue(borrowedValue) {
163+
if (auto *arg = dyn_cast<SILPhiArgument>(borrowedValue)) {
164+
if (auto *ti = arg->getSingleTerminator()) {
165+
assert(!ti->isTransformationTerminator() &&
166+
"Transforming terminators do not have end_borrow");
172167
}
173168
}
169+
}
174170

175-
void emit(SILGenFunction &SGF, CleanupLocation l,
176-
ForUnwind_t forUnwind) override {
177-
SGF.B.createEndBorrow(l, borrowedValue);
178-
}
171+
void EndBorrowCleanup::emit(SILGenFunction &SGF, CleanupLocation l,
172+
ForUnwind_t forUnwind) {
173+
SGF.B.createEndBorrow(l, borrowedValue);
174+
}
179175

180-
void dump(SILGenFunction &) const override {
176+
void EndBorrowCleanup::dump(SILGenFunction &) const {
181177
#ifndef NDEBUG
182-
llvm::errs() << "EndBorrowCleanup "
183-
<< "State:" << getState() << "\n"
184-
<< "borrowed:" << borrowedValue
185-
<< "\n";
178+
llvm::errs() << "EndBorrowCleanup "
179+
<< "State:" << getState() << "\n"
180+
<< "borrowed:" << borrowedValue << "\n";
186181
#endif
187-
}
188-
};
182+
}
183+
184+
namespace {
189185

190186
struct FormalEvaluationEndBorrowCleanup : Cleanup {
191187
FormalEvaluationContext::stable_iterator Depth;

lib/SILGen/SILGenProlog.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -251,17 +251,23 @@ struct ArgumentInitHelper {
251251
// Leave the cleanup on the argument, if any, in place to consume the
252252
// argument if we're responsible for it.
253253
}
254-
SGF.VarLocs[pd] = SILGenFunction::VarLoc::get(argrv.getValue());
255254
SILValue value = argrv.getValue();
256255
SILDebugVariable varinfo(pd->isImmutable(), ArgNo);
257256
if (!argrv.getType().isAddress()) {
257+
if (SGF.getASTContext().LangOpts.EnableExperimentalLexicalLifetimes &&
258+
value->getOwnershipKind() != OwnershipKind::None) {
259+
value =
260+
SILValue(SGF.B.createBeginBorrow(loc, value, /*isLexical*/ true));
261+
SGF.Cleanups.pushCleanup<EndBorrowCleanup>(value);
262+
}
258263
SGF.B.createDebugValue(loc, value, varinfo);
259264
} else {
260265
if (auto AllocStack = dyn_cast<AllocStackInst>(value))
261266
AllocStack->setArgNo(ArgNo);
262267
else
263268
SGF.B.createDebugValueAddr(loc, value, varinfo);
264269
}
270+
SGF.VarLocs[pd] = SILGenFunction::VarLoc::get(value);
265271
}
266272

267273
void emitParam(ParamDecl *PD) {

test/SILGen/borrow.swift

Lines changed: 1 addition & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11

2-
// RUN: %target-swift-emit-silgen -enable-experimental-lexical-lifetimes -module-name borrow -parse-stdlib %s | %FileCheck %s
2+
// RUN: %target-swift-emit-silgen -module-name borrow -parse-stdlib %s | %FileCheck %s
33

44
import Swift
55

@@ -13,7 +13,6 @@ final class C {
1313
var d: D = D()
1414
}
1515

16-
func use<T>(_ t: T) {}
1716
func useD(_ d: D) {}
1817

1918
// CHECK-LABEL: sil hidden [ossa] @$s6borrow44lvalueBorrowShouldBeAtEndOfFormalAccessScope{{.*}} : $@convention(thin) () -> () {
@@ -36,58 +35,3 @@ func lvalueBorrowShouldBeAtEndOfFormalAccessScope() {
3635
var c = C()
3736
useD(c.d)
3837
}
39-
40-
// CHECK-LABEL: sil hidden [ossa] @lexical_borrow_let_class
41-
// CHECK: [[INIT_C:%[^,]+]] = function_ref @$s6borrow1CCACycfC
42-
// CHECK: [[INSTANCE:%[^,]+]] = apply [[INIT_C]]({{%[0-9]+}})
43-
// CHECK: [[BORROW:%[^,]+]] = begin_borrow [lexical] [[INSTANCE]] : $C
44-
// CHECK: end_borrow [[BORROW:%[^,]+]]
45-
// CHECK-LABEL: } // end sil function 'lexical_borrow_let_class'
46-
@_silgen_name("lexical_borrow_let_class")
47-
func lexical_borrow_let_class() {
48-
let c = C()
49-
}
50-
51-
// CHECK-LABEL: sil hidden [ossa] @lexical_borrow_if_let_class
52-
// CHECK: [[INIT_C:%[^,]+]] = function_ref @$s6borrow1CC8failablyACSgyt_tcfC
53-
// CHECK: [[INSTANCE:%[^,]+]] = apply [[INIT_C]]({{%[^,]+}})
54-
// CHECK: switch_enum [[INSTANCE]] : $Optional<C>, case #Optional.some!enumelt: [[BASIC_BLOCK2:bb[^,]+]], case #Optional.none!enumelt: {{bb[^,]+}}
55-
// CHECK: [[BASIC_BLOCK2]]([[INSTANCE:%[^,]+]] : @owned $C):
56-
// CHECK: [[BORROW:%[^,]+]] = begin_borrow [lexical] [[INSTANCE]] : $C
57-
// CHECK: end_borrow [[BORROW]] : $C
58-
// CHECK-LABEL: // end sil function 'lexical_borrow_if_let_class'
59-
@_silgen_name("lexical_borrow_if_let_class")
60-
func lexical_borrow_if_let_class() {
61-
if let c = C(failably: ()) {
62-
use(())
63-
}
64-
}
65-
66-
struct S {
67-
let c: C
68-
}
69-
70-
// CHECK-LABEL: sil hidden [ossa] @lexical_borrow_let_class_in_struct
71-
// CHECK: [[INIT_S:%[^,]+]] = function_ref @$s6borrow1SV1cAcA1CC_tcfC
72-
// CHECK: [[INSTANCE:%[^,]+]] = apply [[INIT_S]]({{%[0-9]+}}, {{%[0-9]+}})
73-
// CHECK: [[BORROW:%[^,]+]] = begin_borrow [lexical] [[INSTANCE]] : $S
74-
// CHECK: end_borrow [[BORROW:%[^,]+]]
75-
// CHECK-LABEL: } // end sil function 'lexical_borrow_let_class_in_struct'
76-
@_silgen_name("lexical_borrow_let_class_in_struct")
77-
func lexical_borrow_let_class_in_struct() {
78-
let s = S(c: C())
79-
}
80-
81-
enum E {
82-
case e(C)
83-
}
84-
85-
// CHECK-LABEL: sil hidden [ossa] @lexical_borrow_let_class_in_enum
86-
// CHECK: [[INSTANCE:%[^,]+]] = enum $E, #E.e!enumelt, {{%[0-9]+}} : $C
87-
// CHECK: [[BORROW:%[^,]+]] = begin_borrow [lexical] [[INSTANCE]] : $E
88-
// CHECK: end_borrow [[BORROW:%[^,]+]]
89-
// CHECK-LABEL: } // end sil function 'lexical_borrow_let_class_in_enum'
90-
@_silgen_name("lexical_borrow_let_class_in_enum")
91-
func lexical_borrow_let_class_in_enum() {
92-
let s = E.e(C())
93-
}

test/SILGen/lexical_lifetime.swift

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
// RUN: %target-swift-emit-silgen -enable-experimental-lexical-lifetimes -module-name borrow -parse-stdlib %s | %FileCheck %s
2+
3+
import Swift
4+
5+
////////////////////////////////////////////////////////////////////////////////
6+
// Declarations {{
7+
////////////////////////////////////////////////////////////////////////////////
8+
9+
final class C {
10+
init() {}
11+
init?(failably: ()) {}
12+
}
13+
14+
struct S {
15+
let c: C
16+
}
17+
18+
struct Trivial {
19+
let i: Int
20+
}
21+
22+
enum E {
23+
case e(C)
24+
}
25+
26+
@_silgen_name("use_generic")
27+
func use_generic<T>(_ t: T) {}
28+
29+
////////////////////////////////////////////////////////////////////////////////
30+
// Declarations }}
31+
////////////////////////////////////////////////////////////////////////////////
32+
33+
34+
////////////////////////////////////////////////////////////////////////////////
35+
// Tests {{
36+
////////////////////////////////////////////////////////////////////////////////
37+
38+
// let bindings:
39+
40+
// CHECK-LABEL: sil hidden [ossa] @lexical_borrow_let_class
41+
// CHECK: [[INIT_C:%[^,]+]] = function_ref @$s6borrow1CCACycfC
42+
// CHECK: [[INSTANCE:%[^,]+]] = apply [[INIT_C]]({{%[0-9]+}})
43+
// CHECK: [[BORROW:%[^,]+]] = begin_borrow [lexical] [[INSTANCE]] : $C
44+
// CHECK: end_borrow [[BORROW:%[^,]+]]
45+
// CHECK-LABEL: } // end sil function 'lexical_borrow_let_class'
46+
@_silgen_name("lexical_borrow_let_class")
47+
func lexical_borrow_let_class() {
48+
let c = C()
49+
}
50+
51+
// CHECK-LABEL: sil hidden [ossa] @lexical_borrow_if_let_class
52+
// CHECK: [[INIT_C:%[^,]+]] = function_ref @$s6borrow1CC8failablyACSgyt_tcfC
53+
// CHECK: [[INSTANCE:%[^,]+]] = apply [[INIT_C]]({{%[^,]+}})
54+
// CHECK: switch_enum [[INSTANCE]] : $Optional<C>, case #Optional.some!enumelt: [[BASIC_BLOCK2:bb[^,]+]], case #Optional.none!enumelt: {{bb[^,]+}}
55+
// CHECK: [[BASIC_BLOCK2]]([[INSTANCE:%[^,]+]] : @owned $C):
56+
// CHECK: [[BORROW:%[^,]+]] = begin_borrow [lexical] [[INSTANCE]] : $C
57+
// CHECK: end_borrow [[BORROW]] : $C
58+
// CHECK-LABEL: // end sil function 'lexical_borrow_if_let_class'
59+
@_silgen_name("lexical_borrow_if_let_class")
60+
func lexical_borrow_if_let_class() {
61+
if let c = C(failably: ()) {
62+
use_generic(())
63+
}
64+
}
65+
66+
// CHECK-LABEL: sil hidden [ossa] @lexical_borrow_let_class_in_struct
67+
// CHECK: [[INIT_S:%[^,]+]] = function_ref @$s6borrow1SV1cAcA1CC_tcfC
68+
// CHECK: [[INSTANCE:%[^,]+]] = apply [[INIT_S]]({{%[0-9]+}}, {{%[0-9]+}})
69+
// CHECK: [[BORROW:%[^,]+]] = begin_borrow [lexical] [[INSTANCE]] : $S
70+
// CHECK: end_borrow [[BORROW:%[^,]+]]
71+
// CHECK-LABEL: } // end sil function 'lexical_borrow_let_class_in_struct'
72+
@_silgen_name("lexical_borrow_let_class_in_struct")
73+
func lexical_borrow_let_class_in_struct() {
74+
let s = S(c: C())
75+
}
76+
77+
// CHECK-LABEL: sil hidden [ossa] @lexical_borrow_let_class_in_enum
78+
// CHECK: [[INSTANCE:%[^,]+]] = enum $E, #E.e!enumelt, {{%[0-9]+}} : $C
79+
// CHECK: [[BORROW:%[^,]+]] = begin_borrow [lexical] [[INSTANCE]] : $E
80+
// CHECK: end_borrow [[BORROW:%[^,]+]]
81+
// CHECK-LABEL: } // end sil function 'lexical_borrow_let_class_in_enum'
82+
@_silgen_name("lexical_borrow_let_class_in_enum")
83+
func lexical_borrow_let_class_in_enum() {
84+
let s = E.e(C())
85+
}
86+
87+
// arguments:
88+
89+
// CHECK-LABEL: sil hidden [ossa] @lexical_borrow_arg_guaranteed_class : $@convention(thin) (@guaranteed C) -> () {
90+
// CHECK: {{bb[^,]+}}([[INSTANCE:%[^,]+]] : @guaranteed $C):
91+
// CHECK: [[LIFETIME:%[^,]+]] = begin_borrow [lexical] [[INSTANCE]]
92+
// CHECK: debug_value [[LIFETIME]]
93+
// CHECK: [[ADDR:%[^,]+]] = alloc_stack $C
94+
// CHECK: store_borrow [[LIFETIME]] to [[ADDR]]
95+
// CHECK: [[USE_GENERIC:%[^,]+]] = function_ref @use_generic
96+
// CHECK: [[REGISTER_6:%[^,]+]] = apply [[USE_GENERIC]]<C>([[ADDR]])
97+
// CHECK: dealloc_stack [[ADDR]]
98+
// CHECK: end_borrow [[LIFETIME]]
99+
// CHECK: [[RETVAL:%[^,]+]] = tuple ()
100+
// CHECK: return [[RETVAL]]
101+
// CHECK-LABEL: } // end sil function 'lexical_borrow_arg_guaranteed_class'
102+
@_silgen_name("lexical_borrow_arg_guaranteed_class")
103+
func lexical_borrow_arg_guaranteed_class(_ c: C) {
104+
use_generic(c)
105+
}
106+
107+
// CHECK-LABEL: sil hidden [ossa] @lexical_borrow_arg_class_addr : $@convention(thin) (@inout C) -> () {
108+
// CHECK-NOT: begin_borrow [lexical]
109+
// CHECK-LABEL: } // end sil function 'lexical_borrow_arg_class_addr'
110+
@_silgen_name("lexical_borrow_arg_class_addr")
111+
func lexical_borrow_arg_class_addr(_ c: inout C) {
112+
use_generic(c)
113+
}
114+
115+
// CHECK-LABEL: sil hidden [ossa] @lexical_borrow_arg_trivial : $@convention(thin) (Trivial) -> () {
116+
// CHECK-NOT: begin_borrow [lexical]
117+
// CHECK-LABEL: } // end sil function 'lexical_borrow_arg_trivial'
118+
@_silgen_name("lexical_borrow_arg_trivial")
119+
func lexical_borrow_arg_trivial(_ trivial: Trivial) {
120+
use_generic(trivial)
121+
}
122+
123+
////////////////////////////////////////////////////////////////////////////////
124+
// Test }}
125+
////////////////////////////////////////////////////////////////////////////////
126+

0 commit comments

Comments
 (0)