Skip to content

Commit 0f319dd

Browse files
committed
[semantic-arc-opts] Eliminate all dead live ranges.
Previously, we only did single copy/destroys. Now we handle a copy + any number of destroy_values.
1 parent 3f61389 commit 0f319dd

File tree

2 files changed

+87
-3
lines changed

2 files changed

+87
-3
lines changed

lib/SILOptimizer/Mandatory/SemanticARCOpts.cpp

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -181,9 +181,10 @@ static bool performGuaranteedCopyValueOptimization(CopyValueInst *cvi) {
181181
return true;
182182
}
183183

184-
bool SemanticARCOptVisitor::visitCopyValueInst(CopyValueInst *cvi) {
185-
// If our copy value inst has a single destroy value user, eliminate
186-
// it.
184+
/// If cvi only has destroy value users, then cvi is a dead live range. Lets
185+
/// eliminate all such dead live ranges.
186+
static bool eliminateDeadLiveRangeCopyValue(CopyValueInst *cvi) {
187+
// See if we are lucky and have a simple case.
187188
if (auto *op = cvi->getSingleUse()) {
188189
if (auto *dvi = dyn_cast<DestroyValueInst>(op->getUser())) {
189190
dvi->eraseFromParent();
@@ -193,6 +194,38 @@ bool SemanticARCOptVisitor::visitCopyValueInst(CopyValueInst *cvi) {
193194
}
194195
}
195196

197+
// If all of our copy_value users are destroy_value, zap all of the
198+
// instructions. We begin by performing that check and gathering up our
199+
// destroy_value.
200+
SmallVector<DestroyValueInst *, 16> destroys;
201+
if (!all_of(cvi->getUses(), [&](Operand *op) {
202+
auto *dvi = dyn_cast<DestroyValueInst>(op->getUser());
203+
if (!dvi)
204+
return false;
205+
206+
// Stash dvi in destroys so we can easily eliminate it later.
207+
destroys.push_back(dvi);
208+
return true;
209+
})) {
210+
return false;
211+
}
212+
213+
// Now that we have a truly dead live range copy value, eliminate it!
214+
while (!destroys.empty()) {
215+
destroys.pop_back_val()->eraseFromParent();
216+
++NumEliminatedInsts;
217+
}
218+
cvi->eraseFromParent();
219+
++NumEliminatedInsts;
220+
return true;
221+
}
222+
223+
bool SemanticARCOptVisitor::visitCopyValueInst(CopyValueInst *cvi) {
224+
// If our copy value inst has only destroy_value users, it is a dead live
225+
// range. Try to eliminate them.
226+
if (eliminateDeadLiveRangeCopyValue(cvi))
227+
return true;
228+
196229
// Then try to perform the guaranteed copy value optimization.
197230
if (performGuaranteedCopyValueOptimization(cvi))
198231
return true;

test/SILOptimizer/semantic-arc-opts.sil

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import Builtin
99
//////////////////
1010

1111
sil @guaranteed_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
12+
sil @owned_user : $@convention(thin) (@owned Builtin.NativeObject) -> ()
1213

1314
struct NativeObjectPair {
1415
var obj1 : Builtin.NativeObject
@@ -188,3 +189,53 @@ bb0(%0 : @unowned $Builtin.NativeObject):
188189
%9999 = tuple()
189190
return %9999 : $()
190191
}
192+
193+
// CHECK-LABEL: sil @dead_live_range_multiple_destroy_value : $@convention(thin) (@owned Builtin.NativeObject) -> () {
194+
// CHECK-NOT: copy_value
195+
// CHECK-NOT: destroy_value
196+
// CHECK: bb3:
197+
// CHECK: destroy_value
198+
// CHECK: } // end sil function 'dead_live_range_multiple_destroy_value'
199+
sil @dead_live_range_multiple_destroy_value : $@convention(thin) (@owned Builtin.NativeObject) -> () {
200+
bb0(%0 : @owned $Builtin.NativeObject) :
201+
%1 = copy_value %0 : $Builtin.NativeObject
202+
cond_br undef, bb1, bb2
203+
204+
bb1:
205+
destroy_value %1 : $Builtin.NativeObject
206+
br bb3
207+
208+
bb2:
209+
destroy_value %1 : $Builtin.NativeObject
210+
br bb3
211+
212+
bb3:
213+
destroy_value %0 : $Builtin.NativeObject
214+
%9999 = tuple()
215+
return %9999 : $()
216+
}
217+
218+
// CHECK-LABEL: sil @dead_live_range_multiple_destroy_value_consuming_user : $@convention(thin) (@owned Builtin.NativeObject) -> () {
219+
// CHECK: copy_value
220+
// CHECK: destroy_value
221+
// CHECK: destroy_value
222+
// CHECK: } // end sil function 'dead_live_range_multiple_destroy_value_consuming_user'
223+
sil @dead_live_range_multiple_destroy_value_consuming_user : $@convention(thin) (@owned Builtin.NativeObject) -> () {
224+
bb0(%0 : @owned $Builtin.NativeObject) :
225+
%1 = copy_value %0 : $Builtin.NativeObject
226+
cond_br undef, bb1, bb2
227+
228+
bb1:
229+
destroy_value %1 : $Builtin.NativeObject
230+
br bb3
231+
232+
bb2:
233+
%2 = function_ref @owned_user : $@convention(thin) (@owned Builtin.NativeObject) -> ()
234+
apply %2(%1) : $@convention(thin) (@owned Builtin.NativeObject) -> ()
235+
br bb3
236+
237+
bb3:
238+
destroy_value %0 : $Builtin.NativeObject
239+
%9999 = tuple()
240+
return %9999 : $()
241+
}

0 commit comments

Comments
 (0)