mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Conformance manglings, which are used for witness tables and related witness thunks, mangle the generic signature of the conformance. Since conformances also describe the conforming type, mangle the conformances's generic signature relative to the conforming type's generic signature. In practice, this means that we don't mangle any part of the generic signature into a conformance mangling now, so we see a decent win: 2.3% smaller trie and 6.4% smaller strings section in the standard library binary. When conditional conformances land, we'll see some generic signatures mangling again (for the additional requirements of the constrained extension).
217 lines
12 KiB
Plaintext
217 lines
12 KiB
Plaintext
// RUN: %target-swift-frontend -primary-file %s -emit-ir | %FileCheck %s --check-prefix=CHECK-%target-runtime --check-prefix=CHECK
|
|
|
|
sil_stage canonical
|
|
|
|
import Builtin
|
|
import Swift
|
|
|
|
class C {}
|
|
class G<T> {}
|
|
|
|
protocol P {}
|
|
|
|
class D : C, P {}
|
|
class E<T> : G<T>, P {}
|
|
|
|
protocol R {}
|
|
|
|
// Make sure we use native reference counting when the existential has a Swift
|
|
// class bound.
|
|
|
|
// CHECK-objc-LABEL: define{{( protected)?}} swiftcc void @checkRefcounting(%T21subclass_existentials1CC*, i8**, %objc_object*, i8**)
|
|
// CHECK-native-LABEL: define{{( protected)?}} swiftcc void @checkRefcounting(%T21subclass_existentials1CC*, i8**, %swift.refcounted*, i8**)
|
|
// CHECK-NEXT: entry:
|
|
// CHECK-objc-NEXT: call void @swift_unknownRelease(%objc_object* %2)
|
|
// CHECK-native-NEXT: call void @swift_rt_swift_release(%swift.refcounted* %2)
|
|
// CHECK-NEXT: call void bitcast (void (%swift.refcounted*)* @swift_rt_swift_release to void (%T21subclass_existentials1CC*)*)(%T21subclass_existentials1CC* %0)
|
|
// CHECK-NEXT: ret void
|
|
|
|
sil @checkRefcounting : $@convention(thin) (@owned C & P, @owned AnyObject & P) -> () {
|
|
bb0(%0 : $C & P, %1 : $AnyObject & P):
|
|
destroy_value %1 : $AnyObject & P
|
|
destroy_value %0 : $C & P
|
|
%6 = tuple ()
|
|
return %6 : $()
|
|
}
|
|
|
|
// Make sure we call the runtime function with the right arguments when we
|
|
// instantiate metadata for a subclass existential.
|
|
|
|
sil @takesMetadata : $@convention(thin) <T> (@thick T.Type) -> ()
|
|
|
|
// CHECK-LABEL: define{{( protected)?}} swiftcc void @checkMetadata()
|
|
// CHECK-NEXT: entry:
|
|
// CHECK-NEXT: %0 = call %swift.type* @_T021subclass_existentials1P_AA1CCXcMa()
|
|
// CHECK-NEXT: call swiftcc void @takesMetadata(%swift.type* %0, %swift.type* %0)
|
|
// CHECK-NEXT: ret void
|
|
|
|
// CHECK-LABEL: define linkonce_odr hidden %swift.type* @_T021subclass_existentials1P_AA1CCXcMa()
|
|
// CHECK: entry:
|
|
// CHECK-NEXT: [[PROTOCOL_ARRAY:%.*]] = alloca [1 x %swift.protocol*]
|
|
// CHECK: cacheIsNull:
|
|
// CHECK: [[PROTOCOLS:%.*]] = bitcast [1 x %swift.protocol*]* [[PROTOCOL_ARRAY]] to %swift.protocol**
|
|
// CHECK-NEXT: [[PROTOCOL:%.*]] = getelementptr inbounds %swift.protocol*, %swift.protocol** [[PROTOCOLS]], i32 0
|
|
// CHECK-NEXT: store %swift.protocol* @_T021subclass_existentials1PMp, %swift.protocol** [[PROTOCOL]]
|
|
// CHECK-NEXT: [[SUPERCLASS:%.*]] = call %swift.type* @_T021subclass_existentials1CCMa()
|
|
// CHECK-NEXT: [[METATYPE:%.*]] = call %swift.type* @swift_rt_swift_getExistentialTypeMetadata(i1 false, %swift.type* [[SUPERCLASS]], {{i32|i64}} 1, %swift.protocol** [[PROTOCOLS]])
|
|
// CHECK: ret
|
|
|
|
sil @checkMetadata : $@convention(thin) () -> () {
|
|
bb0:
|
|
%0 = function_ref @takesMetadata : $@convention(thin) <τ_0_0> (@thick τ_0_0.Type) -> ()
|
|
%1 = metatype $@thin (C & P).Protocol
|
|
%2 = metatype $@thick (C & P).Protocol
|
|
%3 = apply %0<(C & P)>(%2) : $@convention(thin) <τ_0_0> (@thick τ_0_0.Type) -> ()
|
|
%4 = tuple ()
|
|
return %4 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: define{{( protected)?}} swiftcc { %T21subclass_existentials1CC*, i8** } @eraseToExistential(%T21subclass_existentials1DC*)
|
|
// CHECK: [[INSTANCE:%.*]] = bitcast %T21subclass_existentials1DC* %0 to %T21subclass_existentials1CC*
|
|
// CHECK-NEXT: [[RESULT1:%.*]] = insertvalue { %T21subclass_existentials1CC*, i8** } undef, %T21subclass_existentials1CC* [[INSTANCE]], 0
|
|
// CHECK-NEXT: [[RESULT2:%.*]] = insertvalue { %T21subclass_existentials1CC*, i8** } [[RESULT1]], i8** @_T021subclass_existentials1DCAA1PAAWP, 1
|
|
// CHECK-NEXT: ret { %T21subclass_existentials1CC*, i8** } [[RESULT2]]
|
|
sil @eraseToExistential : $@convention(thin) (@owned D) -> @owned C & P {
|
|
bb0(%0 : $D):
|
|
%2 = init_existential_ref %0 : $D : $D, $C & P
|
|
return %2 : $C & P
|
|
}
|
|
|
|
// CHECK-LABEL: define{{( protected)?}} swiftcc { %T21subclass_existentials1GC*, i8** } @eraseToExistentialWithGeneric(%T21subclass_existentials1EC*)
|
|
// CHECK: [[INSTANCE:%.*]] = bitcast %T21subclass_existentials1EC* %0 to %T21subclass_existentials1GC*
|
|
// CHECK-NEXT: [[RESULT1:%.*]] = insertvalue { %T21subclass_existentials1GC*, i8** } undef, %T21subclass_existentials1GC* [[INSTANCE]], 0
|
|
// CHECK-NEXT: [[RESULT2:%.*]] = insertvalue { %T21subclass_existentials1GC*, i8** } [[RESULT1]], i8** @_T021subclass_existentials1ECyxGAA1PAAWP, 1
|
|
// CHECK-NEXT: ret { %T21subclass_existentials1GC*, i8** } [[RESULT2]]
|
|
sil @eraseToExistentialWithGeneric : $@convention(thin) <τ_0_0> (@owned E<τ_0_0>) -> @owned G<τ_0_0> & P {
|
|
bb0(%0 : $E<τ_0_0>):
|
|
%2 = init_existential_ref %0 : $E<τ_0_0> : $E<τ_0_0>, $G<τ_0_0> & P
|
|
return %2 : $G<τ_0_0> & P
|
|
}
|
|
|
|
// CHECK-LABEL: define{{( protected)?}} swiftcc void @checkExistentialDowncast(%T21subclass_existentials1CC*, %T21subclass_existentials1CC*, i8**)
|
|
sil @checkExistentialDowncast : $@convention(thin) (@owned C, @owned C & P) -> () {
|
|
bb0(%0 : $C, %1 : $C & P):
|
|
|
|
// CHECK: [[METATYPE_PTR:%.*]] = bitcast %T21subclass_existentials1CC* %0 to %swift.type**
|
|
// CHECK-NEXT: [[METATYPE:%.*]] = load %swift.type*, %swift.type** [[METATYPE_PTR]], align {{4|8}}
|
|
// CHECK-NEXT: [[VALUE:%.*]] = bitcast %T21subclass_existentials1CC* %0 to i8*
|
|
// CHECK-NEXT: [[SUPERCLASS:%.*]] = call %swift.type* @_T021subclass_existentials1DCMa()
|
|
// CHECK-NEXT: [[RESULT:%.*]] = call { i8*, i8** } @dynamic_cast_existential_1_superclass_unconditional(i8* [[VALUE]], %swift.type* [[METATYPE]], %swift.type* [[SUPERCLASS]], %swift.protocol* @_T021subclass_existentials1RMp)
|
|
// CHECK-NEXT: [[VALUE_ADDR:%.*]] = extractvalue { i8*, i8** } [[RESULT]], 0
|
|
// CHECK-NEXT: [[VALUE:%.*]] = bitcast i8* [[VALUE_ADDR]] to %T21subclass_existentials1DC*
|
|
// CHECK-NEXT: [[WTABLE:%.*]] = extractvalue { i8*, i8** } [[RESULT]], 1
|
|
%2 = unconditional_checked_cast %0 : $C to $D & R
|
|
|
|
// CHECK-NEXT: call void bitcast (void (%swift.refcounted*)* @swift_rt_swift_release to void (%T21subclass_existentials1DC*)*)(%T21subclass_existentials1DC* [[VALUE]])
|
|
destroy_value %2 : $D & R
|
|
|
|
// CHECK-NEXT: [[VALUE:%.*]] = bitcast %T21subclass_existentials1CC* %1 to i8*
|
|
// CHECK-NEXT: [[CLASS_ADDR:%.*]] = bitcast %swift.type* [[SUPERCLASS]] to i8*
|
|
// CHECK-NEXT: [[RESULT:%.*]] = call i8* @swift_dynamicCastClassUnconditional(i8* [[VALUE]], i8* [[CLASS_ADDR]])
|
|
// CHECK-NEXT: [[VALUE:%.*]] = bitcast i8* [[RESULT]] to %T21subclass_existentials1DC*
|
|
%3 = unconditional_checked_cast %1 : $C & P to $D
|
|
|
|
// CHECK-NEXT: call void bitcast (void (%swift.refcounted*)* @swift_rt_swift_release to void (%T21subclass_existentials1DC*)*)(%T21subclass_existentials1DC* [[VALUE]])
|
|
destroy_value %3 : $D
|
|
|
|
// CHECK-NEXT: ret void
|
|
%result = tuple ()
|
|
return %result : $()
|
|
}
|
|
|
|
// CHECK-LABEL: define private { i8*, i8** } @dynamic_cast_existential_1_superclass_unconditional(i8*, %swift.type*, %swift.type*, %swift.protocol*)
|
|
// CHECK: entry:
|
|
// CHECK-NEXT: [[RESULT:%.*]] = call %swift.type* @swift_dynamicCastMetatype(%swift.type* %1, %swift.type* %2)
|
|
// CHECK-NEXT: [[IS_SUBCLASS:%.*]] = icmp ne %swift.type* [[RESULT]], null
|
|
// CHECK-NEXT: br i1 [[IS_SUBCLASS]], label %cont, label %fail
|
|
|
|
// CHECK: cont:
|
|
// CHECK-NEXT: [[WTABLE:%.*]] = call i8** @swift_conformsToProtocol(%swift.type* %1, %swift.protocol* %3)
|
|
// CHECK-NEXT: [[IS_NOT_CONFORMING:%.*]] = icmp eq i8** [[WTABLE]], null
|
|
// CHECK-NEXT: br i1 [[IS_NOT_CONFORMING]], label %fail, label %cont1
|
|
|
|
// CHECK: cont1:
|
|
// CHECK-NEXT: [[RESULT1:%.*]] = insertvalue { i8*, i8** } undef, i8* %0, 0
|
|
// CHECK-NEXT: [[RESULT2:%.*]] = insertvalue { i8*, i8** } [[RESULT1]], i8** [[WTABLE]], 1
|
|
// CHECK-NEXT: ret { i8*, i8** } [[RESULT2]]
|
|
|
|
// CHECK: fail:
|
|
// CHECK-NEXT: call void @llvm.trap()
|
|
// CHECK-NEXT: unreachable
|
|
|
|
// CHECK-LABEL: define{{( protected)?}} swiftcc void @checkExistentialSameClassDowncast(%T21subclass_existentials1CC*)
|
|
sil @checkExistentialSameClassDowncast : $@convention(thin) (@owned C) -> () {
|
|
bb0(%0 : $C):
|
|
|
|
// CHECK: [[METATYPE_PTR:%.*]] = bitcast %T21subclass_existentials1CC* %0 to %swift.type**
|
|
// CHECK-NEXT: [[METATYPE:%.*]] = load %swift.type*, %swift.type** [[METATYPE_PTR]], align {{4|8}}
|
|
// CHECK-NEXT: [[VALUE:%.*]] = bitcast %T21subclass_existentials1CC* %0 to i8*
|
|
// CHECK-NEXT: [[RESULT:%.*]] = call { i8*, i8** } @dynamic_cast_existential_1_unconditional(i8* [[VALUE]], %swift.type* [[METATYPE]], %swift.protocol* @_T021subclass_existentials1PMp)
|
|
// CHECK-NEXT: [[VALUE_ADDR:%.*]] = extractvalue { i8*, i8** } [[RESULT]], 0
|
|
// CHECK-NEXT: [[VALUE:%.*]] = bitcast i8* [[VALUE_ADDR]] to %T21subclass_existentials1CC*
|
|
// CHECK-NEXT: [[WTABLE:%.*]] = extractvalue { i8*, i8** } [[RESULT]], 1
|
|
%2 = unconditional_checked_cast %0 : $C to $C & P
|
|
|
|
// CHECK-NEXT: call void bitcast (void (%swift.refcounted*)* @swift_rt_swift_release to void (%T21subclass_existentials1CC*)*)(%T21subclass_existentials1CC* [[VALUE]])
|
|
destroy_value %2 : $C & P
|
|
|
|
// CHECK-NEXT: ret void
|
|
%result = tuple ()
|
|
return %result : $()
|
|
}
|
|
|
|
// CHECK-LABEL: define private { i8*, i8** } @dynamic_cast_existential_1_unconditional(i8*, %swift.type*, %swift.protocol*)
|
|
// CHECK: entry:
|
|
// CHECK-NEXT: [[WTABLE:%.*]] = call i8** @swift_conformsToProtocol(%swift.type* %1, %swift.protocol* %2)
|
|
// CHECK-NEXT: [[IS_NOT_CONFORMING:%.*]] = icmp eq i8** [[WTABLE]], null
|
|
// CHECK-NEXT: br i1 [[IS_NOT_CONFORMING]], label %fail, label %cont
|
|
|
|
// CHECK: cont:
|
|
// CHECK-NEXT: [[RESULT1:%.*]] = insertvalue { i8*, i8** } undef, i8* %0, 0
|
|
// CHECK-NEXT: [[RESULT2:%.*]] = insertvalue { i8*, i8** } [[RESULT1]], i8** [[WTABLE]], 1
|
|
// CHECK-NEXT: ret { i8*, i8** } [[RESULT2]]
|
|
|
|
// CHECK: fail:
|
|
// CHECK-NEXT: call void @llvm.trap()
|
|
// CHECK-NEXT: unreachable
|
|
|
|
// CHECK-LABEL: define{{( protected)?}} swiftcc void @checkExistentialMetatypeDowncast(%swift.type*, %swift.type*, i8**)
|
|
sil @checkExistentialMetatypeDowncast : $@convention(thin) (@owned @thick C.Type, @owned @thick (C & P).Type) -> () {
|
|
bb0(%0 : $@thick C.Type, %1 : $@thick (C & P).Type):
|
|
|
|
// CHECK: [[METATYPE:%.*]] = bitcast %swift.type* %0 to i8*
|
|
// CHECK-NEXT: [[SUPERCLASS:%.*]] = call %swift.type* @_T021subclass_existentials1DCMa()
|
|
// CHECK-NEXT: [[RESULT:%.*]] = call { i8*, i8** } @dynamic_cast_existential_1_superclass_unconditional(i8* [[METATYPE]], %swift.type* %0, %swift.type* [[SUPERCLASS]], %swift.protocol* @_T021subclass_existentials1RMp)
|
|
// CHECK-NEXT: [[VALUE_ADDR:%.*]] = extractvalue { i8*, i8** } [[RESULT]], 0
|
|
// CHECK-NEXT: [[VALUE:%.*]] = bitcast i8* [[VALUE_ADDR]] to %swift.type*
|
|
// CHECK-NEXT: [[WTABLE:%.*]] = extractvalue { i8*, i8** } [[RESULT]], 1
|
|
%2 = unconditional_checked_cast %0 : $@thick C.Type to $@thick (D & R).Type
|
|
|
|
// CHECK-NEXT: [[RESULT:%.*]] = call %swift.type* @swift_dynamicCastMetatypeUnconditional(%swift.type* %1, %swift.type* [[SUPERCLASS]])
|
|
%3 = unconditional_checked_cast %1 : $@thick (C & P).Type to $@thick D.Type
|
|
|
|
// CHECK-NEXT: ret void
|
|
%result = tuple ()
|
|
return %result : $()
|
|
}
|
|
|
|
// CHECK-LABEL: define{{( protected)?}} swiftcc void @checkExistentialSameClassMetatypeDowncast(%swift.type*)
|
|
sil @checkExistentialSameClassMetatypeDowncast : $@convention(thin) (@owned @thick C.Type) -> () {
|
|
bb0(%0 : $@thick C.Type):
|
|
|
|
// CHECK: [[METATYPE:%.*]] = bitcast %swift.type* %0 to i8*
|
|
// CHECK-NEXT: [[RESULT:%.*]] = call { i8*, i8** } @dynamic_cast_existential_1_unconditional(i8* [[METATYPE]], %swift.type* %0, %swift.protocol* @_T021subclass_existentials1PMp)
|
|
// CHECK-NEXT: [[VALUE_ADDR:%.*]] = extractvalue { i8*, i8** } [[RESULT]], 0
|
|
// CHECK-NEXT: [[VALUE:%.*]] = bitcast i8* [[VALUE_ADDR]] to %swift.type*
|
|
// CHECK-NEXT: [[WTABLE:%.*]] = extractvalue { i8*, i8** } [[RESULT]], 1
|
|
%2 = unconditional_checked_cast %0 : $@thick C.Type to $@thick (C & P).Type
|
|
|
|
// CHECK-NEXT: ret void
|
|
%result = tuple ()
|
|
return %result : $()
|
|
}
|
|
|
|
sil_vtable C {}
|
|
sil_vtable D {}
|
|
sil_vtable G {}
|
|
sil_vtable E {} |