Files
swift-mirror/test/SILOptimizer/devirtualize2.sil
Nate Chandler e5d87f75a8 [SIL] Add source formal type to checked_cast_br.
It is necessary for opaque values where for casts that will newly start
out as checked_cast_brs and be lowered to checked_cast_addr_brs, since
the latter has the source formal type, IRGen relies on being able to
access it, and there's no way in general to obtain the source formal
type from the source lowered type.
2023-07-27 15:04:15 -07:00

127 lines
3.8 KiB
Plaintext

// RUN: %target-sil-opt -enable-sil-verify-all %s -devirtualizer -dce | %FileCheck %s
sil_stage canonical
import Builtin
import Swift
class Bar {
init()
func ping()
}
class Foo : Bar {
override init()
override func ping()
}
sil_global @x : $Bar
// CHECK-LABEL: sil @function_with_cm_with_cast
// CHECK: [[SELF:%.*]] = alloc_ref $Foo
// CHECK: [[CAST_1_SELF:%.*]] = upcast [[SELF]]
// CHECK: [[CAST_2_SELF:%.*]] = unconditional_checked_cast [[CAST_1_SELF]]
// CHECK: [[CAST_3_SELF:%.*]] = upcast [[CAST_2_SELF]]
// CHECK: store [[CAST_3_SELF]] to [[GLOBAL:%.*]] :
// CHECK-NEXT: [[RELOADED_SELF:%.*]] = load [[GLOBAL]]
// CHECK-NOT: class_method
// CHECK: [[REF:%.*]] = function_ref @_TFC4main3Foo4pingfS0_FT_T_
// CHECK: [[SELF:%.*]] = unchecked_ref_cast [[RELOADED_SELF]]
// CHECK: apply [[REF]]([[SELF]])
// CHECK: return
sil @function_with_cm_with_cast : $@convention(thin) () -> () {
bb0:
%0 = global_addr @x : $*Bar // users: %7, %8
%1 = alloc_ref $Foo // users: %5, %3, %2
strong_retain %1 : $Foo // id: %2
%3 = upcast %1 : $Foo to $Bar // user: %4
%4 = unconditional_checked_cast %3 : $Bar to Foo // user: %6
strong_release %1 : $Foo // id: %5
%6 = upcast %4 : $Foo to $Bar // user: %7
store %6 to %0 : $*Bar // id: %7
%8 = load %0 : $*Bar // users: %11, %10, %9
strong_retain %6 : $Bar // id: %9
%10 = class_method %6 : $Bar, #Bar.ping : (Bar) -> () -> (), $@convention(method) (@guaranteed Bar) -> () // user: %11
%11 = apply %10(%8) : $@convention(method) (@guaranteed Bar) -> ()
%12 = tuple () // user: %13
return %12 : $() // id: %13
}
// CHECK-LABEL: sil @function_with_cm_with_dynamic_type_known_from_checked_cast_br
// CHECK-NOT: class_method
// CHECK: bb4([[SELF:%.*]] : $Bar):
// CHECK: [[REF:%.*]] = function_ref @_TFC4main3Bar4pingfS0_FT_T_
// CHECK: apply [[REF]]([[SELF]])
// CHECK: return
sil @function_with_cm_with_dynamic_type_known_from_checked_cast_br : $@convention(thin) (Bar) -> () {
bb0(%0 : $Bar):
checked_cast_br [exact] Bar in %0 : $Bar to Bar, bb1, bb5
bb1(%1 : $Bar):
br bb2(%1 : $Bar)
bb2(%2 : $Bar):
br bb3(%2 : $Bar)
bb3(%3 : $Bar):
br bb4(%3 : $Bar)
bb4(%4 : $Bar):
// Devirtualizer should be able to figure out that the exact dynamic type of %1 is Bar.
%5 = class_method %4 : $Bar, #Bar.ping : (Bar) -> () -> (), $@convention(method) (@guaranteed Bar) -> ()
%6 = apply %5(%4) : $@convention(method) (@guaranteed Bar) -> ()
br bb6
bb5:
br bb6
bb6:
%7 = tuple ()
return %7 : $()
}
// CHECK-LABEL: sil @function_with_cm_with_dynamic_type_known_from_incoming_bb_args
// CHECK-NOT: class_method
// CHECK: bb3([[SELF:%.*]] : $Bar):
// CHECK: [[REF:%.*]] = function_ref @_TFC4main3Bar4pingfS0_FT_T_
// CHECK: apply [[REF]]([[SELF]])
// CHECK: return
sil @function_with_cm_with_dynamic_type_known_from_incoming_bb_args : $@convention(thin) (Builtin.Int1) -> () {
bb0(%0 : $Builtin.Int1):
cond_br %0, bb1, bb2
bb1:
%1 = alloc_ref $Bar
br bb3(%1 : $Bar)
bb2:
%2 = alloc_ref $Bar
br bb3(%2 : $Bar)
bb3(%4 : $Bar):
// Devirtualizer should be able to figure out that the exact dynamic type of %4 is Bar.
%5 = class_method %4 : $Bar, #Bar.ping : (Bar) -> () -> (), $@convention(method) (@guaranteed Bar) -> ()
%6 = apply %5(%4) : $@convention(method) (@guaranteed Bar) -> ()
br bb4
bb4:
strong_release %4 : $Bar
%7 = tuple ()
return %7 : $()
}
sil @_TFC4main3Bar4pingfS0_FT_T_ : $@convention(method) (@guaranteed Bar) -> ()
sil @_TFC4main3Foo4pingfS0_FT_T_ : $@convention(method) (@guaranteed Foo) -> ()
sil_vtable Bar {
#Bar.ping: @_TFC4main3Bar4pingfS0_FT_T_
}
sil_vtable Foo {
#Bar.ping: @_TFC4main3Foo4pingfS0_FT_T_ [override]
}