Skip to content

Commit 2ac6ea5

Browse files
committed
[SIL] Make owned function arguments lexical.
The destroys of owned arguments must not be hoisted over deinit barriers to respect the semantics of lexical lifetimes. Here, owned SILValues which are SILFunctionArguments are made to be lexical. Code which hoists destroys will check this field and not hoist destroys. Allowed more RAUWing to be done with lexical values; specifically, allowed the replacement of a non-lexical value with a lexical value if the replacing value's lifetime wouldn't be extended as a result. Updated tests to get owned values via applies rather than having them passed as arguments.
1 parent f8bcfe2 commit 2ac6ea5

File tree

8 files changed

+274
-183
lines changed

8 files changed

+274
-183
lines changed

lib/SIL/IR/SILValue.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -99,10 +99,8 @@ ValueBase::getDefiningInstructionResult() {
9999
}
100100

101101
bool ValueBase::isLexical() const {
102-
// TODO: Eventually, rather than SILGen'ing a borrow scope for owned
103-
// arguments, we will just have this check here.
104-
// if (auto *argument = dyn_cast<SILArgument>(this))
105-
// return argument->getOwnershipKind() == OwnershipKind::Owned;
102+
if (auto *argument = dyn_cast<SILFunctionArgument>(this))
103+
return argument->getOwnershipKind() == OwnershipKind::Owned;
106104
if (auto *bbi = dyn_cast<BeginBorrowInst>(this))
107105
return bbi->isLexical();
108106
if (auto *mvi = dyn_cast<MoveValueInst>(this))

test/SILGen/moveonly_builtin.swift

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,9 @@ class Klass {}
3131
// CHECK-SIL-NEXT: debug_value
3232
// CHECK-SIL-NEXT: strong_retain
3333
// CHECK-SIL-NEXT: move_value
34-
// CHECK-SIL-NEXT: strong_release
35-
// CHECK-SIL-NEXT: debug_value [poison]
3634
// CHECK-SIL-NEXT: tuple
3735
// CHECK-SIL-NEXT: tuple
36+
// CHECK-SIL-NEXT: strong_release
3837
// CHECK-SIL-NEXT: return
3938
// CHECK-SIL: } // end sil function '$s8moveonly7useMoveyAA5KlassCADnF'
4039
func useMove(_ k: __owned Klass) -> Klass {
@@ -65,10 +64,9 @@ func useMove(_ k: __owned Klass) -> Klass {
6564
// CHECK-SIL-NEXT: debug_value
6665
// CHECK-SIL-NEXT: strong_retain
6766
// CHECK-SIL-NEXT: move_value
68-
// CHECK-SIL-NEXT: strong_release
69-
// CHECK-SIL-NEXT: debug_value [poison]
7067
// CHECK-SIL-NEXT: tuple
7168
// CHECK-SIL-NEXT: tuple
69+
// CHECK-SIL-NEXT: strong_release
7270
// CHECK-SIL-NEXT: return
7371
// CHECK-SIL: } // end sil function '$s8moveonly7useMoveyxxnRlzClF'
7472
func useMove<T : AnyObject>(_ k: __owned T) -> T {

test/SILOptimizer/copy_propagation.sil

Lines changed: 47 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ class C {
3030
sil [ossa] @dummy : $@convention(thin) () -> ()
3131
sil [ossa] @barrier : $@convention(thin) () -> ()
3232
sil [ossa] @getOwnedC : $@convention(thin) () -> (@owned C)
33+
sil [ossa] @getOwnedB : $@convention(thin) () -> (@owned B)
3334
sil [ossa] @takeOwnedC : $@convention(thin) (@owned C) -> ()
3435
sil [ossa] @takeOwnedCTwice : $@convention(thin) (@owned C, @owned C) -> ()
3536
sil [ossa] @takeGuaranteedC : $@convention(thin) (@guaranteed C) -> ()
@@ -38,14 +39,17 @@ sil [ossa] @takeGuaranteedAnyObject : $@convention(thin) (@guaranteed AnyObject)
3839
// -O ignores this because there's no copy_value
3940
// -Onone hoists the destroy and adds a poison flag.
4041
//
41-
// CHECK-LABEL: sil [ossa] @testDestroyAfterCall : $@convention(thin) (@owned B) -> () {
42-
// CHECK: bb0(%0 : @owned $B):
43-
// CHECK-ONONE: destroy_value [poison] %0 : $B
42+
// CHECK-LABEL: sil [ossa] @testDestroyAfterCall : {{.*}} {
43+
// CHECK: bb0:
44+
// CHECK: [[ARG:%.*]] = apply
45+
// CHECK-ONONE: destroy_value [poison] [[ARG]] : $B
4446
// CHECK: apply
45-
// CHECK-OPT: destroy_value %0 : $B
47+
// CHECK-OPT: destroy_value [[ARG]] : $B
4648
// CHECK-LABEL: } // end sil function 'testDestroyAfterCall'
47-
sil [ossa] @testDestroyAfterCall : $@convention(thin) (@owned B) -> () {
48-
bb0(%arg : @owned $B):
49+
sil [ossa] @testDestroyAfterCall : $@convention(thin) () -> () {
50+
bb0:
51+
%getOwnedB = function_ref @getOwnedB : $@convention(thin) () -> (@owned B)
52+
%arg = apply %getOwnedB() : $@convention(thin) () -> (@owned B)
4953
%f = function_ref @dummy : $@convention(thin) () -> ()
5054
%call = apply %f() : $@convention(thin) () -> ()
5155
destroy_value %arg : $B
@@ -57,19 +61,22 @@ bb0(%arg : @owned $B):
5761
// -Onone requres a destroy at the lifetime end. It reuses the
5862
// existing one without adding poison.
5963
//
60-
// CHECK-LABEL: sil [ossa] @testDestroyAfterConsumingStore : $@convention(thin) (@owned C) -> () {
61-
// CHECK: bb0(%0 : @owned $C):
64+
// CHECK-LABEL: sil [ossa] @testDestroyAfterConsumingStore : {{.*}} {
65+
// CHECK: bb0:
66+
// CHECK: [[ARG:%.*]] = apply
6267
// CHECK: [[ADR:%.*]] = alloc_stack $C
6368
// CHECK-OPT-NOT: copy_value
64-
// CHECK-OPT: store %0 to [init] [[ADR]] : $*C
65-
// CHECK-ONONE: [[CP:%.*]] = copy_value %0 : $C
69+
// CHECK-OPT: store [[ARG]] to [init] [[ADR]] : $*C
70+
// CHECK-ONONE: [[CP:%.*]] = copy_value [[ARG]] : $C
6671
// CHECK-ONONE: store [[CP]] to [init] [[ADR]] : $*C
6772
// CHECK-OPT-NOT: destroy_value
68-
// CHECK-ONONE: destroy_value %0 : $C
73+
// CHECK-ONONE: destroy_value [[ARG]] : $C
6974
// CHECK: destroy_addr
7075
// CHECK-LABEL: } // end sil function 'testDestroyAfterConsumingStore'
71-
sil [ossa] @testDestroyAfterConsumingStore : $@convention(thin) (@owned C) -> () {
72-
bb0(%arg : @owned $C):
76+
sil [ossa] @testDestroyAfterConsumingStore : $@convention(thin) () -> () {
77+
bb0:
78+
%getOwnedC = function_ref @getOwnedC : $@convention(thin) () -> (@owned C)
79+
%arg = apply %getOwnedC() : $@convention(thin) () -> (@owned C)
7380
%adr = alloc_stack $C
7481
%copy = copy_value %arg : $C
7582
store %copy to [init] %adr : $*C
@@ -83,19 +90,22 @@ bb0(%arg : @owned $C):
8390
// -O removes the copy/destroy
8491
// -Onone requres a destroy at the lifetime end. It creates a new poison one.
8592
//
86-
// CHECK-LABEL: sil [ossa] @testDestroyAfterConsumingStoreAndCall : $@convention(thin) (@owned C) -> () {
87-
// CHECK: bb0(%0 : @owned $C):
93+
// CHECK-LABEL: sil [ossa] @testDestroyAfterConsumingStoreAndCall : {{.*}} {
94+
// CHECK: bb0:
95+
// CHECK: [[ARG:%.*]] = apply
8896
// CHECK: [[ADR:%.*]] = alloc_stack $C
8997
// CHECK-OPT-NOT: copy_value
90-
// CHECK-ONONE: copy_value %0 : $C
98+
// CHECK-ONONE: copy_value [[ARG]] : $C
9199
// CHECK: store %{{.*}} to [init] [[ADR]] : $*C
92100
// CHECK-OPT-NOT: destroy_value
93-
// CHECK-ONONE: destroy_value [poison] %0 : $C
101+
// CHECK-ONONE: destroy_value [poison] [[ARG]] : $C
94102
// CHECK: apply
95103
// CHECK: destroy_addr
96104
// CHECK-LABEL: } // end sil function 'testDestroyAfterConsumingStoreAndCall'
97-
sil [ossa] @testDestroyAfterConsumingStoreAndCall : $@convention(thin) (@owned C) -> () {
98-
bb0(%arg : @owned $C):
105+
sil [ossa] @testDestroyAfterConsumingStoreAndCall : $@convention(thin) () -> () {
106+
bb0:
107+
%getOwnedC = function_ref @getOwnedC : $@convention(thin) () -> (@owned C)
108+
%arg = apply %getOwnedC() : $@convention(thin) () -> (@owned C)
99109
%adr = alloc_stack $C
100110
%copy = copy_value %arg : $C
101111
store %copy to [init] %adr : $*C
@@ -111,16 +121,19 @@ bb0(%arg : @owned $C):
111121
// -O removes the copy/destroy
112122
// -Onone reuses the existint lifetime-ending destroy.
113123
//
114-
// CHECK-LABEL: sil [ossa] @testDestroyAfterConsumingCall : $@convention(thin) (@owned C) -> () {
115-
// CHECK: bb0(%0 : @owned $C):
124+
// CHECK-LABEL: sil [ossa] @testDestroyAfterConsumingCall : {{.*}} {
125+
// CHECK: bb0:
126+
// CHECK: [[ARG:%.*]] = apply
116127
// CHECK-OPT-NOT: copy_value
117-
// CHECK-ONONE: %1 = copy_value %0 : $C
128+
// CHECK-ONONE: copy_value [[ARG]] : $C
118129
// CHECK: apply {{.*}} : $@convention(thin) (@owned C) -> ()
119130
// CHECK-OPT-NOT: destroy_value
120-
// CHECK-ONONE: destroy_value %0 : $C
131+
// CHECK-ONONE: destroy_value [[ARG]] : $C
121132
// CHECK-LABEL: } // end sil function 'testDestroyAfterConsumingCall'
122-
sil [ossa] @testDestroyAfterConsumingCall : $@convention(thin) (@owned C) -> () {
123-
bb0(%arg : @owned $C):
133+
sil [ossa] @testDestroyAfterConsumingCall : $@convention(thin) () -> () {
134+
bb0:
135+
%getOwnedC = function_ref @getOwnedC : $@convention(thin) () -> (@owned C)
136+
%arg = apply %getOwnedC() : $@convention(thin) () -> (@owned C)
124137
%copy = copy_value %arg : $C
125138
%f = function_ref @takeOwnedC : $@convention(thin) (@owned C) -> ()
126139
%call = apply %f(%copy) : $@convention(thin) (@owned C) -> ()
@@ -132,17 +145,20 @@ bb0(%arg : @owned $C):
132145
// -O removes the copy/destroy
133146
// -Onone requres a destroy at the lifetime end. It creates a new poison one.
134147
//
135-
// CHECK-LABEL: sil [ossa] @testDestroyAfterConsumingCallAndCall : $@convention(thin) (@owned C) -> () {
136-
// CHECK: bb0(%0 : @owned $C):
148+
// CHECK-LABEL: sil [ossa] @testDestroyAfterConsumingCallAndCall : {{.*}} {
149+
// CHECK: bb0:
150+
// CHECK: [[ARG:%.*]] = apply
137151
// CHECK-OPT-NOT: copy_value
138-
// CHECK-ONONE: copy_value %0 : $C
152+
// CHECK-ONONE: copy_value [[ARG]] : $C
139153
// CHECK: apply %{{.*}}(%{{.*}}) : $@convention(thin) (@owned C) -> ()
140154
// CHECK-OPT-NOT: destroy_value
141-
// CHECK-ONONE: destroy_value [poison] %0 : $C
155+
// CHECK-ONONE: destroy_value [poison] [[ARG]] : $C
142156
// CHECK: apply
143157
// CHECK-LABEL: } // end sil function 'testDestroyAfterConsumingCallAndCall'
144-
sil [ossa] @testDestroyAfterConsumingCallAndCall : $@convention(thin) (@owned C) -> () {
145-
bb0(%arg : @owned $C):
158+
sil [ossa] @testDestroyAfterConsumingCallAndCall : $@convention(thin) () -> () {
159+
bb0:
160+
%getOwnedC = function_ref @getOwnedC : $@convention(thin) () -> (@owned C)
161+
%arg = apply %getOwnedC() : $@convention(thin) () -> (@owned C)
146162
%copy = copy_value %arg : $C
147163
%f1 = function_ref @takeOwnedC : $@convention(thin) (@owned C) -> ()
148164
%call1 = apply %f1(%copy) : $@convention(thin) (@owned C) -> ()

0 commit comments

Comments
 (0)