Skip to content

Commit 7dd0a60

Browse files
committed
[AddressLowering] Handle unchecked to loadable.
When casting via unchecked_bitwise_cast, if the destination type is loadable, don't mark the value it produces rewritten--that value is not one that AddressLowering is tracking. Instead, replace its copy_value uses with load [copy] uses of the address the rewritten instruction produces.
1 parent 0aca521 commit 7dd0a60

File tree

3 files changed

+87
-1
lines changed

3 files changed

+87
-1
lines changed

lib/SILOptimizer/Mandatory/AddressLowering.cpp

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2776,7 +2776,26 @@ class UseRewriter : SILInstructionVisitor<UseRewriter> {
27762776
uncheckedCastInst->getLoc(), srcAddr,
27772777
uncheckedCastInst->getType().getAddressType());
27782778

2779-
markRewritten(uncheckedCastInst, destAddr);
2779+
if (uncheckedCastInst->getType().isAddressOnly(*pass.function)) {
2780+
markRewritten(uncheckedCastInst, destAddr);
2781+
return;
2782+
}
2783+
2784+
// For loadable cast destination type, replace copies with load copies.
2785+
if (Operand *use = uncheckedCastInst->getSingleUse()) {
2786+
if (auto *cvi = dyn_cast<CopyValueInst>(use->getUser())) {
2787+
auto *load = builder.createLoad(cvi->getLoc(), destAddr,
2788+
LoadOwnershipQualifier::Copy);
2789+
cvi->replaceAllUsesWith(load);
2790+
pass.deleter.forceDelete(cvi);
2791+
return;
2792+
}
2793+
}
2794+
SILValue load =
2795+
builder.emitLoadBorrowOperation(uncheckedCastInst->getLoc(), destAddr);
2796+
uncheckedCastInst->replaceAllUsesWith(load);
2797+
pass.deleter.forceDelete(uncheckedCastInst);
2798+
emitEndBorrows(load);
27802799
}
27812800

27822801
void visitUnconditionalCheckedCastInst(

test/SILOptimizer/address_lowering.sil

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1554,6 +1554,53 @@ bb0(%0 : @guaranteed $T, %1 : $@thick U.Type):
15541554
return %6 : $U
15551555
}
15561556

