Files
swift-mirror/test/IRGen/existentials_opaque_boxed.sil
Anthony Latsis 17fc00f8a7 [test] IRGen: Adjust FileCheck patterns for new nuw attribute in upstream LLVM
This attribute was introduced in
7eca38ce76d5d1915f4ab7e665964062c0b37697 (llvm-project).

Match it using a wildcard regex, since it is not relevant to these
tests.

This is intended to reduce future conflicts with rebranch.
2025-05-04 03:28:56 +01:00

598 lines
30 KiB
Plaintext

// RUN: %target-swift-frontend -disable-type-layout %s -emit-ir | %FileCheck %s -check-prefix=CHECK -check-prefix=CHECK-%target-ptrsize -DINT=i%target-ptrsize --check-prefix=CHECK-%target-cpu
sil_stage canonical
import Swift
protocol Existential {}
protocol OtherExistential {}
struct Fixed : Existential, OtherExistential {
var x: Int
}
struct NotInlineFixed : Existential, OtherExistential {
var x1: Double
var x2: Double
var x3: Double
var x4: Double
}
struct NonFixed<T> : Existential, OtherExistential {
var x: T
}
// CHECK-LABEL: define {{.*}} @test_init_existential_non_fixed
// CHECK: [[CONTAINER:%.*]] = alloca %T25existentials_opaque_boxed11ExistentialP
// CHECK: [[CALL:%.*]] = call ptr @__swift_allocate_boxed_opaque_existential_1(ptr [[CONTAINER]])
sil @test_init_existential_non_fixed : $@convention(thin) <T> (@in T) -> () {
entry(%0 : $*T):
%exist_container = alloc_stack $Existential
%value_addr = init_existential_addr %exist_container : $*Existential, $NonFixed<T>
dealloc_stack %exist_container : $*Existential
%t = tuple()
return %t : $()
}
sil @test_init_other_existential_non_fixed : $@convention(thin) <T> (@in T) -> () {
entry(%0 : $*T):
%exist_container = alloc_stack $OtherExistential
%value_addr = init_existential_addr %exist_container : $*OtherExistential, $NonFixed<T>
dealloc_stack %exist_container : $*OtherExistential
%t = tuple()
return %t : $()
}
// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} linkonce_odr hidden ptr @__swift_allocate_boxed_opaque_existential_1(ptr %0)
// CHECK: [[METATYPE_ADDR:%.*]] = getelementptr inbounds{{.*}} %__opaque_existential_type_1, ptr %0, i32 0, i32 1
// CHECK: [[METATYPE:%.*]] = load ptr, ptr [[METATYPE_ADDR]]
// CHECK: [[VWT_ADDR:%.*]] = getelementptr inbounds ptr, ptr [[METATYPE]], {{(i64|i32)}} -1
// CHECK: [[VWT:%.*]] = load ptr, ptr [[VWT_ADDR]]
// CHECK-arm64e-NEXT: ptrtoint ptr [[VWT_ADDR]] to i64
// CHECK-arm64e-NEXT: call i64 @llvm.ptrauth.blend
// CHECK-arm64e: [[VWT:%.*]] = inttoptr i64 {{%.*}} to ptr
// CHECK: [[FLAGS_ADDR:%.*]] = getelementptr inbounds{{.*}} %swift.vwtable, ptr [[VWT]], i32 0, i32 10
// CHECK: [[FLAGS:%.*]] = load i32, ptr [[FLAGS_ADDR]]
// CHECK: [[ISNOTINLINE:%.*]] = and i32 [[FLAGS]], 131072
// CHECK: [[ISINLINE:%.*]] = icmp eq i32 [[ISNOTINLINE]], 0
// CHECK: [[EXISTENTIAL_BUFFER:%.*]] = getelementptr inbounds{{.*}} %__opaque_existential_type_1, ptr %0, i32 0, i32 0
// CHECK: br i1 [[ISINLINE]], label %done, label %allocateBox
//
// CHECK:done:
// CHECK: ret ptr [[EXISTENTIAL_BUFFER]]
//
// CHECK:allocateBox:
// CHECK-64: [[CALL:%.*]] = call swiftcc { ptr, ptr } @swift_allocBox(ptr [[METATYPE]])
// CHECK-64: [[BOX:%.*]] = extractvalue { ptr, ptr } [[CALL]], 0
// CHECK-64: [[ADDR:%.*]] = extractvalue { ptr, ptr } [[CALL]], 1
// CHECK-64: store ptr [[BOX]], ptr [[EXISTENTIAL_BUFFER]]
// CHECK-64: ret ptr [[ADDR]]
//
// CHECK-32: [[CALL:%.*]] = call swiftcc { ptr, ptr } @swift_allocBox(ptr [[METATYPE]])
// CHECK-32: [[BOX:%.*]] = extractvalue { ptr, ptr } [[CALL]], 0
// CHECK-32: [[ADDR:%.*]] = extractvalue { ptr, ptr } [[CALL]], 1
// CHECK-32: store ptr [[BOX]], ptr [[EXISTENTIAL_BUFFER]]
// CHECK-32: ret ptr [[ADDR]]
// CHECK-LABEL: define {{.*}} @test_init_existential_fixed
// CHECK: [[CONTAINER:%.*]] = alloca %T25existentials_opaque_boxed11ExistentialP
// The first inline buffer reference is from the emitOpaqueExistentialContainerInit call.
// CHECK: [[INLINEBUFFER:%.*]] = getelementptr inbounds{{.*}} %T25existentials_opaque_boxed11ExistentialP, ptr [[CONTAINER]], i32 0, i32 0
// CHECK: [[INLINEBUFFER:%.*]] = getelementptr inbounds{{.*}} %T25existentials_opaque_boxed11ExistentialP, ptr [[CONTAINER]], i32 0, i32 0
sil @test_init_existential_fixed : $@convention(thin) () -> () {
entry:
%exist_container = alloc_stack $Existential
%value_addr = init_existential_addr %exist_container : $*Existential, $Fixed
dealloc_stack %exist_container : $*Existential
%t = tuple()
return %t : $()
}
sil @test_init_other_existential_fixed : $@convention(thin) () -> () {
entry:
%exist_container = alloc_stack $OtherExistential
%value_addr = init_existential_addr %exist_container : $*OtherExistential, $Fixed
dealloc_stack %exist_container : $*OtherExistential
%t = tuple()
return %t : $()
}
// CHECK-LABEL: define {{.*}} @test_init_existential_fixed_not_inline()
// CHECK: [[CONTAINER:%.*]] = alloca %T25existentials_opaque_boxed11ExistentialP
// CHECK: [[INLINEBUFFER:%.*]] = getelementptr inbounds{{.*}} %T25existentials_opaque_boxed11ExistentialP, ptr [[CONTAINER]], i32 0, i32 0
// CHECK: [[INLINEBUFFER:%.*]] = getelementptr inbounds{{.*}} %T25existentials_opaque_boxed11ExistentialP, ptr [[CONTAINER]], i32 0, i32 0
// CHECK: [[BOX:%.*]] = call noalias ptr @swift_allocObject(ptr getelementptr inbounds (%swift.full_boxmetadata, ptr @metadata, i32 0, i32 2), {{(i64 48|i32 40)}}, {{(i64|i32)}} 7)
// CHECK: [[VALUE_ADDR:%.*]] = getelementptr inbounds{{.*}} <{ %swift.refcounted{{(, \[4 x i8\])?}}, [32 x i8] }>, ptr [[BOX]], i32 0, i32 {{(1|2)}}
// CHECK: store ptr [[BOX]], ptr [[INLINEBUFFER]]
// CHECK: ret void
sil @test_init_existential_fixed_not_inline : $@convention(thin) () -> () {
entry:
%exist_container = alloc_stack $Existential
%value_addr = init_existential_addr %exist_container : $*Existential, $NotInlineFixed
dealloc_stack %exist_container : $*Existential
%t = tuple()
return %t : $()
}
sil @test_init_other_existential_fixed_not_inline : $@convention(thin) () -> () {
entry:
%exist_container = alloc_stack $OtherExistential
%value_addr = init_existential_addr %exist_container : $*OtherExistential, $NotInlineFixed
dealloc_stack %exist_container : $*OtherExistential
%t = tuple()
return %t : $()
}
// CHECK-LABEL: define {{.*}} @test_deinit_existential
// CHECK: [[CONTAINER:%.*]] = alloca %T25existentials_opaque_boxed11ExistentialP
// CHECK: call void @__swift_deallocate_boxed_opaque_existential_1(ptr [[CONTAINER]])
// CHECK: ret void
sil @test_deinit_existential : $@convention(thin) () -> () {
entry:
%exist_container = alloc_stack $Existential
deinit_existential_addr %exist_container : $*Existential
dealloc_stack %exist_container : $*Existential
%t = tuple()
return %t : $()
}
sil @test_deinit_other_existential : $@convention(thin) () -> () {
entry:
%exist_container = alloc_stack $OtherExistential
deinit_existential_addr %exist_container : $*OtherExistential
dealloc_stack %exist_container : $*OtherExistential
%t = tuple()
return %t : $()
}
// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} linkonce_odr hidden void @__swift_deallocate_boxed_opaque_existential_1(ptr %0)
// CHECK: [[META_ADDR:%.*]] = getelementptr inbounds{{.*}} %__opaque_existential_type_1, ptr %0, i32 0, i32 1
// CHECK: [[META:%.*]] = load ptr, ptr [[META_ADDR]]
// CHECK: [[VWT_ADDR:%.*]] = getelementptr inbounds ptr, ptr %2, {{(i64|i32)}} -1
// CHECK: [[VWT:%.*]] = load ptr, ptr [[VWT_ADDR]]
// CHECK-arm64e-NEXT: ptrtoint ptr [[VWT_ADDR]] to i64
// CHECK-arm64e-NEXT: call i64 @llvm.ptrauth.blend
// CHECK-arm64e: [[VWT:%.*]] = inttoptr i64 {{%.*}} to ptr
// CHECK: [[FLAGS_ADDR:%.*]] = getelementptr inbounds{{.*}} %swift.vwtable, ptr [[VWT]], i32 0, i32 10
// CHECK: [[FLAGS:%.*]] = load i32, ptr [[FLAGS_ADDR]]
// CHECK: [[ISNOTINLINE:%.*]] = and i32 [[FLAGS]], 131072
// CHECK: [[ISINLINE:%.*]] = icmp eq i32 [[ISNOTINLINE]], 0
// CHECK: br i1 [[ISINLINE]], label %done, label %deallocateBox
// CHECK: done:
// CHECK: ret void
// CHECK: deallocateBox:
// CHECK: [[BUFFER:%.*]] = getelementptr inbounds{{.*}} %__opaque_existential_type_1, ptr %0, i32 0, i32 0
// CHECK: [[REFERENCE:%.*]] = load ptr, ptr [[BUFFER]]
// CHECK: [[VWT_ADDR2:%.*]] = getelementptr inbounds ptr, ptr [[META]], {{(i64|i32)}} -1
// CHECK: [[VWT2:%.*]] = load ptr, ptr [[VWT_ADDR2]]
// CHECK-arm64e-NEXT: ptrtoint ptr [[VWT_ADDR2]] to i64
// CHECK-arm64e-NEXT: call i64 @llvm.ptrauth.blend
// CHECK-arm64e: [[VWT2:%.*]] = inttoptr i64 {{%.*}} to ptr
// CHECK: [[SIZE2_ADDR:%.*]] = getelementptr inbounds{{.*}} %swift.vwtable, ptr [[VWT2]], i32 0, i32 8
// CHECK: [[SIZE:%.*]] = load [[INT]], ptr [[SIZE2_ADDR]]
// CHECK-64:[[T0:%.*]] = zext i32 [[FLAGS]] to i64
// CHECK-64:[[ALIGNMASK:%.*]] = and i64 [[T0]], 255
// CHECK-32:[[ALIGNMASK:%.*]] = and i32 [[FLAGS]], 255
// CHECK-16:[[T0:%.*]] = trunc i32 [[FLAGS]] to i16
// CHECK-16:[[ALIGNMASK:%.*]] = and i16 [[T0]], 255
// CHECK: [[HEADERSIZEPLUSALIGN:%.*]] = add {{(i64 16|i32 8)}}, [[ALIGNMASK]]
// CHECK: [[NOTALIGNMASK:%.*]] = xor {{(i64|i32)}} [[ALIGNMASK]], -1
// CHECK: [[ALIGNEDSTART:%.*]] = and {{(i64|i32)}} [[HEADERSIZEPLUSALIGN]], [[NOTALIGNMASK]]
// CHECK: [[HEAPSIZE:%.*]] = add {{(i64|i32)}} [[ALIGNEDSTART]], [[SIZE]]
// CHECK: [[ALIGNMASK_ATLEASTPOINTER:%.*]] = or {{(i64|i32)}} [[ALIGNMASK]], {{(7|3)}}
// CHECK: call void @swift_slowDealloc(ptr [[REFERENCE]], {{(i64|i32)}} [[HEAPSIZE]], {{(i64|i32)}} [[ALIGNMASK_ATLEASTPOINTER]])
// CHECK: ret void
// CHECK-LABEL: define {{.*}} @test_open_existential_addr_immutable(ptr
// CHECK: [[META_ADDR:%.*]] = getelementptr inbounds{{.*}} %T25existentials_opaque_boxed11ExistentialP, ptr %0, i32 0, i32 1
// CHECK: [[METATYPE:%.*]] = load ptr, ptr [[META_ADDR]]
// CHECK: [[VWT_ADDR:%.*]] = getelementptr inbounds{{.*}} %T25existentials_opaque_boxed11ExistentialP, ptr %0, i32 0, i32 2
// CHECK: [[VWT:%.*]] = load ptr, ptr [[VWT_ADDR]]
// CHECK: [[VALUE_ADDR:%.*]] = call ptr @__swift_project_boxed_opaque_existential_1(ptr %0, ptr [[METATYPE]])
// CHECK: ret void
sil @test_open_existential_addr_immutable :$@convention(thin) (@in Existential) -> () {
bb0(%0 : $*Existential):
%1 = open_existential_addr immutable_access %0 : $*Existential to $*@opened("01234567-89ab-cdef-0123-000000000000", Existential) Self
%t = tuple()
return %t : $()
}
// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} linkonce_odr hidden ptr @__swift_project_boxed_opaque_existential_1(ptr %0, ptr %1)
// CHECK: [[VWT_ADDR:%.*]] = getelementptr inbounds ptr, ptr %1, {{(i64|i32)}} -1
// CHECK: [[VWT:%.*]] = load ptr, ptr [[VWT_ADDR]]
// CHECK-arm64e-NEXT: ptrtoint ptr [[VWT_ADDR]] to i64
// CHECK-arm64e-NEXT: call i64 @llvm.ptrauth.blend
// CHECK-arm64e: [[VWT:%.*]] = inttoptr i64 {{%.*}} to ptr
// CHECK: [[FLAGS_ADDR:%.*]] = getelementptr inbounds{{.*}} %swift.vwtable, ptr [[VWT]], i32 0, i32 10
// CHECK: [[FLAGS:%.*]] = load i32, ptr [[FLAGS_ADDR]]
// CHECK: [[ISNOTINLINE:%.*]] = and i32 [[FLAGS]], 131072
// CHECK: [[ISINLINE:%.*]] = icmp eq i32 [[ISNOTINLINE]], 0
// CHECK: br i1 [[ISINLINE]], label %done, label %boxed
//
// CHECK: done:
// CHECK: ret ptr %0
//
// CHECK: boxed:
// CHECK: [[REF:%.*]] = load ptr, ptr %0
// CHECK-64:[[T0:%.*]] = zext i32 [[FLAGS]] to i64
// CHECK-64:[[ALIGNMASK:%.*]] = and i64 [[T0]], 255
// CHECK-32:[[ALIGNMASK:%.*]] = and i32 [[FLAGS]], 255
// CHECK-16:[[T0:%.*]] = trunc i32 [[FLAGS]] to i16
// CHECK-16:[[ALIGNMASK:%.*]] = and i16 [[T0]], 255
// CHECK: [[HEADERSIZEPLUSALIGN:%.*]] = add {{(i64 16|i32 8)}}, [[ALIGNMASK]]
// CHECK: [[NOTALIGNMASK:%.*]] = xor {{(i64|i32)}} [[ALIGNMASK]], -1
// CHECK: [[ALIGNEDSTART:%.*]] = and {{(i64|i32)}} [[HEADERSIZEPLUSALIGN]], [[NOTALIGNMASK]]
// CHECK: [[STARTOFVALUE:%.*]] = getelementptr inbounds i8, ptr [[REF]], {{(i64|i32)}} [[ALIGNEDSTART]]
// CHECK: ret ptr [[STARTOFVALUE]]
// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} {{.*}} @test_open_existential_addr_mutable
// CHECK: [[META_ADDR:%.*]] = getelementptr inbounds{{.*}} %T25existentials_opaque_boxed11ExistentialP, ptr %0, i32 0, i32 1
// CHECK: [[METATYPE:%.*]] = load ptr, ptr [[META_ADDR]]
// CHECK: [[VWT_ADDR:%.*]] = getelementptr inbounds{{.*}} %T25existentials_opaque_boxed11ExistentialP, ptr %0, i32 0, i32 2
// CHECK: [[VWT:%.*]] = load ptr, ptr [[VWT_ADDR]]
// CHECK: [[VALUE_ADDR:%.*]] = call ptr @__swift_mutable_project_boxed_opaque_existential_1(ptr %0, ptr [[METATYPE]])
// CHECK: ret void
sil @test_open_existential_addr_mutable :$@convention(thin) (@in Existential) -> () {
bb0(%0 : $*Existential):
%1 = open_existential_addr mutable_access %0 : $*Existential to $*@opened("01234567-89ab-cdef-0123-000000000001", Existential) Self
%t = tuple()
return %t : $()
}
// CHECK: define{{( dllexport)?}}{{( protected)?}} linkonce_odr hidden ptr @__swift_mutable_project_boxed_opaque_existential_1(ptr %0, ptr %1)
// CHECK: [[VWT_ADDR:%.*]] = getelementptr inbounds ptr, ptr %1, {{(i64|i32)}} -1
// CHECK: [[VWT:%.*]] = load ptr, ptr [[VWT_ADDR]]
// CHECK-arm64e-NEXT: ptrtoint ptr [[VWT_ADDR]] to i64
// CHECK-arm64e-NEXT: call i64 @llvm.ptrauth.blend
// CHECK-arm64e: [[VWT:%.*]] = inttoptr i64 {{%.*}} to ptr
// CHECK: [[FLAGS_ADDR:%.*]] = getelementptr inbounds{{.*}} %swift.vwtable, ptr [[VWT]], i32 0, i32 10
// CHECK: [[FLAGS:%.*]] = load i32, ptr [[FLAGS_ADDR]]
// CHECK: [[ISNOTINLINE:%.*]] = and i32 [[FLAGS]], 131072
// CHECK: [[ISINLINE:%.*]] = icmp eq i32 [[ISNOTINLINE]], 0
// CHECK: br i1 [[ISINLINE]], label %done, label %boxed
//
// CHECK: done:
// CHECK: ret ptr %0
// CHECK: boxed:
// CHECK-64:[[T0:%.*]] = zext i32 [[FLAGS]] to i64
// CHECK-64:[[ALIGNMASK:%.*]] = and i64 [[T0]], 255
// CHECK-32:[[ALIGNMASK:%.*]] = and i32 [[FLAGS]], 255
// CHECK-16:[[T0:%.*]] = trunc i32 [[FLAGS]] to i16
// CHECK-16:[[ALIGNMASK:%.*]] = and i16 [[T0]], 255
// CHECK-64: [[REFANDADDR:%.*]] = call swiftcc { ptr, ptr } @swift_makeBoxUnique(ptr %0, ptr %1, {{(i64|i32)}} [[ALIGNMASK]])
// CHECK-32: [[REFANDADDR:%.*]] = call swiftcc { ptr, ptr } @swift_makeBoxUnique(ptr %0, ptr %1, {{(i64|i32)}} [[ALIGNMASK]])
// CHECK: [[REF:%.*]] = extractvalue {{.*}}{ ptr, ptr }{{.*}} [[REFANDADDR]], 0
// CHECK: [[ADDR:%.*]] = extractvalue {{.*}}{ ptr, ptr }{{.*}} [[REFANDADDR]], 1
// CHECK: ret ptr [[ADDR]]
// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc void @test_destroy_existential_addr(ptr
// CHECK: call void @__swift_destroy_boxed_opaque_existential_1(ptr %0)
// CHECK: ret void
sil @test_destroy_existential_addr :$@convention(thin) (@in Existential) -> () {
bb0(%0 : $*Existential):
destroy_addr %0 : $*Existential
%t = tuple()
return %t : $()
}
sil @test_destroy_other_existential_addr :$@convention(thin) (@in OtherExistential) -> () {
bb0(%0 : $*OtherExistential):
destroy_addr %0 : $*OtherExistential
%t = tuple()
return %t : $()
}
// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} linkonce_odr hidden void @__swift_destroy_boxed_opaque_existential_1(ptr %0)
// CHECK: [[METADATA_ADDR:%.*]] = getelementptr inbounds{{.*}} %__opaque_existential_type_1, ptr %0, i32 0, i32 1
// CHECK: [[METADATA:%.*]] = load ptr, ptr [[METADATA_ADDR]]
// CHECK: [[BUFFER_ADDR:%.*]] = getelementptr inbounds{{.*}} %__opaque_existential_type_1, ptr %0, i32 0, i32 0
// CHECK: [[VWT_ADDR:%.*]] = getelementptr inbounds ptr, ptr [[METADATA]], {{(i64|i32)}} -1
// CHECK: [[VWT:%.*]] = load ptr, ptr [[VWT_ADDR]]
// CHECK-arm64e-NEXT: ptrtoint ptr [[VWT_ADDR]] to i64
// CHECK-arm64e-NEXT: call i64 @llvm.ptrauth.blend
// CHECK-arm64e: [[VWT:%.*]] = inttoptr i64 {{%.*}} to ptr
// CHECK: [[FLAGS_ADDR:%.*]] = getelementptr inbounds{{.*}} %swift.vwtable, ptr [[VWT]], i32 0, i32 10
// CHECK: [[FLAGS:%.*]] = load i32, ptr [[FLAGS_ADDR]]
// CHECK: [[ISNOTINLINE:%.*]] = and i32 [[FLAGS]], 131072
// CHECK: [[ISINLINE:%.*]] = icmp eq i32 [[ISNOTINLINE]], 0
// CHECK: br i1 [[ISINLINE]], label %inline, label %outline
//
// CHECK: inline:
// CHECK: [[VWT_ADDR:%.*]] = getelementptr inbounds ptr, ptr [[METADATA]], {{(i64|i32)}} -1
// CHECK: [[VWT:%.*]] = load ptr, ptr [[VWT_ADDR]]
// CHECK-arm64e-NEXT: ptrtoint ptr [[VWT_ADDR]] to i64
// CHECK-arm64e-NEXT: call i64 @llvm.ptrauth.blend
// CHECK-arm64e: [[VWT:%.*]] = inttoptr i64 {{%.*}} to ptr
// CHECK: [[VW_ADDR:%.*]] = getelementptr inbounds ptr, ptr [[VWT]], i32 1
// CHECK: [[VW:%.*]] = load ptr, ptr [[VW_ADDR]]
// CHECK: call void [[VW]](ptr noalias [[BUFFER_ADDR]], ptr [[METADATA]])
// CHECK: ret void
//
// CHECK: outline:
// CHECK: [[REFERENCE:%.*]] = load ptr, ptr [[BUFFER_ADDR]]
// CHECK: call void @swift_release(ptr [[REFERENCE]])
// CHECK: ret void
// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc void @test_assignWithCopy_existential_addr(ptr
// CHECK: [[ALLOCA:%.*]] = alloca %T25existentials_opaque_boxed11ExistentialP
// CHECK: call void @__swift_assign_boxed_opaque_existential_1(ptr [[ALLOCA]], ptr %0)
// CHECK: ret void
// CHECK:}
sil @test_assignWithCopy_existential_addr : $@convention(thin) (@in Existential) -> () {
bb0(%0 : $*Existential):
%s = alloc_stack $Existential
copy_addr %0 to %s : $*Existential
dealloc_stack %s : $*Existential
%t = tuple()
return %t : $()
}
sil @test_assignWithCopy_other_existential_addr : $@convention(thin) (@in OtherExistential) -> () {
bb0(%0 : $*OtherExistential):
%s = alloc_stack $OtherExistential
copy_addr %0 to %s : $*OtherExistential
dealloc_stack %s : $*OtherExistential
%t = tuple()
return %t : $()
}
// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} linkonce_odr hidden void @__swift_assign_boxed_opaque_existential_1(ptr %0, ptr %1)
// CHECK: [[TMPBUFFER:%.*]] = alloca [{{(24|12)}} x i8]
// CHECK: [[SELFASSIGN:%.*]] = icmp eq ptr %0, %1
// CHECK: br i1 [[SELFASSIGN]], label %done, label %cont
//
// CHECK: cont:
// CHECK: [[DEST_BUFFERADDR:%.*]] = getelementptr inbounds{{.*}} %__opaque_existential_type_1, ptr %0, i32 0, i32 0
// CHECK: [[SRC_BUFFERADDR:%.*]] = getelementptr inbounds{{.*}} %__opaque_existential_type_1, ptr %1, i32 0, i32 0
// CHECK: [[DEST_TYPEADDR:%.*]] = getelementptr inbounds{{.*}} %__opaque_existential_type_1, ptr %0, i32 0, i32 1
// CHECK: [[DEST_TYPE:%.*]] = load ptr, ptr [[DEST_TYPEADDR]]
// CHECK: [[SRC_TYPEADDR:%.*]] = getelementptr inbounds{{.*}} %__opaque_existential_type_1, ptr %1, i32 0, i32 1
// CHECK: [[SRC_TYPE:%.*]] = load ptr, ptr [[SRC_TYPEADDR]]
// CHECK: [[ISSAME:%.*]] = icmp eq ptr [[DEST_TYPE]], [[SRC_TYPE]]
// CHECK: br i1 [[ISSAME]], label %match, label %no-match
//
// CHECK: match:
// CHECK: [[VWT_ADDR:%.*]] = getelementptr inbounds ptr, ptr [[DEST_TYPE]], {{(i64|i32)}} -1
// CHECK: [[VWT:%.*]] = load ptr, ptr [[VWT_ADDR]]
// CHECK-arm64e-NEXT: ptrtoint ptr [[VWT_ADDR]] to i64
// CHECK-arm64e-NEXT: call i64 @llvm.ptrauth.blend
// CHECK-arm64e: [[VWT:%.*]] = inttoptr i64 {{%.*}} to ptr
// CHECK: [[FLAGS_ADDR:%.*]] = getelementptr inbounds{{.*}} %swift.vwtable, ptr [[VWT]], i32 0, i32 10
// CHECK: [[FLAGS:%.*]] = load i32, ptr [[FLAGS_ADDR]]
// CHECK: [[ISNOTINLINE:%.*]] = and i32 [[FLAGS]], 131072
// CHECK: [[ISINLINE:%.*]] = icmp eq i32 [[ISNOTINLINE]], 0
// CHECK: br i1 [[ISINLINE]], label %match-inline, label %match-outline
//
// CHECK: match-inline:
// CHECK: [[VWT_ADDR:%.*]] = getelementptr inbounds ptr, ptr [[DEST_TYPE]], {{(i64|i32)}} -1
// CHECK: [[VWT:%.*]] = load ptr, ptr [[VWT_ADDR]]
// CHECK-arm64e-NEXT: ptrtoint ptr [[VWT_ADDR]] to i64
// CHECK-arm64e-NEXT: call i64 @llvm.ptrauth.blend
// CHECK-arm64e: [[VWT:%.*]] = inttoptr i64 {{%.*}} to ptr
// CHECK: [[VW_ADDR:%.*]] = getelementptr inbounds ptr, ptr [[VWT]], i32 3
// CHECK: [[VW:%.*]] = load ptr, ptr [[VW_ADDR]]
// CHECK: call ptr [[VW]](ptr [[DEST_BUFFERADDR]], ptr [[SRC_BUFFERADDR]], ptr [[DEST_TYPE]])
// CHECK: br label %done
//
// CHECK: match-outline:
// CHECK: [[DEST_REF:%.*]] = load ptr, ptr [[DEST_BUFFERADDR]]
// CHECK: [[SRC_REF:%.*]] = load ptr, ptr [[SRC_BUFFERADDR]]
// CHECK: call ptr @swift_retain(ptr returned [[SRC_REF]])
// CHECK: call void @swift_release(ptr [[DEST_REF]])
// CHECK: store ptr [[SRC_REF]], ptr [[DEST_BUFFERADDR]]
// CHECK: br label %done
// CHECK: no-match:
// CHECK: store ptr [[SRC_TYPE]], ptr [[DEST_TYPEADDR]]
// CHECK: [[DEST_PWT_ADDR:%.*]] = getelementptr inbounds{{.*}} %__opaque_existential_type_1, ptr %0, i32 0, i32 2
// CHECK: [[SRC_PWT_ADDR:%.*]] = getelementptr inbounds{{.*}} %__opaque_existential_type_1, ptr %1, i32 0, i32 2
// CHECK: [[SRC_PTW:%.*]] = load ptr, ptr [[SRC_PWT_ADDR]]
// CHECK: store ptr [[SRC_PTW]], ptr [[DEST_PWT_ADDR]]
// CHECK: [[DEST_VWT_ADDR:%.*]] = getelementptr inbounds ptr, ptr [[DEST_TYPE]], {{(i64|i32)}} -1
// CHECK: [[DEST_VWT:%.*]] = load ptr, ptr [[DEST_VWT_ADDR]]
// CHECK-arm64e-NEXT: ptrtoint ptr [[DEST_VWT_ADDR]] to i64
// CHECK-arm64e-NEXT: call i64 @llvm.ptrauth.blend
// CHECK-arm64e: [[DEST_VWT:%.*]] = inttoptr i64 {{%.*}} to ptr
// CHECK: [[DEST_FLAGS_ADDR:%.*]] = getelementptr inbounds{{.*}} %swift.vwtable, ptr [[DEST_VWT]], i32 0, i32 10
// CHECK: [[DEST_FLAGS:%.*]] = load i32, ptr [[DEST_FLAGS_ADDR]]
// CHECK: [[DEST_ISNOTINLINE:%.*]] = and i32 [[DEST_FLAGS]], 131072
// CHECK: [[DEST_ISINLINE:%.*]] = icmp eq i32 [[DEST_ISNOTINLINE]], 0
// CHECK: [[SRC_VWT_ADDR:%.*]] = getelementptr inbounds ptr, ptr [[SRC_TYPE]], {{(i64|i32)}} -1
// CHECK: [[SRC_VWT:%.*]] = load ptr, ptr [[SRC_VWT_ADDR]]
// CHECK-arm64e-NEXT: ptrtoint ptr [[SRC_VWT_ADDR]] to i64
// CHECK-arm64e-NEXT: call i64 @llvm.ptrauth.blend
// CHECK-arm64e: [[SRC_VWT:%.*]] = inttoptr i64 {{%.*}} to ptr
// CHECK: [[SRC_FLAGS_ADDR:%.*]] = getelementptr inbounds{{.*}} %swift.vwtable, ptr [[SRC_VWT]], i32 0, i32 10
// CHECK: [[SRC_FLAGS:%.*]] = load i32, ptr [[SRC_FLAGS_ADDR]]
// CHECK: [[SRC_ISNOTINLINE:%.*]] = and i32 [[SRC_FLAGS]], 131072
// CHECK: [[SRC_ISINLINE:%.*]] = icmp eq i32 [[SRC_ISNOTINLINE]], 0
// CHECK: br i1 [[DEST_ISINLINE]], label %dest-inline, label %dest-outline
//
// CHECK: dest-inline:
// CHECK: [[VWT_ADDR:%.*]] = getelementptr inbounds ptr, ptr [[DEST_TYPE]], {{(i64|i32)}} -1
// CHECK: [[VWT:%.*]] = load ptr, ptr [[VWT_ADDR]]
// CHECK-arm64e-NEXT: ptrtoint ptr [[VWT_ADDR]] to i64
// CHECK-arm64e-NEXT: call i64 @llvm.ptrauth.blend
// CHECK-arm64e: [[VWT:%.*]] = inttoptr i64 {{%.*}} to ptr
// CHECK: [[VW_ADDR:%.*]] = getelementptr inbounds ptr, ptr [[VWT]], i32 4
// CHECK: [[VW:%.*]] = load ptr, ptr [[VW_ADDR]]
// CHECK: call ptr [[VW]](ptr noalias [[TMPBUFFER]], ptr noalias [[DEST_BUFFERADDR]], ptr [[DEST_TYPE]])
// CHECK: br i1 [[SRC_ISINLINE]], label %dest-inline-src-inline, label %dest-inline-src-outline
//
// CHECK: dest-inline-src-inline:
// CHECK: [[VWT_ADDR:%.*]] = getelementptr inbounds ptr, ptr [[SRC_TYPE]], {{(i64|i32)}} -1
// CHECK: [[VWT:%.*]] = load ptr, ptr [[VWT_ADDR]]
// CHECK-arm64e-NEXT: ptrtoint ptr [[VWT_ADDR]] to i64
// CHECK-arm64e-NEXT: call i64 @llvm.ptrauth.blend
// CHECK-arm64e: [[VWT:%.*]] = inttoptr i64 {{%.*}} to ptr
// CHECK: [[VW_ADDR:%.*]] = getelementptr inbounds ptr, ptr [[VWT]], i32 2
// CHECK: [[VW:%.*]] = load ptr, ptr [[VW_ADDR]]
// CHECK: call ptr [[VW]](ptr noalias [[DEST_BUFFERADDR]], ptr noalias [[SRC_BUFFERADDR]], ptr [[SRC_TYPE]])
// CHECK: br label %dest-inline-cont
//
// CHECK: dest-inline-src-outline:
// CHECK: [[SRC_REF:%.*]] = load ptr, ptr [[SRC_BUFFERADDR]]
// CHECK: call ptr @swift_retain(ptr returned [[SRC_REF]])
// CHECK: store ptr [[SRC_REF]], ptr [[DEST_BUFFERADDR]]
// CHECK: br label %dest-inline-cont
//
// CHECK: dest-inline-cont:
// CHECK: [[VWT_ADDR:%.*]] = getelementptr inbounds ptr, ptr [[DEST_TYPE]], {{(i64|i32)}} -1
// CHECK: [[VWT:%.*]] = load ptr, ptr [[VWT_ADDR]]
// CHECK-arm64e-NEXT: ptrtoint ptr [[VWT_ADDR]] to i64
// CHECK-arm64e-NEXT: call i64 @llvm.ptrauth.blend
// CHECK-arm64e: [[VWT:%.*]] = inttoptr i64 {{%.*}} to ptr
// CHECK: [[VW_ADDR:%.*]] = getelementptr inbounds ptr, ptr [[VWT]], i32 1
// CHECK: [[VW:%.*]] = load ptr, ptr [[VW_ADDR]]
// CHECK: call void [[VW]](ptr noalias [[TMPBUFFER]], ptr [[DEST_TYPE]])
// CHECK: br label %done
//
// CHECK: dest-outline:
// CHECK: [[DEST_REF:%.*]] = load ptr, ptr [[DEST_BUFFERADDR]]
// CHECK: br i1 [[SRC_ISINLINE]], label %dest-outline-src-inline, label %dest-outline-src-outline
//
// CHECK: dest-outline-src-inline:
// CHECK: [[VWT_ADDR:%.*]] = getelementptr inbounds ptr, ptr [[SRC_TYPE]], {{(i64|i32)}} -1
// CHECK: [[VWT:%.*]] = load ptr, ptr [[VWT_ADDR]]
// CHECK-arm64e-NEXT: ptrtoint ptr [[VWT_ADDR]] to i64
// CHECK-arm64e-NEXT: call i64 @llvm.ptrauth.blend
// CHECK-arm64e: [[VWT:%.*]] = inttoptr i64 {{%.*}} to ptr
// CHECK: [[VW_ADDR:%.*]] = getelementptr inbounds ptr, ptr [[VWT]], i32 2
// CHECK: [[VW:%.*]] = load ptr, ptr [[VW_ADDR]]
// CHECK: call ptr [[VW]](ptr noalias [[DEST_BUFFERADDR]], ptr noalias [[SRC_BUFFERADDR]], ptr [[SRC_TYPE]])
// CHECK: br label %dest-outline-cont
//
// CHECK: dest-outline-src-outline:
// CHECK: [[SRC_REF:%.*]] = load ptr, ptr [[SRC_BUFFERADDR]]
// CHECK: call ptr @swift_retain(ptr returned [[SRC_REF]])
// CHECK: store ptr [[SRC_REF]], ptr [[DEST_BUFFERADDR]]
// CHECK: br label %dest-outline-cont
//
// CHECK: dest-outline-cont:
// CHECK: call void @swift_release(ptr [[DEST_REF]])
// CHECK: br label %done
//
// CHECK: done:
// CHECK: ret void
// CHECK: define{{( dllexport)?}}{{( protected)?}} swiftcc void @test_assignWithTake_existential_addr(ptr
// CHECK: [[ALLOCA:%.*]] = alloca %T25existentials_opaque_boxed11ExistentialP
// CHECK: call void @__swift_destroy_boxed_opaque_existential_1(ptr [[ALLOCA]])
// CHECK: call ptr @"$s25existentials_opaque_boxed11Existential_pWOb"(ptr %0, ptr [[ALLOCA]])
// CHECK: ret void
sil @test_assignWithTake_existential_addr : $@convention(thin) (@in Existential) -> () {
bb0(%0 : $*Existential):
%s = alloc_stack $Existential
copy_addr [take] %0 to %s : $*Existential
dealloc_stack %s : $*Existential
%t = tuple()
return %t : $()
}
sil @test_assignWithTake_other_existential_addr : $@convention(thin) (@in OtherExistential) -> () {
bb0(%0 : $*OtherExistential):
%s = alloc_stack $OtherExistential
copy_addr [take] %0 to %s : $*OtherExistential
dealloc_stack %s : $*OtherExistential
%t = tuple()
return %t : $()
}
// CHECK-LABEL: define linkonce_odr hidden ptr @"$s25existentials_opaque_boxed11Existential_pWOb"(ptr %0, ptr %1)
// CHECK: call void @llvm.memcpy.p0.p0.{{(i64|i32)}}(ptr align {{(8|4)}} %1, ptr align {{(8|4)}} %0, {{(i64 40|i32 20)}}, i1 false)
// CHECK: ret ptr %1
// CHECK: define{{( dllexport)?}}{{( protected)?}} swiftcc void @test_initWithTake_existential_addr(ptr
// CHECK: [[LOCAL:%.*]] = alloca %T25existentials_opaque_boxed11ExistentialP
// CHECK: call ptr @"$s25existentials_opaque_boxed11Existential_pWOb"(ptr %0, ptr [[LOCAL]])
// CHECK: ret void
sil @test_initWithTake_existential_addr : $@convention(thin) (@in Existential) -> () {
bb0(%0 : $*Existential):
%s = alloc_stack $Existential
copy_addr [take] %0 to [init] %s : $*Existential
dealloc_stack %s : $*Existential
%t = tuple()
return %t : $()
}
sil @test_initWithTake_other_existential_addr : $@convention(thin) (@in OtherExistential) -> () {
bb0(%0 : $*OtherExistential):
%s = alloc_stack $OtherExistential
copy_addr [take] %0 to [init] %s : $*OtherExistential
dealloc_stack %s : $*OtherExistential
%t = tuple()
return %t : $()
}
// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc void @test_initWithCopy_existential_addr(ptr
// CHECK: [[LOCAL:%.*]] = alloca %T25existentials_opaque_boxed11ExistentialP
// CHECK: call ptr @"$s25existentials_opaque_boxed11Existential_pWOc"(ptr %0, ptr [[LOCAL]])
// CHECK: ret void
// CHECK-LABEL: define linkonce_odr hidden ptr @"$s25existentials_opaque_boxed11Existential_pWOc"(ptr %0, ptr %1)
// CHECK: [[TYPE_ADDR:%.*]] = getelementptr inbounds{{.*}} %T25existentials_opaque_boxed11ExistentialP, ptr %0, i32 0, i32 1
// CHECK: [[ARG_TYPE:%.*]] = load ptr, ptr [[TYPE_ADDR]]
// CHECK: [[LOCAL_TYPE_ADDR:%.*]] = getelementptr inbounds{{.*}} %T25existentials_opaque_boxed11ExistentialP, ptr %1, i32 0, i32 1
// CHECK: store ptr [[ARG_TYPE]], ptr [[LOCAL_TYPE_ADDR]]
// CHECK: [[PWT_ADDR:%.*]] = getelementptr inbounds{{.*}} %T25existentials_opaque_boxed11ExistentialP, ptr %0, i32 0, i32 2
// CHECK: [[PWT:%.*]] = load ptr, ptr [[PWT_ADDR]]
// CHECK: [[LOCAL_PWT_ADDR:%.*]] = getelementptr inbounds{{.*}} %T25existentials_opaque_boxed11ExistentialP, ptr %1, i32 0, i32 2
// CHECK: store ptr [[PWT]], ptr [[LOCAL_PWT_ADDR]]
// CHECK: [[BUFFER_ARG_ADDR:%.*]] = getelementptr inbounds{{.*}} %T25existentials_opaque_boxed11ExistentialP, ptr %0, i32 0, i32 0
// CHECK: [[BUFFER_LOCAL_ADDR:%.*]] = getelementptr inbounds{{.*}} %T25existentials_opaque_boxed11ExistentialP, ptr %1, i32 0, i32 0
// CHECK: [[VWT_ADDR:%.*]] = getelementptr inbounds ptr, ptr [[ARG_TYPE]], {{(i64|i32)}} -1
// CHECK: [[VWT:%.*]] = load ptr, ptr [[VWT_ADDR]]
// CHECK-arm64e-NEXT: ptrtoint ptr [[VWT_ADDR]] to i64
// CHECK-arm64e-NEXT: call i64 @llvm.ptrauth.blend
// CHECK-arm64e: [[VWT:%.*]] = inttoptr i64 {{%.*}} to ptr
// CHECK: [[VW:%.*]] = load ptr, ptr [[VWT]]
// CHECK: call ptr [[VW]]({{.*}} noalias [[BUFFER_LOCAL_ADDR]], {{.*}} noalias [[BUFFER_ARG_ADDR]], ptr [[ARG_TYPE]])
// CHECK: ret ptr %1
sil @test_initWithCopy_existential_addr : $@convention(thin) (@in Existential) -> () {
bb0(%0 : $*Existential):
%s = alloc_stack $Existential
copy_addr %0 to [init] %s : $*Existential
dealloc_stack %s : $*Existential
%t = tuple()
return %t : $()
}
sil @test_initWithCopy_other_existential_addr : $@convention(thin) (@in OtherExistential) -> () {
bb0(%0 : $*OtherExistential):
%s = alloc_stack $OtherExistential
copy_addr %0 to [init] %s : $*OtherExistential
dealloc_stack %s : $*OtherExistential
%t = tuple()
return %t : $()
}
@_alignment(16)
struct FixedOveralign : Existential {
var x : Int64
}
// We have to allocate an outline buffer if the fixed size value buffer does not have the right alignment.
// CHECK-LABEL: define {{.*}} @test_init_existential_fixed_align_not_inline()
// CHECK: [[CONTAINER:%.*]] = alloca %T25existentials_opaque_boxed11ExistentialP
// CHECK: [[INLINEBUFFER:%.*]] = getelementptr inbounds{{.*}} %T25existentials_opaque_boxed11ExistentialP, ptr [[CONTAINER]], i32 0, i32 0
// CHECK: [[INLINEBUFFER:%.*]] = getelementptr inbounds{{.*}} %T25existentials_opaque_boxed11ExistentialP, ptr [[CONTAINER]], i32 0, i32 0
// CHECK: [[BOX:%.*]] = call noalias ptr @swift_allocObject(ptr getelementptr inbounds (%swift.full_boxmetadata, ptr @metadata.4, i32 0, i32 2), {{(i64|i32)}} 32, {{(i64|i32)}} 15)
// CHECK: [[VALUE_ADDR:%.*]] = getelementptr inbounds {{.*}}, ptr [[BOX]], i32 0, i32 {{(1|2)}}
// CHECK: store ptr [[BOX]], ptr [[INLINEBUFFER]]
// CHECK: ret void
sil @test_init_existential_fixed_align_not_inline : $@convention(thin) () -> () {
entry:
%exist_container = alloc_stack $Existential
%value_addr = init_existential_addr %exist_container : $*Existential, $FixedOveralign
dealloc_stack %exist_container : $*Existential
%t = tuple()
return %t : $()
}