| // 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_existentials1ECyxGAA1PAAlWP, 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 {} |