1557+
// There's only one use and it's a copy, just rewrite it as a load [copy].
1558+
// CHECK-LABEL: sil hidden [ossa] @test_unchecked_bitwise_cast_to_loadable :
1559+
// CHECK: {{bb[0-9]+}}([[ADDR_IN:%[^,]+]] : $*T):
1560+
// CHECK: [[STACK:%[^,]+]] = alloc_stack $T
1561+
// CHECK: copy_addr [[ADDR_IN]] to [init] [[STACK]]
1562+
// CHECK: [[STACK_AS_CLASS:%[^,]+]] = unchecked_addr_cast [[STACK]] : $*T to $*Klass
1563+
// CHECK: [[KLASS:%[^,]+]] = load [copy] [[STACK_AS_CLASS]]
1564+
// CHECK: destroy_addr [[STACK]]
1565+
// CHECK: dealloc_stack [[STACK]]
1566+
// CHECK: return [[KLASS]]
1567+
// CHECK-LABEL: } // end sil function 'test_unchecked_bitwise_cast_to_loadable'
1568+
sil hidden [ossa] @test_unchecked_bitwise_cast_to_loadable : $@convention(thin) <T> (@in_guaranteed T) -> @owned Klass {
1569+
bb0(%instance : @guaranteed $T):
1570+
%copy = copy_value %instance : $T
1571+
%unowned_klass = unchecked_bitwise_cast %copy : $T to $Klass
1572+
%klass = copy_value %unowned_klass : $Klass
1573+
destroy_value %copy : $T
1574+
return %klass : $Klass
1575+
}
1576+
1577+
// There is more than one use of the unchecked_addr_cast. The value should be
1578+
// load_borrow'd and uses of the original should be uses of that load.
1579+
// CHECK-LABEL: sil hidden [ossa] @test_unchecked_bitwise_cast_to_loadable_multiuse : {{.*}} {
1580+
// CHECK: {{bb[0-9]+}}([[INSTANCE:%[^,]+]] : $*T):
1581+
// CHECK: [[STACK:%[^,]+]] = alloc_stack $T
1582+
// CHECK: copy_addr [[INSTANCE]] to [init] [[STACK]]
1583+
// CHECK: [[STACK_AS_CLASS:%[^,]+]] = unchecked_addr_cast [[STACK]] : $*T to $*Klass
1584+
// CHECK: [[BORROWED_KLASS:%[^,]+]] = load_borrow [[STACK_AS_CLASS]]
1585+
// CHECK: [[KLASS_TO_RETURN:%[^,]+]] = copy_value [[BORROWED_KLASS]]
1586+
// CHECK: [[KLASS_TO_DESTROY:%[^,]+]] = copy_value [[BORROWED_KLASS]]
1587+
// CHECK: end_borrow [[BORROWED_KLASS]]
1588+
// CHECK: destroy_value [[KLASS_TO_DESTROY]]
1589+
// CHECK: destroy_addr [[STACK]]
1590+
// CHECK: dealloc_stack [[STACK]]
1591+
// CHECK: return [[KLASS_TO_RETURN]]
1592+
// CHECK-LABEL: } // end sil function 'test_unchecked_bitwise_cast_to_loadable_multiuse'
1593+
sil hidden [ossa] @test_unchecked_bitwise_cast_to_loadable_multiuse : $@convention(thin) <T> (@in_guaranteed T) -> @owned Klass {
1594+
bb0(%instance : @guaranteed $T):
1595+
%copy = copy_value %instance : $T
1596+
%unowned_klass = unchecked_bitwise_cast %copy : $T to $Klass
1597+
%klass = copy_value %unowned_klass : $Klass
1598+
%klass2 = copy_value %unowned_klass : $Klass
1599+
destroy_value %klass2 : $Klass
1600+
destroy_value %copy : $T
1601+
return %klass : $Klass
1602+
}
1603+
15571604
// CHECK-LABEL: sil hidden [ossa] @test_unconditional_checked_cast1 : $@convention(thin) <T> (Builtin.Int64) -> @out T {
15581605
// CHECK: bb0(%0 : $*T, %1 : $Builtin.Int64):
15591606
// CHECK: [[INT:%.*]] = alloc_stack $Builtin.Int64

test/SILOptimizer/opaque_values_Onone_stdlib.swift

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,3 +50,23 @@ func getRawPointer<T>(to value: T) -> Builtin.RawPointer {
5050
func getUnprotectedRawPointer<T>(to value: T) -> Builtin.RawPointer {
5151
return Builtin.unprotectedAddressOfBorrow(value)
5252
}
53+
54+
// CHECK-LABEL: sil hidden @getBridgeObject : {{.*}} {
55+
// CHECK: [[OBJECT_ADDR:%[^,]+]] = unchecked_addr_cast {{%[^,]+}} : $*T to $*Builtin.BridgeObject
56+
// CHECK: [[OBJECT:%[^,]+]] = load [[OBJECT_ADDR]]
57+
// CHECK: return [[OBJECT]]
58+
// CHECK-LABEL: } // end sil function 'getBridgeObject'
59+
@_silgen_name("getBridgeObject")
60+
func toObject<T>(_ object: inout T) -> Builtin.BridgeObject {
61+
Builtin.reinterpretCast(object)
62+
}
63+
64+
// CHECK-LABEL: sil hidden @getAnotherType : {{.*}} {
65+
// CHECK: {{bb[0-9]+}}([[RETADDR:%[^,]+]] : $*U, {{%[^,]+}} : $*T, {{%[^,]+}} : $@thick U.Type):
66+
// CHECK: [[OTHER_TY_ADDR:%[^,]+]] = unchecked_addr_cast {{%[^,]+}} : $*T to $*U
67+
// CHECK: copy_addr [[OTHER_TY_ADDR]] to [init] [[RETADDR]] : $*U
68+
// CHECK-LABEL: } // end sil function 'getAnotherType'
69+
@_silgen_name("getAnotherType")
70+
func getAnotherType<T, U>(_ object: inout T, to ty: U.Type) -> U {
71+
Builtin.reinterpretCast(object)
72+
}

0 commit comments

Comments
 (0)