blob: 88f6ee13038f0c970072a57dca53114609d056b5 [file] [log] [blame]
// RUN: %target-swift-frontend -swift-version 4 -enforce-exclusivity=checked %s -emit-ir | %FileCheck %s --check-prefix=CHECK
import Builtin
import Swift
class A {
@_hasStorage var property: Int { get set }
@_hasStorage var exProperty: Any { get set }
deinit
init()
}
// CHECK-DAG: [[C:%T14access_markers1AC]] = type
// CHECK-DAG: [[INT:%TSi]] = type <{ [[SIZE:i(32|64)]] }>
sil_vtable A {}
// CHECK-LABEL: define {{.*}}void @testPaired(
sil @testPaired : $(@guaranteed A) -> () {
bb0(%0 : $A):
// CHECK: [[SCRATCH1:%.*]] = alloca [[BUFFER:.* x i8.]], align
// CHECK: [[SCRATCH2:%.*]] = alloca [[BUFFER]], align
// CHECK: [[PROPERTY:%.*]] = getelementptr inbounds [[C]], [[C]]* %0, i32 0, i32 1
%2 = ref_element_addr %0 : $A, #A.property
// CHECK-NEXT: [[T0:%.*]] = bitcast [[BUFFER]]* [[SCRATCH1]] to i8*
// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 {{.*}}, i8* [[T0]])
// CHECK-NEXT: [[T1:%.*]] = bitcast [[INT]]* [[PROPERTY]] to i8*
// CHECK-NEXT: call void @swift_beginAccess(i8* [[T1]], [[BUFFER]]* [[SCRATCH1]], [[SIZE]] 33, i8* null)
%3 = begin_access [modify] [dynamic] %2 : $*Int
// CHECK-NEXT: call void @swift_endAccess([[BUFFER]]* [[SCRATCH1]])
// CHECK-NEXT: [[T0:%.*]] = bitcast [[BUFFER]]* [[SCRATCH1]] to i8*
// CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 {{.*}}, i8* [[T0]])
end_access %3 : $*Int
// CHECK-NEXT: [[T0:%.*]] = bitcast [[BUFFER]]* [[SCRATCH2]] to i8*
// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 {{.*}}, i8* [[T0]])
// CHECK-NEXT: [[T1:%.*]] = bitcast [[INT]]* [[PROPERTY]] to i8*
// CHECK-NEXT: call void @swift_beginAccess(i8* [[T1]], [[BUFFER]]* [[SCRATCH2]], [[SIZE]] 32, i8* null)
%5 = begin_access [read] [dynamic] %2 : $*Int
// CHECK-NEXT: call void @swift_endAccess([[BUFFER]]* [[SCRATCH2]])
// CHECK-NEXT: [[T0:%.*]] = bitcast [[BUFFER]]* [[SCRATCH2]] to i8*
// CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 {{.*}}, i8* [[T0]])
end_access %5 : $*Int
%20 = tuple ()
return %20 : $()
}
// CHECK-LABEL: define {{.*}}void @testUnpaired(
sil @testUnpaired : $(@guaranteed A) -> () {
bb0(%0 : $A):
// CHECK: [[SCRATCH:%.*]] = alloca [[BUFFER:.* x i8.]], align
%1 = alloc_stack $Builtin.UnsafeValueBuffer
// CHECK: [[PROPERTY:%.*]] = getelementptr inbounds [[C]], [[C]]* %0, i32 0, i32 1
%2 = ref_element_addr %0 : $A, #A.property
// CHECK-NEXT: [[T1:%.*]] = bitcast [[INT]]* [[PROPERTY]] to i8*
// CHECK-NEXT: call void @swift_beginAccess(i8* [[T1]], [[BUFFER]]* [[SCRATCH]], [[SIZE]] 33, i8* null)
begin_unpaired_access [modify] [dynamic] %2 : $*Int, %1 : $*Builtin.UnsafeValueBuffer
// CHECK-NEXT: call void @swift_endAccess([[BUFFER]]* [[SCRATCH]])
end_unpaired_access [dynamic] %1 : $*Builtin.UnsafeValueBuffer
// CHECK-NEXT: [[T1:%.*]] = bitcast [[INT]]* [[PROPERTY]] to i8*
// CHECK-NEXT: call void @swift_beginAccess(i8* [[T1]], [[BUFFER]]* [[SCRATCH]], [[SIZE]] 32, i8* null)
begin_unpaired_access [read] [dynamic] %2 : $*Int, %1 : $*Builtin.UnsafeValueBuffer
// CHECK-NEXT: call void @swift_endAccess([[BUFFER]]* [[SCRATCH]])
end_unpaired_access [dynamic] %1 : $*Builtin.UnsafeValueBuffer
dealloc_stack %1 : $*Builtin.UnsafeValueBuffer
%20 = tuple ()
return %20 : $()
}
// CHECK-LABEL: define {{.*}}void @testUnpairedExternal(
sil @testUnpairedExternal : $(@guaranteed A, @inout Builtin.UnsafeValueBuffer) -> () {
bb0(%0 : $A, %1 : $*Builtin.UnsafeValueBuffer):
// CHECK: [[PROPERTY:%.*]] = getelementptr inbounds [[C]], [[C]]* %0, i32 0, i32 1
%2 = ref_element_addr %0 : $A, #A.property
// CHECK-NEXT: [[T1:%.*]] = bitcast [[INT]]* [[PROPERTY]] to i8*
// CHECK-NEXT: [[PC:%.*]] = call i8* @llvm.returnaddress(i32 0)
// CHECK-NEXT: call void @swift_beginAccess(i8* [[T1]], [[BUFFER]]* [[SCRATCH:%1]], [[SIZE]] 33, i8* [[PC]])
begin_unpaired_access [modify] [dynamic] %2 : $*Int, %1 : $*Builtin.UnsafeValueBuffer
// CHECK-NEXT: call void @swift_endAccess([[BUFFER]]* [[SCRATCH]])
end_unpaired_access [dynamic] %1 : $*Builtin.UnsafeValueBuffer
// CHECK-NEXT: [[T1:%.*]] = bitcast [[INT]]* [[PROPERTY]] to i8*
// CHECK-NEXT: [[PC:%.*]] = call i8* @llvm.returnaddress(i32 0)
// CHECK-NEXT: call void @swift_beginAccess(i8* [[T1]], [[BUFFER]]* [[SCRATCH]], [[SIZE]] 32, i8* [[PC]])
begin_unpaired_access [read] [dynamic] %2 : $*Int, %1 : $*Builtin.UnsafeValueBuffer
// CHECK-NEXT: call void @swift_endAccess([[BUFFER]]* [[SCRATCH]])
end_unpaired_access [dynamic] %1 : $*Builtin.UnsafeValueBuffer
%20 = tuple ()
return %20 : $()
}
sil @writeEmptyTuple : $(@inout ()) -> ()
sil @readEmptyTuple : $(@in_guaranteed ()) -> ()
// rdar://32039394 - Don't apply dynamic enforcement to empty types.
// CHECK-LABEL: define {{.*}}void @testPairedBox(
sil @testPairedBox : $(@guaranteed { var () }) -> () {
bb0(%0 : ${ var () }):
// CHECK: entry:
%2 = project_box %0 : ${ var () }, 0
// CHECK-NEXT: call {{.*}}void @writeEmptyTuple(%swift.opaque* nocapture undef)
%3 = begin_access [modify] [dynamic] %2 : $*()
%write_fn = function_ref @writeEmptyTuple : $@convention(thin) (@inout ()) -> ()
apply %write_fn(%3) : $@convention(thin) (@inout ()) -> ()
end_access %3 : $*()
// CHECK-NEXT: call {{.*}}void @readEmptyTuple(%swift.opaque* noalias nocapture undef)
%5 = begin_access [read] [dynamic] %2 : $*()
%read_fn = function_ref @readEmptyTuple : $@convention(thin) (@in_guaranteed ()) -> ()
apply %read_fn(%5) : $@convention(thin) (@in_guaranteed ()) -> ()
end_access %5 : $*()
// CHECK-NEXT: ret void
%20 = tuple ()
return %20 : $()
}
// rdar://31964550
// Just check that this doesn't crash.
sil @testCopyAddr : $(@guaranteed A) -> () {
bb0(%0 : $A):
%1 = alloc_stack $Any
%2 = ref_element_addr %0 : $A, #A.exProperty
%3 = begin_access [dynamic] [read] %2 : $*Any
copy_addr %2 to [initialization] %1 : $*Any
end_access %3 : $*Any
destroy_addr %1 : $*Any
dealloc_stack %1 : $*Any
%20 = tuple ()
return %20 : $()
}
// CHECK-LABEL: define {{.*}}void @testNontracking(
sil @testNontracking : $(@guaranteed A) -> () {
bb0(%0 : $A):
%1 = alloc_stack $Int
// CHECK: [[PROPERTY:%.*]] = getelementptr inbounds [[C]], [[C]]* %0, i32 0, i32 1
%2 = ref_element_addr %0 : $A, #A.property
// CHECK: call void @swift_beginAccess(i8* %{{.*}}, [[BUFFER]]* %{{.*}}, [[SIZE]] 0, i8* null)
%3 = begin_access [read] [dynamic] [no_nested_conflict] %2 : $*Int
copy_addr %3 to [initialization] %1 : $*Int
// CHECK-NOT: end_access
end_access %3 : $*Int
%9 = alloc_stack $Builtin.UnsafeValueBuffer
// CHECK: call void @swift_beginAccess(i8* %{{.*}}, [[BUFFER]]* %{{.*}}, [[SIZE]] 0, i8* null)
begin_unpaired_access [read] [dynamic] [no_nested_conflict] %2 : $*Int, %9 : $*Builtin.UnsafeValueBuffer
copy_addr %2 to %1 : $*Int
dealloc_stack %9 : $*Builtin.UnsafeValueBuffer
dealloc_stack %1 : $*Int
%20 = tuple ()
return %20 : $()
}