Skip to content

Commit 80ba5b5

Browse files
committed
[SSADestroyHoisting] Only lexical alloc_stacks respect deinit barriers.
1 parent b0fb7c5 commit 80ba5b5

File tree

3 files changed

+184
-23
lines changed

3 files changed

+184
-23
lines changed

lib/SILOptimizer/Transforms/SSADestroyHoisting.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -962,7 +962,7 @@ void SSADestroyHoisting::run() {
962962
}
963963
// Alloc stacks always enclose their accesses.
964964
for (auto *asi : asis) {
965-
changed |= hoistDestroys(asi, /*ignoreDeinitBarriers=*/false,
965+
changed |= hoistDestroys(asi, /*ignoreDeinitBarriers=*/!asi->isLexical(),
966966
remainingDestroyAddrs, deleter);
967967
}
968968
// Arguments enclose everything.

test/SILOptimizer/hoist_destroy_addr.sil

Lines changed: 148 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
// RUN: %target-sil-opt -opt-mode=none -enable-sil-verify-all %s -ssa-destroy-hoisting | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECKDEB
2-
// RUN: %target-sil-opt -opt-mode=speed -enable-sil-verify-all %s -ssa-destroy-hoisting | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECKOPT
1+
// RUN: %target-sil-opt -opt-mode=none -enable-sil-verify-all %s -ssa-destroy-hoisting | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECKDEB --check-prefix=CHECK-DEB
2+
// RUN: %target-sil-opt -opt-mode=speed -enable-sil-verify-all %s -ssa-destroy-hoisting | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECKOPT --check-prefix=CHECK-OPT
33
//
44
// TODO: migrate the remaining tests from destroy_hoisting.sil.
55

@@ -188,9 +188,9 @@ bb0(%0 : $*T):
188188
// bb2. Dead debug instructions then need to be deleted before the
189189
// destroy can be merged back onto bb3.
190190
//
191-
// CHECK-LABEL: sil hidden [ossa] @destroyDiamond : $@convention(thin) <T> (@in_guaranteed T, Builtin.Int1) -> () {
191+
// CHECK-LABEL: sil hidden [ossa] @destroyDiamond_lexical : $@convention(thin) <T> (@in_guaranteed T, Builtin.Int1) -> () {
192192
// CHECK: bb0(%0 : $*T, %1 : $Builtin.Int1):
193-
// CHECK: [[ALLOC:%.*]] = alloc_stack $T, var, name "t"
193+
// CHECK: [[ALLOC:%.*]] = alloc_stack [lexical] $T, var, name "t"
194194
// CHECK-NOT: destroy
195195
// CHECK: cond_br %{{.*}}, bb1, bb2
196196
// CHECK: bb1:
@@ -199,13 +199,60 @@ bb0(%0 : $*T):
199199
// CHECK: br bb3
200200
// CHECK: bb2:
201201
// CHECKDEB: debug_value [[ALLOC]] : $*T, let, name "t"
202-
// CHECK-NOT: debug_val [[ALLOC]]
202+
// CHECK-NOT: debug_value [[ALLOC]]
203203
// CHECK: br bb3
204204
// CHECK: bb3:
205205
// CHECK: destroy_addr [[ALLOC]] : $*T
206206
// CHECK: return
207-
// CHECK-LABEL: } // end sil function 'destroyDiamond'
208-
sil hidden [ossa] @destroyDiamond : $@convention(thin) <T> (@in_guaranteed T, Builtin.Int1) -> () {
207+
// CHECK-LABEL: } // end sil function 'destroyDiamond_lexical'
208+
sil hidden [ossa] @destroyDiamond_lexical : $@convention(thin) <T> (@in_guaranteed T, Builtin.Int1) -> () {
209+
bb0(%0 : $*T, %1 : $Builtin.Int1):
210+
debug_value %0 : $*T, let, name "arg", argno 1, expr op_deref
211+
debug_value %1 : $Builtin.Int1, let, name "z", argno 2
212+
%4 = alloc_stack [lexical] $T, var, name "t"
213+
copy_addr %0 to [initialization] %4 : $*T
214+
cond_br %1, bb1, bb2
215+
216+
bb1:
217+
%8 = function_ref @unknown : $@convention(thin) () -> ()
218+
%9 = apply %8() : $@convention(thin) () -> ()
219+
br bb3
220+
221+
bb2:
222+
debug_value %4 : $*T, let, name "t"
223+
br bb3
224+
225+
bb3:
226+
destroy_addr %4 : $*T
227+
dealloc_stack %4 : $*T
228+
%14 = tuple ()
229+
return %14 : $()
230+
}
231+
232+
// In contrast to the lexical variant (destroyDiamond_lexical), the destroy can
233+
// be hoisted over the unknown apply. In the debug case, it can't be hoisted
234+
// over the debug_value. In the optimized case, it can be hoisted up to the
235+
// entry block.
236+
//
237+
// CHECK-LABEL: sil hidden [ossa] @destroyDiamond_nonlexical : $@convention(thin) <T> (@in_guaranteed T, Builtin.Int1) -> () {
238+
// CHECK: {{bb[0-9]+}}
239+
// CHECK: [[ALLOC:%.*]] = alloc_stack
240+
// CHECK-OPT: destroy_addr [[ALLOC]]
241+
// CHECK: cond_br %{{.*}}, [[LEFT:bb[0-9]+]], [[RIGHT:bb[0-9]+]]
242+
// CHECK: [[LEFT]]:
243+
// CHECK-DBG: destroy_addr [[ALLOC]]
244+
// CHECK: apply %{{.*}}()
245+
// CHECK-NOT: destroy_addr
246+
// CHECK: br [[EXIT:bb[0-9]+]]
247+
// CHECK: [[RIGHT]]:
248+
// CHECK-OPT-NOT: debug_value [[ALLOC]]
249+
// CHECK-DBG: debug_value [[ALLOC]]
250+
// CHECK-DBG: destroy_addr [[ALLOC]]
251+
// CHECK: br [[EXIT]]
252+
// CHECK: [[EXIT]]:
253+
// CHECK: return
254+
// CHECK-LABEL: } // end sil function 'destroyDiamond_nonlexical'
255+
sil hidden [ossa] @destroyDiamond_nonlexical : $@convention(thin) <T> (@in_guaranteed T, Builtin.Int1) -> () {
209256
bb0(%0 : $*T, %1 : $Builtin.Int1):
210257
debug_value %0 : $*T, let, name "arg", argno 1, expr op_deref
211258
debug_value %1 : $Builtin.Int1, let, name "z", argno 2
@@ -229,8 +276,8 @@ bb3:
229276
return %14 : $()
230277
}
231278

232-
// CHECK-LABEL: sil hidden [ossa] @destroyLoop : $@convention(thin) <T> (@in_guaranteed T) -> () {
233-
// CHECK: [[ALLOC:%.*]] = alloc_stack $T, var, name "t"
279+
// CHECK-LABEL: sil hidden [ossa] @destroyLoop_lexical : $@convention(thin) <T> (@in_guaranteed T) -> () {
280+
// CHECK: [[ALLOC:%.*]] = alloc_stack [lexical] $T, var, name "t"
234281
// CHECK: br bb1
235282
// CHECK: bb1:
236283
// CHECK: apply %{{.*}}() : $@convention(thin) () -> Builtin.Int1
@@ -242,8 +289,45 @@ bb3:
242289
// CHECKOPT-NOT: debug_value
243290
// CHECK: destroy_addr [[ALLOC]] : $*T
244291
// CHECK: dealloc_stack [[ALLOC]] : $*T
245-
// CHECK-LABEL: } // end sil function 'destroyLoop'
246-
sil hidden [ossa] @destroyLoop : $@convention(thin) <T> (@in_guaranteed T) -> () {
292+
// CHECK-LABEL: } // end sil function 'destroyLoop_lexical'
293+
sil hidden [ossa] @destroyLoop_lexical : $@convention(thin) <T> (@in_guaranteed T) -> () {
294+
bb0(%0 : $*T):
295+
%a = alloc_stack [lexical] $T, var, name "t"
296+
copy_addr %0 to [initialization] %a : $*T
297+
br bb1
298+
299+
bb1:
300+
%f = function_ref @f_bool : $@convention(thin) () -> Builtin.Int1
301+
%c = apply %f() : $@convention(thin) () -> Builtin.Int1
302+
cond_br %c, bb2, bb3
303+
304+
bb2:
305+
br bb1
306+
307+
bb3:
308+
debug_value %a : $*T, let, name "t"
309+
destroy_addr %a : $*T
310+
dealloc_stack %a : $*T
311+
%16 = tuple ()
312+
return %16 : $()
313+
}
314+
315+
// CHECK-LABEL: sil hidden [ossa] @destroyLoop_nonlexical : $@convention(thin) <T> (@in_guaranteed T) -> () {
316+
// CHECK: [[ALLOC:%.*]] = alloc_stack $T, var, name "t"
317+
// CHECK-OPT: destroy_addr [[ALLOC]]
318+
// CHECK: br bb1
319+
// CHECK: bb1:
320+
// CHECK: apply %{{.*}}() : $@convention(thin) () -> Builtin.Int1
321+
// CHECK-NEXT: cond_br %{{.*}}, bb2, bb3
322+
// CHECK: bb2:
323+
// CHECK-NEXT: br bb1
324+
// CHECK: bb3:
325+
// CHECK-DEB: debug_value [[ALLOC]] : $*T, let, name "t"
326+
// CHECK-OPT-NOT: debug_value
327+
// CHECK-DEB: destroy_addr [[ALLOC]] : $*T
328+
// CHECK: dealloc_stack [[ALLOC]] : $*T
329+
// CHECK-LABEL: } // end sil function 'destroyLoop_nonlexical'
330+
sil hidden [ossa] @destroyLoop_nonlexical : $@convention(thin) <T> (@in_guaranteed T) -> () {
247331
bb0(%0 : $*T):
248332
%a = alloc_stack $T, var, name "t"
249333
copy_addr %0 to [initialization] %a : $*T
@@ -352,11 +436,34 @@ exit:
352436
// unreachable-at-begin block is added to the worklist but its predecessor
353437
// isn't discovered.
354438
//
355-
// CHECK-LABEL: sil [ossa] @undiscovered_predecessor_of_unreachable_at_begin : {{.*}} {
439+
// CHECK-LABEL: sil [ossa] @undiscovered_predecessor_of_unreachable_at_begin_lexical : {{.*}} {
356440
// CHECK: apply undef
357441
// CHECK-NEXT: destroy_addr
358-
// CHECK-LABEL: } // end sil function 'undiscovered_predecessor_of_unreachable_at_begin'
359-
sil [ossa] @undiscovered_predecessor_of_unreachable_at_begin : $@convention(thin) (@owned S) -> () {
442+
// CHECK-LABEL: } // end sil function 'undiscovered_predecessor_of_unreachable_at_begin_lexical'
443+
sil [ossa] @undiscovered_predecessor_of_unreachable_at_begin_lexical : $@convention(thin) (@owned S) -> () {
444+
entry(%instance : @owned $S):
445+
%addr = alloc_stack [lexical] $S
446+
store %instance to [init] %addr : $*S
447+
br applier
448+
449+
applier:
450+
apply undef() : $@convention(thin) () -> ()
451+
br good
452+
453+
good:
454+
destroy_addr %addr : $*S
455+
dealloc_stack %addr : $*S
456+
%retval = tuple ()
457+
return %retval : $()
458+
}
459+
460+
// In contrast to the lexical case (undiscovered_predecessor_of_unreachable_at_begin_lexical)
461+
//
462+
// CHECK-LABEL: sil [ossa] @undiscovered_predecessor_of_unreachable_at_begin_nonlexical : {{.*}} {
463+
// CHECK: store
464+
// CHECK-NEXT: destroy_addr
465+
// CHECK-LABEL: } // end sil function 'undiscovered_predecessor_of_unreachable_at_begin_nonlexical'
466+
sil [ossa] @undiscovered_predecessor_of_unreachable_at_begin_nonlexical : $@convention(thin) (@owned S) -> () {
360467
entry(%instance : @owned $S):
361468
%addr = alloc_stack $S
362469
store %instance to [init] %addr : $*S
@@ -545,10 +652,32 @@ entry(%instance : @owned $S):
545652

546653
// Don't fold when there's a deinit barrier in the way.
547654
//
548-
// CHECK-LABEL: sil [ossa] @nofold_scoped_load_barrier : {{.*}} {
655+
// CHECK-LABEL: sil [ossa] @nofold_scoped_load_barrier_lexical : {{.*}} {
549656
// CHECK: load [copy]
550-
// CHECK-LABEL: // end sil function 'nofold_scoped_load_barrier'
551-
sil [ossa] @nofold_scoped_load_barrier : $@convention(thin) (@owned S) -> (@owned S) {
657+
// CHECK-LABEL: // end sil function 'nofold_scoped_load_barrier_lexical'
658+
sil [ossa] @nofold_scoped_load_barrier_lexical : $@convention(thin) (@owned S) -> (@owned S) {
659+
entry(%instance : @owned $S):
660+
%addr = alloc_stack [lexical] $S
661+
%store_scope = begin_access [modify] [static] %addr : $*S
662+
store %instance to [init] %store_scope : $*S
663+
end_access %store_scope : $*S
664+
%load_scope = begin_access [read] [static] %addr : $*S
665+
%value = load [copy] %load_scope : $*S
666+
%unknown = function_ref @unknown : $@convention(thin) () -> ()
667+
apply %unknown() : $@convention(thin) () -> ()
668+
end_access %load_scope : $*S
669+
destroy_addr %addr : $*S
670+
dealloc_stack %addr : $*S
671+
return %value : $S
672+
}
673+
674+
// Fold when there's a deinit barrier in the way if the alloc_stack is
675+
// non-lexical.
676+
//
677+
// CHECK-LABEL: sil [ossa] @nofold_scoped_load_barrier_nonlexical : {{.*}} {
678+
// CHECK: load [take]
679+
// CHECK-LABEL: // end sil function 'nofold_scoped_load_barrier_nonlexical'
680+
sil [ossa] @nofold_scoped_load_barrier_nonlexical : $@convention(thin) (@owned S) -> (@owned S) {
552681
entry(%instance : @owned $S):
553682
%addr = alloc_stack $S
554683
%store_scope = begin_access [modify] [static] %addr : $*S
@@ -647,8 +776,8 @@ entry(%instance : @owned $S):
647776
sil [ossa] @nofold_unrelated_scoped_load_copy : $@convention(thin) (@owned X) -> (@owned X) {
648777
entry(%instance : @owned $X):
649778
%copy = copy_value %instance : $X
650-
%addr_1 = alloc_stack $X
651-
%addr_2 = alloc_stack $X
779+
%addr_1 = alloc_stack [lexical] $X
780+
%addr_2 = alloc_stack [lexical] $X
652781
store %instance to [init] %addr_1 : $*X
653782
store %copy to [init] %addr_2 : $*X
654783

test/SILOptimizer/hoist_destroy_addr_loop.sil

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,44 @@ bb4:
4141
return %23 : $()
4242
}
4343

44-
// CHECK-LABEL: sil [ossa] @nohoist_into_unrelated_access_scope_above_loop : {{.*}} {
44+
// CHECK-LABEL: sil [ossa] @nohoist_into_unrelated_access_scope_above_loop_lexical : {{.*}} {
4545
// CHECK: {{bb[0-9]+}}({{%[^,]+}} : @owned $X, [[REGISTER_1:%[^,]+]] : $*X):
4646
// CHECK: end_access
4747
// CHECK-NEXT: destroy_addr
48-
// CHECK-LABEL: } // end sil function 'nohoist_into_unrelated_access_scope_above_loop'
49-
sil [ossa] @nohoist_into_unrelated_access_scope_above_loop : $@convention(thin) (@owned X, @inout X) -> () {
48+
// CHECK-LABEL: } // end sil function 'nohoist_into_unrelated_access_scope_above_loop_lexical'
49+
sil [ossa] @nohoist_into_unrelated_access_scope_above_loop_lexical : $@convention(thin) (@owned X, @inout X) -> () {
50+
bb0(%instance : @owned $X, %second: $*X):
51+
%addr = alloc_stack [lexical] $X
52+
store %instance to [init] %addr : $*X
53+
%scope = begin_access [modify] [static] %second : $*X
54+
%1 = function_ref @get_owned_X : $@convention(thin) () -> @owned X
55+
%14 = apply %1() : $@convention(thin) () -> @owned X
56+
destroy_value %14 : $X
57+
end_access %scope : $*X
58+
br bb1
59+
60+
bb1:
61+
br bb2
62+
63+
bb2:
64+
cond_br undef, bb3, bb4
65+
66+
bb3:
67+
br bb1
68+
69+
bb4:
70+
destroy_addr %addr : $*X
71+
dealloc_stack %addr : $*X
72+
%23 = tuple ()
73+
return %23 : $()
74+
}
75+
76+
// CHECK-LABEL: sil [ossa] @nohoist_into_unrelated_access_scope_above_loop_nonlexical : {{.*}} {
77+
// CHECK: {{bb[0-9]+}}({{%[^,]+}} : @owned $X, [[REGISTER_1:%[^,]+]] : $*X):
78+
// CHECK: destroy_addr
79+
// CHECK: begin_access
80+
// CHECK-LABEL: } // end sil function 'nohoist_into_unrelated_access_scope_above_loop_nonlexical'
81+
sil [ossa] @nohoist_into_unrelated_access_scope_above_loop_nonlexical : $@convention(thin) (@owned X, @inout X) -> () {
5082
bb0(%instance : @owned $X, %second: $*X):
5183
%addr = alloc_stack $X
5284
store %instance to [init] %addr : $*X

0 commit comments

Comments
 (0)