| // RUN: %empty-directory(%t) |
| // RUN: %build-irgen-test-overlays |
| // RUN: %target-swift-frontend -sdk %S/Inputs -I %t %s -emit-ir | %FileCheck %s |
| |
| // REQUIRES: CPU=x86_64 |
| // REQUIRES: objc_interop |
| |
| sil_stage canonical |
| |
| import Builtin |
| import gizmo |
| |
| typealias AnyObject = Builtin.AnyObject |
| |
| // rdar://16621578 |
| |
| sil @init_opaque_existential : $@convention(thin) <T where T : Gizmo> (@owned T) -> @out Any { |
| bb0(%0 : $*Any, %1 : $T): |
| %2 = init_existential_addr %0 : $*Any, $T |
| store %1 to %2 : $*T |
| %3 = tuple () |
| return %3 : $() |
| } |
| |
| // CHECK-DAG: define{{( protected)?}} swiftcc void @init_opaque_existential([[ANY:%Any]]* noalias nocapture sret, [[GIZMO:%.*]]*, [[TYPE:%.*]]* %T) {{.*}} { |
| // CHECK: [[T0:%.*]] = getelementptr inbounds [[ANY]], [[ANY]]* %0, i32 0, i32 1 |
| // CHECK-NEXT: store [[TYPE]]* %T, [[TYPE]]** [[T0]], align 8 |
| // CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[ANY]], [[ANY]]* %0, i32 0, i32 0 |
| // CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[ANY]], [[ANY]]* %0, i32 0, i32 0 |
| // CHECK-NEXT: [[T1:%.*]] = bitcast [24 x i8]* [[T0]] to [[GIZMO]]** |
| // CHECK-NEXT: store [[GIZMO]]* %1, [[GIZMO]]** [[T1]], align 8 |
| // CHECK-NEXT: ret void |
| |
| sil @take_opaque_existential : $@convention(thin) (@in Any) -> @out Any { |
| bb0(%0 : $*Any, %1 : $*Any): |
| copy_addr [take] %1 to [initialization] %0 : $*Any |
| %3 = tuple () |
| return %3 : $() |
| } |
| |
| // CHECK-DAG: define{{( protected)?}} swiftcc void @take_opaque_existential([[ANY:%Any]]* noalias nocapture sret, %Any* noalias nocapture dereferenceable({{.*}})) {{.*}} { |
| // CHECK: call %Any* @"$sypWOb"(%Any* %1, %Any* %0) |
| // CHECK-NEXT: ret void |
| |
| // CHECK-DAG: define linkonce_odr hidden %Any* @"$sypWOb"(%Any*, %Any*) |
| // CHECK: %2 = bitcast %Any* %1 to i8* |
| // CHECK-NEXT: %3 = bitcast %Any* %0 to i8* |
| // CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %2, i8* align 8 %3, i64 32, i1 false) |
| // CHECK-NEXT: ret %Any* %1 |
| |
| // rdar://problem/19035529 |
| @objc protocol OP {} |
| @objc protocol OP2: OP {} |
| |
| // CHECK-DAG: define{{( protected)?}} swiftcc %objc_object* @init_existential_objc_to_objc(%objc_object*) {{.*}} { |
| // CHECK: ret %objc_object* %0 |
| sil @init_existential_objc_to_objc : $@convention(thin) (@owned OP2) -> @owned OP { |
| entry(%o : $OP2): |
| %a = init_existential_ref %o : $OP2 : $OP2, $OP |
| return %a : $OP |
| } |
| |
| protocol CP: class {} |
| |
| // CHECK-DAG: define{{( protected)?}} swiftcc { %objc_object*, i8** } @class_existential_unowned(%objc_object*, i8**) {{.*}} { |
| sil @class_existential_unowned : $@convention(thin) (@owned CP) -> @owned CP { |
| entry(%s : $CP): |
| %u1 = alloc_stack $@sil_unowned CP |
| %u2 = alloc_stack $@sil_unowned CP |
| // CHECK: [[U1:%.*]] = alloca [[UREF:{ %swift.unowned, i8.. }]], align 8 |
| // CHECK: [[U2:%.*]] = alloca [[UREF]], align 8 |
| |
| store_unowned %s to [initialization] %u1 : $*@sil_unowned CP |
| // CHECK: [[T0:%.*]] = getelementptr inbounds [[UREF]], [[UREF]]* [[U1]], i32 0, i32 1 |
| // CHECK: store i8** %1, i8*** [[T0]], align 8 |
| // CHECK: [[T0:%.*]] = getelementptr inbounds [[UREF]], [[UREF]]* [[U1]], i32 0, i32 0 |
| // CHECK: call %swift.unowned* @swift_unknownObjectUnownedInit(%swift.unowned* returned [[T0]], %objc_object* %0) |
| |
| // CHECK: [[T0:%.*]] = getelementptr inbounds [[UREF]], [[UREF]]* [[U1]], i32 0, i32 0 |
| // CHECK: [[T1:%.*]] = call %objc_object* @swift_unknownObjectUnownedLoadStrong(%swift.unowned* [[T0]]) |
| %t = load_unowned %u1 : $*@sil_unowned CP |
| // CHECK: call void @swift_unknownObjectRelease(%objc_object* [[T1]]) |
| strong_release %t : $CP |
| |
| dealloc_stack %u2 : $*@sil_unowned CP |
| dealloc_stack %u1 : $*@sil_unowned CP |
| |
| %v = ref_to_unmanaged %s : $CP to $@sil_unmanaged CP |
| %z = unmanaged_to_ref %v : $@sil_unmanaged CP to $CP |
| |
| // CHECK: [[RESULT_A:%.*]] = insertvalue { %objc_object*, i8** } undef, %objc_object* %0, 0 |
| // CHECK: [[RESULT_B:%.*]] = insertvalue { %objc_object*, i8** } [[RESULT_A]], i8** %1, 1 |
| // CHECK: ret { %objc_object*, i8** } [[RESULT_B]] |
| |
| return %z : $CP |
| } |
| |
| // CHECK-DAG: define{{( protected)?}} swiftcc void @class_existential_weak({ %swift.weak, i8** }* noalias nocapture sret, i64, i64) |
| sil @class_existential_weak : $@convention(thin) (@owned CP?) -> @out @sil_weak CP? { |
| entry(%w : $*@sil_weak CP?, %a : $CP?): |
| // CHECK: [[V:%.*]] = alloca { %swift.weak, i8** } |
| %v = alloc_stack $@sil_weak CP? |
| |
| // CHECK: [[SRC_REF:%.*]] = inttoptr {{.*}} %objc_object* |
| // CHECK: [[SRC_WITNESS:%.*]] = inttoptr {{.*}} i8** |
| // CHECK: [[DEST_WITNESS_ADDR:%.*]] = getelementptr inbounds { %swift.weak, i8** }, { %swift.weak, i8** }* %0, i32 0, i32 1 |
| // CHECK: store i8** [[SRC_WITNESS]], i8*** [[DEST_WITNESS_ADDR]] |
| // CHECK: [[DEST_REF_ADDR:%.*]] = getelementptr inbounds { %swift.weak, i8** }, { %swift.weak, i8** }* %0, i32 0, i32 0 |
| // CHECK: call %swift.weak* @swift_unknownObjectWeakInit(%swift.weak* returned [[DEST_REF_ADDR]], %objc_object* [[SRC_REF]]) |
| store_weak %a to [initialization] %w : $*@sil_weak CP? |
| |
| // CHECK: [[SRC_REF:%.*]] = inttoptr {{.*}} %objc_object* |
| // CHECK: [[SRC_WITNESS:%.*]] = inttoptr {{.*}} i8** |
| // CHECK: [[DEST_WITNESS_ADDR:%.*]] = getelementptr inbounds { %swift.weak, i8** }, { %swift.weak, i8** }* %0, i32 0, i32 1 |
| // CHECK: store i8** [[SRC_WITNESS]], i8*** [[DEST_WITNESS_ADDR]] |
| // CHECK: [[DEST_REF_ADDR:%.*]] = getelementptr inbounds { %swift.weak, i8** }, { %swift.weak, i8** }* %0, i32 0, i32 0 |
| // CHECK: call %swift.weak* @swift_unknownObjectWeakAssign(%swift.weak* returned [[DEST_REF_ADDR]], %objc_object* [[SRC_REF]]) |
| store_weak %a to %w : $*@sil_weak CP? |
| |
| // CHECK: [[SRC_REF_ADDR:%.*]] = getelementptr inbounds { %swift.weak, i8** }, { %swift.weak, i8** }* %0, i32 0, i32 0 |
| // CHECK: [[DEST_REF:%.*]] = call %objc_object* @swift_unknownObjectWeakTakeStrong(%swift.weak* [[SRC_REF_ADDR]]) |
| // CHECK: [[SRC_WITNESS_ADDR:%.*]] = getelementptr inbounds { %swift.weak, i8** }, { %swift.weak, i8** }* %0, i32 0, i32 1 |
| // CHECK: [[DEST_WITNESS:%.*]] = load i8**, i8*** [[SRC_WITNESS_ADDR]] |
| %b = load_weak [take] %w : $*@sil_weak CP? |
| |
| // CHECK: [[SRC_REF_ADDR:%.*]] = getelementptr inbounds { %swift.weak, i8** }, { %swift.weak, i8** }* %0, i32 0, i32 0 |
| // CHECK: [[DEST_REF:%.*]] = call %objc_object* @swift_unknownObjectWeakLoadStrong(%swift.weak* [[SRC_REF_ADDR]]) |
| // CHECK: [[SRC_WITNESS_ADDR:%.*]] = getelementptr inbounds { %swift.weak, i8** }, { %swift.weak, i8** }* %0, i32 0, i32 1 |
| // CHECK: [[DEST_WITNESS:%.*]] = load i8**, i8*** [[SRC_WITNESS_ADDR]] |
| %c = load_weak %w : $*@sil_weak CP? |
| |
| // CHECK: call { %swift.weak, i8** }* @"$s17existentials_objc2CP_pSgXwWOb"({ %swift.weak, i8** }* %0, { %swift.weak, i8** }* [[V]]) |
| copy_addr [take] %w to [initialization] %v : $*@sil_weak CP? |
| |
| // CHECK: call { %swift.weak, i8** }* @"$s17existentials_objc2CP_pSgXwWOd"({ %swift.weak, i8** }* %0, { %swift.weak, i8** }* [[V]]) |
| copy_addr [take] %w to %v : $*@sil_weak CP? |
| |
| // CHECK: call { %swift.weak, i8** }* @"$s17existentials_objc2CP_pSgXwWOc"({ %swift.weak, i8** }* %0, { %swift.weak, i8** }* [[V]]) |
| copy_addr %w to [initialization] %v : $*@sil_weak CP? |
| |
| // CHECK: call { %swift.weak, i8** }* @"$s17existentials_objc2CP_pSgXwWOf"({ %swift.weak, i8** }* %0, { %swift.weak, i8** }* [[V]]) |
| copy_addr %w to %v : $*@sil_weak CP? |
| |
| // CHECK: call { %swift.weak, i8** }* @"$s17existentials_objc2CP_pSgXwWOh"({ %swift.weak, i8** }* [[V]]) |
| destroy_addr %v : $*@sil_weak CP? |
| |
| dealloc_stack %v : $*@sil_weak CP? |
| |
| return undef : $() |
| } |
| |
| @objc protocol ProtocolA : class { |
| @objc optional func funcA() |
| } |
| |
| // CHECK: define swiftcc void @useObjcProtocol(%objc_object* swiftself) |
| // CHECK: entry: |
| // CHECK: load i8*, i8** @"\01L_selector(funcA)" |
| // CHECK: load i8*, i8** @"\01L_selector(respondsToSelector:)" |
| // CHECK: [[TMP:%.*]] = call i1 bitcast (void ()* @objc_msgSend |
| // CHECK: br i1 [[TMP]] |
| // |
| // CHECK: [[SELF:%.*]] = bitcast %objc_object* %0 to i8* |
| // CHECK: call void bitcast (void ()* @objc_msgSend to void (i8*, i8*)*)(i8* [[SELF]] |
| // CHECK: ret void |
| // CHECK: } |
| |
| sil public @useObjcProtocol : $@convention(method) (@guaranteed ProtocolA) -> () { |
| bb0(%0 : $ProtocolA): |
| dynamic_method_br %0 : $ProtocolA, #ProtocolA.funcA!1.foreign, bb1, bb2 |
| |
| bb1(%1 : $@convention(objc_method) (ProtocolA) -> ()): |
| %3 = apply %1(%0) : $@convention(objc_method) (ProtocolA) -> () |
| br bb3 |
| |
| bb2: |
| br bb3 |
| |
| bb3: |
| %4 = tuple() |
| return %4 : $() |
| } |
| |
| protocol TestP : AnyObject {} |
| |
| class NSObject {} |
| |
| class TestC { |
| @_hasStorage unowned final let t: @sil_unowned NSObject & TestP |
| init(t: NSObject & TestP) |
| } |
| |
| // CHECK-LABEL: define {{.*}}@test_load_unowned |
| // CHECK: [[REF:%.*]] = load %swift.refcounted*, %swift.refcounted** |
| // CHECK: [[CAST:%.*]] = bitcast %swift.refcounted* [[REF]] to %T17existentials_objc8NSObjectC |
| // CHECK: swift_unownedRetainStrong |
| // CHECK: [[EXIST0:%.*]] = insertvalue { %T17existentials_objc8NSObjectC*, i8** } undef, %T17existentials_objc8NSObjectC* [[CAST]], 0 |
| // CHECK: [[EXIST:%.*]] = insertvalue { %T17existentials_objc8NSObjectC*, i8** } [[EXIST0]], i8** {{.*}}, 1 |
| // CHECK: ret { %T17existentials_objc8NSObjectC*, i8** } [[EXIST]] |
| |
| sil @test_load_unowned : $@convention(method) (@guaranteed TestC) -> @owned NSObject & TestP { |
| bb0(%0 : $TestC): |
| %2 = ref_element_addr %0 : $TestC, #TestC.t |
| %3 = load_unowned %2 : $*@sil_unowned NSObject & TestP |
| return %3 : $NSObject & TestP |
| } |
| |
| // CHECK-LABEL: define {{.*}}@test_load_take_unowned |
| // CHECK: [[REF:%.*]] = load %swift.refcounted*, %swift.refcounted** |
| // CHECK: [[CAST:%.*]] = bitcast %swift.refcounted* [[REF]] to %T17existentials_objc8NSObjectC |
| // CHECK: swift_unownedRetainStrongAndRelease |
| // CHECK: [[EXIST0:%.*]] = insertvalue { %T17existentials_objc8NSObjectC*, i8** } undef, %T17existentials_objc8NSObjectC* [[CAST]], 0 |
| // CHECK: [[EXIST:%.*]] = insertvalue { %T17existentials_objc8NSObjectC*, i8** } [[EXIST0]], i8** {{.*}}, 1 |
| // CHECK: ret { %T17existentials_objc8NSObjectC*, i8** } [[EXIST]] |
| |
| sil @test_load_take_unowned : $@convention(method) (@guaranteed TestC) -> @owned NSObject & TestP { |
| bb0(%0 : $TestC): |
| %2 = ref_element_addr %0 : $TestC, #TestC.t |
| %3 = load_unowned [take] %2 : $*@sil_unowned NSObject & TestP |
| return %3 : $NSObject & TestP |
| } |
| |
| sil_vtable TestC { } |
| |
| sil_vtable NSObject { } |