@@ -7,8 +7,17 @@ import Swift
77// Declarations //
88//////////////////
99
10+ typealias AnyObject = Builtin.AnyObject
11+
1012class Klass {}
1113
14+ class X {}
15+
16+ struct S {
17+ var v1: AnyObject
18+ var v2: AnyObject
19+ }
20+
1221struct SmallCodesizeStruct {
1322 var cls1 : Klass
1423 var cls2 : Klass
@@ -40,6 +49,10 @@ public enum FakeOptional<T> {
4049 case none
4150}
4251
52+ struct UInt8 {
53+ var _value : Builtin.Int8
54+ }
55+
4356sil [ossa] @get_nontrivialstruct : $@convention(thin) () -> @owned NonTrivialStruct
4457sil [ossa] @get_nontrivialenum : $@convention(thin) () -> @owned NonTrivialEnum
4558sil [ossa] @get_optionalnontrivialstruct : $@convention(thin) () -> @owned FakeOptional<NonTrivialStruct>
@@ -1114,3 +1127,102 @@ bb9:
11141127 return %res : $()
11151128}
11161129
1130+ // Test that a load [take] of an unchecked_addr_cast doesn't get promoted.
1131+ //
1132+ // CHECK-LABEL: sil [ossa] @load_take_unchecked_addr_cast : {{.*}} {
1133+ // CHECK: load [take]
1134+ // CHECK-LABEL: } // end sil function 'load_take_unchecked_addr_cast'
1135+ sil [ossa] @load_take_unchecked_addr_cast : $@convention(thin) (@guaranteed AnyObject) -> () {
1136+ entry(%instance : @guaranteed $AnyObject):
1137+ %copy = copy_value %instance : $AnyObject
1138+ %storage = alloc_stack $AnyObject
1139+ store %copy to [init] %storage : $*AnyObject
1140+ %cast_addr = unchecked_addr_cast %storage : $*AnyObject to $*Klass
1141+ %value = load [take] %cast_addr : $*Klass
1142+ dealloc_stack %storage : $*AnyObject
1143+ destroy_value %value : $Klass
1144+ %retval = tuple ()
1145+ return %retval : $()
1146+ }
1147+
1148+ // Don't bail if the original address is destroyed even if we see a cast.
1149+ //
1150+ // CHECK-LABEL: sil [ossa] @destroy_original_storage : {{.*}} {
1151+ // CHECK: destroy_value
1152+ // CHECK-LABEL: } // end sil function 'destroy_original_storage'
1153+ sil [ossa] @destroy_original_storage : $@convention(thin) (@guaranteed AnyObject) -> () {
1154+ entry(%instance : @guaranteed $AnyObject):
1155+ %copy = copy_value %instance : $AnyObject
1156+ %storage = alloc_stack $AnyObject
1157+ store %copy to [init] %storage : $*AnyObject
1158+ %cast_addr = unchecked_addr_cast %storage : $*AnyObject to $*Klass
1159+ %value = load [copy] %cast_addr : $*Klass
1160+ destroy_addr %storage : $*AnyObject
1161+ dealloc_stack %storage : $*AnyObject
1162+ destroy_value %value : $Klass
1163+ %retval = tuple ()
1164+ return %retval : $()
1165+ }
1166+
1167+ // Bail if the address produced by an unchecked_addr_cast is destroyed.
1168+ //
1169+ // CHECK-LABEL: sil [ossa] @destroy_addr_unchecked_addr_cast : {{.*}} {
1170+ // CHECK: unchecked_addr_cast
1171+ // CHECK: load [copy]
1172+ // CHECK-LABEL: } // end sil function 'destroy_addr_unchecked_addr_cast'
1173+ sil [ossa] @destroy_addr_unchecked_addr_cast : $@convention(thin) (@guaranteed AnyObject) -> () {
1174+ entry(%instance : @guaranteed $AnyObject):
1175+ %copy = copy_value %instance : $AnyObject
1176+ %storage = alloc_stack $AnyObject
1177+ store %copy to [init] %storage : $*AnyObject
1178+ %cast_addr = unchecked_addr_cast %storage : $*AnyObject to $*Klass
1179+ %value = load [copy] %cast_addr : $*Klass
1180+ destroy_addr %cast_addr : $*Klass
1181+ dealloc_stack %storage : $*AnyObject
1182+ destroy_value %value : $Klass
1183+ %retval = tuple ()
1184+ return %retval : $()
1185+ }
1186+
1187+ // Bail if there's a load [take] of one of multiple non-trivial fields.
1188+ //
1189+ // CHECK-LABEL: sil [ossa] @load_take_one_of_two_nontrivial_struct_fields : {{.*}} {
1190+ // CHECK: load [take]
1191+ // CHECK: destroy_addr
1192+ // CHECK-LABEL: } // end sil function 'load_take_one_of_two_nontrivial_struct_fields'
1193+ sil [ossa] @load_take_one_of_two_nontrivial_struct_fields : $@convention(thin) (@guaranteed S) -> () {
1194+ entry(%instance : @guaranteed $S):
1195+ %copy = copy_value %instance : $S
1196+ %storage = alloc_stack $S
1197+ store %copy to [init] %storage : $*S
1198+ %v1_addr = struct_element_addr %storage : $*S, #S.v1
1199+ %cast_addr = unchecked_addr_cast %v1_addr : $*AnyObject to $*Klass
1200+ %value = load [take] %cast_addr : $*Klass
1201+ %v2_addr = struct_element_addr %storage : $*S, #S.v2
1202+ destroy_addr %v2_addr : $*AnyObject
1203+ //destroy_addr %storage : $*S
1204+ dealloc_stack %storage : $*S
1205+ destroy_value %value : $Klass
1206+ %retval = tuple ()
1207+ return %retval : $()
1208+ }
1209+
1210+ // Don't bail if we happen to see an unchecked_addr_cast but then load [take]
1211+ // the original address.
1212+ //
1213+ // CHECK-LABEL: sil [ossa] @load_take_original_despite_cast : {{.*}} {
1214+ // CHECK: unchecked_bitwise_cast
1215+ // CHECK: destroy_value
1216+ // CHECK-LABEL: } // end sil function 'load_take_original_despite_cast'
1217+ sil [ossa] @load_take_original_despite_cast : $@convention(thin) (@owned AnyObject) -> () {
1218+ entry(%instance : @owned $AnyObject):
1219+ %74 = alloc_stack $AnyObject
1220+ store %instance to [init] %74 : $*AnyObject
1221+ %76 = unchecked_addr_cast %74 : $*AnyObject to $*UInt8
1222+ %77 = load [trivial] %76 : $*UInt8
1223+ %79 = load [take] %74 : $*AnyObject
1224+ destroy_value %79 : $AnyObject
1225+ dealloc_stack %74 : $*AnyObject
1226+ %82 = tuple ()
1227+ return %82 : $()
1228+ }
0 commit comments