blob: ecbb3bff3ebe3da45b35676d619c2dd374dee3ae [file] [log] [blame]
// RUN: %target-swift-frontend -enable-objc-interop -emit-ir %s | %FileCheck %s
// REQUIRES: CPU=x86_64
import Builtin
// These types end up in a completely different order with interop disabled.
// CHECK-DAG: [[TYPE:%swift.type]] = type
// CHECK-DAG: [[OPAQUE:%swift.opaque]] = type opaque
// CHECK-DAG: [[C:%T12unowned_objc1CC]] = type <{ [[REF:%swift.refcounted]] }>
// CHECK-DAG: [[UNKNOWN:%objc_object]] = type
// CHECK-DAG: [[A:%T12unowned_objc1AV]] = type <{ %swift.unowned }>
class C {}
sil_vtable C {}
typealias AnyObject = Builtin.AnyObject
protocol P : class {
func explode()
}
sil @$s12unowned_objc1CCfD : $@convention(method) (C) -> ()
struct A {
unowned var x : C
}
struct B {
unowned var x : P
}
sil @test_weak_rr_class : $@convention(thin) (@sil_unowned C) -> () {
bb0(%0 : $@sil_unowned C):
unowned_retain %0 : $@sil_unowned C
unowned_release %0 : $@sil_unowned C
%3 = tuple ()
return %3 : $()
}
// CHECK: define{{( dllexport)?}}{{( protected)?}} swiftcc void @test_weak_rr_class([[C]]*) {{.*}} {
// CHECK: call [[C]]* bitcast ([[REF]]* ([[REF]]*)* @swift_unownedRetain to [[C]]* ([[C]]*)*)([[C]]* returned %0)
// CHECK-NEXT: call void bitcast (void ([[REF]]*)* @swift_unownedRelease to void ([[C]]*)*)([[C]]* %0)
// CHECK-NEXT: ret void
// CHECK: define{{( dllexport)?}}{{( protected)?}} swiftcc void @test_unknown_unowned_copies([[UNKNOWN]]*, i8**, [[UNKNOWN]]*, i8**)
sil @test_unknown_unowned_copies : $@convention(thin) (@owned P, @owned P) -> () {
bb0(%p : $P, %q : $P):
// CHECK: [[X:%.*]] = alloca [[UREF:{ %swift.unowned, i8.. }]], align 8
// CHECK-NEXT: [[Y:%.*]] = alloca [[UREF]], align 8
// CHECK-NEXT: bitcast
// CHECK-NEXT: llvm.lifetime.start
%x = alloc_stack $@sil_unowned P
// CHECK-NEXT: bitcast
// CHECK-NEXT: llvm.lifetime.start
%y = alloc_stack $@sil_unowned P
// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[UREF]], [[UREF]]* [[X]], i32 0, i32 1
// CHECK-NEXT: store i8** [[PP:%1]], i8*** [[T0]], align 8
// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[UREF]], [[UREF]]* [[X]], i32 0, i32 0
// CHECK-NEXT: call %swift.unowned* @swift_unknownObjectUnownedInit(%swift.unowned* returned [[T0]], [[UNKNOWN]]* [[PV:%0]])
store_unowned %p to [initialization] %x : $*@sil_unowned P
// CHECK-NEXT: call { %swift.unowned, i8** }* @"$s12unowned_objc1P_pXoWOc"({ %swift.unowned, i8** }* [[X]], { %swift.unowned, i8** }* [[Y]])
copy_addr %x to [initialization] %y : $*@sil_unowned P
// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[UREF]], [[UREF]]* [[X]], i32 0, i32 0
// CHECK-NEXT: [[TV:%.*]] = call [[UNKNOWN]]* @swift_unknownObjectUnownedLoadStrong(%swift.unowned* [[T0]])
// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[UREF]], [[UREF]]* [[X]], i32 0, i32 1
// CHECK-NEXT: [[TP:%.*]] = load i8**, i8*** [[T0]], align 8
%t0 = load_unowned %x : $*@sil_unowned P
// CHECK-NEXT: call void @swift_unknownObjectRelease([[UNKNOWN]]* [[TV]])
strong_release %t0 : $P
// CHECK-NEXT: call { %swift.unowned, i8** }* @"$s12unowned_objc1P_pXoWOf"({ %swift.unowned, i8** }* [[X]], { %swift.unowned, i8** }* [[Y]])
copy_addr %x to %y : $*@sil_unowned P
// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[UREF]], [[UREF]]* [[Y]], i32 0, i32 1
// CHECK-NEXT: store i8** [[QP:%3]], i8*** [[T0]], align 8
// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[UREF]], [[UREF]]* [[Y]], i32 0, i32 0
// CHECK-NEXT: call %swift.unowned* @swift_unknownObjectUnownedAssign(%swift.unowned* returned [[T0]], [[UNKNOWN]]* [[QV:%2]])
store_unowned %q to %y : $*@sil_unowned P
// CHECK-NEXT: call { %swift.unowned, i8** }* @"$s12unowned_objc1P_pXoWOd"({ %swift.unowned, i8** }* [[X]], { %swift.unowned, i8** }* [[Y]])
copy_addr [take] %x to %y : $*@sil_unowned P
// CHECK-NEXT: call { %swift.unowned, i8** }* @"$s12unowned_objc1P_pXoWOb"({ %swift.unowned, i8** }* [[Y]], { %swift.unowned, i8** }* [[X]])
copy_addr [take] %y to [initialization] %x : $*@sil_unowned P
// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[UREF]], [[UREF]]* [[Y]], i32 0, i32 0
// CHECK-NEXT: [[TV:%.*]] = call [[UNKNOWN]]* @swift_unknownObjectUnownedTakeStrong(%swift.unowned* [[T0]])
// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[UREF]], [[UREF]]* [[Y]], i32 0, i32 1
// CHECK-NEXT: [[TP:%.*]] = load i8**, i8*** [[T0]], align 8
%t1 = load_unowned [take] %y : $*@sil_unowned P
// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[UREF]], [[UREF]]* [[X]], i32 0, i32 1
// CHECK-NEXT: store i8** [[TP]], i8*** [[T0]], align 8
// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[UREF]], [[UREF]]* [[X]], i32 0, i32 0
// CHECK-NEXT: call %swift.unowned* @swift_unknownObjectUnownedInit(%swift.unowned* returned [[T0]], [[UNKNOWN]]* [[TV]])
store_unowned %t1 to [initialization] %x : $*@sil_unowned P
// CHECK-NEXT: call void @swift_unknownObjectRelease([[UNKNOWN]]* [[TV]])
strong_release %t1 : $P
// CHECK-NEXT: call { %swift.unowned, i8** }* @"$s12unowned_objc1P_pXoWOh"({ %swift.unowned, i8** }*
destroy_addr %x : $*@sil_unowned P
// CHECK-NEXT: bitcast
// CHECK-NEXT: llvm.lifetime.end
dealloc_stack %y : $*@sil_unowned P
// CHECK-NEXT: bitcast
// CHECK-NEXT: llvm.lifetime.end
dealloc_stack %x : $*@sil_unowned P
// CHECK-NEXT: call void @swift_unknownObjectRelease([[UNKNOWN]]* [[PV]])
strong_release %p : $P
// CHECK-NEXT: call void @swift_unknownObjectRelease([[UNKNOWN]]* [[QV]])
strong_release %q : $P
// CHECK-NEXT: ret void
%0 = tuple ()
return %0 : $()
}
// Value witnesses for A:
// initializeBufferWithCopyOfBuffer
// CHECK: define internal [[OPAQUE]]* @"$s12unowned_objc1AVwCP"([[BUFFER:\[24 x i8\]]]* noalias [[DESTBUF:%.*]], [[BUFFER]]* noalias [[SRCBUF:%.*]], [[TYPE]]*
// CHECK: [[DEST:%.*]] = bitcast [[BUFFER]]* [[DESTBUF]] to [[A]]*
// CHECK-NEXT: [[SRC:%.*]] = bitcast [[BUFFER]]* [[SRCBUF]] to [[A]]*
// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[A]], [[A]]* [[DEST]], i32 0, i32 0
// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[A]], [[A]]* [[SRC]], i32 0, i32 0
// CHECK-NEXT: [[T1C:%.*]] = bitcast %swift.unowned* [[T1]] to [[C]]*
// CHECK-NEXT: [[T2:%.*]] = load [[C]]*, [[C]]** [[T1C]], align 8
// CHECK-NEXT: call [[C]]* bitcast ([[REF]]* ([[REF]]*)* @swift_unownedRetain to [[C]]* ([[C]]*)*)([[C]]* returned [[T2]])
// CHECK-NEXT: [[T0C:%.*]] = bitcast %swift.unowned* [[T0]] to [[C]]*
// CHECK-NEXT: store [[C]]* [[T2]], [[C]]** [[T0C]], align 8
// CHECK-NEXT: [[T0:%.*]] = bitcast [[A]]* [[DEST]] to [[OPAQUE]]*
// CHECK-NEXT: ret [[OPAQUE]]* [[T0]]
// destroy
// CHECK: define internal void @"$s12unowned_objc1AVwxx"([[OPAQUE]]* noalias [[ARG:%.*]], [[TYPE]]*
// CHECK: [[T0:%.*]] = bitcast [[OPAQUE]]* [[ARG]] to [[A]]*
// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[A]], [[A]]* [[T0]], i32 0, i32 0
// CHECK-NEXT: [[T1C:%.*]] = bitcast %swift.unowned* [[T1]] to [[C]]*
// CHECK-NEXT: [[T2:%.*]] = load [[C]]*, [[C]]** [[T1C]], align 8
// CHECK-NEXT: call void bitcast (void ([[REF]]*)* @swift_unownedRelease to void ([[C]]*)*)([[C]]* [[T2]])
// CHECK-NEXT: ret void
// initializeWithCopy
// CHECK: define internal [[OPAQUE]]* @"$s12unowned_objc1AVwcp"([[OPAQUE]]* noalias [[DEST_OPQ:%.*]], [[OPAQUE]]* noalias [[SRC_OPQ:%.*]], [[TYPE]]*
// CHECK: [[DEST:%.*]] = bitcast [[OPAQUE]]* [[DEST_OPQ]] to [[A]]*
// CHECK-NEXT: [[SRC:%.*]] = bitcast [[OPAQUE]]* [[SRC_OPQ]] to [[A]]*
// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[A]], [[A]]* [[DEST]], i32 0, i32 0
// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[A]], [[A]]* [[SRC]], i32 0, i32 0
// CHECK-NEXT: [[T1C:%.*]] = bitcast %swift.unowned* [[T1]] to [[C]]*
// CHECK-NEXT: [[T2:%.*]] = load [[C]]*, [[C]]** [[T1C]], align 8
// CHECK-NEXT: call [[C]]* bitcast ([[REF]]* ([[REF]]*)* @swift_unownedRetain to [[C]]* ([[C]]*)*)([[C]]* returned [[T2]])
// CHECK-NEXT: [[T0C:%.*]] = bitcast %swift.unowned* [[T0]] to [[C]]*
// CHECK-NEXT: store [[C]]* [[T2]], [[C]]** [[T0C]], align 8
// CHECK-NEXT: [[T0:%.*]] = bitcast [[A]]* [[DEST]] to [[OPAQUE]]*
// CHECK-NEXT: ret [[OPAQUE]]* [[T0]]
// assignWithCopy
// CHECK: define internal [[OPAQUE]]* @"$s12unowned_objc1AVwca"([[OPAQUE]]* [[DEST_OPQ:%.*]], [[OPAQUE]]* [[SRC_OPQ:%.*]], [[TYPE]]*
// CHECK: [[DEST:%.*]] = bitcast [[OPAQUE]]* [[DEST_OPQ]] to [[A]]*
// CHECK-NEXT: [[SRC:%.*]] = bitcast [[OPAQUE]]* [[SRC_OPQ]] to [[A]]*
// CHECK-NEXT: [[DEST_X:%.*]] = getelementptr inbounds [[A]], [[A]]* [[DEST]], i32 0, i32 0
// CHECK-NEXT: [[SRC_X:%.*]] = getelementptr inbounds [[A]], [[A]]* [[SRC]], i32 0, i32 0
// CHECK-NEXT: [[SRC_X_C:%.*]] = bitcast %swift.unowned* [[SRC_X]] to [[C]]*
// CHECK-NEXT: [[NEW:%.*]] = load [[C]]*, [[C]]** [[SRC_X_C]], align 8
// CHECK-NEXT: call [[C]]* bitcast ([[REF]]* ([[REF]]*)* @swift_unownedRetain to [[C]]* ([[C]]*)*)([[C]]* returned [[NEW]])
// CHECK-NEXT: [[DEST_X_C:%.*]] = bitcast %swift.unowned* [[DEST_X]] to [[C]]*
// CHECK-NEXT: [[OLD:%.*]] = load [[C]]*, [[C]]** [[DEST_X_C]], align 8
// CHECK-NEXT: store [[C]]* [[NEW]], [[C]]** [[DEST_X_C]], align 8
// CHECK-NEXT: call void bitcast (void ([[REF]]*)* @swift_unownedRelease to void ([[C]]*)*)([[C]]* [[OLD]])
// CHECK-NEXT: [[T0:%.*]] = bitcast [[A]]* [[DEST]] to [[OPAQUE]]*
// CHECK-NEXT: ret [[OPAQUE]]* [[T0]]
// assignWithTake
// CHECK: define internal [[OPAQUE]]* @"$s12unowned_objc1AVwta"([[OPAQUE]]* noalias [[DEST_OPQ:%.*]], [[OPAQUE]]* noalias [[SRC_OPQ:%.*]], [[TYPE]]*
// CHECK: [[DEST:%.*]] = bitcast [[OPAQUE]]* [[DEST_OPQ]] to [[A]]*
// CHECK-NEXT: [[SRC:%.*]] = bitcast [[OPAQUE]]* [[SRC_OPQ]] to [[A]]*
// CHECK-NEXT: [[DEST_X:%.*]] = getelementptr inbounds [[A]], [[A]]* [[DEST]], i32 0, i32 0
// CHECK-NEXT: [[SRC_X:%.*]] = getelementptr inbounds [[A]], [[A]]* [[SRC]], i32 0, i32 0
// CHECK-NEXT: [[SRC_X_C:%.*]] = bitcast %swift.unowned* [[SRC_X]] to [[C]]*
// CHECK-NEXT: [[NEW:%.*]] = load [[C]]*, [[C]]** [[SRC_X_C]], align 8
// CHECK-NEXT: [[DEST_X_C:%.*]] = bitcast %swift.unowned* [[DEST_X]] to [[C]]*
// CHECK-NEXT: [[OLD:%.*]] = load [[C]]*, [[C]]** [[DEST_X_C]], align 8
// CHECK-NEXT: store [[C]]* [[NEW]], [[C]]** [[DEST_X_C]], align 8
// CHECK-NEXT: call void bitcast (void ([[REF]]*)* @swift_unownedRelease to void ([[C]]*)*)([[C]]* [[OLD]])
// CHECK-NEXT: [[T0:%.*]] = bitcast [[A]]* [[DEST]] to [[OPAQUE]]*
// CHECK-NEXT: ret [[OPAQUE]]* [[T0]]