Skip to content

Commit fe49499

Browse files
Merge pull request #62486 from nate-chandler/opaque-values/1/20221209
[AddressLowering] Handle store_borrow.
2 parents d6efe55 + 29067a5 commit fe49499

File tree

7 files changed

+83
-14
lines changed

7 files changed

+83
-14
lines changed

docs/SIL.rst

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4070,11 +4070,14 @@ The stack location must not be modified by other instructions than
40704070
``store_borrow``.
40714071
All uses of the store_borrow destination ```%1`` should be via the store_borrow
40724072
return address ``%2`` except dealloc_stack.
4073-
The stored value is alive until the ``end_borrow``. During the its lifetime,the
4073+
The stored value is alive until the ``end_borrow``. During its lifetime, the
40744074
stored value must not be modified or destroyed.
4075-
The source value ``%0`` is borrowed (i.e. not copied) and it's borrow scope
4075+
The source value ``%0`` is borrowed (i.e. not copied) and its borrow scope
40764076
must outlive the lifetime of the stored value.
40774077

4078+
Notionally, the outer borrow scope ensures that there's something to be
4079+
addressed. The inner borrow scope provides the address to work with.
4080+
40784081
begin_borrow
40794082
````````````
40804083

lib/SIL/Verifier/MemoryLifetimeVerifier.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -562,15 +562,16 @@ void MemoryLifetimeVerifier::checkFunction(BitDataflow &dataFlow) {
562562
require(expectedReturnBits & ~bs.data.exitSet,
563563
"indirect argument is not alive at function return", term);
564564
require(bs.data.exitSet & ~expectedReturnBits & nonTrivialLocations,
565-
"memory is initialized at function return but shouldn't", term,
566-
/*excludeTrivialEnums*/ true);
565+
"memory is initialized at function return but shouldn't be",
566+
term,
567+
/*excludeTrivialEnums*/ true);
567568
break;
568569
case SILInstructionKind::ThrowInst:
569570
require(expectedThrowBits & ~bs.data.exitSet,
570571
"indirect argument is not alive at throw", term);
571572
require(bs.data.exitSet & ~expectedThrowBits & nonTrivialLocations,
572-
"memory is initialized at throw but shouldn't", term,
573-
/*excludeTrivialEnums*/ true);
573+
"memory is initialized at throw but shouldn't be", term,
574+
/*excludeTrivialEnums*/ true);
574575
break;
575576
default:
576577
break;

lib/SIL/Verifier/SILVerifier.cpp

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2243,6 +2243,10 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
22432243
require(
22442244
F.hasOwnership(),
22452245
"Inst with qualified ownership in a function that is not qualified");
2246+
if (EBI->getOperand()->getType().isAddress()) {
2247+
require(isa<StoreBorrowInst>(EBI->getOperand()),
2248+
"end_borrow of an address not produced by store_borrow");
2249+
}
22462250
}
22472251

22482252
void checkEndLifetimeInst(EndLifetimeInst *I) {
@@ -2446,23 +2450,22 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
24462450
}
24472451

24482452
void checkStoreBorrowInst(StoreBorrowInst *SI) {
2453+
// A store_borrow must be to an alloc_stack. That alloc_stack can only be
2454+
// used by store_borrows (and dealloc_stacks).
24492455
require(SI->getSrc()->getType().isObject(),
24502456
"Can't store from an address source");
24512457
require(!fnConv.useLoweredAddresses()
24522458
|| SI->getSrc()->getType().isLoadable(*SI->getFunction()),
24532459
"Can't store a non loadable type");
24542460
require(SI->getDest()->getType().isAddress(),
24552461
"Must store to an address dest");
2462+
// Note: This is the current implementation and the design is not final.
24562463
require(isa<AllocStackInst>(SI->getDest()),
2457-
"store_borrow destination should be alloc_stack");
2464+
"store_borrow destination can only be an alloc_stack");
24582465
requireSameType(SI->getDest()->getType().getObjectType(),
24592466
SI->getSrc()->getType(),
24602467
"Store operand type and dest type mismatch");
24612468

2462-
// Note: This is the current implementation and the design is not final.
2463-
require(isa<AllocStackInst>(SI->getDest()),
2464-
"store_borrow destination can only be an alloc_stack");
2465-
24662469
SSAPrunedLiveness scopedAddressLiveness;
24672470
ScopedAddressValue scopedAddress(SI);
24682471
// FIXME: Reenable @test_load_borrow_store_borrow_nested in

lib/SILOptimizer/Mandatory/AddressLowering.cpp

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3101,8 +3101,17 @@ class UseRewriter : SILInstructionVisitor<UseRewriter> {
31013101
llvm::report_fatal_error("Unimplemented SelectValue use.");
31023102
}
31033103

3104-
// Opaque enum operand to a switch_enum.
3105-
void visitSwitchEnumInst(SwitchEnumInst *SEI);
3104+
void visitStoreBorrowInst(StoreBorrowInst *sbi) {
3105+
auto addr = addrMat.materializeAddress(use->get());
3106+
SmallVector<Operand *, 4> uses(sbi->getUses());
3107+
for (auto *use : uses) {
3108+
if (auto *ebi = dyn_cast<EndBorrowInst>(use->getUser())) {
3109+
pass.deleter.forceDelete(ebi);
3110+
}
3111+
}
3112+
sbi->replaceAllUsesWith(addr);
3113+
pass.deleter.forceDelete(sbi);
3114+
}
31063115

31073116
void rewriteStore(SILValue srcVal, SILValue destAddr,
31083117
IsInitialization_t isInit);
@@ -3134,6 +3143,9 @@ class UseRewriter : SILInstructionVisitor<UseRewriter> {
31343143
// member implies an address-only Struct.
31353144
void visitStructInst(StructInst *structInst) {}
31363145

3146+
// Opaque enum operand to a switch_enum.
3147+
void visitSwitchEnumInst(SwitchEnumInst *SEI);
3148+
31373149
// Opaque call argument.
31383150
void visitTryApplyInst(TryApplyInst *tryApplyInst) {
31393151
CallArgRewriter(tryApplyInst, pass).rewriteIndirectArgument(use);

test/SIL/store_borrow_verify_errors.sil

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ bb1:
196196
}
197197

198198
// CHECK: Begin Error in function test_store_borrow_dest
199-
// CHECK: SIL verification failed: store_borrow destination should be alloc_stack: isa<AllocStackInst>(SI->getDest())
199+
// CHECK: SIL verification failed: store_borrow destination can only be an alloc_stack: isa<AllocStackInst>(SI->getDest())
200200
// CHECK: Verifying instruction:
201201
// CHECK: %0 = argument of bb0 : $Klass // user: %3
202202
// CHECK: %2 = struct_element_addr %1 : $*NonTrivialStruct, #NonTrivialStruct.val // user: %3

test/SIL/verifier_failures.sil

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// RUN: %target-sil-opt -emit-sorted-sil -verify-continue-on-failure -o /dev/null %s 2>&1 | %FileCheck %s
2+
// REQUIRES: asserts
3+
4+
sil_stage canonical
5+
6+
import Builtin
7+
import Swift
8+
import SwiftShims
9+
10+
class C {}
11+
12+
// CHECK: Begin Error in function end_borrow_1_addr_alloc_stack
13+
// CHECK-NEXT: SIL verification failed: end_borrow of an address not produced by store_borrow
14+
sil [ossa] @end_borrow_1_addr_alloc_stack : $@convention(thin) () -> () {
15+
%addr = alloc_stack $C
16+
end_borrow %addr : $*C
17+
dealloc_stack %addr : $*C
18+
%retval = tuple ()
19+
return %retval : $()
20+
}

test/SILOptimizer/address_lowering.sil

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2149,6 +2149,36 @@ bb0:
21492149
return %retval : $()
21502150
}
21512151

2152+
// CHECK-LABEL: sil [ossa] @test_store_borrow_1_copy_addr : {{.*}} {
2153+
// CHECK: [[ADDR:%[^,]+]] = alloc_stack
2154+
// CHECK: apply undef<T>([[ADDR]])
2155+
// CHECK: [[COPY:%[^,]+]] = alloc_stack
2156+
// CHECK: copy_addr [[ADDR]] to [init] [[COPY]]
2157+
// CHECK: apply undef<T>([[COPY]])
2158+
// CHECK: destroy_addr [[COPY]]
2159+
// CHECK: dealloc_stack [[COPY]]
2160+
// CHECK-NOT: end_borrow [[ADDR]]
2161+
// CHECK: destroy_addr [[ADDR]]
2162+
// CHECK-LABEL: } // end sil function 'test_store_borrow_1_copy_addr'
2163+
sil [ossa] @test_store_borrow_1_copy_addr : $@convention(thin) <T> () -> () {
2164+
entry:
2165+
%addr = alloc_stack $T
2166+
%instance = apply undef<T>() : $@convention(thin) <τ> () -> (@out τ)
2167+
%lifetime = begin_borrow %instance : $T
2168+
%borrow = store_borrow %lifetime to %addr : $*T
2169+
%copy = alloc_stack $T
2170+
copy_addr %borrow to [init] %copy : $*T
2171+
apply undef<T>(%copy) : $@convention(thin) <τ> (@inout τ) -> ()
2172+
destroy_addr %copy : $*T
2173+
dealloc_stack %copy : $*T
2174+
end_borrow %borrow : $*T
2175+
end_borrow %lifetime : $T
2176+
dealloc_stack %addr : $*T
2177+
destroy_value %instance : $T
2178+
%retval = tuple ()
2179+
return %retval : $()
2180+
}
2181+
21522182
// CHECK-LABEL: sil hidden [ossa] @test_unchecked_bitwise_cast :
21532183
// CHECK: bb0(%0 : $*U, %1 : $*T, %2 : $@thick U.Type):
21542184
// CHECK: [[STK:%.*]] = alloc_stack $T

0 commit comments

Comments
 (0)