xref: /llvm-project/llvm/test/Transforms/FunctionAttrs/argmemonly.ll (revision 29441e4f5fa5f5c7709f7cf180815ba97f611297)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-attributes --version 2
2; RUN: opt -passes=function-attrs -S < %s | FileCheck --check-prefixes=COMMON,FNATTRS %s
3; RUN: opt -passes=attributor-light -S < %s | FileCheck --check-prefixes=COMMON,ATTRIBUTOR %s
4
5@g = global i32 20
6
7define void @test_no_read_or_write() {
8; COMMON: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
9; COMMON-LABEL: define void @test_no_read_or_write
10; COMMON-SAME: () #[[ATTR0:[0-9]+]] {
11; COMMON-NEXT:  entry:
12; COMMON-NEXT:    ret void
13;
14entry:
15  ret void
16}
17
18define i32 @test_only_read_arg(ptr %ptr) {
19; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read)
20; FNATTRS-LABEL: define i32 @test_only_read_arg
21; FNATTRS-SAME: (ptr readonly captures(none) [[PTR:%.*]]) #[[ATTR1:[0-9]+]] {
22; FNATTRS-NEXT:  entry:
23; FNATTRS-NEXT:    [[L:%.*]] = load i32, ptr [[PTR]], align 4
24; FNATTRS-NEXT:    ret i32 [[L]]
25;
26; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read)
27; ATTRIBUTOR-LABEL: define i32 @test_only_read_arg
28; ATTRIBUTOR-SAME: (ptr nofree nonnull readonly captures(none) [[PTR:%.*]]) #[[ATTR1:[0-9]+]] {
29; ATTRIBUTOR-NEXT:  entry:
30; ATTRIBUTOR-NEXT:    [[L:%.*]] = load i32, ptr [[PTR]], align 4
31; ATTRIBUTOR-NEXT:    ret i32 [[L]]
32;
33entry:
34  %l = load i32, ptr %ptr
35  ret i32 %l
36}
37
38define i32 @test_only_read_arg_already_has_argmemonly(ptr %ptr) argmemonly {
39; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read)
40; FNATTRS-LABEL: define i32 @test_only_read_arg_already_has_argmemonly
41; FNATTRS-SAME: (ptr readonly captures(none) [[PTR:%.*]]) #[[ATTR1]] {
42; FNATTRS-NEXT:  entry:
43; FNATTRS-NEXT:    [[L:%.*]] = load i32, ptr [[PTR]], align 4
44; FNATTRS-NEXT:    ret i32 [[L]]
45;
46; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read)
47; ATTRIBUTOR-LABEL: define i32 @test_only_read_arg_already_has_argmemonly
48; ATTRIBUTOR-SAME: (ptr nofree nonnull readonly captures(none) [[PTR:%.*]]) #[[ATTR1]] {
49; ATTRIBUTOR-NEXT:  entry:
50; ATTRIBUTOR-NEXT:    [[L:%.*]] = load i32, ptr [[PTR]], align 4
51; ATTRIBUTOR-NEXT:    ret i32 [[L]]
52;
53entry:
54  %l = load i32, ptr %ptr
55  ret i32 %l
56}
57
58define i32 @test_read_global() {
59; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(read, argmem: none, inaccessiblemem: none)
60; FNATTRS-LABEL: define i32 @test_read_global
61; FNATTRS-SAME: () #[[ATTR2:[0-9]+]] {
62; FNATTRS-NEXT:  entry:
63; FNATTRS-NEXT:    [[L:%.*]] = load i32, ptr @g, align 4
64; FNATTRS-NEXT:    ret i32 [[L]]
65;
66; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(read)
67; ATTRIBUTOR-LABEL: define i32 @test_read_global
68; ATTRIBUTOR-SAME: () #[[ATTR2:[0-9]+]] {
69; ATTRIBUTOR-NEXT:  entry:
70; ATTRIBUTOR-NEXT:    [[L:%.*]] = load i32, ptr @g, align 4
71; ATTRIBUTOR-NEXT:    ret i32 [[L]]
72;
73entry:
74  %l = load i32, ptr @g
75  ret i32 %l
76}
77
78define i32 @test_read_loaded_ptr(ptr %ptr) {
79; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(read, inaccessiblemem: none)
80; FNATTRS-LABEL: define i32 @test_read_loaded_ptr
81; FNATTRS-SAME: (ptr readonly captures(none) [[PTR:%.*]]) #[[ATTR3:[0-9]+]] {
82; FNATTRS-NEXT:  entry:
83; FNATTRS-NEXT:    [[L:%.*]] = load ptr, ptr [[PTR]], align 8
84; FNATTRS-NEXT:    [[L_2:%.*]] = load i32, ptr [[L]], align 4
85; FNATTRS-NEXT:    ret i32 [[L_2]]
86;
87; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(read)
88; ATTRIBUTOR-LABEL: define i32 @test_read_loaded_ptr
89; ATTRIBUTOR-SAME: (ptr nofree nonnull readonly captures(none) [[PTR:%.*]]) #[[ATTR2]] {
90; ATTRIBUTOR-NEXT:  entry:
91; ATTRIBUTOR-NEXT:    [[L:%.*]] = load ptr, ptr [[PTR]], align 8
92; ATTRIBUTOR-NEXT:    [[L_2:%.*]] = load i32, ptr [[L]], align 4
93; ATTRIBUTOR-NEXT:    ret i32 [[L_2]]
94;
95entry:
96  %l = load ptr, ptr %ptr
97  %l.2 = load i32, ptr %l
98  ret i32 %l.2
99}
100
101define void @test_only_write_arg(ptr %ptr) {
102; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write)
103; FNATTRS-LABEL: define void @test_only_write_arg
104; FNATTRS-SAME: (ptr writeonly captures(none) initializes((0, 4)) [[PTR:%.*]]) #[[ATTR4:[0-9]+]] {
105; FNATTRS-NEXT:  entry:
106; FNATTRS-NEXT:    store i32 0, ptr [[PTR]], align 4
107; FNATTRS-NEXT:    ret void
108;
109; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write)
110; ATTRIBUTOR-LABEL: define void @test_only_write_arg
111; ATTRIBUTOR-SAME: (ptr nofree nonnull writeonly captures(none) [[PTR:%.*]]) #[[ATTR3:[0-9]+]] {
112; ATTRIBUTOR-NEXT:  entry:
113; ATTRIBUTOR-NEXT:    store i32 0, ptr [[PTR]], align 4
114; ATTRIBUTOR-NEXT:    ret void
115;
116entry:
117  store i32 0, ptr %ptr
118  ret void
119}
120
121define void @test_write_global() {
122; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(write, argmem: none, inaccessiblemem: none)
123; FNATTRS-LABEL: define void @test_write_global
124; FNATTRS-SAME: () #[[ATTR5:[0-9]+]] {
125; FNATTRS-NEXT:  entry:
126; FNATTRS-NEXT:    store i32 0, ptr @g, align 4
127; FNATTRS-NEXT:    ret void
128;
129; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(write)
130; ATTRIBUTOR-LABEL: define void @test_write_global
131; ATTRIBUTOR-SAME: () #[[ATTR4:[0-9]+]] {
132; ATTRIBUTOR-NEXT:  entry:
133; ATTRIBUTOR-NEXT:    store i32 0, ptr @g, align 4
134; ATTRIBUTOR-NEXT:    ret void
135;
136entry:
137  store i32 0, ptr @g
138  ret void
139}
140
141declare void @fn_may_access_memory()
142
143define void @test_call_may_access_memory() {
144; COMMON-LABEL: define void @test_call_may_access_memory() {
145; COMMON-NEXT:  entry:
146; COMMON-NEXT:    call void @fn_may_access_memory()
147; COMMON-NEXT:    ret void
148;
149entry:
150  call void @fn_may_access_memory()
151  ret void
152}
153
154declare i32 @fn_readnone() readnone
155
156define void @test_call_readnone(ptr %ptr) {
157; FNATTRS: Function Attrs: memory(argmem: write)
158; FNATTRS-LABEL: define void @test_call_readnone
159; FNATTRS-SAME: (ptr writeonly captures(none) initializes((0, 4)) [[PTR:%.*]]) #[[ATTR7:[0-9]+]] {
160; FNATTRS-NEXT:  entry:
161; FNATTRS-NEXT:    [[C:%.*]] = call i32 @fn_readnone()
162; FNATTRS-NEXT:    store i32 [[C]], ptr [[PTR]], align 4
163; FNATTRS-NEXT:    ret void
164;
165; ATTRIBUTOR: Function Attrs: nosync memory(argmem: write)
166; ATTRIBUTOR-LABEL: define void @test_call_readnone
167; ATTRIBUTOR-SAME: (ptr nofree writeonly captures(none) [[PTR:%.*]]) #[[ATTR6:[0-9]+]] {
168; ATTRIBUTOR-NEXT:  entry:
169; ATTRIBUTOR-NEXT:    [[C:%.*]] = call i32 @fn_readnone() #[[ATTR18:[0-9]+]]
170; ATTRIBUTOR-NEXT:    store i32 [[C]], ptr [[PTR]], align 4
171; ATTRIBUTOR-NEXT:    ret void
172;
173entry:
174  %c = call i32 @fn_readnone()
175  store i32 %c, ptr %ptr
176  ret void
177}
178
179declare i32 @fn_argmemonly(ptr) argmemonly
180
181define i32 @test_call_argmemonly(ptr %ptr) {
182; FNATTRS: Function Attrs: memory(argmem: readwrite)
183; FNATTRS-LABEL: define i32 @test_call_argmemonly
184; FNATTRS-SAME: (ptr [[PTR:%.*]]) #[[ATTR8:[0-9]+]] {
185; FNATTRS-NEXT:  entry:
186; FNATTRS-NEXT:    [[C:%.*]] = call i32 @fn_argmemonly(ptr [[PTR]])
187; FNATTRS-NEXT:    ret i32 [[C]]
188;
189; ATTRIBUTOR: Function Attrs: memory(argmem: readwrite)
190; ATTRIBUTOR-LABEL: define i32 @test_call_argmemonly
191; ATTRIBUTOR-SAME: (ptr [[PTR:%.*]]) #[[ATTR7:[0-9]+]] {
192; ATTRIBUTOR-NEXT:  entry:
193; ATTRIBUTOR-NEXT:    [[C:%.*]] = call i32 @fn_argmemonly(ptr [[PTR]])
194; ATTRIBUTOR-NEXT:    ret i32 [[C]]
195;
196entry:
197  %c = call i32 @fn_argmemonly(ptr %ptr)
198  ret i32 %c
199}
200
201define i32 @test_call_fn_where_argmemonly_can_be_inferred(ptr %ptr) {
202; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read)
203; FNATTRS-LABEL: define i32 @test_call_fn_where_argmemonly_can_be_inferred
204; FNATTRS-SAME: (ptr readonly captures(none) [[PTR:%.*]]) #[[ATTR1]] {
205; FNATTRS-NEXT:  entry:
206; FNATTRS-NEXT:    [[C:%.*]] = call i32 @test_only_read_arg(ptr [[PTR]])
207; FNATTRS-NEXT:    ret i32 [[C]]
208;
209; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read)
210; ATTRIBUTOR-LABEL: define i32 @test_call_fn_where_argmemonly_can_be_inferred
211; ATTRIBUTOR-SAME: (ptr nofree readonly captures(none) [[PTR:%.*]]) #[[ATTR1]] {
212; ATTRIBUTOR-NEXT:  entry:
213; ATTRIBUTOR-NEXT:    [[C:%.*]] = call i32 @test_only_read_arg(ptr nofree readonly captures(none) [[PTR]]) #[[ATTR19:[0-9]+]]
214; ATTRIBUTOR-NEXT:    ret i32 [[C]]
215;
216entry:
217  %c = call i32 @test_only_read_arg(ptr %ptr)
218  ret i32 %c
219}
220
221define void @test_memcpy_argonly(ptr %dst, ptr %src) {
222; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite)
223; FNATTRS-LABEL: define void @test_memcpy_argonly
224; FNATTRS-SAME: (ptr writeonly captures(none) initializes((0, 32)) [[DST:%.*]], ptr readonly captures(none) [[SRC:%.*]]) #[[ATTR9:[0-9]+]] {
225; FNATTRS-NEXT:  entry:
226; FNATTRS-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr [[DST]], ptr [[SRC]], i64 32, i1 false)
227; FNATTRS-NEXT:    ret void
228;
229; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite)
230; ATTRIBUTOR-LABEL: define void @test_memcpy_argonly
231; ATTRIBUTOR-SAME: (ptr nofree writeonly captures(none) [[DST:%.*]], ptr nofree readonly captures(none) [[SRC:%.*]]) #[[ATTR8:[0-9]+]] {
232; ATTRIBUTOR-NEXT:  entry:
233; ATTRIBUTOR-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr writeonly captures(none) [[DST]], ptr readonly captures(none) [[SRC]], i64 32, i1 false) #[[ATTR20:[0-9]+]]
234; ATTRIBUTOR-NEXT:    ret void
235;
236entry:
237  call void @llvm.memcpy.p0.p0.i64(ptr %dst, ptr %src, i64 32, i1 false)
238  ret void
239}
240
241declare void @llvm.memcpy.p0.p0.i64(ptr, ptr, i64, i1)
242
243@arr = global [32 x i8] zeroinitializer
244
245define void @test_memcpy_src_global(ptr %dst) {
246; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(readwrite, inaccessiblemem: none)
247; FNATTRS-LABEL: define void @test_memcpy_src_global
248; FNATTRS-SAME: (ptr writeonly captures(none) initializes((0, 32)) [[DST:%.*]]) #[[ATTR11:[0-9]+]] {
249; FNATTRS-NEXT:  entry:
250; FNATTRS-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr [[DST]], ptr @arr, i64 32, i1 false)
251; FNATTRS-NEXT:    ret void
252;
253; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn
254; ATTRIBUTOR-LABEL: define void @test_memcpy_src_global
255; ATTRIBUTOR-SAME: (ptr nofree writeonly captures(none) [[DST:%.*]]) #[[ATTR10:[0-9]+]] {
256; ATTRIBUTOR-NEXT:  entry:
257; ATTRIBUTOR-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr writeonly captures(none) [[DST]], ptr readonly @arr, i64 32, i1 false) #[[ATTR20]]
258; ATTRIBUTOR-NEXT:    ret void
259;
260entry:
261  call void @llvm.memcpy.p0.p0.i64(ptr %dst, ptr @arr, i64 32, i1 false)
262  ret void
263}
264
265define void @test_memcpy_dst_global(ptr %src) {
266; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(readwrite, inaccessiblemem: none)
267; FNATTRS-LABEL: define void @test_memcpy_dst_global
268; FNATTRS-SAME: (ptr readonly captures(none) [[SRC:%.*]]) #[[ATTR11]] {
269; FNATTRS-NEXT:  entry:
270; FNATTRS-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr @arr, ptr [[SRC]], i64 32, i1 false)
271; FNATTRS-NEXT:    ret void
272;
273; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn
274; ATTRIBUTOR-LABEL: define void @test_memcpy_dst_global
275; ATTRIBUTOR-SAME: (ptr nofree readonly captures(none) [[SRC:%.*]]) #[[ATTR10]] {
276; ATTRIBUTOR-NEXT:  entry:
277; ATTRIBUTOR-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr writeonly @arr, ptr readonly captures(none) [[SRC]], i64 32, i1 false) #[[ATTR20]]
278; ATTRIBUTOR-NEXT:    ret void
279;
280entry:
281  call void @llvm.memcpy.p0.p0.i64(ptr @arr, ptr %src, i64 32, i1 false)
282  ret void
283}
284
285define i32 @test_read_arg_access_alloca(ptr %ptr) {
286; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read)
287; FNATTRS-LABEL: define i32 @test_read_arg_access_alloca
288; FNATTRS-SAME: (ptr readonly captures(none) [[PTR:%.*]]) #[[ATTR1]] {
289; FNATTRS-NEXT:  entry:
290; FNATTRS-NEXT:    [[A:%.*]] = alloca i32, align 4
291; FNATTRS-NEXT:    [[L:%.*]] = load i32, ptr [[PTR]], align 4
292; FNATTRS-NEXT:    store i32 [[L]], ptr [[A]], align 4
293; FNATTRS-NEXT:    [[L_2:%.*]] = load i32, ptr [[A]], align 4
294; FNATTRS-NEXT:    ret i32 [[L_2]]
295;
296; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite)
297; ATTRIBUTOR-LABEL: define i32 @test_read_arg_access_alloca
298; ATTRIBUTOR-SAME: (ptr nofree nonnull readonly captures(none) [[PTR:%.*]]) #[[ATTR8]] {
299; ATTRIBUTOR-NEXT:  entry:
300; ATTRIBUTOR-NEXT:    [[A:%.*]] = alloca i32, align 4
301; ATTRIBUTOR-NEXT:    [[L:%.*]] = load i32, ptr [[PTR]], align 4
302; ATTRIBUTOR-NEXT:    store i32 [[L]], ptr [[A]], align 4
303; ATTRIBUTOR-NEXT:    [[L_2:%.*]] = load i32, ptr [[A]], align 4
304; ATTRIBUTOR-NEXT:    ret i32 [[L_2]]
305;
306entry:
307  %a = alloca i32
308  %l = load i32, ptr %ptr
309  store i32 %l, ptr %a
310  %l.2 = load i32, ptr %a
311  ret i32 %l.2
312}
313
314declare void @fn_inaccessiblememonly() inaccessiblememonly
315
316define void @test_inaccessiblememonly() {
317; FNATTRS: Function Attrs: memory(inaccessiblemem: readwrite)
318; FNATTRS-LABEL: define void @test_inaccessiblememonly
319; FNATTRS-SAME: () #[[ATTR12:[0-9]+]] {
320; FNATTRS-NEXT:    call void @fn_inaccessiblememonly()
321; FNATTRS-NEXT:    ret void
322;
323; ATTRIBUTOR: Function Attrs: memory(inaccessiblemem: readwrite)
324; ATTRIBUTOR-LABEL: define void @test_inaccessiblememonly
325; ATTRIBUTOR-SAME: () #[[ATTR11:[0-9]+]] {
326; ATTRIBUTOR-NEXT:    call void @fn_inaccessiblememonly()
327; ATTRIBUTOR-NEXT:    ret void
328;
329  call void @fn_inaccessiblememonly()
330  ret void
331}
332
333define void @test_inaccessiblememonly_readonly() {
334; FNATTRS: Function Attrs: nofree memory(inaccessiblemem: read)
335; FNATTRS-LABEL: define void @test_inaccessiblememonly_readonly
336; FNATTRS-SAME: () #[[ATTR13:[0-9]+]] {
337; FNATTRS-NEXT:    call void @fn_inaccessiblememonly() #[[ATTR19:[0-9]+]]
338; FNATTRS-NEXT:    ret void
339;
340; ATTRIBUTOR: Function Attrs: nosync memory(inaccessiblemem: read)
341; ATTRIBUTOR-LABEL: define void @test_inaccessiblememonly_readonly
342; ATTRIBUTOR-SAME: () #[[ATTR12:[0-9]+]] {
343; ATTRIBUTOR-NEXT:    call void @fn_inaccessiblememonly() #[[ATTR21:[0-9]+]]
344; ATTRIBUTOR-NEXT:    ret void
345;
346  call void @fn_inaccessiblememonly() readonly
347  ret void
348}
349
350define void @test_inaccessibleorargmemonly_readonly(ptr %arg) {
351; FNATTRS: Function Attrs: nofree memory(argmem: read, inaccessiblemem: read)
352; FNATTRS-LABEL: define void @test_inaccessibleorargmemonly_readonly
353; FNATTRS-SAME: (ptr readonly captures(none) [[ARG:%.*]]) #[[ATTR14:[0-9]+]] {
354; FNATTRS-NEXT:    [[TMP1:%.*]] = load i32, ptr [[ARG]], align 4
355; FNATTRS-NEXT:    call void @fn_inaccessiblememonly() #[[ATTR19]]
356; FNATTRS-NEXT:    ret void
357;
358; ATTRIBUTOR: Function Attrs: nosync memory(argmem: read, inaccessiblemem: read)
359; ATTRIBUTOR-LABEL: define void @test_inaccessibleorargmemonly_readonly
360; ATTRIBUTOR-SAME: (ptr nofree nonnull readonly captures(none) [[ARG:%.*]]) #[[ATTR13:[0-9]+]] {
361; ATTRIBUTOR-NEXT:    [[TMP1:%.*]] = load i32, ptr [[ARG]], align 4
362; ATTRIBUTOR-NEXT:    call void @fn_inaccessiblememonly() #[[ATTR21]]
363; ATTRIBUTOR-NEXT:    ret void
364;
365  load i32, ptr %arg
366  call void @fn_inaccessiblememonly() readonly
367  ret void
368}
369
370define void @test_inaccessibleorargmemonly_readwrite(ptr %arg) {
371; FNATTRS: Function Attrs: memory(argmem: write, inaccessiblemem: read)
372; FNATTRS-LABEL: define void @test_inaccessibleorargmemonly_readwrite
373; FNATTRS-SAME: (ptr writeonly captures(none) initializes((0, 4)) [[ARG:%.*]]) #[[ATTR15:[0-9]+]] {
374; FNATTRS-NEXT:    store i32 0, ptr [[ARG]], align 4
375; FNATTRS-NEXT:    call void @fn_inaccessiblememonly() #[[ATTR19]]
376; FNATTRS-NEXT:    ret void
377;
378; ATTRIBUTOR: Function Attrs: nosync memory(argmem: readwrite, inaccessiblemem: readwrite)
379; ATTRIBUTOR-LABEL: define void @test_inaccessibleorargmemonly_readwrite
380; ATTRIBUTOR-SAME: (ptr nofree nonnull writeonly captures(none) [[ARG:%.*]]) #[[ATTR14:[0-9]+]] {
381; ATTRIBUTOR-NEXT:    store i32 0, ptr [[ARG]], align 4
382; ATTRIBUTOR-NEXT:    call void @fn_inaccessiblememonly() #[[ATTR21]]
383; ATTRIBUTOR-NEXT:    ret void
384;
385  store i32 0, ptr %arg
386  call void @fn_inaccessiblememonly() readonly
387  ret void
388}
389
390define void @test_recursive_argmem_read(ptr %p) {
391; FNATTRS: Function Attrs: nofree nosync nounwind memory(read, inaccessiblemem: none)
392; FNATTRS-LABEL: define void @test_recursive_argmem_read
393; FNATTRS-SAME: (ptr readonly captures(none) [[P:%.*]]) #[[ATTR16:[0-9]+]] {
394; FNATTRS-NEXT:    [[PVAL:%.*]] = load ptr, ptr [[P]], align 8
395; FNATTRS-NEXT:    call void @test_recursive_argmem_read(ptr [[PVAL]])
396; FNATTRS-NEXT:    ret void
397;
398; ATTRIBUTOR: Function Attrs: nofree nosync nounwind memory(read)
399; ATTRIBUTOR-LABEL: define void @test_recursive_argmem_read
400; ATTRIBUTOR-SAME: (ptr nofree nonnull readonly captures(none) [[P:%.*]]) #[[ATTR15:[0-9]+]] {
401; ATTRIBUTOR-NEXT:    [[PVAL:%.*]] = load ptr, ptr [[P]], align 8
402; ATTRIBUTOR-NEXT:    call void @test_recursive_argmem_read(ptr nofree readonly captures(none) [[PVAL]]) #[[ATTR15]]
403; ATTRIBUTOR-NEXT:    ret void
404;
405  %pval = load ptr, ptr %p
406  call void @test_recursive_argmem_read(ptr %pval)
407  ret void
408}
409
410define void @test_recursive_argmem_readwrite(ptr %p) {
411; FNATTRS: Function Attrs: nofree nosync nounwind memory(readwrite, inaccessiblemem: none)
412; FNATTRS-LABEL: define void @test_recursive_argmem_readwrite
413; FNATTRS-SAME: (ptr captures(none) [[P:%.*]]) #[[ATTR17:[0-9]+]] {
414; FNATTRS-NEXT:    [[PVAL:%.*]] = load ptr, ptr [[P]], align 8
415; FNATTRS-NEXT:    store i32 0, ptr [[P]], align 4
416; FNATTRS-NEXT:    call void @test_recursive_argmem_readwrite(ptr [[PVAL]])
417; FNATTRS-NEXT:    ret void
418;
419; ATTRIBUTOR: Function Attrs: nofree nosync nounwind
420; ATTRIBUTOR-LABEL: define void @test_recursive_argmem_readwrite
421; ATTRIBUTOR-SAME: (ptr nofree nonnull captures(none) [[P:%.*]]) #[[ATTR16:[0-9]+]] {
422; ATTRIBUTOR-NEXT:    [[PVAL:%.*]] = load ptr, ptr [[P]], align 8
423; ATTRIBUTOR-NEXT:    store i32 0, ptr [[P]], align 4
424; ATTRIBUTOR-NEXT:    call void @test_recursive_argmem_readwrite(ptr nofree captures(none) [[PVAL]]) #[[ATTR16]]
425; ATTRIBUTOR-NEXT:    ret void
426;
427  %pval = load ptr, ptr %p
428  store i32 0, ptr %p
429  call void @test_recursive_argmem_readwrite(ptr %pval)
430  ret void
431}
432
433define void @test_recursive_argmem_read_alloca(ptr %p) {
434; FNATTRS: Function Attrs: nofree nosync nounwind memory(argmem: read)
435; FNATTRS-LABEL: define void @test_recursive_argmem_read_alloca
436; FNATTRS-SAME: (ptr readonly captures(none) [[P:%.*]]) #[[ATTR18:[0-9]+]] {
437; FNATTRS-NEXT:    [[A:%.*]] = alloca ptr, align 8
438; FNATTRS-NEXT:    [[TMP1:%.*]] = load i32, ptr [[P]], align 4
439; FNATTRS-NEXT:    call void @test_recursive_argmem_read_alloca(ptr [[A]])
440; FNATTRS-NEXT:    ret void
441;
442; ATTRIBUTOR: Function Attrs: nofree nosync nounwind memory(argmem: read)
443; ATTRIBUTOR-LABEL: define void @test_recursive_argmem_read_alloca
444; ATTRIBUTOR-SAME: (ptr nofree nonnull readonly captures(none) [[P:%.*]]) #[[ATTR17:[0-9]+]] {
445; ATTRIBUTOR-NEXT:    [[A:%.*]] = alloca ptr, align 8
446; ATTRIBUTOR-NEXT:    [[TMP1:%.*]] = load i32, ptr [[P]], align 4
447; ATTRIBUTOR-NEXT:    call void @test_recursive_argmem_read_alloca(ptr nofree nonnull readonly captures(none) [[A]]) #[[ATTR15]]
448; ATTRIBUTOR-NEXT:    ret void
449;
450  %a = alloca ptr
451  load i32, ptr %p
452  call void @test_recursive_argmem_read_alloca(ptr %a)
453  ret void
454}
455
456define void @test_scc_argmem_read_1(ptr %p) {
457; FNATTRS: Function Attrs: nofree nosync nounwind memory(read, inaccessiblemem: none)
458; FNATTRS-LABEL: define void @test_scc_argmem_read_1
459; FNATTRS-SAME: (ptr readonly captures(none) [[P:%.*]]) #[[ATTR16]] {
460; FNATTRS-NEXT:    [[PVAL:%.*]] = load ptr, ptr [[P]], align 8
461; FNATTRS-NEXT:    call void @test_scc_argmem_read_2(ptr [[PVAL]])
462; FNATTRS-NEXT:    ret void
463;
464; ATTRIBUTOR: Function Attrs: nofree nosync nounwind memory(read)
465; ATTRIBUTOR-LABEL: define void @test_scc_argmem_read_1
466; ATTRIBUTOR-SAME: (ptr nofree nonnull readonly captures(none) [[P:%.*]]) #[[ATTR15]] {
467; ATTRIBUTOR-NEXT:    [[PVAL:%.*]] = load ptr, ptr [[P]], align 8
468; ATTRIBUTOR-NEXT:    call void @test_scc_argmem_read_2(ptr nofree readonly captures(none) [[PVAL]]) #[[ATTR15]]
469; ATTRIBUTOR-NEXT:    ret void
470;
471  %pval = load ptr, ptr %p
472  call void @test_scc_argmem_read_2(ptr %pval)
473  ret void
474}
475
476define void @test_scc_argmem_read_2(ptr %p) {
477; FNATTRS: Function Attrs: nofree nosync nounwind memory(read, inaccessiblemem: none)
478; FNATTRS-LABEL: define void @test_scc_argmem_read_2
479; FNATTRS-SAME: (ptr readonly captures(none) [[P:%.*]]) #[[ATTR16]] {
480; FNATTRS-NEXT:    call void @test_scc_argmem_read_1(ptr [[P]])
481; FNATTRS-NEXT:    ret void
482;
483; ATTRIBUTOR: Function Attrs: nofree nosync nounwind memory(read)
484; ATTRIBUTOR-LABEL: define void @test_scc_argmem_read_2
485; ATTRIBUTOR-SAME: (ptr nofree readonly captures(none) [[P:%.*]]) #[[ATTR15]] {
486; ATTRIBUTOR-NEXT:    call void @test_scc_argmem_read_1(ptr nofree readonly captures(none) [[P]]) #[[ATTR15]]
487; ATTRIBUTOR-NEXT:    ret void
488;
489  call void @test_scc_argmem_read_1(ptr %p)
490  ret void
491}
492
493define i64 @select_same_obj(i1 %c, ptr %p, i64 %x) {
494; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read)
495; FNATTRS-LABEL: define i64 @select_same_obj
496; FNATTRS-SAME: (i1 [[C:%.*]], ptr readonly captures(none) [[P:%.*]], i64 [[X:%.*]]) #[[ATTR1]] {
497; FNATTRS-NEXT:  entry:
498; FNATTRS-NEXT:    [[P2:%.*]] = getelementptr i8, ptr [[P]], i64 [[X]]
499; FNATTRS-NEXT:    [[P3:%.*]] = select i1 [[C]], ptr [[P]], ptr [[P2]]
500; FNATTRS-NEXT:    [[R:%.*]] = load i64, ptr [[P3]], align 4
501; FNATTRS-NEXT:    ret i64 [[R]]
502;
503; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
504; ATTRIBUTOR-LABEL: define i64 @select_same_obj
505; ATTRIBUTOR-SAME: (i1 [[C:%.*]], ptr nofree readonly captures(none) [[P:%.*]], i64 [[X:%.*]]) #[[ATTR0]] {
506; ATTRIBUTOR-NEXT:  entry:
507; ATTRIBUTOR-NEXT:    [[P2:%.*]] = getelementptr i8, ptr [[P]], i64 [[X]]
508; ATTRIBUTOR-NEXT:    [[P3:%.*]] = select i1 [[C]], ptr [[P]], ptr [[P2]]
509; ATTRIBUTOR-NEXT:    [[R:%.*]] = load i64, ptr [[P3]], align 4
510; ATTRIBUTOR-NEXT:    ret i64 [[R]]
511;
512entry:
513  %p2 = getelementptr i8, ptr %p, i64 %x
514  %p3 = select i1 %c, ptr %p, ptr %p2
515  %r = load i64, ptr %p3
516  ret i64 %r
517}
518
519; FIXME: This could be `memory(argmem: read)`.
520define i64 @select_different_obj(i1 %c, ptr %p, ptr %p2) {
521; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(read, inaccessiblemem: none)
522; FNATTRS-LABEL: define i64 @select_different_obj
523; FNATTRS-SAME: (i1 [[C:%.*]], ptr readonly captures(none) [[P:%.*]], ptr readonly captures(none) [[P2:%.*]]) #[[ATTR3]] {
524; FNATTRS-NEXT:  entry:
525; FNATTRS-NEXT:    [[P3:%.*]] = select i1 [[C]], ptr [[P]], ptr [[P2]]
526; FNATTRS-NEXT:    [[R:%.*]] = load i64, ptr [[P3]], align 4
527; FNATTRS-NEXT:    ret i64 [[R]]
528;
529; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
530; ATTRIBUTOR-LABEL: define i64 @select_different_obj
531; ATTRIBUTOR-SAME: (i1 [[C:%.*]], ptr nofree readonly captures(none) [[P:%.*]], ptr nofree readonly captures(none) [[P2:%.*]]) #[[ATTR0]] {
532; ATTRIBUTOR-NEXT:  entry:
533; ATTRIBUTOR-NEXT:    [[P3:%.*]] = select i1 [[C]], ptr [[P]], ptr [[P2]]
534; ATTRIBUTOR-NEXT:    [[R:%.*]] = load i64, ptr [[P3]], align 4
535; ATTRIBUTOR-NEXT:    ret i64 [[R]]
536;
537entry:
538  %p3 = select i1 %c, ptr %p, ptr %p2
539  %r = load i64, ptr %p3
540  ret i64 %r
541}
542
543define i64 @phi_same_obj(i1 %c, ptr %p, i64 %x) {
544; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read)
545; FNATTRS-LABEL: define i64 @phi_same_obj
546; FNATTRS-SAME: (i1 [[C:%.*]], ptr readonly captures(none) [[P:%.*]], i64 [[X:%.*]]) #[[ATTR1]] {
547; FNATTRS-NEXT:  entry:
548; FNATTRS-NEXT:    [[P2:%.*]] = getelementptr i8, ptr [[P]], i64 [[X]]
549; FNATTRS-NEXT:    br i1 [[C]], label [[IF:%.*]], label [[JOIN:%.*]]
550; FNATTRS:       if:
551; FNATTRS-NEXT:    br label [[JOIN]]
552; FNATTRS:       join:
553; FNATTRS-NEXT:    [[P3:%.*]] = phi ptr [ [[P]], [[IF]] ], [ [[P2]], [[ENTRY:%.*]] ]
554; FNATTRS-NEXT:    [[R:%.*]] = load i64, ptr [[P3]], align 4
555; FNATTRS-NEXT:    ret i64 [[R]]
556;
557; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read)
558; ATTRIBUTOR-LABEL: define i64 @phi_same_obj
559; ATTRIBUTOR-SAME: (i1 [[C:%.*]], ptr nofree readonly captures(none) [[P:%.*]], i64 [[X:%.*]]) #[[ATTR1]] {
560; ATTRIBUTOR-NEXT:  entry:
561; ATTRIBUTOR-NEXT:    [[P2:%.*]] = getelementptr i8, ptr [[P]], i64 [[X]]
562; ATTRIBUTOR-NEXT:    br i1 [[C]], label [[IF:%.*]], label [[JOIN:%.*]]
563; ATTRIBUTOR:       if:
564; ATTRIBUTOR-NEXT:    br label [[JOIN]]
565; ATTRIBUTOR:       join:
566; ATTRIBUTOR-NEXT:    [[P3:%.*]] = phi ptr [ [[P]], [[IF]] ], [ [[P2]], [[ENTRY:%.*]] ]
567; ATTRIBUTOR-NEXT:    [[R:%.*]] = load i64, ptr [[P3]], align 4
568; ATTRIBUTOR-NEXT:    ret i64 [[R]]
569;
570entry:
571  %p2 = getelementptr i8, ptr %p, i64 %x
572  br i1 %c, label %if, label %join
573if:
574  br label %join
575join:
576  %p3 = phi ptr [ %p, %if ], [ %p2, %entry ]
577  %r = load i64, ptr %p3
578  ret i64 %r
579}
580
581; FIXME: This could be `memory(argmem: read)`.
582define i64 @phi_different_obj(i1 %c, ptr %p, ptr %p2) {
583; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(read, inaccessiblemem: none)
584; FNATTRS-LABEL: define i64 @phi_different_obj
585; FNATTRS-SAME: (i1 [[C:%.*]], ptr readonly captures(none) [[P:%.*]], ptr readonly captures(none) [[P2:%.*]]) #[[ATTR3]] {
586; FNATTRS-NEXT:  entry:
587; FNATTRS-NEXT:    br i1 [[C]], label [[IF:%.*]], label [[JOIN:%.*]]
588; FNATTRS:       if:
589; FNATTRS-NEXT:    br label [[JOIN]]
590; FNATTRS:       join:
591; FNATTRS-NEXT:    [[P3:%.*]] = phi ptr [ [[P]], [[IF]] ], [ [[P2]], [[ENTRY:%.*]] ]
592; FNATTRS-NEXT:    [[R:%.*]] = load i64, ptr [[P3]], align 4
593; FNATTRS-NEXT:    ret i64 [[R]]
594;
595; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read)
596; ATTRIBUTOR-LABEL: define i64 @phi_different_obj
597; ATTRIBUTOR-SAME: (i1 [[C:%.*]], ptr nofree readonly captures(none) [[P:%.*]], ptr nofree readonly captures(none) [[P2:%.*]]) #[[ATTR1]] {
598; ATTRIBUTOR-NEXT:  entry:
599; ATTRIBUTOR-NEXT:    br i1 [[C]], label [[IF:%.*]], label [[JOIN:%.*]]
600; ATTRIBUTOR:       if:
601; ATTRIBUTOR-NEXT:    br label [[JOIN]]
602; ATTRIBUTOR:       join:
603; ATTRIBUTOR-NEXT:    [[P3:%.*]] = phi ptr [ [[P]], [[IF]] ], [ [[P2]], [[ENTRY:%.*]] ]
604; ATTRIBUTOR-NEXT:    [[R:%.*]] = load i64, ptr [[P3]], align 4
605; ATTRIBUTOR-NEXT:    ret i64 [[R]]
606;
607entry:
608  br i1 %c, label %if, label %join
609if:
610  br label %join
611join:
612  %p3 = phi ptr [ %p, %if ], [ %p2, %entry ]
613  %r = load i64, ptr %p3
614  ret i64 %r
615}
616
617; An `alloca` that won't be handled by `getModRefInfoMask`
618define i64 @alloca_with_phis(i64 %arg, i1 %cmp) {
619; COMMON: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
620; COMMON-LABEL: define i64 @alloca_with_phis
621; COMMON-SAME: (i64 [[ARG:%.*]], i1 [[CMP:%.*]]) #[[ATTR0]] {
622; COMMON-NEXT:  bb:
623; COMMON-NEXT:    [[I:%.*]] = alloca i64, align 8
624; COMMON-NEXT:    store i64 [[ARG]], ptr [[I]], align 4
625; COMMON-NEXT:    br i1 [[CMP]], label [[BB1:%.*]], label [[BB4:%.*]]
626; COMMON:       bb1:
627; COMMON-NEXT:    br i1 [[CMP]], label [[BB8:%.*]], label [[BB2:%.*]]
628; COMMON:       bb2:
629; COMMON-NEXT:    br i1 [[CMP]], label [[BB8]], label [[BB3:%.*]]
630; COMMON:       bb3:
631; COMMON-NEXT:    br i1 [[CMP]], label [[BB8]], label [[BB6:%.*]]
632; COMMON:       bb4:
633; COMMON-NEXT:    br i1 [[CMP]], label [[BB8]], label [[BB5:%.*]]
634; COMMON:       bb5:
635; COMMON-NEXT:    br i1 [[CMP]], label [[BB8]], label [[BB6]]
636; COMMON:       bb6:
637; COMMON-NEXT:    [[I7:%.*]] = phi ptr [ [[I]], [[BB3]] ], [ [[I]], [[BB5]] ]
638; COMMON-NEXT:    br label [[BB8]]
639; COMMON:       bb8:
640; COMMON-NEXT:    [[I9:%.*]] = phi ptr [ [[I]], [[BB1]] ], [ [[I]], [[BB2]] ], [ [[I]], [[BB3]] ], [ [[I]], [[BB4]] ], [ [[I]], [[BB5]] ], [ [[I7]], [[BB6]] ]
641; COMMON-NEXT:    [[RET:%.*]] = load i64, ptr [[I9]], align 4
642; COMMON-NEXT:    ret i64 [[RET]]
643;
644bb:
645  %i = alloca i64
646  store i64 %arg, ptr %i
647  br i1 %cmp, label %bb1, label %bb4
648
649bb1:                                              ; preds = %bb
650  br i1 %cmp, label %bb8, label %bb2
651
652bb2:                                              ; preds = %bb1
653  br i1 %cmp, label %bb8, label %bb3
654
655bb3:                                              ; preds = %bb2
656  br i1 %cmp, label %bb8, label %bb6
657
658bb4:                                              ; preds = %bb
659  br i1 %cmp, label %bb8, label %bb5
660
661bb5:                                              ; preds = %bb4
662  br i1 %cmp, label %bb8, label %bb6
663
664bb6:                                              ; preds = %bb5, %bb3
665  %i7 = phi ptr [ %i, %bb3 ], [ %i, %bb5 ]
666  br label %bb8
667
668bb8:                                              ; preds = %bb6, %bb5, %bb4, %bb3, %bb2, %bb1
669  %i9 = phi ptr [ %i, %bb1 ], [ %i, %bb2 ], [ %i, %bb3 ], [ %i, %bb4 ], [ %i, %bb5 ], [ %i7, %bb6 ]
670  %ret = load i64, ptr %i9
671  ret i64 %ret
672}
673