File: devirtualize_protocol_composition_two_stores.sil

package info (click to toggle)
swiftlang 6.0.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,519,992 kB
  • sloc: cpp: 9,107,863; ansic: 2,040,022; asm: 1,135,751; python: 296,500; objc: 82,456; f90: 60,502; lisp: 34,951; pascal: 19,946; sh: 18,133; perl: 7,482; ml: 4,937; javascript: 4,117; makefile: 3,840; awk: 3,535; xml: 914; fortran: 619; cs: 573; ruby: 573
file content (123 lines) | stat: -rw-r--r-- 5,348 bytes parent folder | download
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
}