Files
swift-mirror/test/IRGen/keypaths.sil
T
John McCall abb146fa0c Teach StackAddress to directly express the kind of allocation that was
performed, and simplify and improve the handling of allocation throughout
IRGen.

The improvements are that we used to use dynamic allocas in a few
places that clearly could and should use static allocas.
2026-03-06 03:15:28 -05:00

622 lines
28 KiB
Plaintext

// RUN: %empty-directory(%t)
// -- Convert <i32 0x...> constants to decimal constants that LLVM will print
// RUN: %{python} %utils/chex.py < %s > %t/keypaths.sil
// RUN: %target-swift-frontend -module-name keypaths -emit-ir %s | %FileCheck %t/keypaths.sil --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize --check-prefix=CHECK-%target-os
sil_stage canonical
import Swift
public struct S: Hashable {
public var x: Int
public let y: String
public var z: C
public var reabstracted: () -> ()
public func hash(into hasher: inout Hasher)
public static func ==(_: S, _: S) -> Bool
}
public class C: Hashable {
public final var x: Int
public final let y: String
public final var z: S
public var w: Int { get set }
public init()
public func hash(into hasher: inout Hasher)
public static func ==(_: C, _: C) -> Bool
}
public class GC<T> {
public final var x: T
}
public struct G<T> {
public var x: T { get set }
public subscript<U: Hashable>(x: U) -> T { get set }
}
public class C1: C { }
public class C2: C1 {
public var reabstracted: () -> ()
}
public struct T {
public var a: (Int, String)
public let b: (f: String, g: Int)
}
public struct TG<T, U, V> {
public var a: (T, U, V)
}
typealias TGA<T, U> = (a: T, b: U)
sil_vtable C {}
sil_vtable C1 {}
sil_vtable C2 {}
// CHECK: %TSi = type <{ [[WORD:i.*]] }>
// -- %a: S.x
// CHECK: [[KP_A:@keypath(\..*)?]] = private global <{ {{.*}} }> <{
// CHECK-SAME: ptr @keypath_once
// CHECK-SAME: @"symbolic{{.*}}8keypaths1SV"
// CHECK-SAME: @"symbolic Si
// -- instantiable in-line, size 4
// CHECK-SAME: <i32 0x8000_0004>,
// -- offset of S.x, mutable
// CHECK-SAME: <i32 0x0180_0000> }>
// -- %b: S.y
// CHECK: [[KP_B:@keypath(\..*)?]] = private global <{ {{.*}} }> <{
// CHECK-SAME: ptr @keypath_once
// CHECK-SAME: @"symbolic{{.*}}8keypaths1SV
// CHECK-SAME: @"symbolic SS
// -- instantiable in-line, size 4
// CHECK-SAME: <i32 0x8000_0004>,
// -- offset of S.y, immutable
// CHECK-32-SAME: <i32 0x0100_0004> }>
// CHECK-64-SAME: <i32 0x0100_0008> }>
// -- %c: S.z
// CHECK: [[KP_C:@keypath(\..*)?]] = private global <{ {{.*}} }> <{
// CHECK-SAME: ptr @keypath_once
// CHECK-SAME: @"symbolic{{.*}}8keypaths1SV
// CHECK-SAME: @"symbolic{{.*}}8keypaths1CC
// -- instantiable in-line, size 4
// CHECK-SAME: <i32 0x8000_0004>,
// -- offset of S.z, mutable
// CHECK-32-SAME: <i32 0x0180_0010> }>
// CHECK-64-SAME: <i32 0x0180_0018> }>
// -- %d: C.x
// CHECK: [[KP_D:@keypath(\..*)?]] = private global <{ {{.*}} }> <{
// CHECK-SAME: ptr @keypath_once
// CHECK-SAME: @"symbolic
// CHECK-SAME: @"symbolic
// -- instantiable in-line, size 4
// CHECK-SAME: <i32 0x8000_0004>,
// -- 0x0300_0000 (class) + mutable + offset of C.x
// CHECK-32-SAME: <i32 0x0380_0008> }>
// CHECK-64-SAME: <i32 0x0380_0010> }>
// -- %d1: C1.x
// CHECK: [[KP_D1:@keypath(\..*)?]] = private global <{ {{.*}} }> <{
// CHECK-SAME: ptr @keypath_once
// CHECK-SAME: @"symbolic
// CHECK-SAME: @"symbolic
// -- instantiable in-line, size 4
// CHECK-SAME: <i32 0x8000_0004>,
// -- 0x0300_0000 (class) + mutable + offset of C.x
// CHECK-32-SAME: <i32 0x0380_0008> }>
// CHECK-64-SAME: <i32 0x0380_0010> }>
// -- %e: C.y
// CHECK: [[KP_E:@keypath(\..*)?]] = private global <{ {{.*}} }> <{
// CHECK-SAME: ptr @keypath_once
// CHECK-SAME: @"symbolic
// CHECK-SAME: @"symbolic
// -- instantiable in-line, size 4
// CHECK-SAME: <i32 0x8000_0004>,
// -- 0x0300_0000 (class) + immutable + offset of C.y
// CHECK-32-SAME: <i32 0x0300_000c> }>
// CHECK-64-SAME: <i32 0x0300_0018> }>
// -- %f: C.z
// CHECK: [[KP_F:@keypath(\..*)?]] = private global <{ {{.*}} }> <{
// CHECK-SAME: ptr @keypath_once
// CHECK-SAME: @"symbolic
// CHECK-SAME: @"symbolic
// -- instantiable in-line, size 4
// CHECK-SAME: <i32 0x8000_0004>,
// -- 0x0300_0000 (class) + mutable offset of C.z
// CHECK-32-SAME: <i32 0x0380_0018> }>
// CHECK-64-SAME: <i32 0x0380_0028> }>
// -- %g: S.z.x
// CHECK: [[KP_G:@keypath(\..*)?]] = private global <{ {{.*}} }> <{
// CHECK-SAME: ptr @keypath_once
// CHECK-SAME: @"symbolic
// CHECK-SAME: @"symbolic
// -- instantiable in-line, size 12
// CHECK-SAME: <i32 0x8000_000c>,
// -- offset of S.z
// CHECK-32-SAME: <i32 0x0180_0010>,
// CHECK-64-SAME: <i32 0x0180_0018>,
// CHECK: @"symbolic
// -- 0x0300_0000 (class) + offset of C.x
// CHECK-32-SAME: <i32 0x0380_0008> }>
// CHECK-64-SAME: <i32 0x0380_0010> }>
// -- %h: C.z.x
// CHECK: [[KP_H:@keypath(\..*)?]] = private global <{ {{.*}} }> <{
// CHECK-SAME: ptr @keypath_once
// CHECK-SAME: @"symbolic
// CHECK-SAME: @"symbolic
// CHECK-SAME: <i32 0x8000_000c>,
// -- 0x0300_0000 (class) + offset of C.z
// CHECK-32-SAME: <i32 0x0380_0018>,
// CHECK-64-SAME: <i32 0x0380_0028>,
// CHECK: @"symbolic
// -- offset of S.x
// CHECK-SAME: <i32 0x0180_0000> }>
// -- %k: computed
// CHECK: [[KP_K:@keypath(\..*)?]] = private global <{ {{.*}} }> <{
// CHECK-SAME: ptr @keypath_once
// CHECK-SAME: @"symbolic
// CHECK-SAME: @"symbolic
// -- instantiable in-line, size 12
// CHECK-SAME: <i32 0x8000_000c>,
// -- computed, get-only, identified by (indirected) function pointer, no args
// CHECK-SAME: <i32 0x0200_0002>,
// CHECK-SAME: @{{got.|"\\01__imp__?}}k_id
// CHECK-SAME: ptr {{.*}}@k_get{{.*}}
// -- %l: computed
// CHECK: [[KP_L:@keypath(\..*)?]] = private global <{ {{.*}} }> <{
// CHECK-SAME: ptr @keypath_once
// CHECK-SAME: @"symbolic
// CHECK-SAME: @"symbolic
// -- instantiable in-line, size 16
// CHECK-SAME: <i32 0x8000_0010>,
// -- computed, settable, nonmutating, identified by direct pointer, no args
// CHECK-SAME: <i32 0x0240_0000>,
// CHECK-SAME: @"$s8keypaths1CCMn"
// CHECK-SAME: ptr @l_get
// CHECK-SAME: ptr @l_set{{.*}}
// -- %m: computed
// CHECK: [[KP_M:@keypath(\..*)?]] = private global <{ {{.*}} }> <{
// CHECK-SAME: ptr @keypath_once
// CHECK-SAME: @"symbolic
// CHECK-SAME: @"symbolic
// -- instantiable in-line, size 16
// CHECK-SAME: <i32 0x8000_0010>,
// -- computed, settable, nonmutating, identified by property offset, no args
// CHECK-SAME: <i32 0x02e0_0000>,
// CHECK-SAME: [[WORD]]
// CHECK-SAME: ptr {{.*}}@m_get
// CHECK-SAME: ptr {{.*}}@m_set{{.*}}
// -- %m2: reabstracted
// Note: the contents here aren't interesting. The test triggered infinite
// looping in the compiler at one point.
// CHECK: [[KP_M:@keypath.*]] = private global <{ {{.*}} }> <{
// -- %t0: T.a.0
// CHECK: [[KP_T0:@keypath(\..*)?]] = private global <{ {{.*}} }> <{
// CHECK-SAME: ptr @keypath_once
// CHECK-SAME: @"symbolic
// CHECK-SAME: @"symbolic
// -- instantiable in-line, size 12
// CHECK-SAME: <i32 0x8000_000c>,
// -- offset of T.a, mutable
// CHECK-SAME: <i32 0x0180_0000>,
// CHECK: @"symbolic
// -- tuple element #0 of T.a
// CHECK-SAME: <i32 0x0180_0000> }>
// -- %t1: T.b.g
// CHECK: [[KP_T1:@keypath(\..*)?]] = private global <{ {{.*}} }> <{
// CHECK-SAME: ptr @keypath_once
// CHECK-SAME: @"symbolic
// CHECK-SAME: @"symbolic
// -- instantiable in-line, size 12
// CHECK-SAME: <i32 0x8000_000c>,
// -- offset of T.b
// CHECK-32-SAME: <i32 0x0100_0010>,
// CHECK-64-SAME: <i32 0x0100_0018>,
// CHECK: @"symbolic
// -- tuple element #1 of T.b
// CHECK-32-SAME: <i32 0x0180_000c> }>
// CHECK-64-SAME: <i32 0x0180_0010> }>
// -- %i: Gen<A>.x
// CHECK: [[KP_I:@keypath(\..*)?]] = private global <{ {{.*}} }> <{
// CHECK-SAME: i32 0
// CHECK-SAME: @"generic environment l"
// CHECK-SAME: @"symbolic{{[^"]*}}8keypaths3GenV{{[^"]*}}"
// CHECK-SAME: @"symbolic x"
// -- size 8
// CHECK-SAME: i32 8,
// -- struct with runtime-resolved offset, mutable
// CHECK-SAME: <i32 0x01fffffe>,
// CHECK-32-SAME: i32 16 }>
// CHECK-64-SAME: i32 32 }>
// -- %j: Gen<A>.y
// CHECK: [[KP_J:@keypath(\..*)?]] = private global <{ {{.*}} }> <{
// CHECK-SAME: i32 0
// CHECK-SAME: @"generic environment l"
// CHECK-SAME: @"symbolic{{[^"]*}}8keypaths3GenV{{[^"]*}}"
// CHECK-SAME: @"symbolic x"
// -- size 8
// CHECK-SAME: i32 8,
// -- struct with runtime-resolved offset
// CHECK-SAME: <i32 0x01fffffe>,
// CHECK-32-SAME: i32 20 }>
// CHECK-64-SAME: i32 36 }>
// -- %tg0: TG<T,U,V>.a.0
// CHECK: [[KP_TG0:@keypath(\..*)?]] = private global <{ {{.*}} }> <{
// CHECK-SAME: @"generic environment r1_l"
// CHECK-SAME: @"symbolic
// CHECK-SAME: @"symbolic
// -- struct with runtime-resolved offset, mutable
// CHECK-SAME: <i32 0x01ff_fffe>,
// -- offset of TG.a
// CHECK-32-SAME: i32 20
// CHECK-64-SAME: i32 40
// CHECK-SAME: @"symbolic
// -- tuple element with compile-time known offset, mutable
// -- tuple element #0 of TG.a
// CHECK-SAME: <i32 0x0180_0000> }>
// -- %tg1: TG<T,U,V>.a.2
// CHECK: [[KP_TG1:@keypath(\..*)?]] = private global <{ {{.*}} }> <{
// CHECK-SAME: @"generic environment r1_l"
// CHECK-SAME: @"symbolic
// CHECK-SAME: @"symbolic
// -- struct with runtime-resolved offset, mutable
// CHECK-SAME: <i32 0x01ff_fffe>,
// -- offset of TG.a
// CHECK-32-SAME: i32 20
// CHECK-64-SAME: i32 40
// CHECK-SAME: @"symbolic
// -- tuple element with runtime-resolved offset, mutable
// CHECK-SAME: <i32 0x01ff_fffe>,
// -- tuple element #2 of TG.a
// CHECK-32-SAME: i32 32 }>
// CHECK-64-SAME: i32 64 }>
// -- %tg2: TGA<T,U>.1
// CHECK: [[KP_TG2:@keypath(\..*)?]] = private global <{ {{.*}} }> <{
// CHECK-SAME: @"generic environment r0_l"
// CHECK-SAME: @"symbolic
// CHECK-SAME: @"symbolic
// -- tuple element with runtime-resolved offset, mutable
// CHECK-SAME: <i32 0x01ff_fffe>,
// -- tuple element #1 of TGA
// CHECK-32-SAME: i32 24 }>
// CHECK-64-SAME: i32 48 }>
// -- %gcx: GC<T>.x
// CHECK: [[KP_GCX:@keypath(\..*)?]] = private global <{ {{.*}} }> <{
// CHECK-SAME: @"generic environment l"
// CHECK-SAME: @"symbolic{{[^"]*}}8keypaths2GCC{{[^"]*}}"
// CHECK-SAME: @"symbolic x"
// -- class with runtime-resolved offset, mutable
// CHECK-SAME: <i32 0x3fffffe>
// CHECK-LABEL: @"generic environment SHRzSHR_r0_l" = linkonce_odr hidden constant
// CHECK-SAME: i32 8193, i16 2, i8 -128, i8 -128, i32 128
// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc void @stored_property_fixed_offsets()
sil @stored_property_fixed_offsets : $@convention(thin) () -> () {
entry:
// CHECK: call ptr @swift_getKeyPath(ptr [[KP_A]], ptr undef)
%a = keypath $KeyPath<S, Int>, (root $S; stored_property #S.x : $Int)
strong_retain %a : $KeyPath<S, Int>
// CHECK: call ptr @swift_getKeyPath(ptr [[KP_B]], ptr undef)
%b = keypath $KeyPath<S, String>, (root $S; stored_property #S.y : $String)
strong_retain %b : $KeyPath<S, String>
// CHECK: call ptr @swift_getKeyPath(ptr [[KP_C]], ptr undef)
%c = keypath $KeyPath<S, C>, (root $S; stored_property #S.z : $C)
strong_retain %c : $KeyPath<S, C>
// CHECK: call ptr @swift_getKeyPath(ptr [[KP_D]], ptr undef)
%d = keypath $KeyPath<C, Int>, (root $C; stored_property #C.x : $Int)
strong_retain %d : $KeyPath<C, Int>
// CHECK: call ptr @swift_getKeyPath(ptr [[KP_D1]], ptr undef)
%d1 = keypath $KeyPath<C1, Int>, (root $C1; stored_property #C.x : $Int)
strong_retain %d1 : $KeyPath<C1, Int>
// CHECK: call ptr @swift_getKeyPath(ptr [[KP_E]], ptr undef)
%e = keypath $KeyPath<C, String>, (root $C; stored_property #C.y : $String)
strong_retain %e : $KeyPath<C, String>
// CHECK: call ptr @swift_getKeyPath(ptr [[KP_F]], ptr undef)
%f = keypath $KeyPath<C, S>, (root $C; stored_property #C.z : $S)
strong_retain %f : $KeyPath<C, S>
// CHECK: call ptr @swift_getKeyPath(ptr [[KP_G]], ptr undef)
%g = keypath $KeyPath<S, Int>, (root $S; stored_property #S.z : $C; stored_property #C.x : $Int)
strong_retain %g : $KeyPath<S, Int>
// CHECK: call ptr @swift_getKeyPath(ptr [[KP_H]], ptr undef)
%h = keypath $KeyPath<C, Int>, (root $C; stored_property #C.z : $S; stored_property #S.x : $Int)
strong_retain %h : $KeyPath<C, Int>
%k = keypath $KeyPath<S, Int>, (root $S; gettable_property $Int, id @k_id : $@convention(thin) () -> (), getter @k_get : $@convention(keypath_accessor_getter) (@in_guaranteed S) -> @out Int)
strong_retain %k : $KeyPath<S, Int>
%l = keypath $KeyPath<C, Int>, (root $C; settable_property $Int, id #C.w!getter, getter @l_get : $@convention(keypath_accessor_getter) (@in_guaranteed C) -> @out Int, setter @l_set : $@convention(keypath_accessor_setter) (@in_guaranteed Int, @in_guaranteed C) -> ())
strong_retain %l : $KeyPath<C, Int>
%m = keypath $KeyPath<S, () -> ()>, (root $S; settable_property $() -> (), id ##S.reabstracted, getter @m_get : $@convention(keypath_accessor_getter) (@in_guaranteed S) -> @out @callee_guaranteed @substituted <A> () -> @out A for <()>, setter @m_set : $@convention(keypath_accessor_setter) (@in_guaranteed @callee_guaranteed @substituted <A> () -> @out A for <()>, @inout S) -> ())
strong_retain %m : $KeyPath<S, () -> ()>
%m2 = keypath $KeyPath<C2, () -> ()>, (root $C2; settable_property $() -> (), id ##C2.reabstracted, getter @m2_get : $@convention(keypath_accessor_getter) (@in_guaranteed C2) -> @out @callee_guaranteed @substituted <A> () -> @out A for <()>, setter @m2_set : $@convention(keypath_accessor_setter) (@in_guaranteed @callee_guaranteed @substituted <A> () -> @out A for <()>, @inout C2) -> ())
strong_retain %m2 : $KeyPath<C2, () -> ()>
// CHECK: call ptr @swift_getKeyPath(ptr [[KP_T0]], ptr undef)
%t0 = keypath $KeyPath<T, Int>, (root $T; stored_property #T.a : $(Int, String); tuple_element #0 : $Int)
strong_retain %t0 : $KeyPath<T, Int>
// CHECK: call ptr @swift_getKeyPath(ptr [[KP_T1]], ptr undef)
%t1 = keypath $KeyPath<T, Int>, (root $T; stored_property #T.b : $(f: String, g: Int); tuple_element #1 : $Int)
strong_retain %t1 : $KeyPath<T, Int>
return undef : $()
}
sil @k_id : $@convention(thin) () -> ()
sil @k_get : $@convention(keypath_accessor_getter) (@in_guaranteed S) -> @out Int {
bb0(%0 : $*Int, %1 : $*S):
unreachable
}
sil @l_get : $@convention(keypath_accessor_getter) (@in_guaranteed C) -> @out Int {
bb0(%0 : $*Int, %1 : $*C):
unreachable
}
sil @l_set : $@convention(keypath_accessor_setter) (@in_guaranteed Int, @in_guaranteed C) -> () {
bb0(%0 : $*Int, %1 : $*C):
unreachable
}
sil @m_get : $@convention(keypath_accessor_getter) (@in_guaranteed S) -> @out @callee_guaranteed @substituted <A> () -> @out A for <()> {
bb0(%0 : $*@callee_guaranteed @substituted <A> () -> @out A for <()>, %1 : $*S):
unreachable
}
sil @m_set : $@convention(keypath_accessor_setter) (@in_guaranteed @callee_guaranteed @substituted <A> () -> @out A for <()>, @inout S) -> () {
bb0(%0 : $*@callee_guaranteed @substituted <A> () -> @out A for <()>, %1 : $*S):
unreachable
}
sil @m2_get : $@convention(keypath_accessor_getter) (@in_guaranteed C2) -> @out @callee_guaranteed @substituted <A> () -> @out A for <()>
sil @m2_set : $@convention(keypath_accessor_setter) (@in_guaranteed @callee_guaranteed @substituted <A> () -> @out A for <()>, @inout C2) -> ()
struct Gen<T, U> {
var x: T
var y: U
}
struct Foo<T> {
var foo: T
}
// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc void @stored_property_generics(ptr %T, ptr %U)
sil @stored_property_generics : $@convention(thin) <T, U> () -> () {
entry:
// CHECK: [[ARGS1:%.*]] = alloca i{{.*}}
// CHECK: [[ARGS2:%.*]] = alloca i{{.*}}
// CHECK: [[ARGS3:%.*]] = alloca i{{.*}}
// CHECK: call void @llvm.lifetime.start.p0(i64 {{.*}}, ptr [[ARGS1]])
// CHECK: store ptr %T, ptr [[ARGS1]]
// CHECK: call ptr @swift_getKeyPath(ptr [[KP_I]], ptr [[ARGS1]])
// CHECK: call void @llvm.lifetime.end.p0(i64 {{.*}}, ptr [[ARGS1]])
%i = keypath $KeyPath<Gen<T,T>, T>, <A> (root $Gen<A, A>; stored_property #Gen.x : $A) <T>
strong_retain %i : $KeyPath<Gen<T,T>, T>
// CHECK: call void @llvm.lifetime.start.p0(i64 {{.*}}, ptr [[ARGS2]])
// CHECK: store ptr %U, ptr [[ARGS2]]
// CHECK: call ptr @swift_getKeyPath(ptr [[KP_J]], ptr [[ARGS2]])
// CHECK: call void @llvm.lifetime.end.p0(i64 {{.*}}, ptr [[ARGS2]])
%j = keypath $KeyPath<Gen<U,U>, U>, <A> (root $Gen<A, A>; stored_property #Gen.y : $A) <U>
strong_retain %j : $KeyPath<Gen<U,U>, U>
// CHECK: call void @llvm.lifetime.start.p0(i64 {{.*}}, ptr [[ARGS3]])
// CHECK: [[T0:%.*]] = call swiftcc %swift.metadata_response @"$s8keypaths3FooVMa"([[WORD]] 0, ptr %T)
// CHECK: [[FOO_T:%.*]] = extractvalue %swift.metadata_response [[T0]], 0
// CHECK: store ptr [[FOO_T]], ptr [[ARGS3]]
// CHECK: call ptr @swift_getKeyPath(ptr [[KP_I]], ptr [[ARGS3]])
// CHECK: call void @llvm.lifetime.end.p0(i64 {{.*}}, ptr [[ARGS3]])
%i2 = keypath $KeyPath<Gen<Foo<T>,Foo<T>>, Foo<T>>, <A> (root $Gen<A, A>; stored_property #Gen.x : $A) <Foo<T>>
strong_retain %i2 : $KeyPath<Gen<Foo<T>,Foo<T>>, Foo<T>>
return undef : $()
}
// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc void @tuple_generics(ptr %T, ptr %U, ptr %V)
sil @tuple_generics : $@convention(thin) <T, U, V> () -> () {
entry:
// CHECK: [[ARGS1:%.*]] = alloca i{{.*}}
// CHECK: [[ARGS2:%.*]] = alloca i{{.*}}
// CHECK: [[ARGS3:%.*]] = alloca i{{.*}}
// CHECK: call void @llvm.lifetime.start.p0(i64 {{.*}}, ptr [[ARGS1]])
// CHECK: store ptr %T, ptr [[ARGS1]]
// CHECK: call ptr @swift_getKeyPath(ptr [[KP_TG0]], ptr [[ARGS1]])
// CHECK: call void @llvm.lifetime.end.p0(i64 {{.*}}, ptr [[ARGS1]])
%tg0 = keypath $KeyPath<TG<T,U,V>, T>, <A,B,C> (root $TG<A,B,C>; stored_property #TG.a : $(A,B,C); tuple_element #0 : $A) <T,U,V>
strong_retain %tg0 : $KeyPath<TG<T,U,V>, T>
// CHECK: call void @llvm.lifetime.start.p0(i64 {{.*}}, ptr [[ARGS2]])
// CHECK: store ptr %T, ptr [[ARGS2]]
// CHECK: call ptr @swift_getKeyPath(ptr [[KP_TG1]], ptr [[ARGS2]])
// CHECK: call void @llvm.lifetime.end.p0(i64 {{.*}}, ptr [[ARGS2]])
%tg1 = keypath $KeyPath<TG<T,U,V>, V>, <A,B,C> (root $TG<A,B,C>; stored_property #TG.a : $(A,B,C); tuple_element #2 : $C) <T,U,V>
strong_retain %tg1 : $KeyPath<TG<T,U,V>, V>
// CHECK: call void @llvm.lifetime.start.p0(i64 {{.*}}, ptr [[ARGS3]])
// CHECK: store ptr %T, ptr [[ARGS3]]
// CHECK: call ptr @swift_getKeyPath(ptr [[KP_TG2]], ptr [[ARGS3]])
// CHECK: call void @llvm.lifetime.end.p0(i64 {{.*}}, ptr [[ARGS3]])
%tg2 = keypath $KeyPath<TGA<T,U>, U>, <A,B> (root $TGA<A,B>; tuple_element #1 : $B) <T,U>
strong_retain %tg2 : $KeyPath<TGA<T,U>, U>
return undef : $()
}
sil @generic_class_stored_final : $@convention(thin) <T> () -> () {
entry:
%gcx = keypath $ReferenceWritableKeyPath<GC<T>, T>, <T> (root $GC<T>; stored_property #GC.x: $T) <T>
strong_retain %gcx : $ReferenceWritableKeyPath<GC<T>, T>
return undef : $()
}
// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc void @computed_property_generics
sil @computed_property_generics : $@convention(thin) <T, U> () -> () {
entry:
%n = keypath $WritableKeyPath<T, U>, <UUU, TTT> (root $TTT; settable_property $UUU, id @n_get : $@convention(keypath_accessor_getter) <UU, TT> (@in_guaranteed TT) -> @out UU, getter @n_get : $@convention(keypath_accessor_getter) <UU, TT> (@in_guaranteed TT) -> @out UU, setter @n_set : $@convention(keypath_accessor_setter) <UU, TT> (@in_guaranteed UU, @in_guaranteed TT) -> ()) <U, T>
return undef : $()
}
sil @n_get : $@convention(keypath_accessor_getter) <UU, TT> (@in_guaranteed TT) -> @out UU
sil @n_set : $@convention(keypath_accessor_setter) <UU, TT> (@in_guaranteed UU, @in_guaranteed TT) -> ()
sil @computed_property_indices : $@convention(thin) (C, S, C, S, C, S) -> () {
entry(%0 : $C, %1 : $S, %2 : $C, %3 : $S, %4 : $C, %5 : $S):
%o = keypath $WritableKeyPath<S, C>, (
root $S;
settable_property $C,
id @o_get : $@convention(keypath_accessor_getter) (@in_guaranteed S, @in_guaranteed Int) -> @out C,
getter @o_get : $@convention(keypath_accessor_getter) (@in_guaranteed S, @in_guaranteed Int) -> @out C,
setter @o_set : $@convention(keypath_accessor_setter) (@in_guaranteed C, @in_guaranteed S, @in_guaranteed Int) -> (),
indices [%$0 : $C : $C],
indices_equals @o_equals : $@convention(keypath_accessor_equals) (@in_guaranteed Int, @in_guaranteed Int) -> Bool,
indices_hash @o_hash : $@convention(keypath_accessor_hash) (@in_guaranteed Int) -> Int
) (%0)
%p = keypath $WritableKeyPath<S, C>, (
root $S;
settable_property $C,
id @o_get : $@convention(keypath_accessor_getter) (@in_guaranteed S, @in_guaranteed Int) -> @out C,
getter @o_get : $@convention(keypath_accessor_getter) (@in_guaranteed S, @in_guaranteed Int) -> @out C,
setter @o_set : $@convention(keypath_accessor_setter) (@in_guaranteed C, @in_guaranteed S, @in_guaranteed Int) -> (),
indices [%$0 : $S : $S, %$1 : $C : $C],
indices_equals @o_equals : $@convention(keypath_accessor_equals) (@in_guaranteed Int, @in_guaranteed Int) -> Bool,
indices_hash @o_hash : $@convention(keypath_accessor_hash) (@in_guaranteed Int) -> Int
) (%1, %2)
%r = keypath $WritableKeyPath<S, S>, (
root $S;
settable_property $C,
id @o_get : $@convention(keypath_accessor_getter) (@in_guaranteed S, @in_guaranteed Int) -> @out C,
getter @o_get : $@convention(keypath_accessor_getter) (@in_guaranteed S, @in_guaranteed Int) -> @out C,
setter @o_set : $@convention(keypath_accessor_setter) (@in_guaranteed C, @in_guaranteed S, @in_guaranteed Int) -> (),
indices [%$0 : $S : $S, %$1 : $C : $C],
indices_equals @o_equals : $@convention(keypath_accessor_equals) (@in_guaranteed Int, @in_guaranteed Int) -> Bool,
indices_hash @o_hash : $@convention(keypath_accessor_hash) (@in_guaranteed Int) -> Int;
settable_property $S,
id @r_get : $@convention(keypath_accessor_getter) (@in_guaranteed C, @in_guaranteed Int) -> @out S,
getter @r_get : $@convention(keypath_accessor_getter) (@in_guaranteed C, @in_guaranteed Int) -> @out S,
setter @r_set : $@convention(keypath_accessor_setter) (@in_guaranteed S, @in_guaranteed C, @in_guaranteed Int) -> (),
indices [%$2 : $S : $S],
indices_equals @o_equals : $@convention(keypath_accessor_equals) (@in_guaranteed Int, @in_guaranteed Int) -> Bool,
indices_hash @o_hash : $@convention(keypath_accessor_hash) (@in_guaranteed Int) -> Int
) (%3, %4, %5)
return undef : $()
}
sil @o_get : $@convention(keypath_accessor_getter) (@in_guaranteed S, @in_guaranteed Int) -> @out C
sil @o_set : $@convention(keypath_accessor_setter) (@in_guaranteed C, @in_guaranteed S, @in_guaranteed Int) -> ()
sil @o_equals : $@convention(keypath_accessor_equals) (@in_guaranteed Int, @in_guaranteed Int) -> Bool
sil @o_hash : $@convention(keypath_accessor_hash) (@in_guaranteed Int) -> Int
sil @r_get : $@convention(keypath_accessor_getter) (@in_guaranteed C, @in_guaranteed Int) -> @out S
sil @r_set : $@convention(keypath_accessor_setter) (@in_guaranteed S, @in_guaranteed C, @in_guaranteed Int) -> ()
sil @generic_computed_property_indices : $@convention(thin) <A: Hashable, B: Hashable> (@in_guaranteed A, @in_guaranteed B, @in_guaranteed A, @in_guaranteed B, @in_guaranteed A, @in_guaranteed B) -> () {
entry(%0 : $*A, %1 : $*B, %2 : $*A, %3 : $*B, %4 : $*A, %5 : $*B):
%s = keypath $WritableKeyPath<A, B>, <X: Hashable, Y: Hashable> (
root $X;
settable_property $Y,
id @s_get : $@convention(keypath_accessor_getter) <T: Hashable, U: Hashable> (@in_guaranteed T, @in_guaranteed Int) -> @out U,
getter @s_get : $@convention(keypath_accessor_getter) <T: Hashable, U: Hashable> (@in_guaranteed T, @in_guaranteed Int) -> @out U,
setter @s_set : $@convention(keypath_accessor_setter) <T: Hashable, U: Hashable> (@in_guaranteed U, @in_guaranteed T, @in_guaranteed Int) -> (),
indices [%$0 : $X : $*X],
indices_equals @s_equals : $@convention(keypath_accessor_equals) <T: Hashable, U: Hashable> (@in_guaranteed Int, @in_guaranteed Int) -> Bool,
indices_hash @s_hash : $@convention(keypath_accessor_hash) <T: Hashable, U: Hashable> (@in_guaranteed Int) -> Int
) <A, B> (%0)
%t = keypath $WritableKeyPath<A, B>, <X: Hashable, Y: Hashable> (
root $X;
settable_property $Y,
id @s_get : $@convention(keypath_accessor_getter) <T: Hashable, U: Hashable> (@in_guaranteed T, @in_guaranteed Int) -> @out U,
getter @s_get : $@convention(keypath_accessor_getter) <T: Hashable, U: Hashable> (@in_guaranteed T, @in_guaranteed Int) -> @out U,
setter @s_set : $@convention(keypath_accessor_setter) <T: Hashable, U: Hashable> (@in_guaranteed U, @in_guaranteed T, @in_guaranteed Int) -> (),
indices [%$0 : $Y : $*Y, %$1 : $X : $*X],
indices_equals @s_equals : $@convention(keypath_accessor_equals) <T: Hashable, U: Hashable> (@in_guaranteed Int, @in_guaranteed Int) -> Bool,
indices_hash @s_hash : $@convention(keypath_accessor_hash) <T: Hashable, U: Hashable> (@in_guaranteed Int) -> Int
) <A, B> (%1, %2)
%v = keypath $WritableKeyPath<A, A>, <X: Hashable, Y: Hashable> (
root $X;
settable_property $Y,
id @s_get : $@convention(keypath_accessor_getter) <T: Hashable, U: Hashable> (@in_guaranteed T, @in_guaranteed Int) -> @out U,
getter @s_get : $@convention(keypath_accessor_getter) <T: Hashable, U: Hashable> (@in_guaranteed T, @in_guaranteed Int) -> @out U,
setter @s_set : $@convention(keypath_accessor_setter) <T: Hashable, U: Hashable> (@in_guaranteed U, @in_guaranteed T, @in_guaranteed Int) -> (),
indices [%$0 : $Y : $*Y, %$1 : $X : $*X],
indices_equals @s_equals : $@convention(keypath_accessor_equals) <T: Hashable, U: Hashable> (@in_guaranteed Int, @in_guaranteed Int) -> Bool,
indices_hash @s_hash : $@convention(keypath_accessor_hash) <T: Hashable, U: Hashable> (@in_guaranteed Int) -> Int;
settable_property $X,
id @v_get : $@convention(keypath_accessor_getter) <T: Hashable, U: Hashable> (@in_guaranteed U, @in_guaranteed Int) -> @out T,
getter @v_get : $@convention(keypath_accessor_getter) <T: Hashable, U: Hashable> (@in_guaranteed U, @in_guaranteed Int) -> @out T,
setter @v_set : $@convention(keypath_accessor_setter) <T: Hashable, U: Hashable> (@in_guaranteed T, @in_guaranteed U, @in_guaranteed Int) -> (),
indices [%$2 : $Y : $*Y],
indices_equals @s_equals : $@convention(keypath_accessor_equals) <T: Hashable, U: Hashable> (@in_guaranteed Int, @in_guaranteed Int) -> Bool,
indices_hash @s_hash : $@convention(keypath_accessor_hash) <T: Hashable, U: Hashable> (@in_guaranteed Int) -> Int
) <A, B> (%3, %4, %5)
strong_retain %s : $WritableKeyPath<A, B>
strong_retain %t : $WritableKeyPath<A, B>
strong_retain %v : $WritableKeyPath<A, A>
return undef : $()
}
sil @identity : $@convention(thin) <T> () -> () {
entry:
%v = keypath $WritableKeyPath<T, T>, <A> (root $A; objc "self") <T>
%w = keypath $WritableKeyPath<Int, Int>, (root $Int; objc "self")
return undef : $()
}
public class GC2<T> {
public final var x: T
public var y: String
}
sil @class_constrained : $@convention(thin) <V where V : C> () -> () {
bb0:
%k = keypath $KeyPath<V, String>, <τ_0_0 where τ_0_0 : C> (root $τ_0_0; stored_property #C.y : $String) <V>
%t = tuple ()
return %t : $()
}
sil @generic_class_constrained : $@convention(thin) <U, V where V : GC2<U>> () -> () {
bb0:
%k = keypath $KeyPath<V, String>, <τ_0_0, τ_0_1 where τ_0_1 : GC2<τ_0_0>> (root $τ_0_1; stored_property #GC2.y : $String) <U, V>
%t = tuple ()
return %t : $()
}
sil @s_get : $@convention(keypath_accessor_getter) <A: Hashable, B: Hashable> (@in_guaranteed A, @in_guaranteed Int) -> @out B
sil @s_set : $@convention(keypath_accessor_setter) <A: Hashable, B: Hashable> (@in_guaranteed B, @in_guaranteed A, @in_guaranteed Int) -> ()
sil @s_equals : $@convention(keypath_accessor_equals) <A: Hashable, B: Hashable> (@in_guaranteed Int, @in_guaranteed Int) -> Bool
sil @s_hash : $@convention(keypath_accessor_hash) <A: Hashable, B: Hashable> (@in_guaranteed Int) -> Int
sil @v_get : $@convention(keypath_accessor_getter) <A: Hashable, B: Hashable> (@in_guaranteed B, @in_guaranteed Int) -> @out A
sil @v_set : $@convention(keypath_accessor_setter) <A: Hashable, B: Hashable> (@in_guaranteed A, @in_guaranteed B, @in_guaranteed Int) -> ()