blob: b60254bce1d591dfb630659694734600650ddff8 [file] [log] [blame]
// RUN: %target-swift-frontend -primary-file %s -emit-ir | %FileCheck %s --check-prefix=CHECK-%target-runtime --check-prefix=CHECK -DINT=i%target-ptrsize
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{{( dllexport)?}}{{( protected)?}} swiftcc void @checkRefcounting(%T21subclass_existentials1CC*, i8**, %objc_object*, i8**)
// CHECK-native-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc void @checkRefcounting(%T21subclass_existentials1CC*, i8**, %swift.refcounted*, i8**)
// CHECK-NEXT: entry:
// CHECK-objc-NEXT: call void @swift_unknownObjectRelease(%objc_object* %2)
// CHECK-native-NEXT: call void @swift_release(%swift.refcounted* %2)
// CHECK-NEXT: call void bitcast (void (%swift.refcounted*)* @swift_release to void (%T21subclass_existentials1CC*)*)(%T21subclass_existentials1CC* %0)
// CHECK-NEXT: ret void
sil [ossa] @checkRefcounting : $@convention(thin) (@owned C & P, @owned AnyObject & P) -> () {
bb0(%0 : @owned $C & P, %1 : @owned $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{{( dllexport)?}}{{( protected)?}} swiftcc void @checkMetadata()
// CHECK-NEXT: entry:
// CHECK-NEXT: [[TMP:%.*]] = call swiftcc %swift.metadata_response @"$s21subclass_existentials1P_AA1CCXcMa"([[INT]] 0)
// CHECK-NEXT: [[TYPE:%.*]] = extractvalue %swift.metadata_response [[TMP]], 0
// CHECK-NEXT: call swiftcc void @takesMetadata(%swift.type* [[TYPE]], %swift.type* [[TYPE]])
// CHECK-NEXT: ret void
// CHECK-LABEL: define linkonce_odr hidden swiftcc %swift.metadata_response @"$s21subclass_existentials1P_AA1CCXcMa"
// CHECK-SAME: ([[INT]])
// CHECK: entry:
// CHECK-NEXT: [[PROTOCOL_ARRAY:%.*]] = alloca [1 x [[INT]]]
// CHECK: cacheIsNull:
// CHECK: [[PROTOCOLS:%.*]] = bitcast [1 x [[INT]]]* [[PROTOCOL_ARRAY]] to [[INT]]*
// CHECK-NEXT: [[PROTOCOL:%.*]] = getelementptr inbounds [[INT]], [[INT]]* [[PROTOCOLS]], i32 0
// CHECK-NEXT: store [[INT]] ptrtoint ({{.*}} @"$s21subclass_existentials1PMp" to [[INT]]), [[INT]]* [[PROTOCOL]]
// CHECK-NEXT: [[TMP:%.*]] = call swiftcc %swift.metadata_response @"$s21subclass_existentials1CCMa"([[INT]] 255)
// CHECK-NEXT: [[SUPERCLASS:%.*]] = extractvalue %swift.metadata_response [[TMP]], 0
// CHECK-NEXT: extractvalue %swift.metadata_response [[TMP]], 1
// CHECK-NEXT: [[METATYPE:%.*]] = call %swift.type* @swift_getExistentialTypeMetadata(i1 false, %swift.type* [[SUPERCLASS]], {{i32|i64}} 1, [[INT]]* [[PROTOCOLS]])
// CHECK: ret
sil [ossa] @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{{( dllexport)?}}{{( 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** @"$s21subclass_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{{( dllexport)?}}{{( 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** @"$s21subclass_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{{( dllexport)?}}{{( protected)?}} swiftcc void @checkExistentialDowncast(%T21subclass_existentials1CC*, %T21subclass_existentials1CC*, i8**)
sil [ossa] @checkExistentialDowncast : $@convention(thin) (@owned C, @owned C & P) -> () {
bb0(%0 : @owned $C, %1 : @owned $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: [[TMP:%.*]] = call swiftcc %swift.metadata_response @"$s21subclass_existentials1DCMa"([[INT]] 0)
// CHECK-NEXT: [[SUPERCLASS:%.*]] = extractvalue %swift.metadata_response [[TMP]], 0
// CHECK-NEXT: [[RESULT:%.*]] = call { i8*, i8** } @dynamic_cast_existential_1_superclass_unconditional(i8* [[VALUE]], %swift.type* [[METATYPE]], %swift.type* [[SUPERCLASS]], {{.*}} @"$s21subclass_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_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_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*
// 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, {{.*}} %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{{( dllexport)?}}{{( protected)?}} swiftcc void @checkExistentialSameClassDowncast(%T21subclass_existentials1CC*)
sil [ossa] @checkExistentialSameClassDowncast : $@convention(thin) (@owned C) -> () {
bb0(%0 : @owned $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]], {{.*}} @"$s21subclass_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_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*
// CHECK: entry:
// CHECK-NEXT: [[WTABLE:%.*]] = call i8** @swift_conformsToProtocol(%swift.type* %1, {{.*}} %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{{( dllexport)?}}{{( 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: [[TMP:%.*]] = call swiftcc %swift.metadata_response @"$s21subclass_existentials1DCMa"([[INT]] 0)
// CHECK-NEXT: [[SUPERCLASS:%.*]] = extractvalue %swift.metadata_response [[TMP]], 0
// CHECK-NEXT: [[RESULT:%.*]] = call { i8*, i8** } @dynamic_cast_existential_1_superclass_unconditional(i8* [[METATYPE]], %swift.type* %0, %swift.type* [[SUPERCLASS]], {{.*}} @"$s21subclass_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{{( dllexport)?}}{{( 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, {{.*}} @"$s21subclass_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 {}