mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
When we generate code that asks for complete metadata for a fully concrete specific type that doesn't have trivial metadata access, like `(Int, String)` or `[String: [Any]]`, generate a cache variable that points to a mangled name, and use a common accessor function that turns that cache variable into a pointer to the instantiated metadata. This saves a bunch of code size, and should have minimal runtime impact, since the demangling of any string only has to happen once. This mostly just works, though it exposed a couple of issues: - Mangling a type ref including objc protocols didn't cause the objc protocol record to get instantiated. Fixed as part of this patch. - The runtime type demangler doesn't correctly handle retroactive conformances. If there are multiple retroactive conformances in a process at runtime, then even though the mangled string refers to a specific conformance, the runtime still just picks one without listening to the mangler. This is left to fix later, rdar://problem/53828345. There is some more follow-up work that we can do to further improve the gains: - We could improve the runtime-provided entry points, adding versions that don't require size to be cached, and which can handle arbitrary metadata requests. This would allow for mangled names to also be used for incomplete metadata accesses and improve code size of some generic type accessors. However, we'd only be able to take advantage of the new entry points in OSes that ship a new runtime. - We could choose to always symbolic reference all type references, which would generally reduce the size of mangled strings, as well as make runtime demangling more efficient, since it wouldn't need to hit the runtime caches. This would however require that we be able to handle symbolic references across files in the MetadataReader in order to avoid regressing remote mirror functionality.
117 lines
4.1 KiB
Plaintext
117 lines
4.1 KiB
Plaintext
// RUN: %target-swift-frontend -emit-ir %s | %FileCheck %s -DINT=i%target-ptrsize
|
|
|
|
// REQUIRES: CPU=i386 || CPU=x86_64
|
|
|
|
// We have to claim this is raw SIL because there are critical edges from non
|
|
// cond_br instructions.
|
|
sil_stage raw
|
|
|
|
import Builtin
|
|
import Swift
|
|
|
|
protocol P {
|
|
func f() -> Self
|
|
}
|
|
|
|
struct S {
|
|
var v: Int
|
|
}
|
|
|
|
// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc void @testUnconditional0(
|
|
sil @testUnconditional0 : $@convention(thin) (@in P) -> () {
|
|
bb0(%0 : $*P):
|
|
// CHECK: [[T0:%.*]] = alloca [[S:%.*]], align
|
|
// CHECK: [[T1:%.*]] = bitcast [[S]]* [[T0]] to [[OPAQUE:%swift.opaque]]*
|
|
// CHECK: [[T2:%.*]] = bitcast [[P:%.*]]* {{%.*}} to [[OPAQUE]]*
|
|
// CHECK: [[T4:%.*]] = call {{.*}}@"$s12dynamic_cast1P_pMD"
|
|
// CHECK: call i1 @swift_dynamicCast([[OPAQUE]]* [[T1]], [[OPAQUE]]* [[T2]], %swift.type* [[T4]], %swift.type* {{.*}}, [[INT]] 7)
|
|
%1 = alloc_stack $S
|
|
unconditional_checked_cast_addr P in %0 : $*P to S in %1 : $*S
|
|
destroy_addr %1 : $*S
|
|
dealloc_stack %1 : $*S
|
|
%2 = tuple ()
|
|
return %2 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc void @testUnconditional1(
|
|
sil @testUnconditional1 : $@convention(thin) (@in P) -> () {
|
|
bb0(%0 : $*P):
|
|
// CHECK: [[T0:%.*]] = alloca [[S:%.*]], align
|
|
// CHECK: [[T1:%.*]] = bitcast [[S]]* [[T0]] to [[OPAQUE:%swift.opaque]]*
|
|
// CHECK: [[T2:%.*]] = bitcast [[P:%.*]]* {{%.*}} to [[OPAQUE]]*
|
|
// CHECK: [[T4:%.*]] = call {{.*}}@"$s12dynamic_cast1P_pMD"
|
|
// CHECK: call i1 @swift_dynamicCast([[OPAQUE]]* [[T1]], [[OPAQUE]]* [[T2]], %swift.type* [[T4]], %swift.type* {{.*}}, [[INT]] 7)
|
|
%1 = alloc_stack $S
|
|
unconditional_checked_cast_addr P in %0 : $*P to S in %1 : $*S
|
|
destroy_addr %1 : $*S
|
|
dealloc_stack %1 : $*S
|
|
%2 = tuple ()
|
|
return %2 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc void @testConditional0(
|
|
sil @testConditional0 : $@convention(thin) (@in P) -> () {
|
|
bb0(%0 : $*P):
|
|
// CHECK: [[T0:%.*]] = alloca [[S:%.*]], align
|
|
// CHECK: [[T1:%.*]] = bitcast [[S]]* [[T0]] to [[OPAQUE:%swift.opaque]]*
|
|
// CHECK: [[T2:%.*]] = bitcast [[P:%.*]]* {{%.*}} to [[OPAQUE]]*
|
|
// CHECK: [[T4:%.*]] = call {{.*}}@"$s12dynamic_cast1P_pMD"
|
|
// CHECK: [[T5:%.*]] = call i1 @swift_dynamicCast([[OPAQUE]]* [[T1]], [[OPAQUE]]* [[T2]], %swift.type* [[T4]], %swift.type* {{.*}}, [[INT]] 6)
|
|
// CHECK: br i1 [[T5]],
|
|
%1 = alloc_stack $S
|
|
checked_cast_addr_br take_always P in %0 : $*P to S in %1 : $*S, bb1, bb2
|
|
bb1:
|
|
br bb3
|
|
bb2:
|
|
br bb3
|
|
bb3:
|
|
destroy_addr %1 : $*S
|
|
dealloc_stack %1 : $*S
|
|
%2 = tuple ()
|
|
return %2 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc void @testConditional1(
|
|
sil @testConditional1 : $@convention(thin) (@in P) -> () {
|
|
bb0(%0 : $*P):
|
|
// CHECK: [[T0:%.*]] = alloca [[S:%.*]], align
|
|
// CHECK: [[T1:%.*]] = bitcast [[S]]* [[T0]] to [[OPAQUE:%swift.opaque]]*
|
|
// CHECK: [[T2:%.*]] = bitcast [[P:%.*]]* {{%.*}} to [[OPAQUE]]*
|
|
// CHECK: [[T4:%.*]] = call {{.*}}@"$s12dynamic_cast1P_pMD"
|
|
// CHECK: [[T5:%.*]] = call i1 @swift_dynamicCast([[OPAQUE]]* [[T1]], [[OPAQUE]]* [[T2]], %swift.type* [[T4]], %swift.type* {{.*}}, [[INT]] 2)
|
|
// CHECK: br i1 [[T5]],
|
|
%1 = alloc_stack $S
|
|
checked_cast_addr_br take_on_success P in %0 : $*P to S in %1 : $*S, bb1, bb2
|
|
bb1:
|
|
br bb3
|
|
bb2:
|
|
br bb3
|
|
bb3:
|
|
destroy_addr %1 : $*S
|
|
dealloc_stack %1 : $*S
|
|
%2 = tuple ()
|
|
return %2 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc void @testConditional2(
|
|
sil @testConditional2 : $@convention(thin) (@in P) -> () {
|
|
bb0(%0 : $*P):
|
|
// CHECK: [[T0:%.*]] = alloca [[S:%.*]], align
|
|
// CHECK: [[T1:%.*]] = bitcast [[S]]* [[T0]] to [[OPAQUE:%swift.opaque]]*
|
|
// CHECK: [[T2:%.*]] = bitcast [[P:%.*]]* {{%.*}} to [[OPAQUE]]*
|
|
// CHECK: [[T4:%.*]] = call {{.*}}@"$s12dynamic_cast1P_pMD"
|
|
// CHECK: [[T5:%.*]] = call i1 @swift_dynamicCast([[OPAQUE]]* [[T1]], [[OPAQUE]]* [[T2]], %swift.type* [[T4]], %swift.type* {{.*}}, [[INT]] 0)
|
|
// CHECK: br i1 [[T5]],
|
|
%1 = alloc_stack $S
|
|
checked_cast_addr_br copy_on_success P in %0 : $*P to S in %1 : $*S, bb1, bb2
|
|
bb1:
|
|
br bb3
|
|
bb2:
|
|
br bb3
|
|
bb3:
|
|
destroy_addr %1 : $*S
|
|
dealloc_stack %1 : $*S
|
|
%2 = tuple ()
|
|
return %2 : $()
|
|
}
|