| // 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 : $() |
| } |