xref: /llvm-project/llvm/test/Transforms/FunctionAttrs/readattrs.ll (revision 29441e4f5fa5f5c7709f7cf180815ba97f611297)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes
2; RUN: opt < %s -passes=function-attrs -S | FileCheck --check-prefixes=COMMON,FNATTRS %s
3; RUN: opt < %s -passes=attributor-light -S | FileCheck --check-prefixes=COMMON,ATTRIBUTOR %s
4; RUN: opt < %s -passes=attributor-light-cgscc -S | FileCheck --check-prefixes=COMMON,ATTRIBUTOR-CGSCC %s
5
6@x = global i32 0
7
8declare void @test1_1(ptr %x1_1, ptr nocapture readonly %y1_1, ...)
9
10define void @test1_2(ptr %x1_2, ptr %y1_2, ptr %z1_2) {
11; FNATTRS-LABEL: define {{[^@]+}}@test1_2
12; FNATTRS-SAME: (ptr [[X1_2:%.*]], ptr readonly captures(none) [[Y1_2:%.*]], ptr [[Z1_2:%.*]]) {
13; FNATTRS-NEXT:    call void (ptr, ptr, ...) @test1_1(ptr [[X1_2]], ptr [[Y1_2]], ptr [[Z1_2]])
14; FNATTRS-NEXT:    store i32 0, ptr @x, align 4
15; FNATTRS-NEXT:    ret void
16;
17; ATTRIBUTOR-LABEL: define {{[^@]+}}@test1_2
18; ATTRIBUTOR-SAME: (ptr [[X1_2:%.*]], ptr nofree readonly captures(none) [[Y1_2:%.*]], ptr [[Z1_2:%.*]]) {
19; ATTRIBUTOR-NEXT:    call void (ptr, ptr, ...) @test1_1(ptr [[X1_2]], ptr nofree readonly captures(none) [[Y1_2]], ptr [[Z1_2]])
20; ATTRIBUTOR-NEXT:    store i32 0, ptr @x, align 4
21; ATTRIBUTOR-NEXT:    ret void
22;
23; ATTRIBUTOR-CGSCC-LABEL: define {{[^@]+}}@test1_2
24; ATTRIBUTOR-CGSCC-SAME: (ptr [[X1_2:%.*]], ptr nofree readonly captures(none) [[Y1_2:%.*]], ptr [[Z1_2:%.*]]) {
25; ATTRIBUTOR-CGSCC-NEXT:    call void (ptr, ptr, ...) @test1_1(ptr [[X1_2]], ptr nofree readonly captures(none) [[Y1_2]], ptr [[Z1_2]])
26; ATTRIBUTOR-CGSCC-NEXT:    store i32 0, ptr @x, align 4
27; ATTRIBUTOR-CGSCC-NEXT:    ret void
28;
29  call void (ptr, ptr, ...) @test1_1(ptr %x1_2, ptr %y1_2, ptr %z1_2)
30  store i32 0, ptr @x
31  ret void
32}
33
34; TODO: Missing with attributor-light: argmem: none, inaccessiblemem: none
35define ptr @test2(ptr %p) {
36; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(write, argmem: none, inaccessiblemem: none)
37; FNATTRS-LABEL: define {{[^@]+}}@test2
38; FNATTRS-SAME: (ptr readnone returned [[P:%.*]]) #[[ATTR0:[0-9]+]] {
39; FNATTRS-NEXT:    store i32 0, ptr @x, align 4
40; FNATTRS-NEXT:    ret ptr [[P]]
41;
42; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(write)
43; ATTRIBUTOR-LABEL: define {{[^@]+}}@test2
44; ATTRIBUTOR-SAME: (ptr nofree readnone [[P:%.*]]) #[[ATTR0:[0-9]+]] {
45; ATTRIBUTOR-NEXT:    store i32 0, ptr @x, align 4
46; ATTRIBUTOR-NEXT:    ret ptr [[P]]
47;
48; ATTRIBUTOR-CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(write)
49; ATTRIBUTOR-CGSCC-LABEL: define {{[^@]+}}@test2
50; ATTRIBUTOR-CGSCC-SAME: (ptr nofree readnone [[P:%.*]]) #[[ATTR0:[0-9]+]] {
51; ATTRIBUTOR-CGSCC-NEXT:    store i32 0, ptr @x, align 4
52; ATTRIBUTOR-CGSCC-NEXT:    ret ptr [[P]]
53;
54  store i32 0, ptr @x
55  ret ptr %p
56}
57
58define i1 @test3(ptr %p, ptr %q) {
59; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
60; FNATTRS-LABEL: define {{[^@]+}}@test3
61; FNATTRS-SAME: (ptr readnone [[P:%.*]], ptr readnone [[Q:%.*]]) #[[ATTR1:[0-9]+]] {
62; FNATTRS-NEXT:    [[A:%.*]] = icmp ult ptr [[P]], [[Q]]
63; FNATTRS-NEXT:    ret i1 [[A]]
64;
65; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
66; ATTRIBUTOR-LABEL: define {{[^@]+}}@test3
67; ATTRIBUTOR-SAME: (ptr nofree readnone [[P:%.*]], ptr nofree readnone [[Q:%.*]]) #[[ATTR1:[0-9]+]] {
68; ATTRIBUTOR-NEXT:    [[A:%.*]] = icmp ult ptr [[P]], [[Q]]
69; ATTRIBUTOR-NEXT:    ret i1 [[A]]
70;
71; ATTRIBUTOR-CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
72; ATTRIBUTOR-CGSCC-LABEL: define {{[^@]+}}@test3
73; ATTRIBUTOR-CGSCC-SAME: (ptr nofree readnone [[P:%.*]], ptr nofree readnone [[Q:%.*]]) #[[ATTR1:[0-9]+]] {
74; ATTRIBUTOR-CGSCC-NEXT:    [[A:%.*]] = icmp ult ptr [[P]], [[Q]]
75; ATTRIBUTOR-CGSCC-NEXT:    ret i1 [[A]]
76;
77  %A = icmp ult ptr %p, %q
78  ret i1 %A
79}
80
81declare void @test4_1(ptr nocapture) readonly
82
83define void @test4_2(ptr %p) {
84; FNATTRS: Function Attrs: nofree memory(read)
85; FNATTRS-LABEL: define {{[^@]+}}@test4_2
86; FNATTRS-SAME: (ptr readonly captures(none) [[P:%.*]]) #[[ATTR3:[0-9]+]] {
87; FNATTRS-NEXT:    call void @test4_1(ptr [[P]])
88; FNATTRS-NEXT:    ret void
89;
90; ATTRIBUTOR: Function Attrs: nosync memory(read)
91; ATTRIBUTOR-LABEL: define {{[^@]+}}@test4_2
92; ATTRIBUTOR-SAME: (ptr readonly captures(none) [[P:%.*]]) #[[ATTR3:[0-9]+]] {
93; ATTRIBUTOR-NEXT:    call void @test4_1(ptr readonly captures(none) [[P]]) #[[ATTR3]]
94; ATTRIBUTOR-NEXT:    ret void
95;
96; ATTRIBUTOR-CGSCC: Function Attrs: nosync memory(read)
97; ATTRIBUTOR-CGSCC-LABEL: define {{[^@]+}}@test4_2
98; ATTRIBUTOR-CGSCC-SAME: (ptr readonly captures(none) [[P:%.*]]) #[[ATTR3:[0-9]+]] {
99; ATTRIBUTOR-CGSCC-NEXT:    call void @test4_1(ptr readonly captures(none) [[P]]) #[[ATTR3]]
100; ATTRIBUTOR-CGSCC-NEXT:    ret void
101;
102  call void @test4_1(ptr %p)
103  ret void
104}
105
106; Missed optz'n: we could make %q readnone, but don't break test6!
107define void @test5(ptr %p, ptr %q) {
108; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write)
109; FNATTRS-LABEL: define {{[^@]+}}@test5
110; FNATTRS-SAME: (ptr writeonly captures(none) initializes((0, 8)) [[P:%.*]], ptr [[Q:%.*]]) #[[ATTR4:[0-9]+]] {
111; FNATTRS-NEXT:    store ptr [[Q]], ptr [[P]], align 8
112; FNATTRS-NEXT:    ret void
113;
114; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write)
115; ATTRIBUTOR-LABEL: define {{[^@]+}}@test5
116; ATTRIBUTOR-SAME: (ptr nofree nonnull writeonly captures(none) [[P:%.*]], ptr nofree writeonly [[Q:%.*]]) #[[ATTR4:[0-9]+]] {
117; ATTRIBUTOR-NEXT:    store ptr [[Q]], ptr [[P]], align 8
118; ATTRIBUTOR-NEXT:    ret void
119;
120; ATTRIBUTOR-CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write)
121; ATTRIBUTOR-CGSCC-LABEL: define {{[^@]+}}@test5
122; ATTRIBUTOR-CGSCC-SAME: (ptr nofree nonnull writeonly captures(none) [[P:%.*]], ptr nofree writeonly [[Q:%.*]]) #[[ATTR4:[0-9]+]] {
123; ATTRIBUTOR-CGSCC-NEXT:    store ptr [[Q]], ptr [[P]], align 8
124; ATTRIBUTOR-CGSCC-NEXT:    ret void
125;
126  store ptr %q, ptr %p
127  ret void
128}
129
130declare void @test6_1()
131
132; This is not a missed optz'n.
133define void @test6_2(ptr %p, ptr %q) {
134; FNATTRS-LABEL: define {{[^@]+}}@test6_2
135; FNATTRS-SAME: (ptr writeonly captures(none) initializes((0, 8)) [[P:%.*]], ptr [[Q:%.*]]) {
136; FNATTRS-NEXT:    store ptr [[Q]], ptr [[P]], align 8
137; FNATTRS-NEXT:    call void @test6_1()
138; FNATTRS-NEXT:    ret void
139;
140; ATTRIBUTOR-LABEL: define {{[^@]+}}@test6_2
141; ATTRIBUTOR-SAME: (ptr nofree nonnull writeonly captures(none) [[P:%.*]], ptr nofree [[Q:%.*]]) {
142; ATTRIBUTOR-NEXT:    store ptr [[Q]], ptr [[P]], align 8
143; ATTRIBUTOR-NEXT:    call void @test6_1()
144; ATTRIBUTOR-NEXT:    ret void
145;
146; ATTRIBUTOR-CGSCC-LABEL: define {{[^@]+}}@test6_2
147; ATTRIBUTOR-CGSCC-SAME: (ptr nofree nonnull writeonly captures(none) [[P:%.*]], ptr nofree [[Q:%.*]]) {
148; ATTRIBUTOR-CGSCC-NEXT:    store ptr [[Q]], ptr [[P]], align 8
149; ATTRIBUTOR-CGSCC-NEXT:    call void @test6_1()
150; ATTRIBUTOR-CGSCC-NEXT:    ret void
151;
152  store ptr %q, ptr %p
153  call void @test6_1()
154  ret void
155}
156
157; inalloca parameters are always considered written
158define void @test7_1(ptr inalloca(i32) %a) {
159; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite)
160; FNATTRS-LABEL: define {{[^@]+}}@test7_1
161; FNATTRS-SAME: (ptr inalloca(i32) captures(none) [[A:%.*]]) #[[ATTR5:[0-9]+]] {
162; FNATTRS-NEXT:    ret void
163;
164; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
165; ATTRIBUTOR-LABEL: define {{[^@]+}}@test7_1
166; ATTRIBUTOR-SAME: (ptr nofree nonnull writeonly inalloca(i32) captures(none) [[A:%.*]]) #[[ATTR1]] {
167; ATTRIBUTOR-NEXT:    ret void
168;
169; ATTRIBUTOR-CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
170; ATTRIBUTOR-CGSCC-LABEL: define {{[^@]+}}@test7_1
171; ATTRIBUTOR-CGSCC-SAME: (ptr nofree nonnull writeonly inalloca(i32) captures(none) [[A:%.*]]) #[[ATTR1]] {
172; ATTRIBUTOR-CGSCC-NEXT:    ret void
173;
174  ret void
175}
176
177; preallocated parameters are always considered written
178define void @test7_2(ptr preallocated(i32) %a) {
179; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite)
180; FNATTRS-LABEL: define {{[^@]+}}@test7_2
181; FNATTRS-SAME: (ptr preallocated(i32) captures(none) [[A:%.*]]) #[[ATTR5]] {
182; FNATTRS-NEXT:    ret void
183;
184; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
185; ATTRIBUTOR-LABEL: define {{[^@]+}}@test7_2
186; ATTRIBUTOR-SAME: (ptr nofree nonnull writeonly preallocated(i32) captures(none) [[A:%.*]]) #[[ATTR1]] {
187; ATTRIBUTOR-NEXT:    ret void
188;
189; ATTRIBUTOR-CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
190; ATTRIBUTOR-CGSCC-LABEL: define {{[^@]+}}@test7_2
191; ATTRIBUTOR-CGSCC-SAME: (ptr nofree nonnull writeonly preallocated(i32) captures(none) [[A:%.*]]) #[[ATTR1]] {
192; ATTRIBUTOR-CGSCC-NEXT:    ret void
193;
194  ret void
195}
196
197define ptr @test8_1(ptr %p) {
198; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
199; FNATTRS-LABEL: define {{[^@]+}}@test8_1
200; FNATTRS-SAME: (ptr readnone returned [[P:%.*]]) #[[ATTR1]] {
201; FNATTRS-NEXT:  entry:
202; FNATTRS-NEXT:    ret ptr [[P]]
203;
204; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
205; ATTRIBUTOR-LABEL: define {{[^@]+}}@test8_1
206; ATTRIBUTOR-SAME: (ptr nofree readnone [[P:%.*]]) #[[ATTR1]] {
207; ATTRIBUTOR-NEXT:  entry:
208; ATTRIBUTOR-NEXT:    ret ptr [[P]]
209;
210; ATTRIBUTOR-CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
211; ATTRIBUTOR-CGSCC-LABEL: define {{[^@]+}}@test8_1
212; ATTRIBUTOR-CGSCC-SAME: (ptr nofree readnone [[P:%.*]]) #[[ATTR1]] {
213; ATTRIBUTOR-CGSCC-NEXT:  entry:
214; ATTRIBUTOR-CGSCC-NEXT:    ret ptr [[P]]
215;
216entry:
217  ret ptr %p
218}
219
220define void @test8_2(ptr %p) {
221; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write)
222; FNATTRS-LABEL: define {{[^@]+}}@test8_2
223; FNATTRS-SAME: (ptr writeonly [[P:%.*]]) #[[ATTR4]] {
224; FNATTRS-NEXT:  entry:
225; FNATTRS-NEXT:    [[CALL:%.*]] = call ptr @test8_1(ptr [[P]])
226; FNATTRS-NEXT:    store i32 10, ptr [[CALL]], align 4
227; FNATTRS-NEXT:    ret void
228;
229; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(write)
230; ATTRIBUTOR-LABEL: define {{[^@]+}}@test8_2
231; ATTRIBUTOR-SAME: (ptr nofree writeonly captures(none) [[P:%.*]]) #[[ATTR0]] {
232; ATTRIBUTOR-NEXT:  entry:
233; ATTRIBUTOR-NEXT:    [[CALL:%.*]] = call ptr @test8_1(ptr nofree readnone [[P]]) #[[ATTR14:[0-9]+]]
234; ATTRIBUTOR-NEXT:    store i32 10, ptr [[CALL]], align 4
235; ATTRIBUTOR-NEXT:    ret void
236;
237; ATTRIBUTOR-CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(write)
238; ATTRIBUTOR-CGSCC-LABEL: define {{[^@]+}}@test8_2
239; ATTRIBUTOR-CGSCC-SAME: (ptr nofree writeonly [[P:%.*]]) #[[ATTR5:[0-9]+]] {
240; ATTRIBUTOR-CGSCC-NEXT:  entry:
241; ATTRIBUTOR-CGSCC-NEXT:    [[CALL:%.*]] = call ptr @test8_1(ptr nofree readnone [[P]]) #[[ATTR14:[0-9]+]]
242; ATTRIBUTOR-CGSCC-NEXT:    store i32 10, ptr [[CALL]], align 4
243; ATTRIBUTOR-CGSCC-NEXT:    ret void
244;
245entry:
246  %call = call ptr @test8_1(ptr %p)
247  store i32 10, ptr %call, align 4
248  ret void
249}
250
251declare void @llvm.masked.scatter.v4i32.v4p0(<4 x i32>%val, <4 x ptr>, i32, <4 x i1>)
252
253define void @test9(<4 x ptr> %ptrs, <4 x i32>%val) {
254; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(write)
255; FNATTRS-LABEL: define {{[^@]+}}@test9
256; FNATTRS-SAME: (<4 x ptr> [[PTRS:%.*]], <4 x i32> [[VAL:%.*]]) #[[ATTR7:[0-9]+]] {
257; FNATTRS-NEXT:    call void @llvm.masked.scatter.v4i32.v4p0(<4 x i32> [[VAL]], <4 x ptr> [[PTRS]], i32 4, <4 x i1> <i1 true, i1 false, i1 true, i1 false>)
258; FNATTRS-NEXT:    ret void
259;
260; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(write)
261; ATTRIBUTOR-LABEL: define {{[^@]+}}@test9
262; ATTRIBUTOR-SAME: (<4 x ptr> [[PTRS:%.*]], <4 x i32> [[VAL:%.*]]) #[[ATTR0]] {
263; ATTRIBUTOR-NEXT:    call void @llvm.masked.scatter.v4i32.v4p0(<4 x i32> [[VAL]], <4 x ptr> [[PTRS]], i32 4, <4 x i1> <i1 true, i1 false, i1 true, i1 false>) #[[ATTR15:[0-9]+]]
264; ATTRIBUTOR-NEXT:    ret void
265;
266; ATTRIBUTOR-CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(write)
267; ATTRIBUTOR-CGSCC-LABEL: define {{[^@]+}}@test9
268; ATTRIBUTOR-CGSCC-SAME: (<4 x ptr> [[PTRS:%.*]], <4 x i32> [[VAL:%.*]]) #[[ATTR0]] {
269; ATTRIBUTOR-CGSCC-NEXT:    call void @llvm.masked.scatter.v4i32.v4p0(<4 x i32> [[VAL]], <4 x ptr> [[PTRS]], i32 4, <4 x i1> <i1 true, i1 false, i1 true, i1 false>) #[[ATTR15:[0-9]+]]
270; ATTRIBUTOR-CGSCC-NEXT:    ret void
271;
272  call void @llvm.masked.scatter.v4i32.v4p0(<4 x i32>%val, <4 x ptr> %ptrs, i32 4, <4 x i1><i1 true, i1 false, i1 true, i1 false>)
273  ret void
274}
275
276declare <4 x i32> @llvm.masked.gather.v4i32.v4p0(<4 x ptr>, i32, <4 x i1>, <4 x i32>)
277define <4 x i32> @test10(<4 x ptr> %ptrs) {
278; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(read)
279; FNATTRS-LABEL: define {{[^@]+}}@test10
280; FNATTRS-SAME: (<4 x ptr> [[PTRS:%.*]]) #[[ATTR9:[0-9]+]] {
281; FNATTRS-NEXT:    [[RES:%.*]] = call <4 x i32> @llvm.masked.gather.v4i32.v4p0(<4 x ptr> [[PTRS]], i32 4, <4 x i1> <i1 true, i1 false, i1 true, i1 false>, <4 x i32> undef)
282; FNATTRS-NEXT:    ret <4 x i32> [[RES]]
283;
284; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(read)
285; ATTRIBUTOR-LABEL: define {{[^@]+}}@test10
286; ATTRIBUTOR-SAME: (<4 x ptr> [[PTRS:%.*]]) #[[ATTR7:[0-9]+]] {
287; ATTRIBUTOR-NEXT:    [[RES:%.*]] = call <4 x i32> @llvm.masked.gather.v4i32.v4p0(<4 x ptr> [[PTRS]], i32 4, <4 x i1> <i1 true, i1 false, i1 true, i1 false>, <4 x i32> undef) #[[ATTR16:[0-9]+]]
288; ATTRIBUTOR-NEXT:    ret <4 x i32> [[RES]]
289;
290; ATTRIBUTOR-CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(read)
291; ATTRIBUTOR-CGSCC-LABEL: define {{[^@]+}}@test10
292; ATTRIBUTOR-CGSCC-SAME: (<4 x ptr> [[PTRS:%.*]]) #[[ATTR8:[0-9]+]] {
293; ATTRIBUTOR-CGSCC-NEXT:    [[RES:%.*]] = call <4 x i32> @llvm.masked.gather.v4i32.v4p0(<4 x ptr> [[PTRS]], i32 4, <4 x i1> <i1 true, i1 false, i1 true, i1 false>, <4 x i32> undef) #[[ATTR16:[0-9]+]]
294; ATTRIBUTOR-CGSCC-NEXT:    ret <4 x i32> [[RES]]
295;
296  %res = call <4 x i32> @llvm.masked.gather.v4i32.v4p0(<4 x ptr> %ptrs, i32 4, <4 x i1><i1 true, i1 false, i1 true, i1 false>, <4 x i32>undef)
297  ret <4 x i32> %res
298}
299
300declare <4 x i32> @test11_1(<4 x ptr>) argmemonly nounwind readonly
301define <4 x i32> @test11_2(<4 x ptr> %ptrs) {
302; FNATTRS: Function Attrs: nofree nounwind memory(argmem: read)
303; FNATTRS-LABEL: define {{[^@]+}}@test11_2
304; FNATTRS-SAME: (<4 x ptr> [[PTRS:%.*]]) #[[ATTR11:[0-9]+]] {
305; FNATTRS-NEXT:    [[RES:%.*]] = call <4 x i32> @test11_1(<4 x ptr> [[PTRS]])
306; FNATTRS-NEXT:    ret <4 x i32> [[RES]]
307;
308; ATTRIBUTOR: Function Attrs: nosync nounwind memory(argmem: read)
309; ATTRIBUTOR-LABEL: define {{[^@]+}}@test11_2
310; ATTRIBUTOR-SAME: (<4 x ptr> [[PTRS:%.*]]) #[[ATTR9:[0-9]+]] {
311; ATTRIBUTOR-NEXT:    [[RES:%.*]] = call <4 x i32> @test11_1(<4 x ptr> [[PTRS]]) #[[ATTR3]]
312; ATTRIBUTOR-NEXT:    ret <4 x i32> [[RES]]
313;
314; ATTRIBUTOR-CGSCC: Function Attrs: nosync nounwind memory(argmem: read)
315; ATTRIBUTOR-CGSCC-LABEL: define {{[^@]+}}@test11_2
316; ATTRIBUTOR-CGSCC-SAME: (<4 x ptr> [[PTRS:%.*]]) #[[ATTR10:[0-9]+]] {
317; ATTRIBUTOR-CGSCC-NEXT:    [[RES:%.*]] = call <4 x i32> @test11_1(<4 x ptr> [[PTRS]]) #[[ATTR3]]
318; ATTRIBUTOR-CGSCC-NEXT:    ret <4 x i32> [[RES]]
319;
320  %res = call <4 x i32> @test11_1(<4 x ptr> %ptrs)
321  ret <4 x i32> %res
322}
323
324declare <4 x i32> @test12_1(<4 x ptr>) argmemonly nounwind
325define <4 x i32> @test12_2(<4 x ptr> %ptrs) {
326; FNATTRS: Function Attrs: nounwind memory(argmem: readwrite)
327; FNATTRS-LABEL: define {{[^@]+}}@test12_2
328; FNATTRS-SAME: (<4 x ptr> [[PTRS:%.*]]) #[[ATTR12:[0-9]+]] {
329; FNATTRS-NEXT:    [[RES:%.*]] = call <4 x i32> @test12_1(<4 x ptr> [[PTRS]])
330; FNATTRS-NEXT:    ret <4 x i32> [[RES]]
331;
332; ATTRIBUTOR: Function Attrs: nounwind memory(argmem: readwrite)
333; ATTRIBUTOR-LABEL: define {{[^@]+}}@test12_2
334; ATTRIBUTOR-SAME: (<4 x ptr> [[PTRS:%.*]]) #[[ATTR10:[0-9]+]] {
335; ATTRIBUTOR-NEXT:    [[RES:%.*]] = call <4 x i32> @test12_1(<4 x ptr> [[PTRS]])
336; ATTRIBUTOR-NEXT:    ret <4 x i32> [[RES]]
337;
338; ATTRIBUTOR-CGSCC: Function Attrs: nounwind memory(argmem: readwrite)
339; ATTRIBUTOR-CGSCC-LABEL: define {{[^@]+}}@test12_2
340; ATTRIBUTOR-CGSCC-SAME: (<4 x ptr> [[PTRS:%.*]]) #[[ATTR11:[0-9]+]] {
341; ATTRIBUTOR-CGSCC-NEXT:    [[RES:%.*]] = call <4 x i32> @test12_1(<4 x ptr> [[PTRS]])
342; ATTRIBUTOR-CGSCC-NEXT:    ret <4 x i32> [[RES]]
343;
344  %res = call <4 x i32> @test12_1(<4 x ptr> %ptrs)
345  ret <4 x i32> %res
346}
347
348define i32 @volatile_load(ptr %p) {
349; FNATTRS: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite, inaccessiblemem: readwrite)
350; FNATTRS-LABEL: define {{[^@]+}}@volatile_load
351; FNATTRS-SAME: (ptr [[P:%.*]]) #[[ATTR13:[0-9]+]] {
352; FNATTRS-NEXT:    [[LOAD:%.*]] = load volatile i32, ptr [[P]], align 4
353; FNATTRS-NEXT:    ret i32 [[LOAD]]
354;
355; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite)
356; ATTRIBUTOR-LABEL: define {{[^@]+}}@volatile_load
357; ATTRIBUTOR-SAME: (ptr nofree [[P:%.*]]) #[[ATTR11:[0-9]+]] {
358; ATTRIBUTOR-NEXT:    [[LOAD:%.*]] = load volatile i32, ptr [[P]], align 4
359; ATTRIBUTOR-NEXT:    ret i32 [[LOAD]]
360;
361; ATTRIBUTOR-CGSCC: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite)
362; ATTRIBUTOR-CGSCC-LABEL: define {{[^@]+}}@volatile_load
363; ATTRIBUTOR-CGSCC-SAME: (ptr nofree [[P:%.*]]) #[[ATTR12:[0-9]+]] {
364; ATTRIBUTOR-CGSCC-NEXT:    [[LOAD:%.*]] = load volatile i32, ptr [[P]], align 4
365; ATTRIBUTOR-CGSCC-NEXT:    ret i32 [[LOAD]]
366;
367  %load = load volatile i32, ptr %p
368  ret i32 %load
369}
370
371declare void @escape_readnone_ptr(ptr %addr, ptr readnone %ptr)
372declare void @escape_readonly_ptr(ptr %addr, ptr readonly %ptr)
373
374; The argument pointer %escaped_then_written cannot be marked readnone/only even
375; though the only direct use, in @escape_readnone_ptr/@escape_readonly_ptr,
376; is marked as readnone/only. However, the functions can write the pointer into
377; %addr, causing the store to write to %escaped_then_written.
378define void @unsound_readnone(ptr %ignored, ptr %escaped_then_written) {
379; FNATTRS-LABEL: define {{[^@]+}}@unsound_readnone
380; FNATTRS-SAME: (ptr readnone captures(none) [[IGNORED:%.*]], ptr [[ESCAPED_THEN_WRITTEN:%.*]]) {
381; FNATTRS-NEXT:    [[ADDR:%.*]] = alloca ptr, align 8
382; FNATTRS-NEXT:    call void @escape_readnone_ptr(ptr [[ADDR]], ptr [[ESCAPED_THEN_WRITTEN]])
383; FNATTRS-NEXT:    [[ADDR_LD:%.*]] = load ptr, ptr [[ADDR]], align 8
384; FNATTRS-NEXT:    store i8 0, ptr [[ADDR_LD]], align 1
385; FNATTRS-NEXT:    ret void
386;
387; ATTRIBUTOR-LABEL: define {{[^@]+}}@unsound_readnone
388; ATTRIBUTOR-SAME: (ptr nofree readnone captures(none) [[IGNORED:%.*]], ptr nofree [[ESCAPED_THEN_WRITTEN:%.*]]) {
389; ATTRIBUTOR-NEXT:    [[ADDR:%.*]] = alloca ptr, align 8
390; ATTRIBUTOR-NEXT:    call void @escape_readnone_ptr(ptr [[ADDR]], ptr nofree [[ESCAPED_THEN_WRITTEN]])
391; ATTRIBUTOR-NEXT:    [[ADDR_LD:%.*]] = load ptr, ptr [[ADDR]], align 8
392; ATTRIBUTOR-NEXT:    store i8 0, ptr [[ADDR_LD]], align 1
393; ATTRIBUTOR-NEXT:    ret void
394;
395; ATTRIBUTOR-CGSCC-LABEL: define {{[^@]+}}@unsound_readnone
396; ATTRIBUTOR-CGSCC-SAME: (ptr nofree readnone captures(none) [[IGNORED:%.*]], ptr nofree [[ESCAPED_THEN_WRITTEN:%.*]]) {
397; ATTRIBUTOR-CGSCC-NEXT:    [[ADDR:%.*]] = alloca ptr, align 8
398; ATTRIBUTOR-CGSCC-NEXT:    call void @escape_readnone_ptr(ptr [[ADDR]], ptr nofree [[ESCAPED_THEN_WRITTEN]])
399; ATTRIBUTOR-CGSCC-NEXT:    [[ADDR_LD:%.*]] = load ptr, ptr [[ADDR]], align 8
400; ATTRIBUTOR-CGSCC-NEXT:    store i8 0, ptr [[ADDR_LD]], align 1
401; ATTRIBUTOR-CGSCC-NEXT:    ret void
402;
403  %addr = alloca ptr
404  call void @escape_readnone_ptr(ptr %addr, ptr %escaped_then_written)
405  %addr.ld = load ptr, ptr %addr
406  store i8 0, ptr %addr.ld
407  ret void
408}
409
410define void @unsound_readonly(ptr %ignored, ptr %escaped_then_written) {
411; FNATTRS-LABEL: define {{[^@]+}}@unsound_readonly
412; FNATTRS-SAME: (ptr readnone captures(none) [[IGNORED:%.*]], ptr [[ESCAPED_THEN_WRITTEN:%.*]]) {
413; FNATTRS-NEXT:    [[ADDR:%.*]] = alloca ptr, align 8
414; FNATTRS-NEXT:    call void @escape_readonly_ptr(ptr [[ADDR]], ptr [[ESCAPED_THEN_WRITTEN]])
415; FNATTRS-NEXT:    [[ADDR_LD:%.*]] = load ptr, ptr [[ADDR]], align 8
416; FNATTRS-NEXT:    store i8 0, ptr [[ADDR_LD]], align 1
417; FNATTRS-NEXT:    ret void
418;
419; ATTRIBUTOR-LABEL: define {{[^@]+}}@unsound_readonly
420; ATTRIBUTOR-SAME: (ptr nofree readnone captures(none) [[IGNORED:%.*]], ptr nofree [[ESCAPED_THEN_WRITTEN:%.*]]) {
421; ATTRIBUTOR-NEXT:    [[ADDR:%.*]] = alloca ptr, align 8
422; ATTRIBUTOR-NEXT:    call void @escape_readonly_ptr(ptr [[ADDR]], ptr nofree [[ESCAPED_THEN_WRITTEN]])
423; ATTRIBUTOR-NEXT:    [[ADDR_LD:%.*]] = load ptr, ptr [[ADDR]], align 8
424; ATTRIBUTOR-NEXT:    store i8 0, ptr [[ADDR_LD]], align 1
425; ATTRIBUTOR-NEXT:    ret void
426;
427; ATTRIBUTOR-CGSCC-LABEL: define {{[^@]+}}@unsound_readonly
428; ATTRIBUTOR-CGSCC-SAME: (ptr nofree readnone captures(none) [[IGNORED:%.*]], ptr nofree [[ESCAPED_THEN_WRITTEN:%.*]]) {
429; ATTRIBUTOR-CGSCC-NEXT:    [[ADDR:%.*]] = alloca ptr, align 8
430; ATTRIBUTOR-CGSCC-NEXT:    call void @escape_readonly_ptr(ptr [[ADDR]], ptr nofree [[ESCAPED_THEN_WRITTEN]])
431; ATTRIBUTOR-CGSCC-NEXT:    [[ADDR_LD:%.*]] = load ptr, ptr [[ADDR]], align 8
432; ATTRIBUTOR-CGSCC-NEXT:    store i8 0, ptr [[ADDR_LD]], align 1
433; ATTRIBUTOR-CGSCC-NEXT:    ret void
434;
435  %addr = alloca ptr
436  call void @escape_readonly_ptr(ptr %addr, ptr %escaped_then_written)
437  %addr.ld = load ptr, ptr %addr
438  store i8 0, ptr %addr.ld
439  ret void
440}
441
442define void @fptr_test1a(ptr %p, ptr %f) {
443; FNATTRS-LABEL: define {{[^@]+}}@fptr_test1a
444; FNATTRS-SAME: (ptr readnone captures(none) [[P:%.*]], ptr readonly captures(none) [[F:%.*]]) {
445; FNATTRS-NEXT:    call void [[F]](ptr readnone captures(none) [[P]])
446; FNATTRS-NEXT:    ret void
447;
448; ATTRIBUTOR-LABEL: define {{[^@]+}}@fptr_test1a
449; ATTRIBUTOR-SAME: (ptr nofree captures(none) [[P:%.*]], ptr nofree nonnull captures(none) [[F:%.*]]) {
450; ATTRIBUTOR-NEXT:    call void [[F]](ptr nofree readnone captures(none) [[P]])
451; ATTRIBUTOR-NEXT:    ret void
452;
453; ATTRIBUTOR-CGSCC-LABEL: define {{[^@]+}}@fptr_test1a
454; ATTRIBUTOR-CGSCC-SAME: (ptr nofree captures(none) [[P:%.*]], ptr nofree nonnull captures(none) [[F:%.*]]) {
455; ATTRIBUTOR-CGSCC-NEXT:    call void [[F]](ptr nofree readnone captures(none) [[P]])
456; ATTRIBUTOR-CGSCC-NEXT:    ret void
457;
458  call void %f(ptr nocapture readnone %p)
459  ret void
460}
461
462; Can't infer readnone here because call might capture %p
463define void @fptr_test1b(ptr %p, ptr %f) {
464; FNATTRS-LABEL: define {{[^@]+}}@fptr_test1b
465; FNATTRS-SAME: (ptr [[P:%.*]], ptr readonly captures(none) [[F:%.*]]) {
466; FNATTRS-NEXT:    call void [[F]](ptr readnone [[P]])
467; FNATTRS-NEXT:    ret void
468;
469; ATTRIBUTOR-LABEL: define {{[^@]+}}@fptr_test1b
470; ATTRIBUTOR-SAME: (ptr nofree [[P:%.*]], ptr nofree nonnull captures(none) [[F:%.*]]) {
471; ATTRIBUTOR-NEXT:    call void [[F]](ptr nofree readnone [[P]])
472; ATTRIBUTOR-NEXT:    ret void
473;
474; ATTRIBUTOR-CGSCC-LABEL: define {{[^@]+}}@fptr_test1b
475; ATTRIBUTOR-CGSCC-SAME: (ptr nofree [[P:%.*]], ptr nofree nonnull captures(none) [[F:%.*]]) {
476; ATTRIBUTOR-CGSCC-NEXT:    call void [[F]](ptr nofree readnone [[P]])
477; ATTRIBUTOR-CGSCC-NEXT:    ret void
478;
479  call void %f(ptr readnone %p)
480  ret void
481}
482
483define void @fptr_test1c(ptr %p, ptr %f) {
484; FNATTRS: Function Attrs: nofree memory(read)
485; FNATTRS-LABEL: define {{[^@]+}}@fptr_test1c
486; FNATTRS-SAME: (ptr readnone [[P:%.*]], ptr readonly captures(none) [[F:%.*]]) #[[ATTR3]] {
487; FNATTRS-NEXT:    call void [[F]](ptr readnone [[P]]) #[[ATTR2:[0-9]+]]
488; FNATTRS-NEXT:    ret void
489;
490; ATTRIBUTOR: Function Attrs: memory(read)
491; ATTRIBUTOR-LABEL: define {{[^@]+}}@fptr_test1c
492; ATTRIBUTOR-SAME: (ptr nofree readonly [[P:%.*]], ptr nofree nonnull readonly captures(none) [[F:%.*]]) #[[ATTR2:[0-9]+]] {
493; ATTRIBUTOR-NEXT:    call void [[F]](ptr nofree readnone [[P]]) #[[ATTR2]]
494; ATTRIBUTOR-NEXT:    ret void
495;
496; ATTRIBUTOR-CGSCC: Function Attrs: memory(read)
497; ATTRIBUTOR-CGSCC-LABEL: define {{[^@]+}}@fptr_test1c
498; ATTRIBUTOR-CGSCC-SAME: (ptr nofree readonly [[P:%.*]], ptr nofree nonnull readonly captures(none) [[F:%.*]]) #[[ATTR2:[0-9]+]] {
499; ATTRIBUTOR-CGSCC-NEXT:    call void [[F]](ptr nofree readnone [[P]]) #[[ATTR2]]
500; ATTRIBUTOR-CGSCC-NEXT:    ret void
501;
502  call void %f(ptr readnone %p) readonly
503  ret void
504}
505
506define void @fptr_test2a(ptr %p, ptr %f) {
507; FNATTRS-LABEL: define {{[^@]+}}@fptr_test2a
508; FNATTRS-SAME: (ptr readonly captures(none) [[P:%.*]], ptr readonly captures(none) [[F:%.*]]) {
509; FNATTRS-NEXT:    call void [[F]](ptr readonly captures(none) [[P]])
510; FNATTRS-NEXT:    ret void
511;
512; ATTRIBUTOR-LABEL: define {{[^@]+}}@fptr_test2a
513; ATTRIBUTOR-SAME: (ptr nofree captures(none) [[P:%.*]], ptr nofree nonnull captures(none) [[F:%.*]]) {
514; ATTRIBUTOR-NEXT:    call void [[F]](ptr nofree readonly captures(none) [[P]])
515; ATTRIBUTOR-NEXT:    ret void
516;
517; ATTRIBUTOR-CGSCC-LABEL: define {{[^@]+}}@fptr_test2a
518; ATTRIBUTOR-CGSCC-SAME: (ptr nofree captures(none) [[P:%.*]], ptr nofree nonnull captures(none) [[F:%.*]]) {
519; ATTRIBUTOR-CGSCC-NEXT:    call void [[F]](ptr nofree readonly captures(none) [[P]])
520; ATTRIBUTOR-CGSCC-NEXT:    ret void
521;
522  call void %f(ptr nocapture readonly %p)
523  ret void
524}
525
526define void @fptr_test2b(ptr %p, ptr %f) {
527  ; Can't infer readonly here because call might capture %p
528; FNATTRS-LABEL: define {{[^@]+}}@fptr_test2b
529; FNATTRS-SAME: (ptr [[P:%.*]], ptr readonly captures(none) [[F:%.*]]) {
530; FNATTRS-NEXT:    call void [[F]](ptr readonly [[P]])
531; FNATTRS-NEXT:    ret void
532;
533; ATTRIBUTOR-LABEL: define {{[^@]+}}@fptr_test2b
534; ATTRIBUTOR-SAME: (ptr nofree [[P:%.*]], ptr nofree nonnull captures(none) [[F:%.*]]) {
535; ATTRIBUTOR-NEXT:    call void [[F]](ptr nofree readonly [[P]])
536; ATTRIBUTOR-NEXT:    ret void
537;
538; ATTRIBUTOR-CGSCC-LABEL: define {{[^@]+}}@fptr_test2b
539; ATTRIBUTOR-CGSCC-SAME: (ptr nofree [[P:%.*]], ptr nofree nonnull captures(none) [[F:%.*]]) {
540; ATTRIBUTOR-CGSCC-NEXT:    call void [[F]](ptr nofree readonly [[P]])
541; ATTRIBUTOR-CGSCC-NEXT:    ret void
542;
543  call void %f(ptr readonly %p)
544  ret void
545}
546
547define void @fptr_test2c(ptr %p, ptr %f) {
548; FNATTRS: Function Attrs: nofree memory(read)
549; FNATTRS-LABEL: define {{[^@]+}}@fptr_test2c
550; FNATTRS-SAME: (ptr readonly [[P:%.*]], ptr readonly captures(none) [[F:%.*]]) #[[ATTR3]] {
551; FNATTRS-NEXT:    call void [[F]](ptr readonly [[P]]) #[[ATTR2]]
552; FNATTRS-NEXT:    ret void
553;
554; ATTRIBUTOR: Function Attrs: memory(read)
555; ATTRIBUTOR-LABEL: define {{[^@]+}}@fptr_test2c
556; ATTRIBUTOR-SAME: (ptr nofree readonly [[P:%.*]], ptr nofree nonnull readonly captures(none) [[F:%.*]]) #[[ATTR2]] {
557; ATTRIBUTOR-NEXT:    call void [[F]](ptr nofree readonly [[P]]) #[[ATTR2]]
558; ATTRIBUTOR-NEXT:    ret void
559;
560; ATTRIBUTOR-CGSCC: Function Attrs: memory(read)
561; ATTRIBUTOR-CGSCC-LABEL: define {{[^@]+}}@fptr_test2c
562; ATTRIBUTOR-CGSCC-SAME: (ptr nofree readonly [[P:%.*]], ptr nofree nonnull readonly captures(none) [[F:%.*]]) #[[ATTR2]] {
563; ATTRIBUTOR-CGSCC-NEXT:    call void [[F]](ptr nofree readonly [[P]]) #[[ATTR2]]
564; ATTRIBUTOR-CGSCC-NEXT:    ret void
565;
566  call void %f(ptr readonly %p) readonly
567  ret void
568}
569
570define void @alloca_recphi() {
571; FNATTRS: Function Attrs: nofree norecurse nosync nounwind memory(none)
572; FNATTRS-LABEL: define {{[^@]+}}@alloca_recphi
573; FNATTRS-SAME: () #[[ATTR14:[0-9]+]] {
574; FNATTRS-NEXT:  entry:
575; FNATTRS-NEXT:    [[A:%.*]] = alloca [8 x i32], align 4
576; FNATTRS-NEXT:    [[A_END:%.*]] = getelementptr i32, ptr [[A]], i64 8
577; FNATTRS-NEXT:    br label [[LOOP:%.*]]
578; FNATTRS:       loop:
579; FNATTRS-NEXT:    [[P:%.*]] = phi ptr [ [[A]], [[ENTRY:%.*]] ], [ [[P_NEXT:%.*]], [[LOOP]] ]
580; FNATTRS-NEXT:    store i32 0, ptr [[P]], align 4
581; FNATTRS-NEXT:    [[TMP0:%.*]] = load i32, ptr [[P]], align 4
582; FNATTRS-NEXT:    [[P_NEXT]] = getelementptr i32, ptr [[P]], i64 1
583; FNATTRS-NEXT:    [[C:%.*]] = icmp ne ptr [[P_NEXT]], [[A_END]]
584; FNATTRS-NEXT:    br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]]
585; FNATTRS:       exit:
586; FNATTRS-NEXT:    ret void
587;
588; ATTRIBUTOR: Function Attrs: nofree norecurse nosync nounwind memory(none)
589; ATTRIBUTOR-LABEL: define {{[^@]+}}@alloca_recphi
590; ATTRIBUTOR-SAME: () #[[ATTR12:[0-9]+]] {
591; ATTRIBUTOR-NEXT:  entry:
592; ATTRIBUTOR-NEXT:    [[A:%.*]] = alloca [8 x i32], align 4
593; ATTRIBUTOR-NEXT:    [[A_END:%.*]] = getelementptr i32, ptr [[A]], i64 8
594; ATTRIBUTOR-NEXT:    br label [[LOOP:%.*]]
595; ATTRIBUTOR:       loop:
596; ATTRIBUTOR-NEXT:    [[P:%.*]] = phi ptr [ [[A]], [[ENTRY:%.*]] ], [ [[P_NEXT:%.*]], [[LOOP]] ]
597; ATTRIBUTOR-NEXT:    store i32 0, ptr [[P]], align 4
598; ATTRIBUTOR-NEXT:    [[TMP0:%.*]] = load i32, ptr [[P]], align 4
599; ATTRIBUTOR-NEXT:    [[P_NEXT]] = getelementptr i32, ptr [[P]], i64 1
600; ATTRIBUTOR-NEXT:    [[C:%.*]] = icmp ne ptr [[P_NEXT]], [[A_END]]
601; ATTRIBUTOR-NEXT:    br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]]
602; ATTRIBUTOR:       exit:
603; ATTRIBUTOR-NEXT:    ret void
604;
605; ATTRIBUTOR-CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
606; ATTRIBUTOR-CGSCC-LABEL: define {{[^@]+}}@alloca_recphi
607; ATTRIBUTOR-CGSCC-SAME: () #[[ATTR1]] {
608; ATTRIBUTOR-CGSCC-NEXT:  entry:
609; ATTRIBUTOR-CGSCC-NEXT:    [[A:%.*]] = alloca [8 x i32], align 4
610; ATTRIBUTOR-CGSCC-NEXT:    [[A_END:%.*]] = getelementptr i32, ptr [[A]], i64 8
611; ATTRIBUTOR-CGSCC-NEXT:    br label [[LOOP:%.*]]
612; ATTRIBUTOR-CGSCC:       loop:
613; ATTRIBUTOR-CGSCC-NEXT:    [[P:%.*]] = phi ptr [ [[A]], [[ENTRY:%.*]] ], [ [[P_NEXT:%.*]], [[LOOP]] ]
614; ATTRIBUTOR-CGSCC-NEXT:    store i32 0, ptr [[P]], align 4
615; ATTRIBUTOR-CGSCC-NEXT:    [[TMP0:%.*]] = load i32, ptr [[P]], align 4
616; ATTRIBUTOR-CGSCC-NEXT:    [[P_NEXT]] = getelementptr i32, ptr [[P]], i64 1
617; ATTRIBUTOR-CGSCC-NEXT:    [[C:%.*]] = icmp ne ptr [[P_NEXT]], [[A_END]]
618; ATTRIBUTOR-CGSCC-NEXT:    br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]]
619; ATTRIBUTOR-CGSCC:       exit:
620; ATTRIBUTOR-CGSCC-NEXT:    ret void
621;
622entry:
623  %a = alloca [8 x i32]
624  %a.end = getelementptr i32, ptr %a, i64 8
625  br label %loop
626
627loop:
628  %p = phi ptr [ %a, %entry ], [ %p.next, %loop ]
629  store i32 0, ptr %p
630  load i32, ptr %p
631  %p.next = getelementptr i32, ptr %p, i64 1
632  %c = icmp ne ptr %p.next, %a.end
633  br i1 %c, label %loop, label %exit
634
635exit:
636  ret void
637}
638
639declare void @readnone_param(ptr nocapture readnone %p)
640declare void @readonly_param(ptr nocapture readonly %p)
641
642; FIXME: While this can't be readnone, this could be readonly.
643define void @op_bundle_readnone_deopt(ptr %p) {
644; FNATTRS-LABEL: define {{[^@]+}}@op_bundle_readnone_deopt
645; FNATTRS-SAME: (ptr captures(none) [[P:%.*]]) {
646; FNATTRS-NEXT:    call void @readnone_param(ptr [[P]]) [ "deopt"() ]
647; FNATTRS-NEXT:    ret void
648;
649; ATTRIBUTOR-LABEL: define {{[^@]+}}@op_bundle_readnone_deopt
650; ATTRIBUTOR-SAME: (ptr nofree captures(none) [[P:%.*]]) {
651; ATTRIBUTOR-NEXT:    call void @readnone_param(ptr nofree captures(none) [[P]]) [ "deopt"() ]
652; ATTRIBUTOR-NEXT:    ret void
653;
654; ATTRIBUTOR-CGSCC-LABEL: define {{[^@]+}}@op_bundle_readnone_deopt
655; ATTRIBUTOR-CGSCC-SAME: (ptr nofree captures(none) [[P:%.*]]) {
656; ATTRIBUTOR-CGSCC-NEXT:    call void @readnone_param(ptr nofree captures(none) [[P]]) [ "deopt"() ]
657; ATTRIBUTOR-CGSCC-NEXT:    ret void
658;
659  call void @readnone_param(ptr %p) ["deopt"()]
660  ret void
661}
662
663define void @op_bundle_readnone_unknown(ptr %p) {
664; FNATTRS-LABEL: define {{[^@]+}}@op_bundle_readnone_unknown
665; FNATTRS-SAME: (ptr captures(none) [[P:%.*]]) {
666; FNATTRS-NEXT:    call void @readnone_param(ptr [[P]]) [ "unknown"() ]
667; FNATTRS-NEXT:    ret void
668;
669; ATTRIBUTOR-LABEL: define {{[^@]+}}@op_bundle_readnone_unknown
670; ATTRIBUTOR-SAME: (ptr nofree captures(none) [[P:%.*]]) {
671; ATTRIBUTOR-NEXT:    call void @readnone_param(ptr nofree captures(none) [[P]]) [ "unknown"() ]
672; ATTRIBUTOR-NEXT:    ret void
673;
674; ATTRIBUTOR-CGSCC-LABEL: define {{[^@]+}}@op_bundle_readnone_unknown
675; ATTRIBUTOR-CGSCC-SAME: (ptr nofree captures(none) [[P:%.*]]) {
676; ATTRIBUTOR-CGSCC-NEXT:    call void @readnone_param(ptr nofree captures(none) [[P]]) [ "unknown"() ]
677; ATTRIBUTOR-CGSCC-NEXT:    ret void
678;
679  call void @readnone_param(ptr %p) ["unknown"()]
680  ret void
681}
682
683define void @op_bundle_readonly_deopt(ptr %p) {
684; FNATTRS-LABEL: define {{[^@]+}}@op_bundle_readonly_deopt
685; FNATTRS-SAME: (ptr readonly captures(none) [[P:%.*]]) {
686; FNATTRS-NEXT:    call void @readonly_param(ptr [[P]]) [ "deopt"() ]
687; FNATTRS-NEXT:    ret void
688;
689; ATTRIBUTOR-LABEL: define {{[^@]+}}@op_bundle_readonly_deopt
690; ATTRIBUTOR-SAME: (ptr nofree captures(none) [[P:%.*]]) {
691; ATTRIBUTOR-NEXT:    call void @readonly_param(ptr nofree captures(none) [[P]]) [ "deopt"() ]
692; ATTRIBUTOR-NEXT:    ret void
693;
694; ATTRIBUTOR-CGSCC-LABEL: define {{[^@]+}}@op_bundle_readonly_deopt
695; ATTRIBUTOR-CGSCC-SAME: (ptr nofree captures(none) [[P:%.*]]) {
696; ATTRIBUTOR-CGSCC-NEXT:    call void @readonly_param(ptr nofree captures(none) [[P]]) [ "deopt"() ]
697; ATTRIBUTOR-CGSCC-NEXT:    ret void
698;
699  call void @readonly_param(ptr %p) ["deopt"()]
700  ret void
701}
702
703define void @op_bundle_readonly_unknown(ptr %p) {
704; FNATTRS-LABEL: define {{[^@]+}}@op_bundle_readonly_unknown
705; FNATTRS-SAME: (ptr captures(none) [[P:%.*]]) {
706; FNATTRS-NEXT:    call void @readonly_param(ptr [[P]]) [ "unknown"() ]
707; FNATTRS-NEXT:    ret void
708;
709; ATTRIBUTOR-LABEL: define {{[^@]+}}@op_bundle_readonly_unknown
710; ATTRIBUTOR-SAME: (ptr nofree captures(none) [[P:%.*]]) {
711; ATTRIBUTOR-NEXT:    call void @readonly_param(ptr nofree captures(none) [[P]]) [ "unknown"() ]
712; ATTRIBUTOR-NEXT:    ret void
713;
714; ATTRIBUTOR-CGSCC-LABEL: define {{[^@]+}}@op_bundle_readonly_unknown
715; ATTRIBUTOR-CGSCC-SAME: (ptr nofree captures(none) [[P:%.*]]) {
716; ATTRIBUTOR-CGSCC-NEXT:    call void @readonly_param(ptr nofree captures(none) [[P]]) [ "unknown"() ]
717; ATTRIBUTOR-CGSCC-NEXT:    ret void
718;
719  call void @readonly_param(ptr %p) ["unknown"()]
720  ret void
721}
722
723define i32 @writable_readonly(ptr writable dereferenceable(4) %p) {
724; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read)
725; FNATTRS-LABEL: define {{[^@]+}}@writable_readonly
726; FNATTRS-SAME: (ptr readonly captures(none) dereferenceable(4) [[P:%.*]]) #[[ATTR15:[0-9]+]] {
727; FNATTRS-NEXT:    [[V:%.*]] = load i32, ptr [[P]], align 4
728; FNATTRS-NEXT:    ret i32 [[V]]
729;
730; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read)
731; ATTRIBUTOR-LABEL: define {{[^@]+}}@writable_readonly
732; ATTRIBUTOR-SAME: (ptr nofree nonnull readonly captures(none) dereferenceable(4) [[P:%.*]]) #[[ATTR13:[0-9]+]] {
733; ATTRIBUTOR-NEXT:    [[V:%.*]] = load i32, ptr [[P]], align 4
734; ATTRIBUTOR-NEXT:    ret i32 [[V]]
735;
736; ATTRIBUTOR-CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read)
737; ATTRIBUTOR-CGSCC-LABEL: define {{[^@]+}}@writable_readonly
738; ATTRIBUTOR-CGSCC-SAME: (ptr nofree nonnull readonly captures(none) dereferenceable(4) [[P:%.*]]) #[[ATTR13:[0-9]+]] {
739; ATTRIBUTOR-CGSCC-NEXT:    [[V:%.*]] = load i32, ptr [[P]], align 4
740; ATTRIBUTOR-CGSCC-NEXT:    ret i32 [[V]]
741;
742  %v = load i32, ptr %p
743  ret i32 %v
744}
745
746define void @writable_readnone(ptr writable dereferenceable(4) %p) {
747; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
748; FNATTRS-LABEL: define {{[^@]+}}@writable_readnone
749; FNATTRS-SAME: (ptr readnone captures(none) dereferenceable(4) [[P:%.*]]) #[[ATTR1]] {
750; FNATTRS-NEXT:    ret void
751;
752; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
753; ATTRIBUTOR-LABEL: define {{[^@]+}}@writable_readnone
754; ATTRIBUTOR-SAME: (ptr nofree nonnull readnone captures(none) dereferenceable(4) [[P:%.*]]) #[[ATTR1]] {
755; ATTRIBUTOR-NEXT:    ret void
756;
757; ATTRIBUTOR-CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
758; ATTRIBUTOR-CGSCC-LABEL: define {{[^@]+}}@writable_readnone
759; ATTRIBUTOR-CGSCC-SAME: (ptr nofree nonnull readnone captures(none) dereferenceable(4) [[P:%.*]]) #[[ATTR1]] {
760; ATTRIBUTOR-CGSCC-NEXT:    ret void
761;
762  ret void
763}
764
765declare void @byval_param(ptr byval(i32) %p)
766
767define void @call_byval_param(ptr %p) {
768; FNATTRS-LABEL: define {{[^@]+}}@call_byval_param
769; FNATTRS-SAME: (ptr readonly captures(none) [[P:%.*]]) {
770; FNATTRS-NEXT:    call void @byval_param(ptr byval(i32) [[P]])
771; FNATTRS-NEXT:    ret void
772;
773; ATTRIBUTOR-LABEL: define {{[^@]+}}@call_byval_param
774; ATTRIBUTOR-SAME: (ptr readonly captures(none) [[P:%.*]]) {
775; ATTRIBUTOR-NEXT:    call void @byval_param(ptr readonly byval(i32) captures(none) [[P]])
776; ATTRIBUTOR-NEXT:    ret void
777;
778; ATTRIBUTOR-CGSCC-LABEL: define {{[^@]+}}@call_byval_param
779; ATTRIBUTOR-CGSCC-SAME: (ptr readonly captures(none) [[P:%.*]]) {
780; ATTRIBUTOR-CGSCC-NEXT:    call void @byval_param(ptr readonly byval(i32) captures(none) [[P]])
781; ATTRIBUTOR-CGSCC-NEXT:    ret void
782;
783  call void @byval_param(ptr byval(i32) %p)
784  ret void
785}
786
787;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
788; COMMON: {{.*}}
789