Skip to content

Commit 7a4f3a3

Browse files
committed
[SILOpt] Don't opt move-only lifetimes.
According to language rules, such lifetimes are fixed and the relative order of their deinits is guaranteed. rdar://110913116
1 parent 2cf1917 commit 7a4f3a3

File tree

4 files changed

+91
-0
lines changed

4 files changed

+91
-0
lines changed

lib/SILOptimizer/Transforms/SSADestroyHoisting.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -870,6 +870,11 @@ bool hoistDestroys(SILValue root, bool ignoreDeinitBarriers,
870870
BasicCalleeAnalysis *calleeAnalysis) {
871871
LLVM_DEBUG(llvm::dbgs() << "Performing destroy hoisting on " << root);
872872

873+
// Don't canonicalize the lifetimes of addresses of move-only type.
874+
// According to language rules, they are fixed.
875+
if (root->getType().isMoveOnly())
876+
return false;
877+
873878
SILFunction *function = root->getFunction();
874879
if (!function)
875880
return false;

lib/SILOptimizer/Utils/CanonicalizeOSSALifetime.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1084,6 +1084,12 @@ void CanonicalizeOSSALifetime::rewriteLifetimes() {
10841084
bool CanonicalizeOSSALifetime::canonicalizeValueLifetime(SILValue def) {
10851085
LivenessState livenessState(*this, def);
10861086

1087+
// Don't canonicalize the lifetimes of values of move-only type. According to
1088+
// language rules, they are fixed.
1089+
if (def->getType().isMoveOnly()) {
1090+
return false;
1091+
}
1092+
10871093
// Step 1: Compute liveness.
10881094
if (!computeLiveness()) {
10891095
LLVM_DEBUG(llvm::dbgs() << "Failed to compute liveness boundary!\n");

test/SILOptimizer/canonicalize_ossa_lifetime_unit.sil

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
class C {}
44

5+
@_moveOnly struct MoS {}
6+
@_moveOnly struct MoE {}
7+
58
// When access scopes are respected, the lifetime which previously extended
69
// beyond the access scope still extends beyond it.
710
// CHECK-LABEL: begin running test 1 of 2 on retract_value_lifetime_into_access_scope_when_access_scopes_not_respected: canonicalize-ossa-lifetime with: true, false, true, @trace
@@ -45,3 +48,46 @@ bb0(%addr : $*C):
4548
%retval = tuple ()
4649
return %retval : $()
4750
}
51+
52+
sil @empty : $@convention(thin) () -> () {
53+
[global: ]
54+
bb0:
55+
%0 = tuple ()
56+
return %0 : $()
57+
}
58+
59+
// Even though the apply of %empty is not a deinit barrier, verify that the
60+
// destroy is not hoisted, because MoS is move-only.
61+
// CHECK-LABEL: begin running test {{.*}} on dont_move_destroy_value_of_moveonly_struct: canonicalize-ossa-lifetime with: true, false, true, @argument
62+
// CHECK-LABEL: sil [ossa] @dont_move_destroy_value_of_moveonly_struct : {{.*}} {
63+
// CHECK: {{bb[0-9]+}}([[INSTANCE:%[^,]+]] :
64+
// CHECK: apply
65+
// CHECK: destroy_value [[INSTANCE]]
66+
// CHECK-LABEL: } // end sil function 'dont_move_destroy_value_of_moveonly_struct'
67+
// CHECK-LABEL: end running test {{.*}} on dont_move_destroy_value_of_moveonly_struct: canonicalize-ossa-lifetime with: true, false, true, @argument
68+
sil [ossa] @dont_move_destroy_value_of_moveonly_struct : $@convention(thin) (@owned MoS) -> () {
69+
entry(%instance : @owned $MoS):
70+
test_specification "canonicalize-ossa-lifetime true false true @argument"
71+
%empty = function_ref @empty : $@convention(thin) () -> ()
72+
apply %empty() : $@convention(thin) () -> ()
73+
destroy_value %instance : $MoS
74+
%retval = tuple ()
75+
return %retval : $()
76+
}
77+
78+
// CHECK-LABEL: begin running test {{.*}} on dont_move_destroy_value_of_moveonly_enum: canonicalize-ossa-lifetime with: true, false, true, @argument
79+
// CHECK-LABEL: sil [ossa] @dont_move_destroy_value_of_moveonly_enum : {{.*}} {
80+
// CHECK: {{bb[0-9]+}}([[INSTANCE:%[^,]+]] :
81+
// CHECK: apply
82+
// CHECK: destroy_value [[INSTANCE]]
83+
// CHECK-LABEL: } // end sil function 'dont_move_destroy_value_of_moveonly_enum'
84+
// CHECK-LABEL: end running test {{.*}} on dont_move_destroy_value_of_moveonly_enum: canonicalize-ossa-lifetime with: true, false, true, @argument
85+
sil [ossa] @dont_move_destroy_value_of_moveonly_enum : $@convention(thin) (@owned MoE) -> () {
86+
entry(%instance : @owned $MoE):
87+
test_specification "canonicalize-ossa-lifetime true false true @argument"
88+
%empty = function_ref @empty : $@convention(thin) () -> ()
89+
apply %empty() : $@convention(thin) () -> ()
90+
destroy_value %instance : $MoE
91+
%retval = tuple ()
92+
return %retval : $()
93+
}

test/SILOptimizer/hoist_destroy_addr.sil

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,9 @@ struct STXXITXXII {
7979
var i: I
8080
}
8181

82+
@_moveOnly struct MoS {}
83+
@_moveOnly struct MoE {}
84+
8285
sil @unknown : $@convention(thin) () -> ()
8386
sil @use_S : $@convention(thin) (@in_guaranteed S) -> ()
8487

@@ -1145,3 +1148,34 @@ entry(%addr : $*X):
11451148
%retval = tuple ()
11461149
return %retval : $()
11471150
}
1151+
1152+
// Even though the apply of %empty is not a deinit barrier (c.f.
1153+
// hoist_over_apply_of_non_barrier_fn), verify that the destroy_addr is not
1154+
// hoisted, because MoS is move-only.
1155+
// CHECK-LABEL: sil [ossa] @dont_move_destroy_addr_of_moveonly_struct : {{.*}} {
1156+
// CHECK: {{bb[0-9]+}}([[ADDR:%[^,]+]] :
1157+
// CHECK: apply
1158+
// CHECK: destroy_addr [[ADDR]]
1159+
// CHECK-LABEL: } // end sil function 'dont_move_destroy_addr_of_moveonly_struct'
1160+
sil [ossa] @dont_move_destroy_addr_of_moveonly_struct : $@convention(thin) (@in MoS) -> () {
1161+
entry(%addr : $*MoS):
1162+
%empty = function_ref @empty : $@convention(thin) () -> ()
1163+
apply %empty() : $@convention(thin) () -> ()
1164+
destroy_addr %addr : $*MoS
1165+
%retval = tuple ()
1166+
return %retval : $()
1167+
}
1168+
1169+
// CHECK-LABEL: sil [ossa] @dont_move_destroy_addr_of_moveonly_enum : {{.*}} {
1170+
// CHECK: {{bb[0-9]+}}([[ADDR:%[^,]+]] :
1171+
// CHECK: apply
1172+
// CHECK: destroy_addr [[ADDR]]
1173+
// CHECK-LABEL: } // end sil function 'dont_move_destroy_addr_of_moveonly_enum'
1174+
sil [ossa] @dont_move_destroy_addr_of_moveonly_enum : $@convention(thin) (@in MoE) -> () {
1175+
entry(%addr : $*MoE):
1176+
%empty = function_ref @empty : $@convention(thin) () -> ()
1177+
apply %empty() : $@convention(thin) () -> ()
1178+
destroy_addr %addr : $*MoE
1179+
%retval = tuple ()
1180+
return %retval : $()
1181+
}

0 commit comments

Comments
 (0)