blob: 3f42a78604ae79a27f8b66e6be559cf771355f91 [file] [log] [blame]
// RUN: %target-swift-frontend -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{{( protected)?}} void @generic([[OPAQUE]]* noalias nocapture, [[TYPE]]* %T) {{.*}} {
// The fixed-size buffer.
// CHECK: [[YBUF:%.*]] = alloca [[BUFFER:.*]], align
// CHECK-NEXT: [[YBUFLIFE:%.*]] = bitcast [[BUFFER]]* [[YBUF]] to i8*
// CHECK-NEXT: call void @llvm.lifetime.start(i64 [[BUFFER_SIZE:12|24]], i8* [[YBUFLIFE]])
// Allocate it.
// CHECK-NEXT: [[T0:%.*]] = bitcast [[TYPE]]* %T to i8***
// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds i8**, i8*** [[T0]], {{i32|i64}} -1
// CHECK-NEXT: [[VWTABLE:%.*]] = load i8**, i8*** [[T1]], align
// CHECK-NEXT: [[T3:%.*]] = getelementptr inbounds i8*, i8** [[VWTABLE]], i32 5
// CHECK-NEXT: [[T4:%.*]] = load i8*, i8** [[T3]], align
// CHECK-NEXT: [[BUFFER_COPY_FN:%.*]] = bitcast i8* [[T4]] to [[OPAQUE]]* ([[BUFFER]]*, [[OPAQUE]]*, [[TYPE]]*)*
// Copy 'x' into 'y'.
// CHECK-NEXT: [[Y:%.*]] = call [[OPAQUE]]* [[BUFFER_COPY_FN]]([[BUFFER]]* [[YBUF]], [[OPAQUE]]* [[X:%.*]], [[TYPE]]* %T)
// Destroy and deallocate 'y'.
// CHECK-NEXT: [[T4:%.*]] = load i8*, i8** [[VWTABLE]], align
// CHECK-NEXT: [[DESTROY_BUFFER_FN:%.*]] = bitcast i8* [[T4]] to void ([[BUFFER]]*, [[TYPE]]*)*
// CHECK-NEXT: call void [[DESTROY_BUFFER_FN]]([[BUFFER]]* [[YBUF]], [[TYPE]]* %T)
// CHECK-NEXT: [[YBUFLIFE:%.*]] = bitcast [[BUFFER]]* [[YBUF]] to i8*
// CHECK-NEXT: call void @llvm.lifetime.end(i64 [[BUFFER_SIZE]], i8* [[YBUFLIFE]])
// Destroy 'x'.
// CHECK-NEXT: [[T3:%.*]] = getelementptr inbounds i8*, i8** [[VWTABLE]], i32 4
// 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]]* [[X]], [[TYPE]]* %T)
// 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{{( protected)?}} void @generic_with_reuse([[OPAQUE]]* noalias nocapture, [[TYPE]]* %T) {{.*}} {
// The fixed-size buffer.
// CHECK: [[YBUF:%.*]] = alloca [[BUFFER:.*]], align
// CHECK-NEXT: [[YBUFLIFE:%.*]] = bitcast [[BUFFER]]* [[YBUF]] to i8*
// CHECK-NEXT: call void @llvm.lifetime.start(i64 [[BUFFER_SIZE:12|24]], i8* [[YBUFLIFE]])
// Allocate it.
// CHECK-NEXT: [[T0:%.*]] = bitcast [[TYPE]]* %T to i8***
// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds i8**, i8*** [[T0]], {{i32|i64}} -1
// CHECK-NEXT: [[VWTABLE:%.*]] = load i8**, i8*** [[T1]], align
// CHECK-NEXT: [[T3:%.*]] = getelementptr inbounds i8*, i8** [[VWTABLE]], i32 5
// CHECK-NEXT: [[T4:%.*]] = load i8*, i8** [[T3]], align
// CHECK-NEXT: [[BUFFER_COPY_FN:%.*]] = bitcast i8* [[T4]] to [[OPAQUE]]* ([[BUFFER]]*, [[OPAQUE]]*, [[TYPE]]*)*
// Copy 'x' into 'y'.
// CHECK-NEXT: [[Y:%.*]] = call [[OPAQUE]]* [[BUFFER_COPY_FN]]([[BUFFER]]* [[YBUF]], [[OPAQUE]]* [[X:%.*]], [[TYPE]]* %T)
// Destroy 'y'.
// CHECK-NEXT: [[T3:%.*]] = getelementptr inbounds i8*, i8** [[VWTABLE]], i32 4
// 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]]* [[Y]], [[TYPE]]* %T)
// Copy 'x' into 'y' again, this time as a take.
// CHECK-NEXT: [[T3:%.*]] = getelementptr inbounds i8*, i8** [[VWTABLE]], i32 9
// 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]]* [[Y]], [[OPAQUE]]* [[X]], [[TYPE]]* %T)
// Destroy and deallocate 'y'.
// CHECK-NEXT: [[T4:%.*]] = load i8*, i8** [[VWTABLE]], align
// CHECK-NEXT: [[DESTROY_BUFFER_FN:%.*]] = bitcast i8* [[T4]] to void ([[BUFFER]]*, [[TYPE]]*)*
// CHECK-NEXT: call void [[DESTROY_BUFFER_FN]]([[BUFFER]]* [[YBUF]], [[TYPE]]* %T)
// CHECK-NEXT: [[YBUFLIFE:%.*]] = bitcast [[BUFFER]]* [[YBUF]] to i8*
// CHECK-NEXT: call void @llvm.lifetime.end(i64 [[BUFFER_SIZE]], 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{{( protected)?}} 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(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(i64 8, i8* [[XBUFLIFE]])