Skip to content

Commit b3ee1fd

Browse files
committed
[AddrLowering] Copy for out-of-range owned stores.
Skip the store-copy optimization if the store instruction occurs outside the lifetime of the value being copied.
1 parent 2a81238 commit b3ee1fd

File tree

2 files changed

+65
-14
lines changed

2 files changed

+65
-14
lines changed

lib/SILOptimizer/Mandatory/AddressLowering.cpp

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,22 @@ static bool isStoreCopy(SILValue value) {
352352
if (!storeInst)
353353
return false;
354354

355+
SSAPrunedLiveness liveness;
356+
auto isStoreOutOfRange = [&liveness, storeInst](SILValue root) {
357+
liveness.initializeDef(root);
358+
auto summary = liveness.computeSimple();
359+
if (summary.addressUseKind != AddressUseKind::NonEscaping) {
360+
return true;
361+
}
362+
if (summary.innerBorrowKind != InnerBorrowKind::Contained) {
363+
return true;
364+
}
365+
if (!liveness.isWithinBoundary(storeInst)) {
366+
return true;
367+
}
368+
return false;
369+
};
370+
355371
auto source = copyInst->getOperand();
356372
if (source->getOwnershipKind() == OwnershipKind::Guaranteed) {
357373
// [in_guaranteed_begin_apply_results] If any root of the source is a
@@ -361,30 +377,22 @@ static bool isStoreCopy(SILValue value) {
361377
SmallVector<SILValue, 4> roots;
362378
findGuaranteedReferenceRoots(source, /*lookThroughNestedBorrows=*/true,
363379
roots);
364-
SSAPrunedLiveness liveness;
365-
if (llvm::any_of(roots, [&liveness, storeInst](SILValue root) {
380+
if (llvm::any_of(roots, [&](SILValue root) {
366381
// Handle forwarding phis conservatively rather than recursing.
367382
if (SILArgument::asPhi(root) && !BorrowedValue(root))
368383
return true;
369384

370385
if (isa<BeginApplyInst>(root->getDefiningInstruction())) {
371386
return true;
372387
}
373-
liveness.initializeDef(root);
374-
auto summary = liveness.computeSimple();
375-
if (summary.addressUseKind != AddressUseKind::NonEscaping) {
376-
return true;
377-
}
378-
if (summary.innerBorrowKind != InnerBorrowKind::Contained) {
379-
return true;
380-
}
381-
if (!liveness.isWithinBoundary(storeInst)) {
382-
return true;
383-
}
384-
return false;
388+
return isStoreOutOfRange(root);
385389
})) {
386390
return false;
387391
}
392+
} else if (source->getOwnershipKind() == OwnershipKind::Owned) {
393+
if (isStoreOutOfRange(source)) {
394+
return false;
395+
}
388396
}
389397

390398
return true;

test/SILOptimizer/address_lowering.sil

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1881,6 +1881,49 @@ entry(%addr : $*T):
18811881
return %retval : $()
18821882
}
18831883

1884+
// CHECK-LABEL: sil [ossa] @testCopyValue2StoreCopyAfterDestroy : {{.*}} {
1885+
// CHECK: {{bb[0-9]+}}([[ADDR:%[^,]+]] :
1886+
// CHECK: [[INSTANCE_ADDR:%[^,]+]] = alloc_stack $T
1887+
// CHECK: [[COPY_ADDR:%[^,]+]] = alloc_stack $T
1888+
// CHECK: apply undef<T>([[INSTANCE_ADDR]])
1889+
// CHECK: copy_addr [[INSTANCE_ADDR]] to [init] [[COPY_ADDR]]
1890+
// CHECK: destroy_addr [[INSTANCE_ADDR]]
1891+
// CHECK: copy_addr [take] [[COPY_ADDR]] to [[ADDR]]
1892+
// CHECK-LABEL: } // end sil function 'testCopyValue2StoreCopyAfterDestroy'
1893+
sil [ossa] @testCopyValue2StoreCopyAfterDestroy : $@convention(thin) <T> (@inout T) -> () {
1894+
entry(%addr : $*T):
1895+
%instance = apply undef<T>() : $@convention(thin) <Tee> () -> @out Tee
1896+
%copy = copy_value %instance : $T
1897+
destroy_value %instance : $T
1898+
store %copy to [assign] %addr : $*T
1899+
%retval = tuple ()
1900+
return %retval : $()
1901+
}
1902+
1903+
// CHECK-LABEL: sil [ossa] @testCopyValue3StoreTupleDestructureFieldAfterDestroy : $@convention(thin) <T> (@inout T) -> () {
1904+
// CHECK: {{bb[0-9]+}}([[ADDR:%[^,]+]] :
1905+
// CHECK: [[INSTANCE_ADDR:%[^,]+]] = alloc_stack $(T, T)
1906+
// CHECK: [[COPY_ADDR:%[^,]+]] = alloc_stack $T
1907+
// CHECK: apply undef<T>([[INSTANCE_ADDR]]) : $@convention(thin) <τ_0_0> () -> @out (τ_0_0, τ_0_0)
1908+
// CHECK: [[ONE_ADDR:%[^,]+]] = tuple_element_addr [[INSTANCE_ADDR]]{{.*}}, 0
1909+
// CHECK: [[TWO_ADDR:%[^,]+]] = tuple_element_addr [[INSTANCE_ADDR]]{{.*}}, 1
1910+
// CHECK: copy_addr [[ONE_ADDR]] to [init] [[COPY_ADDR]]
1911+
// CHECK: destroy_addr [[ONE_ADDR]]
1912+
// CHECK: destroy_addr [[TWO_ADDR]]
1913+
// CHECK: copy_addr [take] [[COPY_ADDR]] to [[ADDR]]
1914+
// CHECK-LABEL: } // end sil function 'testCopyValue3StoreTupleDestructureFieldAfterDestroy'
1915+
sil [ossa] @testCopyValue3StoreTupleDestructureFieldAfterDestroy : $@convention(thin) <T> (@inout T) -> () {
1916+
entry(%addr : $*T):
1917+
%instance = apply undef<T>() : $@convention(thin) <Tee> () -> @out (Tee, Tee)
1918+
(%one, %two) = destructure_tuple %instance : $(T, T)
1919+
%copy = copy_value %one : $T
1920+
destroy_value %one : $T
1921+
destroy_value %two : $T
1922+
store %copy to [assign] %addr : $*T
1923+
%retval = tuple ()
1924+
return %retval : $()
1925+
}
1926+
18841927
// CHECK-LABEL: sil hidden [ossa] @testOpaqueYield :
18851928
// CHECK: bb0(%0 : @guaranteed $TestGeneric<T>):
18861929
// CHECK: [[REF:%.*]] = ref_element_addr %0 : $TestGeneric<T>, #TestGeneric.borrowedGeneric

0 commit comments

Comments
 (0)