Skip to content

Commit 1158b58

Browse files
committed
[AddressLowering] Addr'd some unconditional_casts.
All checked casts are emitted as unconditional_checked_cast instructions. More than just the instructions which produce or consume an opaque value must be rewritten as unconditional_checked_cast_addr instructions. In particular, all those instructions for which canIRGenUseScalarCheckedCastInstructions returns false must be rewritten as unconditional_checked_cast_addr instructions. Note the instructions to rewrite like that while visiting values and then rewrite them near the end of rewriting.
1 parent a7e6af2 commit 1158b58

File tree

3 files changed

+118
-2
lines changed

3 files changed

+118
-2
lines changed

lib/SILOptimizer/Mandatory/AddressLowering.cpp

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,10 @@ struct AddressLoweringState {
419419
// parameters are rewritten.
420420
SmallBlotSetVector<FullApplySite, 16> indirectApplies;
421421

422+
// unconditional_checked_cast instructions of loadable type which need to be
423+
// rewritten.
424+
SmallVector<UnconditionalCheckedCastInst *, 2> nonopaqueResultUCCs;
425+
422426
// All function-exiting terminators (return or throw instructions).
423427
SmallVector<TermInst *, 8> exitingInsts;
424428

@@ -639,8 +643,18 @@ void OpaqueValueVisitor::checkForIndirectApply(FullApplySite applySite) {
639643

640644
/// If `value` is address-only, add it to the `valueStorageMap`.
641645
void OpaqueValueVisitor::visitValue(SILValue value) {
642-
if (!value->getType().isObject()
643-
|| !value->getType().isAddressOnly(*pass.function)) {
646+
if (!value->getType().isObject())
647+
return;
648+
if (!value->getType().isAddressOnly(*pass.function)) {
649+
if (auto *ucci = dyn_cast<UnconditionalCheckedCastInst>(value)) {
650+
if (ucci->getSourceLoweredType().isAddressOnly(*pass.function))
651+
return;
652+
if (!canIRGenUseScalarCheckedCastInstructions(
653+
pass.function->getModule(), ucci->getSourceFormalType(),
654+
ucci->getTargetFormalType())) {
655+
pass.nonopaqueResultUCCs.push_back(ucci);
656+
}
657+
}
644658
return;
645659
}
646660
if (pass.valueStorageMap.contains(value)) {
@@ -3354,6 +3368,39 @@ static void rewriteIndirectApply(FullApplySite apply,
33543368
}
33553369
}
33563370

3371+
static void rewriteNonopaqueUnconditionalCheckedCast(
3372+
UnconditionalCheckedCastInst *uncondCheckedCast,
3373+
AddressLoweringState &pass) {
3374+
auto loc = uncondCheckedCast->getLoc();
3375+
SILValue srcVal = uncondCheckedCast->getOperand();
3376+
auto srcType = srcVal->getType();
3377+
auto destType = uncondCheckedCast->getType();
3378+
assert(srcType.isLoadable(*pass.function));
3379+
assert(!destType.isAddressOnly(*pass.function));
3380+
3381+
// Create a stack temporary to store the source
3382+
auto builder = pass.getBuilder(uncondCheckedCast->getIterator());
3383+
SILValue srcAddr = builder.createAllocStack(loc, srcType);
3384+
builder.createStore(loc, srcVal, srcAddr,
3385+
srcType.isTrivial(*pass.function)
3386+
? StoreOwnershipQualifier::Trivial
3387+
: StoreOwnershipQualifier::Init);
3388+
SILValue destAddr = builder.createAllocStack(loc, destType);
3389+
builder.createUnconditionalCheckedCastAddr(loc, srcAddr, srcType.getASTType(),
3390+
destAddr, destType.getASTType());
3391+
3392+
auto afterBuilder =
3393+
pass.getBuilder(uncondCheckedCast->getNextInstruction()->getIterator());
3394+
auto *load = afterBuilder.createLoad(loc, destAddr,
3395+
destType.isTrivial(*pass.function)
3396+
? LoadOwnershipQualifier::Trivial
3397+
: LoadOwnershipQualifier::Take);
3398+
uncondCheckedCast->replaceAllUsesWith(load);
3399+
pass.deleter.forceDelete(uncondCheckedCast);
3400+
afterBuilder.createDeallocStack(loc, destAddr);
3401+
afterBuilder.createDeallocStack(loc, srcAddr);
3402+
}
3403+
33573404
static void rewriteFunction(AddressLoweringState &pass) {
33583405
// During rewriting, storage references are stable.
33593406
pass.valueStorageMap.setStable();
@@ -3402,6 +3449,10 @@ static void rewriteFunction(AddressLoweringState &pass) {
34023449
}
34033450
}
34043451

3452+
for (auto *ucci : pass.nonopaqueResultUCCs) {
3453+
rewriteNonopaqueUnconditionalCheckedCast(ucci, pass);
3454+
}
3455+
34053456
// Rewrite this function's return value now that all opaque values within the
34063457
// function are rewritten. This still depends on a valid ValueStorage
34073458
// projection operands.

test/SILOptimizer/address_lowering.sil

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1763,6 +1763,39 @@ bb0(%0 : @guaranteed $T):
17631763
return %6 : $U
17641764
}
17651765

1766+
// Verify lowering of unconditional_checked_cast not involving address-only
1767+
// values.
1768+
// CHECK-LABEL: sil hidden [ossa] @test_unconditional_checked_cast4 : {{.*}} {
1769+
// CHECK: {{bb[0-9]+}}([[SRC:%[^,]+]] :
1770+
// CHECK: [[SRC_ADDR:%[^,]+]] = alloc_stack $AnyObject
1771+
// CHECK: store [[SRC]] to [init] [[SRC_ADDR]] : $*AnyObject
1772+
// CHECK: [[DEST_ADDR:%[^,]+]] = alloc_stack $@thick any AnyObject.Type
1773+
// CHECK: unconditional_checked_cast_addr AnyObject in [[SRC_ADDR]] {{.*}} to @thick any AnyObject.Type in [[DEST_ADDR]]
1774+
// CHECK: load [trivial] [[DEST_ADDR]] : $*@thick any AnyObject.Type
1775+
// CHECK-LABEL: } // end sil function 'test_unconditional_checked_cast4'
1776+
sil hidden [ossa] @test_unconditional_checked_cast4 : $@convention(thin) (@owned AnyObject) -> () {
1777+
entry(%instance : @owned $AnyObject):
1778+
%casted = unconditional_checked_cast %instance : $AnyObject to any AnyObject.Type
1779+
%retval = tuple ()
1780+
return %retval : $()
1781+
}
1782+
1783+
// Verify lowering of unconditional_checked_cast that involves address-only
1784+
// values and also non-address-only values which on its own requires lowering
1785+
// to unconditional_checked_cast_addr.
1786+
// CHECK-LABEL: sil [ossa] @test_unconditional_checked_cast5 : {{.*}} {
1787+
// CHECK: {{bb[0-9]+}}([[SRC_ADDR:%[^,]+]] :
1788+
// CHECK: [[DEST_ADDR:%[^,]+]] = alloc_stack $@thick any AnyObject.Type
1789+
// CHECK: unconditional_checked_cast_addr T in [[SRC_ADDR]] {{.*}} to @thick any AnyObject.Type in [[DEST_ADDR]]
1790+
// CHECK: load [trivial] [[DEST_ADDR]] : $*@thick any AnyObject.Type
1791+
// CHECK-LABEL: } // end sil function 'test_unconditional_checked_cast5'
1792+
sil [ossa] @test_unconditional_checked_cast5 : $@convention(thin) <T> (@in T) -> () {
1793+
entry(%instance : @owned $T):
1794+
%casted = unconditional_checked_cast %instance : $T to any AnyObject.Type
1795+
%retval = tuple ()
1796+
return %retval : $()
1797+
}
1798+
17661799
// CHECK-LABEL: sil [ossa] @yield_two : {{.*}} {
17671800
// CHECK: tuple_element_addr
17681801
// CHECK: tuple_element_addr

test/SILOptimizer/opaque_values_Onone.swift

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,3 +180,35 @@ func give_a_generic_tuple<This>(of ty: This.Type) -> (This, This)
180180
func get_a_generic_tuple<This>(ty: This.Type) {
181181
let p = give_a_generic_tuple(of: ty)
182182
}
183+
184+
// CHECK-LABEL: sil hidden @castAnyObjectToMeta {{.*}} {
185+
// CHECK: {{bb[0-9]+}}([[SRC:%[^,]+]] :
186+
// CHECK: [[SRC_ADDR:%[^,]+]] = alloc_stack $AnyObject
187+
// CHECK: store [[SRC]] to [[SRC_ADDR]]
188+
// CHECK: [[DEST_ADDR:%[^,]+]] = alloc_stack $@thick any AnyObject.Type
189+
// CHECK: unconditional_checked_cast_addr AnyObject in [[SRC_ADDR]] {{.*}} to @thick any AnyObject.Type in [[DEST_ADDR]]
190+
// CHECK: [[DEST:%[^,]+]] = load [[DEST_ADDR]]
191+
// CHECK: dealloc_stack [[DEST_ADDR]]
192+
// CHECK: dealloc_stack [[SRC_ADDR]]
193+
// CHECK: return [[DEST]]
194+
// CHECK-LABEL: } // end sil function 'castAnyObjectToMeta'
195+
@_silgen_name("castAnyObjectToMeta")
196+
func castAnyObjectToMeta(_ ao: any AnyObject) -> AnyObject.Type {
197+
ao as! AnyObject.Type
198+
}
199+
200+
// CHECK-LABEL: sil hidden @castGenericToMeta : {{.*}} {
201+
// CHECK: {{bb[0-9]+}}([[SRC:%[^,]+]] :
202+
// CHECK: [[SRC_ADDR:%[^,]+]] = alloc_stack $T
203+
// CHECK: copy_addr [[SRC]] to [init] [[SRC_ADDR]]
204+
// CHECK: [[DEST_ADDR:%[^,]+]] = alloc_stack $@thick any AnyObject.Type
205+
// CHECK: unconditional_checked_cast_addr T in [[SRC_ADDR]] {{.*}} to @thick any AnyObject.Type in [[DEST_ADDR]]
206+
// CHECK: [[DEST:%[^,]+]] = load [[DEST_ADDR]]
207+
// CHECK: dealloc_stack [[DEST_ADDR]]
208+
// CHECK: dealloc_stack [[SRC_ADDR]]
209+
// CHECK: return [[DEST]]
210+
// CHECK-LABEL: } // end sil function 'castGenericToMeta'
211+
@_silgen_name("castGenericToMeta")
212+
func castGenericToMeta<T>(_ t: T) -> AnyObject.Type {
213+
t as! AnyObject.Type
214+
}

0 commit comments

Comments
 (0)