1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-attributes
2; RUN: opt -passes=function-attrs -S %s | FileCheck %s
3
4@g = global i32 20
5
6define void @test_no_read_or_write() {
7; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind readnone willreturn
8; CHECK-LABEL: @test_no_read_or_write(
9; CHECK-NEXT:  entry:
10; CHECK-NEXT:    ret void
11;
12entry:
13  ret void
14}
15
16define i32 @test_only_read_arg(i32* %ptr) {
17; CHECK: Function Attrs: argmemonly mustprogress nofree norecurse nosync nounwind readonly willreturn
18; CHECK-LABEL: @test_only_read_arg(
19; CHECK-NEXT:  entry:
20; CHECK-NEXT:    [[L:%.*]] = load i32, i32* [[PTR:%.*]], align 4
21; CHECK-NEXT:    ret i32 [[L]]
22;
23entry:
24  %l = load i32, i32* %ptr
25  ret i32 %l
26}
27
28define i32 @test_read_global() {
29; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind readonly willreturn
30; CHECK-LABEL: @test_read_global(
31; CHECK-NEXT:  entry:
32; CHECK-NEXT:    [[L:%.*]] = load i32, i32* @g, align 4
33; CHECK-NEXT:    ret i32 [[L]]
34;
35entry:
36  %l = load i32, i32* @g
37  ret i32 %l
38}
39
40define i32 @test_read_loaded_ptr(i32** %ptr) {
41; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind readonly willreturn
42; CHECK-LABEL: @test_read_loaded_ptr(
43; CHECK-NEXT:  entry:
44; CHECK-NEXT:    [[L:%.*]] = load i32*, i32** [[PTR:%.*]], align 8
45; CHECK-NEXT:    [[L_2:%.*]] = load i32, i32* [[L]], align 4
46; CHECK-NEXT:    ret i32 [[L_2]]
47;
48entry:
49  %l = load i32*, i32** %ptr
50  %l.2 = load i32, i32* %l
51  ret i32 %l.2
52}
53
54define void @test_only_write_arg(i32* %ptr) {
55; CHECK: Function Attrs: argmemonly mustprogress nofree norecurse nosync nounwind willreturn writeonly
56; CHECK-LABEL: @test_only_write_arg(
57; CHECK-NEXT:  entry:
58; CHECK-NEXT:    store i32 0, i32* [[PTR:%.*]], align 4
59; CHECK-NEXT:    ret void
60;
61entry:
62  store i32 0, i32* %ptr
63  ret void
64}
65
66define void @test_write_global() {
67; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn writeonly
68; CHECK-LABEL: @test_write_global(
69; CHECK-NEXT:  entry:
70; CHECK-NEXT:    store i32 0, i32* @g, align 4
71; CHECK-NEXT:    ret void
72;
73entry:
74  store i32 0, i32* @g
75  ret void
76}
77
78declare void @fn_may_access_memory()
79
80define void @test_call_may_access_memory() {
81; CHECK-LABEL: @test_call_may_access_memory(
82; CHECK-NEXT:  entry:
83; CHECK-NEXT:    call void @fn_may_access_memory()
84; CHECK-NEXT:    ret void
85;
86entry:
87  call void @fn_may_access_memory()
88  ret void
89}
90
91declare i32 @fn_readnone() readnone
92
93define void @test_call_readnone(i32* %ptr) {
94; CHECK: Function Attrs: argmemonly writeonly
95; CHECK-LABEL: @test_call_readnone(
96; CHECK-NEXT:  entry:
97; CHECK-NEXT:    [[C:%.*]] = call i32 @fn_readnone()
98; CHECK-NEXT:    store i32 [[C]], i32* [[PTR:%.*]], align 4
99; CHECK-NEXT:    ret void
100;
101entry:
102  %c = call i32 @fn_readnone()
103  store i32 %c, i32* %ptr
104  ret void
105}
106
107declare i32 @fn_argmemonly(i32*) argmemonly
108
109define i32 @test_call_argmemonly(i32* %ptr) {
110; CHECK-LABEL: @test_call_argmemonly(
111; CHECK-NEXT:  entry:
112; CHECK-NEXT:    [[C:%.*]] = call i32 @fn_argmemonly(i32* [[PTR:%.*]])
113; CHECK-NEXT:    ret i32 [[C]]
114;
115entry:
116  %c = call i32 @fn_argmemonly(i32* %ptr)
117  ret i32 %c
118}
119
120define i32 @test_call_fn_where_argmemonly_can_be_inferred(i32* %ptr) {
121; CHECK: Function Attrs: argmemonly mustprogress nofree norecurse nosync nounwind readonly willreturn
122; CHECK-LABEL: @test_call_fn_where_argmemonly_can_be_inferred(
123; CHECK-NEXT:  entry:
124; CHECK-NEXT:    [[C:%.*]] = call i32 @test_only_read_arg(i32* [[PTR:%.*]])
125; CHECK-NEXT:    ret i32 [[C]]
126;
127entry:
128  %c = call i32 @test_only_read_arg(i32* %ptr)
129  ret i32 %c
130}
131
132define void @test_memcpy_argonly(i8* %dst, i8* %src) {
133; CHECK: Function Attrs: argmemonly mustprogress nofree nosync nounwind willreturn
134; CHECK-LABEL: @test_memcpy_argonly(
135; CHECK-NEXT:  entry:
136; CHECK-NEXT:    call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[DST:%.*]], i8* [[SRC:%.*]], i64 32, i1 false)
137; CHECK-NEXT:    ret void
138;
139entry:
140  call void @llvm.memcpy.p0i8.p0i8.i64(i8* %dst, i8* %src, i64 32, i1 false)
141  ret void
142}
143
144declare void @llvm.memcpy.p0i8.p0i8.i64(i8*, i8*, i64, i1)
145
146@arr = global [32 x i8] zeroinitializer
147
148define void @test_memcpy_src_global(i8* %dst) {
149; CHECK: Function Attrs: mustprogress nofree nosync nounwind willreturn
150; CHECK-LABEL: @test_memcpy_src_global(
151; CHECK-NEXT:  entry:
152; CHECK-NEXT:    [[BC:%.*]] = bitcast [32 x i8]* @arr to i8*
153; CHECK-NEXT:    call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[DST:%.*]], i8* [[BC]], i64 32, i1 false)
154; CHECK-NEXT:    ret void
155;
156entry:
157  %bc = bitcast [32 x i8]* @arr to i8*
158  call void @llvm.memcpy.p0i8.p0i8.i64(i8* %dst, i8* %bc, i64 32, i1 false)
159  ret void
160}
161
162define void @test_memcpy_dst_global(i8* %src) {
163; CHECK: Function Attrs: mustprogress nofree nosync nounwind willreturn
164; CHECK-LABEL: @test_memcpy_dst_global(
165; CHECK-NEXT:  entry:
166; CHECK-NEXT:    [[BC:%.*]] = bitcast [32 x i8]* @arr to i8*
167; CHECK-NEXT:    call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[BC]], i8* [[SRC:%.*]], i64 32, i1 false)
168; CHECK-NEXT:    ret void
169;
170entry:
171  %bc = bitcast [32 x i8]* @arr to i8*
172  call void @llvm.memcpy.p0i8.p0i8.i64(i8* %bc, i8* %src, i64 32, i1 false)
173  ret void
174}
175
176define i32 @test_read_arg_access_alloca(i32* %ptr) {
177; CHECK: Function Attrs: argmemonly mustprogress nofree norecurse nosync nounwind readonly willreturn
178; CHECK-LABEL: @test_read_arg_access_alloca(
179; CHECK-NEXT:  entry:
180; CHECK-NEXT:    [[A:%.*]] = alloca i32, align 4
181; CHECK-NEXT:    [[L:%.*]] = load i32, i32* [[PTR:%.*]], align 4
182; CHECK-NEXT:    store i32 [[L]], i32* [[A]], align 4
183; CHECK-NEXT:    [[L_2:%.*]] = load i32, i32* [[A]], align 4
184; CHECK-NEXT:    ret i32 [[L_2]]
185;
186entry:
187  %a = alloca i32
188  %l = load i32, i32* %ptr
189  store i32 %l, i32* %a
190  %l.2 = load i32, i32* %a
191  ret i32 %l.2
192}
193