Files
swift-mirror/test/IRGen/existentials_objc.sil
Anthony Latsis 55e5618eab [test] Match nocapture to succeed both on main and rebranch
Both the syntax and relative order of the LLVM `nocapture` parameter
attribute changed upstream in 29441e4f5fa5f5c7709f7cf180815ba97f611297.
To reduce conflicts with rebranch, adjust FileCheck patterns to expect
both syntaxes and orders anywhere the presence of the attribute is not
critical to the test. These changes are temporary and will be cleaned
up once rebranch is merged into main.
2025-05-08 23:52:43 +01:00

225 lines
8.8 KiB
Plaintext

// RUN: %empty-directory(%t)
// RUN: %build-irgen-test-overlays
// RUN: %target-swift-frontend -disable-type-layout -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(ptr noalias{{( nocapture)?}} sret({{.*}}){{( captures\(none\))?}} %0, ptr %1, ptr %T) {{.*}} {
// CHECK: [[T0:%.*]] = getelementptr inbounds{{.*}} [[ANY:%Any]], ptr %0, i32 0, i32 1
// CHECK-NEXT: store ptr %T, ptr [[T0]], align 8
// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds{{.*}} [[ANY]], ptr %0, i32 0, i32 0
// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds{{.*}} [[ANY]], ptr %0, i32 0, i32 0
// CHECK-NEXT: store ptr %1, ptr [[T0]], 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 [init] %0 : $*Any
%3 = tuple ()
return %3 : $()
}
// CHECK-DAG: define{{( protected)?}} swiftcc void @take_opaque_existential(ptr noalias{{( nocapture)?}} sret({{.*}}){{( captures\(none\))?}} %0, ptr noalias {{(nocapture|captures\(none\))}} dereferenceable({{.*}}) %1) {{.*}} {
// CHECK: call ptr @"$sypWOb"(ptr %1, ptr %0)
// CHECK-NEXT: ret void
// CHECK-DAG: define linkonce_odr hidden ptr @"$sypWOb"(ptr %0, ptr %1)
// CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 8 %1, ptr align 8 %0, i64 32, i1 false)
// CHECK-NEXT: ret ptr %1
// rdar://problem/19035529
@objc protocol OP {}
@objc protocol OP2: OP {}
// CHECK-DAG: define{{( protected)?}} swiftcc ptr @init_existential_objc_to_objc(ptr %0) {{.*}} {
// CHECK: ret ptr %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 { ptr, ptr } @class_existential_unowned(ptr %0, ptr %1) {{.*}} {
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, ptr }]], align 8
// CHECK: [[U2:%.*]] = alloca [[UREF]], align 8
store_unowned %s to [init] %u1 : $*@sil_unowned CP
// CHECK: [[T0:%.*]] = getelementptr inbounds{{.*}} [[UREF]], ptr [[U1]], i32 0, i32 1
// CHECK: store ptr %1, ptr [[T0]], align 8
// CHECK: [[T0:%.*]] = getelementptr inbounds{{.*}} [[UREF]], ptr [[U1]], i32 0, i32 0
// CHECK: call ptr @swift_unknownObjectUnownedInit(ptr returned [[T0]], ptr %0)
// CHECK: [[T0:%.*]] = getelementptr inbounds{{.*}} [[UREF]], ptr [[U1]], i32 0, i32 0
// CHECK: [[T1:%.*]] = call ptr @swift_unknownObjectUnownedLoadStrong(ptr [[T0]])
%t = load_unowned %u1 : $*@sil_unowned CP
// CHECK: call void @swift_unknownObjectRelease(ptr [[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
// CHECK: call ptr @swift_unknownObjectRetain(ptr
%v_copy = strong_copy_unmanaged_value %v : $@sil_unmanaged CP
// CHECK: call void @swift_unknownObjectRelease(ptr
strong_release %v_copy : $CP
%z = unmanaged_to_ref %v : $@sil_unmanaged CP to $CP
// CHECK: [[RESULT_A:%.*]] = insertvalue { ptr, ptr } undef, ptr %0, 0
// CHECK: [[RESULT_B:%.*]] = insertvalue { ptr, ptr } [[RESULT_A]], ptr %1, 1
// CHECK: ret { ptr, ptr } [[RESULT_B]]
return %z : $CP
}
// CHECK-DAG: define{{( protected)?}} swiftcc void @class_existential_weak(ptr noalias sret({{.*}}) %0, i64 %1, i64 %2)
sil @class_existential_weak : $@convention(thin) (@owned CP?) -> @out @sil_weak CP? {
entry(%w : $*@sil_weak CP?, %a : $CP?):
// CHECK: [[V:%.*]] = alloca { %swift.weak, ptr }
%v = alloc_stack $@sil_weak CP?
// CHECK: [[SRC_REF:%.*]] = inttoptr {{.*}} ptr
// CHECK: [[SRC_WITNESS:%.*]] = inttoptr {{.*}} ptr
// CHECK: [[DEST_WITNESS_ADDR:%.*]] = getelementptr inbounds{{.*}} { %swift.weak, ptr }, ptr %0, i32 0, i32 1
// CHECK: store ptr [[SRC_WITNESS]], ptr [[DEST_WITNESS_ADDR]]
// CHECK: [[DEST_REF_ADDR:%.*]] = getelementptr inbounds{{.*}} { %swift.weak, ptr }, ptr %0, i32 0, i32 0
// CHECK: call ptr @swift_unknownObjectWeakInit(ptr returned [[DEST_REF_ADDR]], ptr [[SRC_REF]])
store_weak %a to [init] %w : $*@sil_weak CP?
// CHECK: [[SRC_REF:%.*]] = inttoptr {{.*}} ptr
// CHECK: [[SRC_WITNESS:%.*]] = inttoptr {{.*}} ptr
// CHECK: [[DEST_WITNESS_ADDR:%.*]] = getelementptr inbounds{{.*}} { %swift.weak, ptr }, ptr %0, i32 0, i32 1
// CHECK: store ptr [[SRC_WITNESS]], ptr [[DEST_WITNESS_ADDR]]
// CHECK: [[DEST_REF_ADDR:%.*]] = getelementptr inbounds{{.*}} { %swift.weak, ptr }, ptr %0, i32 0, i32 0
// CHECK: call ptr @swift_unknownObjectWeakAssign(ptr returned [[DEST_REF_ADDR]], ptr [[SRC_REF]])
store_weak %a to %w : $*@sil_weak CP?
// CHECK: [[SRC_REF_ADDR:%.*]] = getelementptr inbounds{{.*}} { %swift.weak, ptr }, ptr %0, i32 0, i32 0
// CHECK: [[DEST_REF:%.*]] = call ptr @swift_unknownObjectWeakTakeStrong(ptr [[SRC_REF_ADDR]])
// CHECK: [[SRC_WITNESS_ADDR:%.*]] = getelementptr inbounds{{.*}} { %swift.weak, ptr }, ptr %0, i32 0, i32 1
// CHECK: [[DEST_WITNESS:%.*]] = load ptr, ptr [[SRC_WITNESS_ADDR]]
%b = load_weak [take] %w : $*@sil_weak CP?
// CHECK: [[SRC_REF_ADDR:%.*]] = getelementptr inbounds{{.*}} { %swift.weak, ptr }, ptr %0, i32 0, i32 0
// CHECK: [[DEST_REF:%.*]] = call ptr @swift_unknownObjectWeakLoadStrong(ptr [[SRC_REF_ADDR]])
// CHECK: [[SRC_WITNESS_ADDR:%.*]] = getelementptr inbounds{{.*}} { %swift.weak, ptr }, ptr %0, i32 0, i32 1
// CHECK: [[DEST_WITNESS:%.*]] = load ptr, ptr [[SRC_WITNESS_ADDR]]
%c = load_weak %w : $*@sil_weak CP?
// CHECK: call ptr @"$s17existentials_objc2CP_pSgXwWOb"(ptr %0, ptr [[V]])
copy_addr [take] %w to [init] %v : $*@sil_weak CP?
// CHECK: call ptr @"$s17existentials_objc2CP_pSgXwWOd"(ptr %0, ptr [[V]])
copy_addr [take] %w to %v : $*@sil_weak CP?
// CHECK: call ptr @"$s17existentials_objc2CP_pSgXwWOc"(ptr %0, ptr [[V]])
copy_addr %w to [init] %v : $*@sil_weak CP?
// CHECK: call ptr @"$s17existentials_objc2CP_pSgXwWOf"(ptr %0, ptr [[V]])
copy_addr %w to %v : $*@sil_weak CP?
// CHECK: call ptr @"$s17existentials_objc2CP_pSgXwWOh"(ptr [[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(ptr swiftself %0)
// CHECK: entry:
// CHECK: load ptr, ptr @"\01L_selector(funcA)"
// CHECK: load ptr, ptr @"\01L_selector(respondsToSelector:)"
// CHECK: [[TMP:%.*]] = call i1 @objc_msgSend
// CHECK: br i1 [[TMP]]
//
// CHECK: call void @objc_msgSend(ptr %0
// CHECK: ret void
// CHECK: }
sil public @useObjcProtocol : $@convention(method) (@guaranteed ProtocolA) -> () {
bb0(%0 : $ProtocolA):
dynamic_method_br %0 : $ProtocolA, #ProtocolA.funcA!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 ptr, ptr
// CHECK: swift_unownedRetainStrong
// CHECK: [[EXIST0:%.*]] = insertvalue { ptr, ptr } undef, ptr [[REF]], 0
// CHECK: [[EXIST:%.*]] = insertvalue { ptr, ptr } [[EXIST0]], ptr {{.*}}, 1
// CHECK: ret { ptr, ptr } [[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 ptr, ptr
// CHECK: swift_unownedRetainStrongAndRelease
// CHECK: [[EXIST0:%.*]] = insertvalue { ptr, ptr } undef, ptr [[REF]], 0
// CHECK: [[EXIST:%.*]] = insertvalue { ptr, ptr } [[EXIST0]], ptr {{.*}}, 1
// CHECK: ret { ptr, ptr } [[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 { }