Skip to content

Commit a42e76b

Browse files
committed
SimplifyLoad/SimplifyLoadBorrow: replace address casts of head objects
Replaces address casts of heap objects ``` %1 = unchecked_addr_cast %0 : $*SomeClass to $*OtherClass %2 = load [copy] %1 ``` with ref-casts of the loaded value ``` %1 = load [copy] %0 %2 = unchecked_ref_cast %1 : $SomeClass to $OtherClass ```
1 parent 27d9ec8 commit a42e76b

File tree

5 files changed

+148
-4
lines changed

5 files changed

+148
-4
lines changed

SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyLoad.swift

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ extension LoadInst : OnoneSimplifiable, SILCombineSimplifiable {
2626
if replaceLoadOfGlobalLet(context) {
2727
return
2828
}
29+
if tryRemoveAddressCast(context) {
30+
return
31+
}
2932
removeIfDead(context)
3033
}
3134

@@ -116,6 +119,27 @@ extension LoadInst : OnoneSimplifiable, SILCombineSimplifiable {
116119
return true
117120
}
118121

122+
/// Replaces address casts of heap objects
123+
/// ```
124+
/// %1 = unchecked_addr_cast %0 : $*SomeClass to $*OtherClass
125+
/// %2 = load [copy] %1
126+
/// ```
127+
/// with ref-casts of the loaded value
128+
/// ```
129+
/// %1 = load [copy] %0
130+
/// %2 = unchecked_ref_cast %1 : $SomeClass to $OtherClass
131+
/// ```
132+
private func tryRemoveAddressCast(_ context: SimplifyContext) -> Bool {
133+
guard let addrCast = address.isAddressCastOfHeapObjects else {
134+
return false
135+
}
136+
let builder = Builder(before: self, context)
137+
let newLoad = builder.createLoad(fromAddress: addrCast.fromAddress, ownership: loadOwnership)
138+
let cast = builder.createUncheckedRefCast(from: newLoad, to: addrCast.type.objectType)
139+
replace(with: cast, context)
140+
return true
141+
}
142+
119143
private func isZeroLoadFromEmptyCollection() -> Bool {
120144
if !type.isBuiltinInteger {
121145
return false
@@ -364,6 +388,18 @@ private extension Value {
364388
}
365389
}
366390

391+
extension Value {
392+
var isAddressCastOfHeapObjects: UncheckedAddrCastInst? {
393+
if let addrCast = self as? UncheckedAddrCastInst,
394+
addrCast.fromAddress.type.isHeapObjectReferenceType,
395+
addrCast.type.isHeapObjectReferenceType
396+
{
397+
return addrCast
398+
}
399+
return nil
400+
}
401+
}
402+
367403
private extension Instruction {
368404
var isShiftRightByAtLeastOne: Bool {
369405
guard let bi = self as? BuiltinInst,

SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyLoadBorrow.swift

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,20 +32,64 @@ extension LoadBorrowInst : Simplifiable, SILCombineSimplifiable {
3232
// %3 = some_forwarding_instruction %1 // zero or more forwarding instructions
3333
// ```
3434
//
35-
tryCombineWithCopy(context)
35+
if tryCombineWithCopy(context) {
36+
return
37+
}
38+
39+
if tryRemoveAddrCast(context) {
40+
return
41+
}
42+
43+
tryForwardStoreBorrow(context)
3644
}
3745

38-
private func tryCombineWithCopy(_ context: SimplifyContext) {
46+
private func tryCombineWithCopy(_ context: SimplifyContext) -> Bool {
3947
let forwardedValue = lookThroughOwnedConvertibaleForwardingChain()
4048
guard let singleUser = forwardedValue.uses.ignore(usersOfType: EndBorrowInst.self).singleUse?.instruction,
4149
let copy = singleUser as? CopyValueInst,
4250
copy.parentBlock == self.parentBlock else {
43-
return
51+
return false
4452
}
4553
let builder = Builder(before: self, context)
4654
let loadCopy = builder.createLoad(fromAddress: address, ownership: .copy)
4755
let forwardedOwnedValue = replaceGuaranteed(value: self, withOwnedValue: loadCopy, context)
4856
copy.replace(with: forwardedOwnedValue, context)
4957
context.erase(instructionIncludingAllUsers: self)
58+
return true
59+
}
60+
61+
/// Replaces address casts of heap objects
62+
/// ```
63+
/// %1 = unchecked_addr_cast %0 : $*SomeClass to $*OtherClass
64+
/// %2 = load_borrow %1
65+
/// // ... uses of %2
66+
/// end_borrow %2
67+
/// ```
68+
/// with ref-casts of the loaded value
69+
/// ```
70+
/// %1 = load_borrow %0
71+
/// %2 = unchecked_ref_cast %1 : $SomeClass to $OtherClass
72+
/// // ... uses of %2
73+
/// end_borrow %2
74+
/// ```
75+
private func tryRemoveAddrCast(_ context: SimplifyContext) -> Bool {
76+
guard let addrCast = address.isAddressCastOfHeapObjects else {
77+
return false
78+
}
79+
let builder = Builder(before: self, context)
80+
let newLoad = builder.createLoadBorrow(fromAddress: addrCast.fromAddress)
81+
let cast = builder.createUncheckedRefCast(from: newLoad, to: addrCast.type.objectType)
82+
replace(with: newLoad, context)
83+
newLoad.uses.filter{ !$0.endsLifetime }.ignore(user: cast).replaceAll(with: cast, context)
84+
return true
85+
}
86+
87+
private func tryForwardStoreBorrow(_ context: SimplifyContext) {
88+
guard let storeBorrow = address as? StoreBorrowInst else {
89+
return
90+
}
91+
let builder = Builder(before: self, context)
92+
let beginBorrow = builder.createBeginBorrow(of: storeBorrow.source)
93+
replace(with: beginBorrow, context)
5094
}
5195
}

test/SILOptimizer/pre_specialize_layouts.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,8 @@ internal func testEmitIntoClient<T>(t: T) {
158158
// OPT: [[R8:%.*]] = unchecked_addr_cast [[R7]] : $*AnyObject to $*SomeClass
159159
// OPT: [[F6:%.*]] = function_ref @$s30pre_specialized_module_layouts14InternalThing2V9computedZxvryXl_Ts5 : $@yield_once @convention(method) (@guaranteed InternalThing2<AnyObject>) -> @yields @in_guaranteed AnyObject
160160
// OPT: ([[R9:%.*]], {{%.*}}) = begin_apply [[F6]]({{.*}}) : $@yield_once @convention(method) (@guaranteed InternalThing2<AnyObject>) -> @yields @in_guaranteed AnyObject
161-
// OPT: [[R10:%.*]] = unchecked_addr_cast [[R9]] : $*AnyObject to $*SomeClass
161+
// OPT: [[LD:%.*]] = load [[R9]]
162+
// OPT: [[R10:%.*]] = unchecked_ref_cast [[LD]] : $AnyObject to $SomeClass
162163
// OPT: } // end sil function '$s30pre_specialized_module_layouts16useInternalThingyyxlFAA9SomeClassC_Tg5'
163164

164165
public func usePrespecializedEntryPoints(wrapperStruct: ReferenceWrapperStruct, overaligned: OveralignedReferenceWrapperStruct, array: [Int], stride96: Stride96) {

test/SILOptimizer/simplify_load.sil

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ class D : C {
3131
@_hasStorage var d: Builtin.Int64
3232
}
3333

34+
struct AO {
35+
let a: AnyObject
36+
}
37+
3438
sil_global hidden [let] @gb : $B
3539
sil_global hidden [let] @gb2 : $(B, Int64)
3640

@@ -543,3 +547,45 @@ bb0:
543547
return %4
544548
}
545549

550+
// CHECK-LABEL: sil [ossa] @load_of_addr_cast :
551+
// CHECK: %1 = load [copy] %0
552+
// CHECK: %2 = unchecked_ref_cast %1 : $B to $AnyObject
553+
// CHECK: fix_lifetime %2
554+
// CHECK: destroy_value %2
555+
// CHECK: } // end sil function 'load_of_addr_cast'
556+
sil [ossa] @load_of_addr_cast : $@convention(thin) (@inout B) -> () {
557+
bb0(%0 : $*B):
558+
%1 = unchecked_addr_cast %0 to $*AnyObject
559+
%2 = load [copy] %1
560+
fix_lifetime %2
561+
destroy_value %2
562+
%6 = tuple ()
563+
return %6
564+
}
565+
566+
// CHECK-LABEL: sil [ossa] @dont_remove_non_class_addr_cast1 :
567+
// CHECK: %1 = unchecked_addr_cast %0
568+
// CHECK: } // end sil function 'dont_remove_non_class_addr_cast1'
569+
sil [ossa] @dont_remove_non_class_addr_cast1 : $@convention(thin) (@inout AO) -> () {
570+
bb0(%0 : $*AO):
571+
%1 = unchecked_addr_cast %0 to $*AnyObject
572+
%2 = load [copy] %1
573+
fix_lifetime %2
574+
destroy_value %2
575+
%6 = tuple ()
576+
return %6
577+
}
578+
579+
// CHECK-LABEL: sil [ossa] @dont_remove_non_class_addr_cast2 :
580+
// CHECK: %1 = unchecked_addr_cast %0
581+
// CHECK: } // end sil function 'dont_remove_non_class_addr_cast2'
582+
sil [ossa] @dont_remove_non_class_addr_cast2 : $@convention(thin) (@inout AnyObject) -> () {
583+
bb0(%0 : $*AnyObject):
584+
%1 = unchecked_addr_cast %0 to $*AO
585+
%2 = load [copy] %1
586+
fix_lifetime %2
587+
destroy_value %2
588+
%6 = tuple ()
589+
return %6
590+
}
591+

test/SILOptimizer/simplify_load_borrow.sil

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,3 +93,20 @@ bb0(%0 : $*B):
9393
%4 = tuple ()
9494
return %4
9595
}
96+
97+
// CHECK-LABEL: sil [ossa] @load_of_addr_cast :
98+
// CHECK: %1 = load_borrow %0
99+
// CHECK: %2 = unchecked_ref_cast %1 to $AnyObject
100+
// CHECK: fix_lifetime %2
101+
// CHECK: end_borrow %1
102+
// CHECK: } // end sil function 'load_of_addr_cast'
103+
sil [ossa] @load_of_addr_cast : $@convention(thin) (@inout B) -> () {
104+
bb0(%0 : $*B):
105+
%1 = unchecked_addr_cast %0 to $*AnyObject
106+
%2 = load_borrow %1
107+
fix_lifetime %2
108+
end_borrow %2
109+
%6 = tuple ()
110+
return %6
111+
}
112+

0 commit comments

Comments
 (0)