mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
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
221 lines
5.8 KiB
Plaintext
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
|
|
}
|
|
|
|
|