1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
|
// RUN: %target-sil-opt -O -wmo -enable-sil-verify-all %s | %FileCheck %s
// REQUIRES: swift_in_compiler
sil_stage canonical
import Builtin
import Swift
import SwiftShims
public class A {
deinit
init()
}
public protocol P {
func foo() -> Int64
}
public class B : A, P {
public func foo() -> Int64
deinit
override init()
}
public class C : A, P {
public func foo() -> Int64
deinit
override init()
}
func imp(x: A & P, y: A & P) -> Int64
public func test(x: B, y: C) -> Int64
// protocol witness for P.foo() in conformance B
sil shared [transparent] [serialized] [thunk] @Pfoo : $@convention(witness_method: P) (@in_guaranteed B) -> Int64 {
// %0 // user: %1
bb0(%0 : $*B):
%1 = load %0 : $*B // users: %2, %3
%2 = class_method %1 : $B, #B.foo : (B) -> () -> Int64, $@convention(method) (@guaranteed B) -> Int64 // user: %3
%3 = apply %2(%1) : $@convention(method) (@guaranteed B) -> Int64 // user: %4
return %3 : $Int64 // id: %4
} // end sil function 'Pfoo'
// B.foo()
sil [noinline] @foo : $@convention(method) (@guaranteed B) -> Int64 {
// %0 // user: %1
bb0(%0 : $B):
debug_value %0 : $B, let, name "self", argno 1 // id: %1
%2 = integer_literal $Builtin.Int64, 1 // user: %3
%3 = struct $Int64 (%2 : $Builtin.Int64) // user: %4
return %3 : $Int64 // id: %4
} // end sil function 'foo'
// This function calls @impl. The optimizer generates a specialization of impl
// based on the arguments passed to it here. Even though this function isn't
// directly checked, it is essential for the optimization.
// test(x:y:)
sil @test :$@convention(thin) (@guaranteed B, @guaranteed C) -> Int64 {
// %0 // users: %5, %4, %2
// %1 // users: %7, %6, %3
bb0(%0 : $B, %1 : $C):
debug_value %0 : $B, let, name "x", argno 1 // id: %2
debug_value %1 : $C, let, name "y", argno 2 // id: %3
strong_retain %0 : $B // id: %4
%5 = init_existential_ref %0 : $B : $B, $A & P // users: %11, %9
strong_retain %1 : $C // id: %6
%7 = init_existential_ref %1 : $C : $C, $A & P // users: %10, %9
// function_ref imp(x:y:)
%8 = function_ref @impl : $@convention(thin) (@guaranteed A & P, @guaranteed A & P) -> Int64 // user: %9
%9 = apply %8(%5, %7) : $@convention(thin) (@guaranteed A & P, @guaranteed A & P) -> Int64 // user: %12
strong_release %7 : $A & P // id: %10
strong_release %5 : $A & P // id: %11
return %9 : $Int64 // id: %12
} // end sil function 'test'
// We're looking of an optimized specialization of @impl, not @impl itself.
// CHECK-NOT: @impl
// CHECK-LABEL: sil shared [noinline] @{{.*}}impl{{.*}}
// In the optimization pass we look for uses of alloc_stack (aka %5).
// This test makes sure that we look at the correct uses with the
// correct dominance order (store before apply before dealloc).
// This function will be passed arguments of type B and C for arguments
// %0 and %1 respectively. We want to make sure that we call B's foo method
// and not C's foo method.
sil hidden [noinline] @impl : $@convention(thin) (@guaranteed A & P, @guaranteed A & P) -> Int64 {
bb0(%0 : $A & P, %1 : $A & P):
%2 = open_existential_ref %0 : $A & P to $@opened("A1F1B526-1463-11EA-932F-ACBC329C418B", A & P) Self
%3 = unchecked_ref_cast %1 : $A & P to $@opened("A1F1B526-1463-11EA-932F-ACBC329C418B", A & P) Self
%5 = alloc_stack $@opened("A1F1B526-1463-11EA-932F-ACBC329C418B", A & P) Self
store %2 to %5 : $*@opened("A1F1B526-1463-11EA-932F-ACBC329C418B", A & P) Self
// We want to make sure that we picked up on the FIRST store and not the second one.
// class C's foo method is named "bar" whereas class B's foo method is named "foo".
// We want to make sure that we call a function named "foo" not "bar".
// CHECK: [[FN:%[0-9]+]] = function_ref @${{.*}}foo{{.*}} : $@convention(thin) () -> Int64
%7 = witness_method $@opened("A1F1B526-1463-11EA-932F-ACBC329C418B", A & P) Self, #P.foo : <Self where Self : P> (Self) -> () -> Int64, %2 : $@opened("A1F1B526-1463-11EA-932F-ACBC329C418B", A & P) Self : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> Int64
// CHECK: apply [[FN]]
%8 = apply %7<@opened("A1F1B526-1463-11EA-932F-ACBC329C418B", A & P) Self>(%5) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> Int64
store %3 to %5 : $*@opened("A1F1B526-1463-11EA-932F-ACBC329C418B", A & P) Self
dealloc_stack %5 : $*@opened("A1F1B526-1463-11EA-932F-ACBC329C418B", A & P) Self
return %8 : $Int64
// CHECK-LABEL: end sil function {{.*}}impl{{.*}}
} // end sil function 'impl'
// C.foo()
sil @bar : $@convention(method) (@guaranteed C) -> Int64
sil_vtable [serialized] B {
#B.foo: (B) -> () -> Int64 : @foo // B.foo()
}
sil_vtable [serialized] C {
#C.foo: (C) -> () -> Int64 : @bar
}
sil_witness_table [serialized] B: P module run {
method #P.foo: <Self where Self : P> (Self) -> () -> Int64 : @Pfoo // protocol witness for P.foo() in conformance B
}
|