Skip to content

Commit df00577

Browse files
authored
Merge pull request swiftlang#62609 from nate-chandler/opaque-values/2/20221214
[AddressLowering] Copy for out-of-range stores.
2 parents 3ffbc45 + 356f2b7 commit df00577

File tree

4 files changed

+115
-17
lines changed

4 files changed

+115
-17
lines changed

lib/SIL/Verifier/SILOwnershipVerifier.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -683,7 +683,7 @@ bool SILValueOwnershipChecker::checkUses() {
683683
// outlive the current function always.
684684
//
685685
// In the case of a yielded guaranteed value, we need to validate that all
686-
// regular uses of the value are within the co
686+
// regular uses of the value are within the coroutine.
687687
if (lifetimeEndingUsers.empty()) {
688688
if (checkValueWithoutLifetimeEndingUses(regularUsers))
689689
return false;

lib/SILOptimizer/Mandatory/AddressLowering.cpp

Lines changed: 47 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,27 @@ static bool isStoreCopy(SILValue value) {
347347
if (!copyInst->hasOneUse())
348348
return false;
349349

350+
auto *user = value->getSingleUse()->getUser();
351+
auto *storeInst = dyn_cast<StoreInst>(user);
352+
if (!storeInst)
353+
return false;
354+
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+
350371
auto source = copyInst->getOperand();
351372
if (source->getOwnershipKind() == OwnershipKind::Guaranteed) {
352373
// [in_guaranteed_begin_apply_results] If any root of the source is a
@@ -356,19 +377,30 @@ static bool isStoreCopy(SILValue value) {
356377
SmallVector<SILValue, 4> roots;
357378
findGuaranteedReferenceRoots(source, /*lookThroughNestedBorrows=*/true,
358379
roots);
359-
if (llvm::any_of(roots, [](SILValue root) {
360-
// Handle forwarding phis conservatively rather than recursing.
361-
if (SILArgument::asPhi(root) && !BorrowedValue(root))
362-
return true;
363-
364-
return isa<BeginApplyInst>(root->getDefiningInstruction());
365-
})) {
380+
// TODO: Rather than checking whether the store is out of range of any
381+
// guaranteed root's SSAPrunedLiveness, instead check whether it is out of
382+
// range of ExtendedLiveness of the borrow introducers:
383+
// - visit borrow introducers via visitBorrowIntroducers
384+
// - call ExtendedLiveness.compute on each borrow introducer
385+
if (llvm::any_of(roots, [&](SILValue root) {
386+
// Handle forwarding phis conservatively rather than recursing.
387+
if (SILArgument::asPhi(root) && !BorrowedValue(root))
388+
return true;
389+
390+
if (isa<BeginApplyInst>(root->getDefiningInstruction())) {
391+
return true;
392+
}
393+
return isStoreOutOfRange(root);
394+
})) {
395+
return false;
396+
}
397+
} else if (source->getOwnershipKind() == OwnershipKind::Owned) {
398+
if (isStoreOutOfRange(source)) {
366399
return false;
367400
}
368401
}
369402

370-
auto *user = value->getSingleUse()->getUser();
371-
return isa<StoreInst>(user);
403+
return true;
372404
}
373405

374406
void ValueStorageMap::insertValue(SILValue value, SILValue storageAddress) {
@@ -2280,9 +2312,9 @@ void ApplyRewriter::convertBeginApplyWithOpaqueYield() {
22802312
info.isConsumed() ? IsTake : IsNotTake,
22812313
IsInitialization);
22822314
} else {
2283-
// [in_guaranteed_begin_apply_results] Because OSSA ensure that all uses
2284-
// of a guaranteed value produced by a begin_apply are used within the
2285-
// coroutine's range, AddressLowering will not introduce uses of
2315+
// [in_guaranteed_begin_apply_results] Because OSSA ensures that all
2316+
// uses of a guaranteed value produced by a begin_apply are used within
2317+
// the coroutine's range, AddressLowering will not introduce uses of
22862318
// invalid memory by rewriting the uses of a yielded guaranteed opaque
22872319
// value as uses of yielded guaranteed storage. However, it must
22882320
// allocate storage for copies of [projections of] such values.
@@ -2994,12 +3026,12 @@ class UseRewriter : SILInstructionVisitor<UseRewriter> {
29943026
switch (bi->getBuiltinKind().value_or(BuiltinValueKind::None)) {
29953027
case BuiltinValueKind::ResumeNonThrowingContinuationReturning: {
29963028
SILValue opAddr = addrMat.materializeAddress(use->get());
2997-
bi->setOperand(1, opAddr);
3029+
bi->setOperand(use->getOperandNumber(), opAddr);
29983030
break;
29993031
}
30003032
case BuiltinValueKind::ResumeThrowingContinuationReturning: {
30013033
SILValue opAddr = addrMat.materializeAddress(use->get());
3002-
bi->setOperand(1, opAddr);
3034+
bi->setOperand(use->getOperandNumber(), opAddr);
30033035
break;
30043036
}
30053037
case BuiltinValueKind::Copy: {
@@ -3768,7 +3800,7 @@ static void rewriteFunction(AddressLoweringState &pass) {
37683800
originalUses.insert(oper);
37693801
UseRewriter::rewriteUse(oper, pass);
37703802
}
3771-
// Rewrite every new uses that was added.
3803+
// Rewrite every new use that was added.
37723804
uses.clear();
37733805
for (auto *use : valueDef->getUses()) {
37743806
if (originalUses.contains(use))

test/SILOptimizer/address_lowering.sil

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1858,6 +1858,72 @@ entry:
18581858
return %retval : $()
18591859
}
18601860

1861+
// CHECK-LABEL: sil [ossa] @testCopyValue1StoreExtractAfterDestroyAggregate : {{.*}} {
1862+
// CHECK: {{bb[0-9]+}}([[ADDR:%[^,]+]] :
1863+
// CHECK: [[INSTANCE_ADDR:%[^,]+]] = alloc_stack $Pair<T>
1864+
// CHECK: [[COPY_ADDR:%[^,]+]] = alloc_stack $T
1865+
// CHECK: apply undef<T>([[INSTANCE_ADDR]])
1866+
// CHECK: [[X_ADDR:%[^,]+]] = struct_element_addr [[INSTANCE_ADDR]]{{.*}}, #Pair.x
1867+
// CHECK: copy_addr [[X_ADDR]] to [init] [[COPY_ADDR]]
1868+
// CHECK: destroy_addr [[INSTANCE_ADDR]]
1869+
// CHECK: copy_addr [take] [[COPY_ADDR]] to [[ADDR]]
1870+
// CHECK-LABEL: } // end sil function 'testCopyValue1StoreExtractAfterDestroyAggregate'
1871+
sil [ossa] @testCopyValue1StoreExtractAfterDestroyAggregate : $@convention(thin) <T> (@inout T) -> () {
1872+
entry(%addr : $*T):
1873+
%instance = apply undef<T>() : $@convention(thin) <Tee> () -> @out Pair<Tee>
1874+
%lifetime = begin_borrow %instance : $Pair<T>
1875+
%x = struct_extract %lifetime : $Pair<T>, #Pair.x
1876+
%copy = copy_value %x : $T
1877+
end_borrow %lifetime : $Pair<T>
1878+
destroy_value %instance : $Pair<T>
1879+
store %copy to [assign] %addr : $*T
1880+
%retval = tuple ()
1881+
return %retval : $()
1882+
}
1883+
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+
18611927
// CHECK-LABEL: sil hidden [ossa] @testOpaqueYield :
18621928
// CHECK: bb0(%0 : @guaranteed $TestGeneric<T>):
18631929
// CHECK: [[REF:%.*]] = ref_element_addr %0 : $TestGeneric<T>, #TestGeneric.borrowedGeneric

test/SILOptimizer/opaque_values_Onone_stdlib.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ func foo(@_noImplicitCopy _ x: __owned X) {
4141
// CHECK: {{bb[0-9]+}}([[OUT_ADDR:%[^,]+]] : $*T, [[IN_ADDR:%[^,]+]] : $*T):
4242
// CHECK: [[TMP_ADDR:%[^,]+]] = alloc_stack $T
4343
// CHECK: copy_addr [[IN_ADDR]] to [init] [[TMP_ADDR]] : $*T
44-
// CHECK: [[REGISTER_5:%[^,]+]] = builtin "copy"<T>([[OUT_ADDR]] : $*T, [[TMP_ADDR]] : $*T) : $()
44+
// CHECK: builtin "copy"<T>([[OUT_ADDR]] : $*T, [[TMP_ADDR]] : $*T) : $()
4545
// CHECK: dealloc_stack [[TMP_ADDR]] : $*T
4646
// CHECK: return {{%[^,]+}} : $()
4747
// CHECK-LABEL: } // end sil function '_copy'

0 commit comments

Comments
 (0)