Skip to content

Commit 47f02a7

Browse files
Merge pull request #62018 from nate-chandler/opaque-values/1/20221109
[AddressLowering] Handle non-opaque checked casts.
2 parents 65a5147 + d3717d3 commit 47f02a7

File tree

3 files changed

+232
-3
lines changed

3 files changed

+232
-3
lines changed

lib/SILOptimizer/Mandatory/AddressLowering.cpp

Lines changed: 74 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@
139139
#include "swift/Basic/Range.h"
140140
#include "swift/SIL/BasicBlockUtils.h"
141141
#include "swift/SIL/DebugUtils.h"
142+
#include "swift/SIL/DynamicCasts.h"
142143
#include "swift/SIL/OwnershipUtils.h"
143144
#include "swift/SIL/PrettyStackTrace.h"
144145
#include "swift/SIL/PrunedLiveness.h"
@@ -419,6 +420,13 @@ struct AddressLoweringState {
419420
// parameters are rewritten.
420421
SmallBlotSetVector<FullApplySite, 16> indirectApplies;
421422

423+
// unconditional_checked_cast instructions of loadable type which need to be
424+
// rewritten.
425+
SmallVector<UnconditionalCheckedCastInst *, 2> nonopaqueResultUCCs;
426+
427+
// checked_cast_br instructions to loadable type which need to be rewritten.
428+
SmallVector<CheckedCastBranchInst *, 2> nonopaqueResultCCBs;
429+
422430
// All function-exiting terminators (return or throw instructions).
423431
SmallVector<TermInst *, 8> exitingInsts;
424432

@@ -639,8 +647,31 @@ void OpaqueValueVisitor::checkForIndirectApply(FullApplySite applySite) {
639647

640648
/// If `value` is address-only, add it to the `valueStorageMap`.
641649
void OpaqueValueVisitor::visitValue(SILValue value) {
642-
if (!value->getType().isObject()
643-
|| !value->getType().isAddressOnly(*pass.function)) {
650+
if (!value->getType().isObject())
651+
return;
652+
if (!value->getType().isAddressOnly(*pass.function)) {
653+
if (auto *ucci = dyn_cast<UnconditionalCheckedCastInst>(value)) {
654+
if (ucci->getSourceLoweredType().isAddressOnly(*pass.function))
655+
return;
656+
if (!canIRGenUseScalarCheckedCastInstructions(
657+
pass.function->getModule(), ucci->getSourceFormalType(),
658+
ucci->getTargetFormalType())) {
659+
pass.nonopaqueResultUCCs.push_back(ucci);
660+
}
661+
} else if (auto *arg = dyn_cast<SILArgument>(value)) {
662+
if (auto *ccbi = dyn_cast_or_null<CheckedCastBranchInst>(
663+
arg->getTerminatorForResult())) {
664+
if (ccbi->getSuccessBB() != arg->getParent())
665+
return;
666+
if (ccbi->getSourceLoweredType().isAddressOnly(*pass.function))
667+
return;
668+
if (!canIRGenUseScalarCheckedCastInstructions(
669+
pass.function->getModule(), ccbi->getSourceFormalType(),
670+
ccbi->getTargetFormalType())) {
671+
pass.nonopaqueResultCCBs.push_back(ccbi);
672+
}
673+
}
674+
}
644675
return;
645676
}
646677
if (pass.valueStorageMap.contains(value)) {
@@ -3354,6 +3385,39 @@ static void rewriteIndirectApply(FullApplySite apply,
33543385
}
33553386
}
33563387

3388+
static void rewriteNonopaqueUnconditionalCheckedCast(
3389+
UnconditionalCheckedCastInst *uncondCheckedCast,
3390+
AddressLoweringState &pass) {
3391+
auto loc = uncondCheckedCast->getLoc();
3392+
SILValue srcVal = uncondCheckedCast->getOperand();
3393+
auto srcType = srcVal->getType();
3394+
auto destType = uncondCheckedCast->getType();
3395+
assert(srcType.isLoadable(*pass.function));
3396+
assert(!destType.isAddressOnly(*pass.function));
3397+
3398+
// Create a stack temporary to store the source
3399+
auto builder = pass.getBuilder(uncondCheckedCast->getIterator());
3400+
SILValue srcAddr = builder.createAllocStack(loc, srcType);
3401+
builder.createStore(loc, srcVal, srcAddr,
3402+
srcType.isTrivial(*pass.function)
3403+
? StoreOwnershipQualifier::Trivial
3404+
: StoreOwnershipQualifier::Init);
3405+
SILValue destAddr = builder.createAllocStack(loc, destType);
3406+
builder.createUnconditionalCheckedCastAddr(loc, srcAddr, srcType.getASTType(),
3407+
destAddr, destType.getASTType());
3408+
3409+
auto afterBuilder =
3410+
pass.getBuilder(uncondCheckedCast->getNextInstruction()->getIterator());
3411+
auto *load = afterBuilder.createLoad(loc, destAddr,
3412+
destType.isTrivial(*pass.function)
3413+
? LoadOwnershipQualifier::Trivial
3414+
: LoadOwnershipQualifier::Take);
3415+
uncondCheckedCast->replaceAllUsesWith(load);
3416+
pass.deleter.forceDelete(uncondCheckedCast);
3417+
afterBuilder.createDeallocStack(loc, destAddr);
3418+
afterBuilder.createDeallocStack(loc, srcAddr);
3419+
}
3420+
33573421
static void rewriteFunction(AddressLoweringState &pass) {
33583422
// During rewriting, storage references are stable.
33593423
pass.valueStorageMap.setStable();
@@ -3402,6 +3466,14 @@ static void rewriteFunction(AddressLoweringState &pass) {
34023466
}
34033467
}
34043468

3469+
for (auto *ucci : pass.nonopaqueResultUCCs) {
3470+
rewriteNonopaqueUnconditionalCheckedCast(ucci, pass);
3471+
}
3472+
3473+
for (auto *ccbi : pass.nonopaqueResultCCBs) {
3474+
CheckedCastBrRewriter(ccbi, pass).rewrite();
3475+
}
3476+
34053477
// Rewrite this function's return value now that all opaque values within the
34063478
// function are rewritten. This still depends on a valid ValueStorage
34073479
// projection operands.

test/SILOptimizer/address_lowering.sil

Lines changed: 88 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1614,7 +1614,7 @@ bb3:
16141614
}
16151615

16161616
// Test the result being stored into an @out enum.
1617-
// CHECK-LABEL: sil [ossa] @test_checked_cast_br4 : $@convention(method) <Element><T> (@owned TestGeneric<Element>) -> @out Optional<T> {
1617+
// CHECK-LABEL: sil [ossa] @test_checked_cast_br4 : {{.*}} {
16181618
// CHECK: {{bb[0-9]+}}([[OUT_ADDR:%[^,]+]] : $*Optional<T>, [[INSTANCE:%[^,]+]] : @owned $TestGeneric<Element>):
16191619
// CHECK: [[TEMP:%[^,]+]] = alloc_stack $Optional<T>
16201620
// CHECK: [[CAST_DEST_ADDR:%[^,]+]] = init_enum_data_addr [[TEMP]] : $*Optional<T>, #Optional.some!enumelt
@@ -1643,6 +1643,60 @@ bb3(%12 : @owned $Optional<T>):
16431643
return %12 : $Optional<T>
16441644
}
16451645

1646+
// Verify that checked_cast_br neither from nor to an address-only value but
1647+
// whose operands require rewriting to checked_cast_addr_br gets rewritten.
1648+
// CHECK-LABEL: sil [ossa] @test_checked_cast_br5 : {{.*}} {
1649+
// CHECK: {{bb[0-9]+}}([[SRC:%[^,]+]] :
1650+
// CHECK: [[SRC_ADDR:%[^,]+]] = alloc_stack $AnyObject
1651+
// CHECK: store [[SRC]] to [init] [[SRC_ADDR]]
1652+
// CHECK: [[DEST_ADDR:%[^,]+]] = alloc_stack $@thick any AnyObject.Type
1653+
// CHECK: checked_cast_addr_br take_on_success AnyObject in [[SRC_ADDR]] {{.*}} to any AnyObject.Type in [[DEST_ADDR]] {{.*}}, [[SUCCESS:bb[0-9]+]], [[FAILURE:bb[0-9]+]]
1654+
// CHECK: [[FAILURE]]:
1655+
// CHECK: load [take] [[SRC_ADDR]] : $*AnyObject
1656+
// CHECK: [[SUCCESS]]:
1657+
// CHECK: load [trivial] [[DEST_ADDR]] : $*@thick any AnyObject.Type
1658+
// CHECK-LABEL: } // end sil function 'test_checked_cast_br5'
1659+
sil [ossa] @test_checked_cast_br5 : $@convention(thin) (@owned AnyObject) -> () {
1660+
entry(%instance : @owned $AnyObject):
1661+
checked_cast_br %instance : $AnyObject to any AnyObject.Type, success, failure
1662+
1663+
success(%metatype : $@thick any AnyObject.Type):
1664+
br exit
1665+
1666+
failure(%original : @owned $AnyObject):
1667+
destroy_value %original : $AnyObject
1668+
br exit
1669+
1670+
exit:
1671+
%retval = tuple ()
1672+
return %retval : $()
1673+
}
1674+
1675+
// Verify that checked_cast_br which both has an address-only value and also
1676+
// produces a value whose type would anyway require rewriting but is not
1677+
// address-only gets lowered properly.
1678+
// CHECK-LABEL: sil [ossa] @test_checked_cast_br6 : {{.*}} {
1679+
// CHECK: {{bb[0-9]+}}([[SRC:%[^,]+]] :
1680+
// CHECK: [[DEST_ADDR:%[^,]+]] = alloc_stack $@thick any AnyObject.Type
1681+
// CHECK: checked_cast_addr_br take_on_success T in [[SRC]] {{.*}} to any AnyObject.Type in [[DEST_ADDR]] {{.*}}, [[SUCCESS]], [[FAILURE]]
1682+
// CHECK: [[FAILURE]]:
1683+
// CHECK: destroy_addr [[SRC]] : $*T
1684+
// CHECK: [[SUCCESS]]:
1685+
// CHECK: [[REGISTER_3:%[^,]+]] = load [trivial] [[DEST_ADDR]] : $*@thick any AnyObject.Type
1686+
// CHECK-LABEL: } // end sil function 'test_checked_cast_br6'
1687+
sil [ossa] @test_checked_cast_br6 : $@convention(thin) <T> (@in T) -> () {
1688+
entry(%instance : @owned $T):
1689+
checked_cast_br %instance : $T to any AnyObject.Type, success, failure
1690+
success(%metatype : $@thick any AnyObject.Type):
1691+
br exit
1692+
failure(%original : @owned $T):
1693+
destroy_value %original : $T
1694+
br exit
1695+
exit:
1696+
%retval = tuple ()
1697+
return %retval : $()
1698+
}
1699+
16461700
// CHECK-LABEL: sil hidden [ossa] @test_unchecked_bitwise_cast :
16471701
// CHECK: bb0(%0 : $*U, %1 : $*T, %2 : $@thick U.Type):
16481702
// CHECK: [[STK:%.*]] = alloc_stack $T
@@ -1763,6 +1817,39 @@ bb0(%0 : @guaranteed $T):
17631817
return %6 : $U
17641818
}
17651819

1820+
// Verify lowering of unconditional_checked_cast not involving address-only
1821+
// values.
1822+
// CHECK-LABEL: sil hidden [ossa] @test_unconditional_checked_cast4 : {{.*}} {
1823+
// CHECK: {{bb[0-9]+}}([[SRC:%[^,]+]] :
1824+
// CHECK: [[SRC_ADDR:%[^,]+]] = alloc_stack $AnyObject
1825+
// CHECK: store [[SRC]] to [init] [[SRC_ADDR]] : $*AnyObject
1826+
// CHECK: [[DEST_ADDR:%[^,]+]] = alloc_stack $@thick any AnyObject.Type
1827+
// CHECK: unconditional_checked_cast_addr AnyObject in [[SRC_ADDR]] {{.*}} to @thick any AnyObject.Type in [[DEST_ADDR]]
1828+
// CHECK: load [trivial] [[DEST_ADDR]] : $*@thick any AnyObject.Type
1829+
// CHECK-LABEL: } // end sil function 'test_unconditional_checked_cast4'
1830+
sil hidden [ossa] @test_unconditional_checked_cast4 : $@convention(thin) (@owned AnyObject) -> () {
1831+
entry(%instance : @owned $AnyObject):
1832+
%casted = unconditional_checked_cast %instance : $AnyObject to any AnyObject.Type
1833+
%retval = tuple ()
1834+
return %retval : $()
1835+
}
1836+
1837+
// Verify lowering of unconditional_checked_cast that involves address-only
1838+
// values and also non-address-only values which on its own requires lowering
1839+
// to unconditional_checked_cast_addr.
1840+
// CHECK-LABEL: sil [ossa] @test_unconditional_checked_cast5 : {{.*}} {
1841+
// CHECK: {{bb[0-9]+}}([[SRC_ADDR:%[^,]+]] :
1842+
// CHECK: [[DEST_ADDR:%[^,]+]] = alloc_stack $@thick any AnyObject.Type
1843+
// CHECK: unconditional_checked_cast_addr T in [[SRC_ADDR]] {{.*}} to @thick any AnyObject.Type in [[DEST_ADDR]]
1844+
// CHECK: load [trivial] [[DEST_ADDR]] : $*@thick any AnyObject.Type
1845+
// CHECK-LABEL: } // end sil function 'test_unconditional_checked_cast5'
1846+
sil [ossa] @test_unconditional_checked_cast5 : $@convention(thin) <T> (@in T) -> () {
1847+
entry(%instance : @owned $T):
1848+
%casted = unconditional_checked_cast %instance : $T to any AnyObject.Type
1849+
%retval = tuple ()
1850+
return %retval : $()
1851+
}
1852+
17661853
// CHECK-LABEL: sil [ossa] @yield_two : {{.*}} {
17671854
// CHECK: tuple_element_addr
17681855
// CHECK: tuple_element_addr

test/SILOptimizer/opaque_values_Onone.swift

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,3 +180,73 @@ 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+
}
215+
216+
// CHECK-LABEL: sil hidden @maybeCastAnyObjectToMeta : {{.*}} {
217+
// CHECK: {{bb[0-9]+}}([[SRC:%[^,]+]] :
218+
// CHECK: [[SRC_ADDR:%[^,]+]] = alloc_stack $AnyObject
219+
// CHECK: store [[SRC]] to [[SRC_ADDR]] : $*AnyObject
220+
// CHECK: [[DEST_ADDR:%[^,]+]] = alloc_stack $@thick any AnyObject.Type
221+
// CHECK: checked_cast_addr_br take_on_success AnyObject in [[SRC_ADDR]] {{.*}} to any AnyObject.Type in [[DEST_ADDR]] {{.*}}, [[SUCCESS:bb[0-9]+]], [[FAILURE:bb[0-9]+]]
222+
// CHECK: [[SUCCESS]]:
223+
// CHECK: load [[DEST_ADDR]] : $*@thick any AnyObject.Type
224+
// CHECK: [[FAILURE]]:
225+
// CHECK: load [[SRC_ADDR]] : $*AnyObject
226+
// CHECK-LABEL: } // end sil function 'maybeCastAnyObjectToMeta'
227+
@_silgen_name("maybeCastAnyObjectToMeta")
228+
func maybeCastAnyObjectToMeta(_ ao: any AnyObject) -> AnyObject.Type? {
229+
if let m = ao as? AnyObject.Type {
230+
return m
231+
}
232+
return nil
233+
}
234+
235+
// CHECK-LABEL: sil hidden @maybeCastGenericToMeta : {{.*}} {
236+
// CHECK: {{bb[0-9]+}}([[SRC:%[^,]+]] :
237+
// CHECK: [[SRC_ADDR:%[^,]+]] = alloc_stack $T
238+
// CHECK: copy_addr [[SRC]] to [init] [[SRC_ADDR]]
239+
// CHECK: [[DEST_ADDR:%[^,]+]] = alloc_stack $@thick any AnyObject.Type
240+
// CHECK: checked_cast_addr_br take_on_success T in [[SRC_ADDR]] {{.*}} to any AnyObject.Type in [[DEST_ADDR]] {{.*}}, [[SUCCESS:bb[0-9]+]], [[FAILURE:bb[0-9]+]]
241+
// CHECK: [[SUCCESS]]:
242+
// CHECK: load [[DEST_ADDR]]
243+
// CHECK: [[FAILURE]]:
244+
// CHECK: destroy_addr [[SRC_ADDR]]
245+
// CHECK-LABEL: } // end sil function 'maybeCastGenericToMeta'
246+
@_silgen_name("maybeCastGenericToMeta")
247+
func maybeCastGenericToMeta<T>(_ t: T) -> AnyObject.Type? {
248+
if let m = t as? AnyObject.Type {
249+
return m
250+
}
251+
return nil
252+
}

0 commit comments

Comments
 (0)