Files
swift-mirror/test/SILOptimizer/function_uses.sil
Yuta Saito c5314bd3af Centralize KeyPath accessor calling convention logic to IRGen
KeyPath's getter/setter/hash/equals functions have their own calling
convention, which receives generic arguments and embedded indices from a
given KeyPath argument buffer.
The convention was previously implemented by:
1. Accepting an argument buffer as an UnsafeRawPointer and casting it to
   indices tuple pointer in SIL.
2. Bind generic arguments info from the given argument buffer while emitting
   prologue in IRGen by creating a new forwarding thunk.

This 2-phase lowering approach was not ideal, as it blocked KeyPath
projection optimization [^1], and also required having a target arch
specific signature lowering logic in SIL-level [^2].

This patch centralizes the KeyPath accessor calling convention logic to
IRGen, by introducing `@convention(keypath_accessor_XXX)` convention in
SIL and lowering it in IRGen. This change unblocks the KeyPath projection
optimization while capturing subscript indices, and also makes it easier
to support WebAssembly target.

[^1]: https://github.com/apple/swift/pull/28799
[^2]: https://forums.swift.org/t/wasm-support/16087/21
2023-09-20 11:25:39 -07:00

221 lines
5.8 KiB
Plaintext

// RUN: %target-sil-opt -wmo -dump-function-uses %s -o /dev/null | %FileCheck %s
// REQUIRES: swift_in_compiler
sil_stage canonical
import Builtin
import Swift
import SwiftShims
// CHECK-LABEL: Uses of public_func
// CHECK-NEXT: [
// CHECK-NEXT: <unknown uses>
// CHECK-NEXT: @other_public_func:
// CHECK-NEXT: %0 = function_ref @public_func
// CHECK-NEXT: @internal_func:
// CHECK-NEXT: %1 = function_ref @public_func
// CHECK-NEXT: @internal_func:
// CHECK-NEXT: %0 = function_ref @public_func
// CHECK-NEXT: ]
// CHECK-NEXT: End function public_func
sil @public_func : $@convention(thin) () -> ()
// CHECK-LABEL: Uses of internal_func
// CHECK-NEXT: [
// CHECK-NEXT: @other_public_func:
// CHECK-NEXT: %1 = dynamic_function_ref @internal_func
// CHECK-NEXT: ]
// CHECK-NEXT: End function internal_func
sil hidden [dynamically_replacable] @internal_func : $@convention(thin) () -> () {
bb0:
%0 = function_ref @public_func : $@convention(thin) () -> ()
%1 = function_ref @public_func : $@convention(thin) () -> ()
%7 = tuple ()
return %7 : $()
}
// CHECK-LABEL: Uses of other_public_func
// CHECK-NEXT: [
// CHECK-NEXT: <unknown uses>
// CHECK-NEXT: ]
// CHECK-NEXT: End function other_public_func
sil @other_public_func : $@convention(thin) () -> () {
bb0:
%0 = function_ref @public_func : $@convention(thin) () -> ()
%1 = dynamic_function_ref @internal_func : $@convention(thin) () -> ()
%7 = tuple ()
return %7 : $()
}
struct S: Hashable {
var x: Int
let y: String
var z: C
func hash(into hasher: inout Hasher)
static func ==(x: S, y: S) -> Bool
}
class C: Hashable {
final var x: Int
final let y: String
final var z: S
init()
var overridable: Int {
get set
}
func hash(into hasher: inout Hasher)
static func ==(x: C, y: C) -> Bool
}
// CHECK-LABEL: Uses of id_a
// CHECK-NEXT: [
// CHECK-NEXT: @test_keypath: %2 = keypath {{.*}}
// CHECK-NEXT: ]
// CHECK-NEXT: End function id_a
sil hidden @id_a : $@convention(thin) () -> () {
bb0:
unreachable
}
// CHECK-LABEL: Uses of get_s_int_subs
// CHECK-NEXT: [
// CHECK-NEXT: @test_keypath: %2 = keypath {{.*}}
// CHECK-NEXT: ]
// CHECK-NEXT: End function get_s_int_subs
sil hidden @get_s_int_subs : $@convention(keypath_accessor_getter) (@in_guaranteed S, @in_guaranteed (S, C)) -> @out Int {
bb0(%0 : $*Int, %1 : $*S, %2 : $*(S, C)):
unreachable
}
// CHECK-LABEL: Uses of set_s_int_subs
// CHECK-NEXT: [
// CHECK-NEXT: @test_keypath: %2 = keypath {{.*}}
// CHECK-NEXT: ]
// CHECK-NEXT: End function set_s_int_subs
sil hidden @set_s_int_subs : $@convention(keypath_accessor_setter) (@in_guaranteed Int, @in_guaranteed S, @in_guaranteed (S, C)) -> () {
bb0(%0 : $*Int, %1 : $*S, %2 : $*(S, C)):
unreachable
}
// CHECK-LABEL: Uses of subs_eq
// CHECK-NEXT: [
// CHECK-NEXT: @test_keypath: %2 = keypath {{.*}}
// CHECK-NEXT: ]
// CHECK-NEXT: End function subs_eq
sil hidden @subs_eq : $@convention(keypath_accessor_equals) (@in_guaranteed (S, C), @in_guaranteed (S, C)) -> Bool {
bb0(%0 : $*(S, C), %1 : $*(S, C)):
unreachable
}
// CHECK-LABEL: Uses of subs_hash
// CHECK-NEXT: [
// CHECK-NEXT: @test_keypath: %2 = keypath {{.*}}
// CHECK-NEXT: ]
// CHECK-NEXT: End function subs_hash
sil hidden @subs_hash : $@convention(keypath_accessor_hash) (@in_guaranteed (S, C)) -> Int {
bb0(%0 : $*(S, C)):
unreachable
}
// CHECK-LABEL: Uses of test_keypath
// CHECK-NEXT: [
// CHECK-NEXT: <unknown uses>
// CHECK-NEXT: ]
// CHECK-NEXT: End function test_keypath
sil @test_keypath : $@convention(thin) (S, C) -> () {
bb0(%0 : $S, %1 : $C):
%2 = keypath $KeyPath<S, Int>, (root $S; settable_property $Int, id @id_a : $@convention(thin) () -> (), getter @get_s_int_subs : $@convention(keypath_accessor_getter) (@in_guaranteed S, @in_guaranteed (S, C)) -> @out Int, setter @set_s_int_subs : $@convention(keypath_accessor_setter) (@in_guaranteed Int, @in_guaranteed S, @in_guaranteed (S, C)) -> (), indices [%$0 : $S : $S, %$1 : $C : $C], indices_equals @subs_eq : $@convention(keypath_accessor_equals) (@in_guaranteed (S, C), @in_guaranteed (S, C)) -> Bool, indices_hash @subs_hash : $@convention(keypath_accessor_hash) (@in_guaranteed (S, C)) -> Int) (%0, %1)
%7 = tuple ()
return %7 : $()
}
public protocol RP {
func default_witness()
}
// CHECK-LABEL: Uses of default_witness
// CHECK-NEXT: [
// CHECK-NEXT: <unknown uses>
// CHECK-NEXT: ]
// CHECK-NEXT: End function default_witness
sil hidden @default_witness : $@convention(witness_method: RP) <Self where Self : RP> (@in_guaranteed Self) -> () {
bb0(%0 : $*Self):
%7 = tuple ()
return %7 : $()
}
sil_default_witness_table RP {
method #RP.default_witness: @default_witness
}
public protocol RP2 {
}
sil_default_witness_table RP2 {
no_default
}
protocol P {
func witness()
func witness2()
}
struct SP : P {
func witness()
func witness2()
}
struct SP2 : P {
func witness()
func witness2()
}
// CHECK-LABEL: Uses of witness
// CHECK-NEXT: [
// CHECK-NEXT: <unknown uses>
// CHECK-NEXT: ]
// CHECK-NEXT: End function witness
sil @witness : $@convention(witness_method: P) (@inout SP) -> () {
bb0(%0 : $*SP):
%7 = tuple ()
return %7 : $()
}
sil @witness2 : $@convention(witness_method: P) (@inout SP) -> () {
bb0(%0 : $*SP):
%7 = tuple ()
return %7 : $()
}
sil_witness_table SP: P module witness_tables {
method #P.witness: @witness
method #P.witness2: @witness2
}
sil_witness_table SP2: P module witness_tables {
method #P.witness: @witness
method #P.witness2: @witness2
}
// CHECK-LABEL: Uses of hash_func
// CHECK-NEXT: [
// CHECK-NEXT: <unknown uses>
// CHECK-NEXT: ]
// CHECK-NEXT: End function hash_func
sil hidden @hash_func : $@convention(method) (@inout Hasher, @guaranteed C) -> () {
bb0(%0 : $*Hasher, %1 : $C):
%4 = tuple ()
return %4 : $()
}
sil_vtable C {
#C.hash: (C) -> (inout Hasher) -> () : @hash_func
}