| // RUN: %target-swift-frontend -assume-parsing-unqualified-ownership-sil -gnone -emit-ir %s | %FileCheck %s |
| |
| // CHECK: [[OPAQUE:%swift.opaque]] = type opaque |
| // CHECK: [[TYPE:%swift.type]] = type |
| |
| sil_stage canonical |
| |
| import Builtin |
| |
| sil @generic : $@convention(thin) <T> (@in T) -> () { |
| bb0(%x : $*T): |
| %y = alloc_stack $T |
| copy_addr %x to [initialization] %y : $*T |
| destroy_addr %y : $*T |
| dealloc_stack %y : $*T |
| destroy_addr %x : $*T |
| %0 = tuple () |
| return %0 : $() |
| } |
| // CHECK: define{{( dllexport)?}}{{( protected)?}} swiftcc void @generic([[OPAQUE]]* noalias nocapture, [[TYPE]]* %T) {{.*}} { |
| // Allocate it. |
| // CHECK: [[TYPE_ADDR:%.*]] = bitcast %swift.type* %T to i8*** |
| // CHECK-NEXT: [[VWT_ADDR:%.*]] = getelementptr inbounds i8**, i8*** [[TYPE_ADDR]], {{(i32|i64)}} -1 |
| // CHECK-NEXT: [[VWT:%.*]] = load i8**, i8*** [[VWT_ADDR]] |
| // CHECK-NEXT: [[SIZE_WITNESS_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 8 |
| // CHECK-NEXT: [[SIZE_WITNESS:%.*]] = load i8*, i8** [[SIZE_WITNESS_ADDR]] |
| // CHECK-NEXT: [[SIZE:%.*]] = ptrtoint i8* [[SIZE_WITNESS]] |
| // CHECK-NEXT: [[Y_ALLOCA:%.*]] = alloca i8, {{.*}} [[SIZE]], align 16 |
| // CHECK-NEXT: call void @llvm.lifetime.start.p0i8({{(i32|i64)}} -1, i8* [[Y_ALLOCA]]) |
| // CHECK-NEXT: [[Y_TMP:%.*]] = bitcast i8* [[Y_ALLOCA]] to %swift.opaque* |
| // Copy 'x' into 'y'. |
| // CHECK-NEXT: [[T3:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 2 |
| // CHECK-NEXT: [[T4:%.*]] = load i8*, i8** [[T3]], align |
| // CHECK-NEXT: [[INIT_WITH_COPY_FN:%.*]] = bitcast i8* [[T4]] to [[OPAQUE]]* ([[OPAQUE]]*, [[OPAQUE]]*, [[TYPE]]*)* |
| // CHECK-NEXT: [[Y:%.*]] = call [[OPAQUE]]* [[INIT_WITH_COPY_FN]]([[OPAQUE]]* noalias [[Y_TMP]], [[OPAQUE]]* noalias [[X:%.*]], [[TYPE]]* %T) |
| // Destroy 'y'. |
| // CHECK-NEXT: [[T3:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 1 |
| // CHECK-NEXT: [[T4:%.*]] = load i8*, i8** [[T3]], align |
| // CHECK-NEXT: [[DESTROY_FN:%.*]] = bitcast i8* [[T4]] to void ([[OPAQUE]]*, [[TYPE]]*)* |
| // CHECK-NEXT: call void [[DESTROY_FN]]([[OPAQUE]]* noalias [[Y_TMP]], [[TYPE]]* %T) |
| // Destroy 'x'. |
| // CHECK-NEXT: call void [[DESTROY_FN]]([[OPAQUE]]* noalias [[X]], [[TYPE]]* %T) |
| // CHECK-NEXT: [[YBUFLIFE:%.*]] = bitcast [[OPAQUE]]* [[Y_TMP]] to i8* |
| // CHECK-NEXT: call void @llvm.lifetime.end.p0i8({{(i32|i64)}} -1, i8* [[YBUFLIFE]]) |
| // Return. |
| // CHECK-NEXT: ret void |
| |
| sil @generic_with_reuse : $@convention(thin) <T> (@in T) -> () { |
| bb0(%x : $*T): |
| %y = alloc_stack $T |
| copy_addr %x to [initialization] %y : $*T |
| destroy_addr %y : $*T |
| copy_addr [take] %x to [initialization] %y : $*T |
| destroy_addr %y : $*T |
| dealloc_stack %y : $*T |
| %0 = tuple () |
| return %0 : $() |
| } |
| // CHECK: define{{( dllexport)?}}{{( protected)?}} swiftcc void @generic_with_reuse([[OPAQUE]]* noalias nocapture, [[TYPE]]* %T) {{.*}} { |
| // Allocate it. |
| // CHECK: [[TYPE_ADDR:%.*]] = bitcast %swift.type* %T to i8*** |
| // CHECK-NEXT: [[VWT_ADDR:%.*]] = getelementptr inbounds i8**, i8*** [[TYPE_ADDR]], {{(i32|i64)}} -1 |
| // CHECK-NEXT: [[VWT:%.*]] = load i8**, i8*** [[VWT_ADDR]] |
| // CHECK-NEXT: [[SIZE_WITNESS_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 8 |
| // CHECK-NEXT: [[SIZE_WITNESS:%.*]] = load i8*, i8** [[SIZE_WITNESS_ADDR]] |
| // CHECK-NEXT: [[SIZE:%.*]] = ptrtoint i8* [[SIZE_WITNESS]] |
| // CHECK-NEXT: [[Y_ALLOCA:%.*]] = alloca i8, {{.*}} [[SIZE]], align 16 |
| // CHECK-NEXT: call void @llvm.lifetime.start.p0i8({{(i32|i64)}} -1, i8* [[Y_ALLOCA]]) |
| // CHECK-NEXT: [[Y_TMP:%.*]] = bitcast i8* [[Y_ALLOCA]] to %swift.opaque* |
| // Copy 'x' into 'y'. |
| // CHECK-NEXT: [[T3:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 2 |
| // CHECK-NEXT: [[T4:%.*]] = load i8*, i8** [[T3]], align |
| // CHECK-NEXT: [[INIT_WITH_COPY_FN:%.*]] = bitcast i8* [[T4]] to [[OPAQUE]]* ([[OPAQUE]]*, [[OPAQUE]]*, [[TYPE]]*)* |
| // CHECK-NEXT: [[Y:%.*]] = call [[OPAQUE]]* [[INIT_WITH_COPY_FN]]([[OPAQUE]]* noalias [[Y_TMP]], [[OPAQUE]]* noalias [[X:%.*]], [[TYPE]]* %T) |
| // Destroy 'y'. |
| // CHECK-NEXT: [[T3:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 1 |
| // CHECK-NEXT: [[T4:%.*]] = load i8*, i8** [[T3]], align |
| // CHECK-NEXT: [[DESTROY_FN:%.*]] = bitcast i8* [[T4]] to void ([[OPAQUE]]*, [[TYPE]]*)* |
| // CHECK-NEXT: call void [[DESTROY_FN]]([[OPAQUE]]* noalias [[Y_TMP]], [[TYPE]]* %T) |
| // Copy 'x' into 'y' again, this time as a take. |
| // CHECK-NEXT: [[T3:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 4 |
| // CHECK-NEXT: [[T4:%.*]] = load i8*, i8** [[T3]], align |
| // CHECK-NEXT: [[TAKE_FN:%.*]] = bitcast i8* [[T4]] to [[OPAQUE]]* ([[OPAQUE]]*, [[OPAQUE]]*, [[TYPE]]*)* |
| // CHECK-NEXT: call [[OPAQUE]]* [[TAKE_FN]]([[OPAQUE]]* noalias [[Y_TMP]], [[OPAQUE]]* noalias [[X]], [[TYPE]]* %T) |
| // Destroy 'y'. |
| // CHECK-NEXT: call void [[DESTROY_FN]]([[OPAQUE]]* noalias [[Y_TMP]], [[TYPE]]* %T) |
| // CHECK-NEXT: [[YBUFLIFE:%.*]] = bitcast [[OPAQUE]]* [[Y_TMP]] to i8* |
| // CHECK-NEXT: call void @llvm.lifetime.end.p0i8({{(i32|i64)}} -1, i8* [[YBUFLIFE]]) |
| // Return. |
| // CHECK-NEXT: ret void |
| |
| sil @fixed_size : $@convention(thin) (@in Builtin.Int64) -> () { |
| bb0(%x : $*Builtin.Int64): |
| %y = alloc_stack $Builtin.Int64 |
| copy_addr %x to [initialization] %y : $*Builtin.Int64 |
| destroy_addr %y : $*Builtin.Int64 |
| dealloc_stack %y : $*Builtin.Int64 |
| destroy_addr %x : $*Builtin.Int64 |
| %0 = tuple () |
| return %0 : $() |
| } |
| // CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc void @fixed_size(i64* noalias nocapture dereferenceable(8)) |
| // CHECK: [[XBUF:%.*]] = alloca i64 |
| // CHECK-NEXT: [[XBUFLIFE:%.*]] = bitcast i64* [[XBUF]] to i8* |
| // CHECK-NEXT: call void @llvm.lifetime.start.p0i8({{(i32|i64)}} 8, i8* [[XBUFLIFE]]) |
| // CHECK-NEXT: load |
| // CHECK-NEXT: store |
| // CHECK-NEXT: [[XBUFLIFE:%.*]] = bitcast i64* [[XBUF]] to i8* |
| // CHECK-NEXT: call void @llvm.lifetime.end.p0i8({{(i32|i64)}} 8, i8* [[XBUFLIFE]]) |
| |