Skip to content

Commit d3717d3

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

File tree

3 files changed

+113
-0
lines changed

3 files changed

+113
-0
lines changed

lib/SILOptimizer/Mandatory/AddressLowering.cpp

Lines changed: 21 additions & 0 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"
@@ -423,6 +424,9 @@ struct AddressLoweringState {
423424
// rewritten.
424425
SmallVector<UnconditionalCheckedCastInst *, 2> nonopaqueResultUCCs;
425426

427+
// checked_cast_br instructions to loadable type which need to be rewritten.
428+
SmallVector<CheckedCastBranchInst *, 2> nonopaqueResultCCBs;
429+
426430
// All function-exiting terminators (return or throw instructions).
427431
SmallVector<TermInst *, 8> exitingInsts;
428432

@@ -654,6 +658,19 @@ void OpaqueValueVisitor::visitValue(SILValue value) {
654658
ucci->getTargetFormalType())) {
655659
pass.nonopaqueResultUCCs.push_back(ucci);
656660
}
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+
}
657674
}
658675
return;
659676
}
@@ -3453,6 +3470,10 @@ static void rewriteFunction(AddressLoweringState &pass) {
34533470
rewriteNonopaqueUnconditionalCheckedCast(ucci, pass);
34543471
}
34553472

3473+
for (auto *ccbi : pass.nonopaqueResultCCBs) {
3474+
CheckedCastBrRewriter(ccbi, pass).rewrite();
3475+
}
3476+
34563477
// Rewrite this function's return value now that all opaque values within the
34573478
// function are rewritten. This still depends on a valid ValueStorage
34583479
// projection operands.

test/SILOptimizer/address_lowering.sil

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

test/SILOptimizer/opaque_values_Onone.swift

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,3 +212,41 @@ func castAnyObjectToMeta(_ ao: any AnyObject) -> AnyObject.Type {
212212
func castGenericToMeta<T>(_ t: T) -> AnyObject.Type {
213213
t as! AnyObject.Type
214214
}
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)