// 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] %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_ }