1; RUN: opt < %s -function-attrs         -S | FileCheck %s
2; RUN: opt < %s -passes=function-attrs -S | FileCheck %s
3
4; CHECK: define void @nouses-argworn-funrn(i32* nocapture readnone %.aaa) #0 {
5define void @nouses-argworn-funrn(i32* writeonly %.aaa) {
6nouses-argworn-funrn_entry:
7  ret void
8}
9
10; CHECK: define void @nouses-argworn-funro(i32* nocapture readnone %.aaa, i32* nocapture readonly %.bbb) #1 {
11define void @nouses-argworn-funro(i32* writeonly %.aaa, i32* %.bbb) {
12nouses-argworn-funro_entry:
13  %val = load i32 , i32* %.bbb
14  ret void
15}
16
17%_type_of_d-ccc = type <{ i8*, i8, i8, i8, i8 }>
18
19@d-ccc = internal global %_type_of_d-ccc <{ i8* null, i8 1, i8 13, i8 0, i8 -127 }>, align 8
20
21; CHECK: define void @nouses-argworn-funwo(i32* nocapture readnone %.aaa) #2 {
22define void @nouses-argworn-funwo(i32* writeonly %.aaa) {
23nouses-argworn-funwo_entry:
24  store i8 0, i8* getelementptr inbounds (%_type_of_d-ccc, %_type_of_d-ccc* @d-ccc, i32 0, i32 3)
25  ret void
26}
27
28; CHECK: define void @test_store(i8* nocapture writeonly %p)
29define void @test_store(i8* %p) {
30  store i8 0, i8* %p
31  ret void
32}
33
34@G = external global i8*
35; CHECK: define i8 @test_store_capture(i8* %p)
36define i8 @test_store_capture(i8* %p) {
37  store i8* %p, i8** @G
38  %p2 = load i8*, i8** @G
39  %v = load i8, i8* %p2
40  ret i8 %v
41}
42
43; CHECK: define void @test_addressing(i8* nocapture writeonly %p)
44define void @test_addressing(i8* %p) {
45  %gep = getelementptr i8, i8* %p, i64 8
46  %bitcast = bitcast i8* %gep to i32*
47  store i32 0, i32* %bitcast
48  ret void
49}
50
51; CHECK: define void @test_readwrite(i8* nocapture %p)
52define void @test_readwrite(i8* %p) {
53  %v = load i8, i8* %p
54  store i8 %v, i8* %p
55  ret void
56}
57
58; CHECK: define void @test_volatile(i8* %p)
59define void @test_volatile(i8* %p) {
60  store volatile i8 0, i8* %p
61  ret void
62}
63
64; CHECK: define void @test_atomicrmw(i8* nocapture %p)
65define void @test_atomicrmw(i8* %p) {
66  atomicrmw add i8* %p, i8 0  seq_cst
67  ret void
68}
69
70
71declare void @direct1_callee(i8* %p)
72
73; CHECK: define void @direct1(i8* %p)
74define void @direct1(i8* %p) {
75  call void @direct1_callee(i8* %p)
76  ret void
77}
78
79declare void @direct2_callee(i8* %p) writeonly
80
81; writeonly w/o nocapture is not enough
82; CHECK: define void @direct2(i8* %p)
83define void @direct2(i8* %p) {
84  call void @direct2_callee(i8* %p)
85  ; read back from global, read through pointer...
86  ret void
87}
88
89; CHECK: define void @direct2b(i8* nocapture writeonly %p)
90define void @direct2b(i8* %p) {
91  call void @direct2_callee(i8* nocapture %p)
92  ret void
93}
94
95declare void @direct3_callee(i8* nocapture writeonly %p)
96
97; CHECK: define void @direct3(i8* nocapture writeonly %p)
98define void @direct3(i8* %p) {
99  call void @direct3_callee(i8* %p)
100  ret void
101}
102
103; CHECK: define void @direct3b(i8* %p)
104define void @direct3b(i8* %p) {
105  call void @direct3_callee(i8* %p) ["may-read-and-capture"(i8* %p)]
106  ret void
107}
108
109; CHECK: define void @fptr_test1(i8* %p, void (i8*)* nocapture readonly %f)
110define void @fptr_test1(i8* %p, void (i8*)* %f) {
111  call void %f(i8* %p)
112  ret void
113}
114
115; CHECK: define void @fptr_test2(i8* nocapture writeonly %p, void (i8*)* nocapture readonly %f)
116define void @fptr_test2(i8* %p, void (i8*)* %f) {
117  call void %f(i8* nocapture writeonly %p)
118  ret void
119}
120
121; CHECK: define void @fptr_test3(i8* nocapture writeonly %p, void (i8*)* nocapture readonly %f)
122define void @fptr_test3(i8* %p, void (i8*)* %f) {
123  call void %f(i8* nocapture %p) writeonly
124  ret void
125}
126
127; CHECK: attributes #0 = { {{.*}}readnone{{.*}} }
128; CHECK: attributes #1 = { {{.*}}readonly{{.*}} }
129; CHECK: attributes #2 = { {{.*}}writeonly{{.*}} }
130