@@ -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>
@@ -1113,3 +1126,102 @@ bb9:
11131126 return %res : $()
11141127}
11151128
1129+ // Test that a load [take] of an unchecked_addr_cast doesn't get promoted.
1130+ //
1131+ // CHECK-LABEL: sil [ossa] @load_take_unchecked_addr_cast : {{.*}} {
1132+ // CHECK: load [take]
1133+ // CHECK-LABEL: } // end sil function 'load_take_unchecked_addr_cast'
1134+ sil [ossa] @load_take_unchecked_addr_cast : $@convention(thin) (@guaranteed AnyObject) -> () {
1135+ entry(%instance : @guaranteed $AnyObject):
1136+ %copy = copy_value %instance : $AnyObject
1137+ %storage = alloc_stack $AnyObject
1138+ store %copy to [init] %storage : $*AnyObject
1139+ %cast_addr = unchecked_addr_cast %storage : $*AnyObject to $*Klass
1140+ %value = load [take] %cast_addr : $*Klass
1141+ dealloc_stack %storage : $*AnyObject
1142+ destroy_value %value : $Klass
1143+ %retval = tuple ()
1144+ return %retval : $()
1145+ }
1146+
1147+ // Don't bail if the original address is destroyed even if we see a cast.
1148+ //
1149+ // CHECK-LABEL: sil [ossa] @destroy_original_storage : {{.*}} {
1150+ // CHECK: destroy_value
1151+ // CHECK-LABEL: } // end sil function 'destroy_original_storage'
1152+ sil [ossa] @destroy_original_storage : $@convention(thin) (@guaranteed AnyObject) -> () {
1153+ entry(%instance : @guaranteed $AnyObject):
1154+ %copy = copy_value %instance : $AnyObject
1155+ %storage = alloc_stack $AnyObject
1156+ store %copy to [init] %storage : $*AnyObject
1157+ %cast_addr = unchecked_addr_cast %storage : $*AnyObject to $*Klass
1158+ %value = load [copy] %cast_addr : $*Klass
1159+ destroy_addr %storage : $*AnyObject
1160+ dealloc_stack %storage : $*AnyObject
1161+ destroy_value %value : $Klass
1162+ %retval = tuple ()
1163+ return %retval : $()
1164+ }
1165+
1166+ // Bail if the address produced by an unchecked_addr_cast is destroyed.
1167+ //
1168+ // CHECK-LABEL: sil [ossa] @destroy_addr_unchecked_addr_cast : {{.*}} {
1169+ // CHECK: unchecked_addr_cast
1170+ // CHECK: load [copy]
1171+ // CHECK-LABEL: } // end sil function 'destroy_addr_unchecked_addr_cast'
1172+ sil [ossa] @destroy_addr_unchecked_addr_cast : $@convention(thin) (@guaranteed AnyObject) -> () {
1173+ entry(%instance : @guaranteed $AnyObject):
1174+ %copy = copy_value %instance : $AnyObject
1175+ %storage = alloc_stack $AnyObject
1176+ store %copy to [init] %storage : $*AnyObject
1177+ %cast_addr = unchecked_addr_cast %storage : $*AnyObject to $*Klass
1178+ %value = load [copy] %cast_addr : $*Klass
1179+ destroy_addr %cast_addr : $*Klass
1180+ dealloc_stack %storage : $*AnyObject
1181+ destroy_value %value : $Klass
1182+ %retval = tuple ()
1183+ return %retval : $()
1184+ }
1185+
1186+ // Bail if there's a load [take] of one of multiple non-trivial fields.
1187+ //
1188+ // CHECK-LABEL: sil [ossa] @load_take_one_of_two_nontrivial_struct_fields : {{.*}} {
1189+ // CHECK: load [take]
1190+ // CHECK: destroy_addr
1191+ // CHECK-LABEL: } // end sil function 'load_take_one_of_two_nontrivial_struct_fields'
1192+ sil [ossa] @load_take_one_of_two_nontrivial_struct_fields : $@convention(thin) (@guaranteed S) -> () {
1193+ entry(%instance : @guaranteed $S):
1194+ %copy = copy_value %instance : $S
1195+ %storage = alloc_stack $S
1196+ store %copy to [init] %storage : $*S
1197+ %v1_addr = struct_element_addr %storage : $*S, #S.v1
1198+ %cast_addr = unchecked_addr_cast %v1_addr : $*AnyObject to $*Klass
1199+ %value = load [take] %cast_addr : $*Klass
1200+ %v2_addr = struct_element_addr %storage : $*S, #S.v2
1201+ destroy_addr %v2_addr : $*AnyObject
1202+ //destroy_addr %storage : $*S
1203+ dealloc_stack %storage : $*S
1204+ destroy_value %value : $Klass
1205+ %retval = tuple ()
1206+ return %retval : $()
1207+ }
1208+
1209+ // Don't bail if we happen to see an unchecked_addr_cast but then load [take]
1210+ // the original address.
1211+ //
1212+ // CHECK-LABEL: sil [ossa] @load_take_original_despite_cast : {{.*}} {
1213+ // CHECK: unchecked_bitwise_cast
1214+ // CHECK: destroy_value
1215+ // CHECK-LABEL: } // end sil function 'load_take_original_despite_cast'
1216+ sil [ossa] @load_take_original_despite_cast : $@convention(thin) (@owned AnyObject) -> () {
1217+ entry(%instance : @owned $AnyObject):
1218+ %74 = alloc_stack $AnyObject
1219+ store %instance to [init] %74 : $*AnyObject
1220+ %76 = unchecked_addr_cast %74 : $*AnyObject to $*UInt8
1221+ %77 = load [trivial] %76 : $*UInt8
1222+ %79 = load [take] %74 : $*AnyObject
1223+ destroy_value %79 : $AnyObject
1224+ dealloc_stack %74 : $*AnyObject
1225+ %82 = tuple ()
1226+ return %82 : $()
1227+ }
0 commit comments