| // RUN: %target-swift-frontend -assume-parsing-unqualified-ownership-sil -emit-ir %s | %FileCheck %s |
| // RUN: %target-swift-frontend -assume-parsing-unqualified-ownership-sil -O -S %s | %FileCheck %s --check-prefix=TAILCALL |
| |
| // REQUIRES: CPU=x86_64 |
| // XFAIL: linux |
| |
| // CHECK-DAG: [[TYPE:%swift.type]] = type |
| // CHECK-DAG: [[OPAQUE:%swift.opaque]] = type opaque |
| // CHECK-DAG: [[C:%T4weak1CC]] = type <{ [[REF:%swift.refcounted]] }> |
| // CHECK-DAG: [[UNKNOWN:%objc_object]] = type opaque |
| // CHECK-DAG: [[A:%T4weak1AV]] = type <{ [[WEAK:%swift.weak]] }> |
| // CHECK-DAG: [[WEAK]] = type |
| // CHECK-DAG: [[B:%T4weak1BV]] = type <{ { [[WEAK]], i8** } }> |
| |
| sil_stage canonical |
| |
| import Swift |
| |
| public class C {} |
| sil_vtable C {} |
| sil @$S4weak1CCfD : $@convention(method) (C) -> () |
| |
| protocol P : class { |
| func explode() |
| } |
| |
| public struct A { |
| weak var x : C? |
| } |
| |
| // size 8 |
| // flags 0x1100007 == 1114119 (non-POD, non-inline, non-bitwise-takable) |
| // stride 8 |
| // CHECK: @"$S4weak1AVWV" = {{.*}} i8* inttoptr (i64 8 to i8*), i8* inttoptr (i64 1114119 to i8*), i8* inttoptr (i64 8 to i8*)] |
| |
| sil @test_weak_load_store : $@convention(thin) (@inout A, Optional<C>) -> () { |
| bb0(%0 : $*A, %1 : $Optional<C>): |
| %2 = struct_element_addr %0 : $*A, #A.x |
| %3 = load_weak %2 : $*@sil_weak Optional<C> |
| store_weak %1 to %2 : $*@sil_weak Optional<C> |
| release_value %3 : $Optional<C> |
| %4 = tuple () |
| return %4 : $() |
| } |
| // CHECK: define{{( protected)?}} swiftcc void @test_weak_load_store([[A]]* nocapture dereferenceable({{.*}}), i64) {{.*}} { |
| // CHECK: [[X:%.*]] = getelementptr inbounds [[A]], [[A]]* %0, i32 0, i32 0 |
| // CHECK-NEXT: [[T0:%.*]] = call [[C]]* bitcast ([[REF]]* ([[WEAK]]*)* @swift_weakLoadStrong to [[C]]* ([[WEAK]]*)*)([[WEAK]]* [[X]]) |
| // CHECK-NEXT: %3 = ptrtoint %T4weak1CC* %2 to i64 |
| // CHECK-NEXT: %4 = inttoptr |
| // CHECK-NEXT: call [[WEAK]]* bitcast ([[WEAK]]* ([[WEAK]]*, [[REF]]*)* @swift_weakAssign to [[WEAK]]* ([[WEAK]]*, [[C]]*)*)([[WEAK]]* returned [[X]], [[C]]* %4) |
| // CHECK-NEXT: %6 = inttoptr i64 %3 to %swift.refcounted* |
| // CHECK-NEXT: call void @swift_release([[REF]]* %6) |
| // CHECK-NEXT: ret void |
| |
| struct B { |
| weak var x : P? |
| } |
| |
| sil @test_weak_load_store_proto : $@convention(thin) (@inout B, Optional<P>) -> () { |
| bb0(%0 : $*B, %1 : $Optional<P>): |
| %2 = struct_element_addr %0 : $*B, #B.x |
| %3 = load_weak %2 : $*@sil_weak Optional<P> |
| store_weak %1 to %2 : $*@sil_weak Optional<P> |
| release_value %3 : $Optional<P> |
| %4 = tuple () |
| return %4 : $() |
| } |
| // CHECK: define{{( protected)?}} swiftcc void @test_weak_load_store_proto([[B]]* nocapture dereferenceable({{.*}}), i64, i64) |
| // CHECK: [[X:%.*]] = getelementptr inbounds [[B]], [[B]]* %0, i32 0, i32 0 |
| // CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds { [[WEAK]], i8** }, { [[WEAK]], i8** }* [[X]], i32 0, i32 0 |
| // CHECK-NEXT: [[T1:%.*]] = call [[UNKNOWN]]* @swift_unknownWeakLoadStrong([[WEAK]]* [[T0]]) |
| // CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds { [[WEAK]], i8** }, { [[WEAK]], i8** }* [[X]], i32 0, i32 1 |
| // CHECK-NEXT: [[W:%.*]] = load i8**, i8*** [[T0]], align 8 |
| // CHECK: [[TMPOBJ:%.*]] = inttoptr {{.*}} to %objc_object* |
| // CHECK: [[TMPTAB:%.*]] = inttoptr {{.*}} to i8** |
| // CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds { [[WEAK]], i8** }, { [[WEAK]], i8** }* [[X]], i32 0, i32 1 |
| // CHECK-NEXT: store i8** [[TMPTAB]], i8*** [[T0]], align 8 |
| // CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds { [[WEAK]], i8** }, { [[WEAK]], i8** }* [[X]], i32 0, i32 0 |
| // CHECK-NEXT: call [[WEAK]]* @swift_unknownWeakAssign([[WEAK]]* returned [[T0]], [[UNKNOWN]]* [[TMPOBJ]]) |
| // CHECK: call void @"$S4weak1P_pSgWOe" |
| |
| sil @test_weak_alloc_stack : $@convention(thin) (Optional<P>) -> () { |
| bb0(%0 : $Optional<P>): |
| %1 = alloc_stack $@sil_weak Optional<P> |
| store_weak %0 to [initialization] %1 : $*@sil_weak Optional<P> |
| destroy_addr %1 : $*@sil_weak Optional<P> |
| dealloc_stack %1 : $*@sil_weak Optional<P> |
| %4 = tuple () |
| return %4 : $() |
| } |
| // CHECK: define{{( protected)?}} swiftcc void @test_weak_alloc_stack(i64, i64) |
| // CHECK: [[X:%.*]] = alloca { [[WEAK]], i8** }, align 8 |
| // CHECK: [[TMPOBJ:%.*]] = inttoptr {{.*}} to %objc_object* |
| // CHECK: [[TMPTAB:%.*]] = inttoptr {{.*}} to i8** |
| // CHECK: [[T0:%.*]] = getelementptr inbounds { [[WEAK]], i8** }, { [[WEAK]], i8** }* [[X]], i32 0, i32 1 |
| // CHECK-NEXT: store i8** [[TMPTAB:%.*]], i8*** [[T0]], align 8 |
| // CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds { [[WEAK]], i8** }, { [[WEAK]], i8** }* [[X]], i32 0, i32 0 |
| // CHECK-NEXT: call [[WEAK]]* @swift_unknownWeakInit([[WEAK]]* returned [[T0]], [[UNKNOWN]]* [[TMPOBJ:%.*]]) |
| // CHECK-NEXT: call { %swift.weak, i8** }* @"$S4weak1P_pSgXwWOh"({ %swift.weak, i8** }* [[X]]) |
| // CHECK-NEXT: bitcast |
| // CHECK-NEXT: llvm.lifetime.end |
| // CHECK-NEXT: ret void |
| |
| // Value witnesses for A: |
| |
| // initializeBufferWithCopyOfBuffer |
| // CHECK: define linkonce_odr hidden [[OPAQUE]]* @"$S4weak1AVwCP"([[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: call [[WEAK]]* @swift_weakCopyInit([[WEAK]]* returned [[T0]], [[WEAK]]* [[T1]]) |
| // CHECK-NEXT: [[T0:%.*]] = bitcast [[A]]* [[DEST]] to [[OPAQUE]]* |
| // CHECK-NEXT: ret [[OPAQUE]]* [[T0]] |
| |
| // TAILCALL: _$S4weak1AVwCP: |
| // TAILCALL: jmp _swift_weakCopyInit |
| |
| // destroy |
| // CHECK: define linkonce_odr hidden void @"$S4weak1AVwxx"([[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: call void @swift_weakDestroy([[WEAK]]* [[T1]]) |
| // CHECK-NEXT: ret void |
| |
| // TAILCALL: _$S4weak1AVwxx: |
| // TAILCALL: jmp _swift_weakDestroy |
| |
| // initializeWithCopy |
| // CHECK: define linkonce_odr hidden [[OPAQUE]]* @"$S4weak1AVwcp"([[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: call [[WEAK]]* @swift_weakCopyInit([[WEAK]]* returned [[T0]], [[WEAK]]* [[T1]]) |
| // CHECK-NEXT: [[T0:%.*]] = bitcast [[A]]* [[DEST]] to [[OPAQUE]]* |
| // CHECK-NEXT: ret [[OPAQUE]]* [[T0]] |
| |
| // TAILCALL: _$S4weak1AVwcp: |
| // TAILCALL: jmp _swift_weakCopyInit |
| |
| // assignWithCopy |
| // CHECK: define linkonce_odr hidden [[OPAQUE]]* @"$S4weak1AVwca"([[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: call [[WEAK]]* @swift_weakCopyAssign([[WEAK]]* returned [[DEST_X]], [[WEAK]]* [[SRC_X]]) |
| // CHECK-NEXT: [[T0:%.*]] = bitcast [[A]]* [[DEST]] to [[OPAQUE]]* |
| // CHECK-NEXT: ret [[OPAQUE]]* [[T0]] |
| |
| // TAILCALL: _$S4weak1AVwca: |
| // TAILCALL: jmp _swift_weakCopyAssign |
| |
| // assignWithTake |
| // CHECK: define linkonce_odr hidden [[OPAQUE]]* @"$S4weak1AVwta"([[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: call [[WEAK]]* @swift_weakTakeAssign([[WEAK]]* returned [[DEST_X]], [[WEAK]]* [[SRC_X]]) |
| // CHECK-NEXT: [[T0:%.*]] = bitcast [[A]]* [[DEST]] to [[OPAQUE]]* |
| // CHECK-NEXT: ret [[OPAQUE]]* [[T0]] |
| |
| // TAILCALL: _$S4weak1AVwtk: |
| // TAILCALL: jmp _swift_weakTakeInit |
| |
| // TAILCALL: _$S4weak1AVwta: |
| // TAILCALL: jmp _swift_weakTakeAssign |
| |
| // TAILCALL: _$S4weak1AVwTK: |
| // TAILCALL: jmp _swift_weakTakeInit |