xref: /llvm-project/llvm/test/Transforms/FunctionAttrs/nocapture.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 ptr null		; <ptr> [#uses=1]
6
7define ptr @c1(ptr %q) {
8; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
9; FNATTRS-LABEL: define ptr @c1
10; FNATTRS-SAME: (ptr readnone returned [[Q:%.*]]) #[[ATTR0:[0-9]+]] {
11; FNATTRS-NEXT:    ret ptr [[Q]]
12;
13; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
14; ATTRIBUTOR-LABEL: define ptr @c1
15; ATTRIBUTOR-SAME: (ptr nofree readnone [[Q:%.*]]) #[[ATTR0:[0-9]+]] {
16; ATTRIBUTOR-NEXT:    ret ptr [[Q]]
17;
18  ret ptr %q
19}
20
21; It would also be acceptable to mark %q as readnone. Update @c3 too.
22define void @c2(ptr %q) {
23; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(write, argmem: none, inaccessiblemem: none)
24; FNATTRS-LABEL: define void @c2
25; FNATTRS-SAME: (ptr [[Q:%.*]]) #[[ATTR1:[0-9]+]] {
26; FNATTRS-NEXT:    store ptr [[Q]], ptr @g, align 8
27; FNATTRS-NEXT:    ret void
28;
29; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(write)
30; ATTRIBUTOR-LABEL: define void @c2
31; ATTRIBUTOR-SAME: (ptr nofree writeonly [[Q:%.*]]) #[[ATTR1:[0-9]+]] {
32; ATTRIBUTOR-NEXT:    store ptr [[Q]], ptr @g, align 8
33; ATTRIBUTOR-NEXT:    ret void
34;
35  store ptr %q, ptr @g
36  ret void
37}
38
39define void @c3(ptr %q) {
40; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(write, inaccessiblemem: none)
41; FNATTRS-LABEL: define void @c3
42; FNATTRS-SAME: (ptr [[Q:%.*]]) #[[ATTR2:[0-9]+]] {
43; FNATTRS-NEXT:    call void @c2(ptr [[Q]])
44; FNATTRS-NEXT:    ret void
45;
46; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(write)
47; ATTRIBUTOR-LABEL: define void @c3
48; ATTRIBUTOR-SAME: (ptr nofree writeonly [[Q:%.*]]) #[[ATTR1]] {
49; ATTRIBUTOR-NEXT:    call void @c2(ptr nofree writeonly [[Q]]) #[[ATTR16:[0-9]+]]
50; ATTRIBUTOR-NEXT:    ret void
51;
52  call void @c2(ptr %q)
53  ret void
54}
55
56define i1 @c4(ptr %q, i32 %bitno) {
57; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
58; FNATTRS-LABEL: define noundef i1 @c4
59; FNATTRS-SAME: (ptr [[Q:%.*]], i32 [[BITNO:%.*]]) #[[ATTR0]] {
60; FNATTRS-NEXT:    [[TMP:%.*]] = ptrtoint ptr [[Q]] to i32
61; FNATTRS-NEXT:    [[TMP2:%.*]] = lshr i32 [[TMP]], [[BITNO]]
62; FNATTRS-NEXT:    [[BIT:%.*]] = trunc i32 [[TMP2]] to i1
63; FNATTRS-NEXT:    br i1 [[BIT]], label [[L1:%.*]], label [[L0:%.*]]
64; FNATTRS:       l0:
65; FNATTRS-NEXT:    ret i1 false
66; FNATTRS:       l1:
67; FNATTRS-NEXT:    ret i1 true
68;
69; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
70; ATTRIBUTOR-LABEL: define i1 @c4
71; ATTRIBUTOR-SAME: (ptr nofree readnone [[Q:%.*]], i32 [[BITNO:%.*]]) #[[ATTR0]] {
72; ATTRIBUTOR-NEXT:    [[TMP:%.*]] = ptrtoint ptr [[Q]] to i32
73; ATTRIBUTOR-NEXT:    [[TMP2:%.*]] = lshr i32 [[TMP]], [[BITNO]]
74; ATTRIBUTOR-NEXT:    [[BIT:%.*]] = trunc i32 [[TMP2]] to i1
75; ATTRIBUTOR-NEXT:    br i1 [[BIT]], label [[L1:%.*]], label [[L0:%.*]]
76; ATTRIBUTOR:       l0:
77; ATTRIBUTOR-NEXT:    ret i1 false
78; ATTRIBUTOR:       l1:
79; ATTRIBUTOR-NEXT:    ret i1 true
80;
81  %tmp = ptrtoint ptr %q to i32
82  %tmp2 = lshr i32 %tmp, %bitno
83  %bit = trunc i32 %tmp2 to i1
84  br i1 %bit, label %l1, label %l0
85l0:
86  ret i1 0 ; escaping value not caught by def-use chaining.
87l1:
88  ret i1 1 ; escaping value not caught by def-use chaining.
89}
90
91; c4b is c4 but without the escaping part
92define i1 @c4b(ptr %q, i32 %bitno) {
93; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
94; FNATTRS-LABEL: define noundef i1 @c4b
95; FNATTRS-SAME: (ptr [[Q:%.*]], i32 [[BITNO:%.*]]) #[[ATTR0]] {
96; FNATTRS-NEXT:    [[TMP:%.*]] = ptrtoint ptr [[Q]] to i32
97; FNATTRS-NEXT:    [[TMP2:%.*]] = lshr i32 [[TMP]], [[BITNO]]
98; FNATTRS-NEXT:    [[BIT:%.*]] = trunc i32 [[TMP2]] to i1
99; FNATTRS-NEXT:    br i1 [[BIT]], label [[L1:%.*]], label [[L0:%.*]]
100; FNATTRS:       l0:
101; FNATTRS-NEXT:    ret i1 false
102; FNATTRS:       l1:
103; FNATTRS-NEXT:    ret i1 false
104;
105; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
106; ATTRIBUTOR-LABEL: define i1 @c4b
107; ATTRIBUTOR-SAME: (ptr nofree readnone [[Q:%.*]], i32 [[BITNO:%.*]]) #[[ATTR0]] {
108; ATTRIBUTOR-NEXT:    [[TMP:%.*]] = ptrtoint ptr [[Q]] to i32
109; ATTRIBUTOR-NEXT:    [[TMP2:%.*]] = lshr i32 [[TMP]], [[BITNO]]
110; ATTRIBUTOR-NEXT:    [[BIT:%.*]] = trunc i32 [[TMP2]] to i1
111; ATTRIBUTOR-NEXT:    br i1 [[BIT]], label [[L1:%.*]], label [[L0:%.*]]
112; ATTRIBUTOR:       l0:
113; ATTRIBUTOR-NEXT:    ret i1 false
114; ATTRIBUTOR:       l1:
115; ATTRIBUTOR-NEXT:    ret i1 false
116;
117  %tmp = ptrtoint ptr %q to i32
118  %tmp2 = lshr i32 %tmp, %bitno
119  %bit = trunc i32 %tmp2 to i1
120  br i1 %bit, label %l1, label %l0
121l0:
122  ret i1 0 ; not escaping!
123l1:
124  ret i1 0 ; not escaping!
125}
126
127@lookup_table = global [2 x i1] [ i1 0, i1 1 ]
128
129define i1 @c5(ptr %q, i32 %bitno) {
130; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(read, argmem: none, inaccessiblemem: none)
131; FNATTRS-LABEL: define i1 @c5
132; FNATTRS-SAME: (ptr [[Q:%.*]], i32 [[BITNO:%.*]]) #[[ATTR3:[0-9]+]] {
133; FNATTRS-NEXT:    [[TMP:%.*]] = ptrtoint ptr [[Q]] to i32
134; FNATTRS-NEXT:    [[TMP2:%.*]] = lshr i32 [[TMP]], [[BITNO]]
135; FNATTRS-NEXT:    [[BIT:%.*]] = and i32 [[TMP2]], 1
136; FNATTRS-NEXT:    [[LOOKUP:%.*]] = getelementptr [2 x i1], ptr @lookup_table, i32 0, i32 [[BIT]]
137; FNATTRS-NEXT:    [[VAL:%.*]] = load i1, ptr [[LOOKUP]], align 1
138; FNATTRS-NEXT:    ret i1 [[VAL]]
139;
140; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(read)
141; ATTRIBUTOR-LABEL: define i1 @c5
142; ATTRIBUTOR-SAME: (ptr nofree readonly [[Q:%.*]], i32 [[BITNO:%.*]]) #[[ATTR2:[0-9]+]] {
143; ATTRIBUTOR-NEXT:    [[TMP:%.*]] = ptrtoint ptr [[Q]] to i32
144; ATTRIBUTOR-NEXT:    [[TMP2:%.*]] = lshr i32 [[TMP]], [[BITNO]]
145; ATTRIBUTOR-NEXT:    [[BIT:%.*]] = and i32 [[TMP2]], 1
146; ATTRIBUTOR-NEXT:    [[LOOKUP:%.*]] = getelementptr [2 x i1], ptr @lookup_table, i32 0, i32 [[BIT]]
147; ATTRIBUTOR-NEXT:    [[VAL:%.*]] = load i1, ptr [[LOOKUP]], align 1
148; ATTRIBUTOR-NEXT:    ret i1 [[VAL]]
149;
150  %tmp = ptrtoint ptr %q to i32
151  %tmp2 = lshr i32 %tmp, %bitno
152  %bit = and i32 %tmp2, 1
153  ; subtle escape mechanism follows
154  %lookup = getelementptr [2 x i1], ptr @lookup_table, i32 0, i32 %bit
155  %val = load i1, ptr %lookup
156  ret i1 %val
157}
158
159declare void @throw_if_bit_set(ptr, i8) readonly
160
161define i1 @c6(ptr %q, i8 %bit) personality ptr @__gxx_personality_v0 {
162; FNATTRS: Function Attrs: nofree memory(read)
163; FNATTRS-LABEL: define noundef i1 @c6
164; FNATTRS-SAME: (ptr readonly [[Q:%.*]], i8 [[BIT:%.*]]) #[[ATTR5:[0-9]+]] personality ptr @__gxx_personality_v0 {
165; FNATTRS-NEXT:    invoke void @throw_if_bit_set(ptr [[Q]], i8 [[BIT]])
166; FNATTRS-NEXT:            to label [[RET0:%.*]] unwind label [[RET1:%.*]]
167; FNATTRS:       ret0:
168; FNATTRS-NEXT:    ret i1 false
169; FNATTRS:       ret1:
170; FNATTRS-NEXT:    [[EXN:%.*]] = landingpad { ptr, i32 }
171; FNATTRS-NEXT:            cleanup
172; FNATTRS-NEXT:    ret i1 true
173;
174; ATTRIBUTOR: Function Attrs: nosync memory(read)
175; ATTRIBUTOR-LABEL: define i1 @c6
176; ATTRIBUTOR-SAME: (ptr readonly [[Q:%.*]], i8 [[BIT:%.*]]) #[[ATTR4:[0-9]+]] personality ptr @__gxx_personality_v0 {
177; ATTRIBUTOR-NEXT:    invoke void @throw_if_bit_set(ptr [[Q]], i8 [[BIT]]) #[[ATTR4]]
178; ATTRIBUTOR-NEXT:            to label [[RET0:%.*]] unwind label [[RET1:%.*]]
179; ATTRIBUTOR:       ret0:
180; ATTRIBUTOR-NEXT:    ret i1 false
181; ATTRIBUTOR:       ret1:
182; ATTRIBUTOR-NEXT:    [[EXN:%.*]] = landingpad { ptr, i32 }
183; ATTRIBUTOR-NEXT:            cleanup
184; ATTRIBUTOR-NEXT:    ret i1 true
185;
186  invoke void @throw_if_bit_set(ptr %q, i8 %bit)
187  to label %ret0 unwind label %ret1
188ret0:
189  ret i1 0
190ret1:
191  %exn = landingpad {ptr, i32}
192  cleanup
193  ret i1 1
194}
195
196declare i32 @__gxx_personality_v0(...)
197
198define ptr @lookup_bit(ptr %q, i32 %bitno) readnone nounwind {
199; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
200; FNATTRS-LABEL: define ptr @lookup_bit
201; FNATTRS-SAME: (ptr [[Q:%.*]], i32 [[BITNO:%.*]]) #[[ATTR0]] {
202; FNATTRS-NEXT:    [[TMP:%.*]] = ptrtoint ptr [[Q]] to i32
203; FNATTRS-NEXT:    [[TMP2:%.*]] = lshr i32 [[TMP]], [[BITNO]]
204; FNATTRS-NEXT:    [[BIT:%.*]] = and i32 [[TMP2]], 1
205; FNATTRS-NEXT:    [[LOOKUP:%.*]] = getelementptr [2 x i1], ptr @lookup_table, i32 0, i32 [[BIT]]
206; FNATTRS-NEXT:    ret ptr [[LOOKUP]]
207;
208; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
209; ATTRIBUTOR-LABEL: define ptr @lookup_bit
210; ATTRIBUTOR-SAME: (ptr nofree readnone [[Q:%.*]], i32 [[BITNO:%.*]]) #[[ATTR0]] {
211; ATTRIBUTOR-NEXT:    [[TMP:%.*]] = ptrtoint ptr [[Q]] to i32
212; ATTRIBUTOR-NEXT:    [[TMP2:%.*]] = lshr i32 [[TMP]], [[BITNO]]
213; ATTRIBUTOR-NEXT:    [[BIT:%.*]] = and i32 [[TMP2]], 1
214; ATTRIBUTOR-NEXT:    [[LOOKUP:%.*]] = getelementptr [2 x i1], ptr @lookup_table, i32 0, i32 [[BIT]]
215; ATTRIBUTOR-NEXT:    ret ptr [[LOOKUP]]
216;
217  %tmp = ptrtoint ptr %q to i32
218  %tmp2 = lshr i32 %tmp, %bitno
219  %bit = and i32 %tmp2, 1
220  %lookup = getelementptr [2 x i1], ptr @lookup_table, i32 0, i32 %bit
221  ret ptr %lookup
222}
223
224define i1 @c7(ptr %q, i32 %bitno) {
225; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(read, inaccessiblemem: none)
226; FNATTRS-LABEL: define i1 @c7
227; FNATTRS-SAME: (ptr readonly [[Q:%.*]], i32 [[BITNO:%.*]]) #[[ATTR6:[0-9]+]] {
228; FNATTRS-NEXT:    [[PTR:%.*]] = call ptr @lookup_bit(ptr [[Q]], i32 [[BITNO]])
229; FNATTRS-NEXT:    [[VAL:%.*]] = load i1, ptr [[PTR]], align 1
230; FNATTRS-NEXT:    ret i1 [[VAL]]
231;
232; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(read)
233; ATTRIBUTOR-LABEL: define i1 @c7
234; ATTRIBUTOR-SAME: (ptr nofree readonly [[Q:%.*]], i32 [[BITNO:%.*]]) #[[ATTR2]] {
235; ATTRIBUTOR-NEXT:    [[PTR:%.*]] = call ptr @lookup_bit(ptr nofree readnone [[Q]], i32 [[BITNO]]) #[[ATTR17:[0-9]+]]
236; ATTRIBUTOR-NEXT:    [[VAL:%.*]] = load i1, ptr [[PTR]], align 1
237; ATTRIBUTOR-NEXT:    ret i1 [[VAL]]
238;
239  %ptr = call ptr @lookup_bit(ptr %q, i32 %bitno)
240  %val = load i1, ptr %ptr
241  ret i1 %val
242}
243
244
245define i32 @nc1(ptr %q, ptr %p, i1 %b) {
246; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(readwrite, inaccessiblemem: none)
247; FNATTRS-LABEL: define i32 @nc1
248; FNATTRS-SAME: (ptr [[Q:%.*]], ptr captures(none) [[P:%.*]], i1 [[B:%.*]]) #[[ATTR7:[0-9]+]] {
249; FNATTRS-NEXT:  e:
250; FNATTRS-NEXT:    br label [[L:%.*]]
251; FNATTRS:       l:
252; FNATTRS-NEXT:    [[X:%.*]] = phi ptr [ [[P]], [[E:%.*]] ]
253; FNATTRS-NEXT:    [[Y:%.*]] = phi ptr [ [[Q]], [[E]] ]
254; FNATTRS-NEXT:    [[TMP2:%.*]] = select i1 [[B]], ptr [[X]], ptr [[Y]]
255; FNATTRS-NEXT:    [[VAL:%.*]] = load i32, ptr [[TMP2]], align 4
256; FNATTRS-NEXT:    store i32 0, ptr [[X]], align 4
257; FNATTRS-NEXT:    store ptr [[Y]], ptr @g, align 8
258; FNATTRS-NEXT:    ret i32 [[VAL]]
259;
260; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn
261; ATTRIBUTOR-LABEL: define i32 @nc1
262; ATTRIBUTOR-SAME: (ptr nofree [[Q:%.*]], ptr nofree captures(none) [[P:%.*]], i1 [[B:%.*]]) #[[ATTR5:[0-9]+]] {
263; ATTRIBUTOR-NEXT:  e:
264; ATTRIBUTOR-NEXT:    br label [[L:%.*]]
265; ATTRIBUTOR:       l:
266; ATTRIBUTOR-NEXT:    [[X:%.*]] = phi ptr [ [[P]], [[E:%.*]] ]
267; ATTRIBUTOR-NEXT:    [[Y:%.*]] = phi ptr [ [[Q]], [[E]] ]
268; ATTRIBUTOR-NEXT:    [[TMP2:%.*]] = select i1 [[B]], ptr [[X]], ptr [[Y]]
269; ATTRIBUTOR-NEXT:    [[VAL:%.*]] = load i32, ptr [[TMP2]], align 4
270; ATTRIBUTOR-NEXT:    store i32 0, ptr [[X]], align 4
271; ATTRIBUTOR-NEXT:    store ptr [[Y]], ptr @g, align 8
272; ATTRIBUTOR-NEXT:    ret i32 [[VAL]]
273;
274e:
275  br label %l
276l:
277  %x = phi ptr [ %p, %e ]
278  %y = phi ptr [ %q, %e ]
279  %tmp2 = select i1 %b, ptr %x, ptr %y
280  %val = load i32, ptr %tmp2		; <i32> [#uses=1]
281  store i32 0, ptr %x
282  store ptr %y, ptr @g
283  ret i32 %val
284}
285
286define i32 @nc1_addrspace(ptr %q, ptr addrspace(1) %p, i1 %b) {
287; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(readwrite, inaccessiblemem: none)
288; FNATTRS-LABEL: define i32 @nc1_addrspace
289; FNATTRS-SAME: (ptr [[Q:%.*]], ptr addrspace(1) captures(none) [[P:%.*]], i1 [[B:%.*]]) #[[ATTR7]] {
290; FNATTRS-NEXT:  e:
291; FNATTRS-NEXT:    br label [[L:%.*]]
292; FNATTRS:       l:
293; FNATTRS-NEXT:    [[X:%.*]] = phi ptr addrspace(1) [ [[P]], [[E:%.*]] ]
294; FNATTRS-NEXT:    [[Y:%.*]] = phi ptr [ [[Q]], [[E]] ]
295; FNATTRS-NEXT:    [[TMP:%.*]] = addrspacecast ptr addrspace(1) [[X]] to ptr
296; FNATTRS-NEXT:    [[TMP2:%.*]] = select i1 [[B]], ptr [[TMP]], ptr [[Y]]
297; FNATTRS-NEXT:    [[VAL:%.*]] = load i32, ptr [[TMP2]], align 4
298; FNATTRS-NEXT:    store i32 0, ptr [[TMP]], align 4
299; FNATTRS-NEXT:    store ptr [[Y]], ptr @g, align 8
300; FNATTRS-NEXT:    ret i32 [[VAL]]
301;
302; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn
303; ATTRIBUTOR-LABEL: define i32 @nc1_addrspace
304; ATTRIBUTOR-SAME: (ptr nofree [[Q:%.*]], ptr addrspace(1) nofree captures(none) [[P:%.*]], i1 [[B:%.*]]) #[[ATTR5]] {
305; ATTRIBUTOR-NEXT:  e:
306; ATTRIBUTOR-NEXT:    br label [[L:%.*]]
307; ATTRIBUTOR:       l:
308; ATTRIBUTOR-NEXT:    [[X:%.*]] = phi ptr addrspace(1) [ [[P]], [[E:%.*]] ]
309; ATTRIBUTOR-NEXT:    [[Y:%.*]] = phi ptr [ [[Q]], [[E]] ]
310; ATTRIBUTOR-NEXT:    [[TMP:%.*]] = addrspacecast ptr addrspace(1) [[X]] to ptr
311; ATTRIBUTOR-NEXT:    [[TMP2:%.*]] = select i1 [[B]], ptr [[TMP]], ptr [[Y]]
312; ATTRIBUTOR-NEXT:    [[VAL:%.*]] = load i32, ptr [[TMP2]], align 4
313; ATTRIBUTOR-NEXT:    store i32 0, ptr [[TMP]], align 4
314; ATTRIBUTOR-NEXT:    store ptr [[Y]], ptr @g, align 8
315; ATTRIBUTOR-NEXT:    ret i32 [[VAL]]
316;
317e:
318  br label %l
319l:
320  %x = phi ptr addrspace(1) [ %p, %e ]
321  %y = phi ptr [ %q, %e ]
322  %tmp = addrspacecast ptr addrspace(1) %x to ptr		; <ptr> [#uses=2]
323  %tmp2 = select i1 %b, ptr %tmp, ptr %y
324  %val = load i32, ptr %tmp2		; <i32> [#uses=1]
325  store i32 0, ptr %tmp
326  store ptr %y, ptr @g
327  ret i32 %val
328}
329
330define void @nc2(ptr %p, ptr %q) {
331; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(readwrite, inaccessiblemem: none)
332; FNATTRS-LABEL: define void @nc2
333; FNATTRS-SAME: (ptr captures(none) [[P:%.*]], ptr [[Q:%.*]]) #[[ATTR7]] {
334; FNATTRS-NEXT:    [[TMP1:%.*]] = call i32 @nc1(ptr [[Q]], ptr [[P]], i1 false)
335; FNATTRS-NEXT:    ret void
336;
337; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn
338; ATTRIBUTOR-LABEL: define void @nc2
339; ATTRIBUTOR-SAME: (ptr nofree captures(none) [[P:%.*]], ptr nofree [[Q:%.*]]) #[[ATTR5]] {
340; ATTRIBUTOR-NEXT:    [[TMP1:%.*]] = call i32 @nc1(ptr nofree [[Q]], ptr nofree captures(none) [[P]], i1 false) #[[ATTR18:[0-9]+]]
341; ATTRIBUTOR-NEXT:    ret void
342;
343  %1 = call i32 @nc1(ptr %q, ptr %p, i1 0)		; <i32> [#uses=0]
344  ret void
345}
346
347
348define void @nc3(ptr %p) {
349; FNATTRS-LABEL: define void @nc3
350; FNATTRS-SAME: (ptr readonly captures(none) [[P:%.*]]) {
351; FNATTRS-NEXT:    call void [[P]]()
352; FNATTRS-NEXT:    ret void
353;
354; ATTRIBUTOR-LABEL: define void @nc3
355; ATTRIBUTOR-SAME: (ptr nofree nonnull captures(none) [[P:%.*]]) {
356; ATTRIBUTOR-NEXT:    call void [[P]]()
357; ATTRIBUTOR-NEXT:    ret void
358;
359  call void %p()
360  ret void
361}
362
363declare void @external(ptr) readonly nounwind
364define void @nc4(ptr %p) {
365; FNATTRS: Function Attrs: nofree nounwind memory(read)
366; FNATTRS-LABEL: define void @nc4
367; FNATTRS-SAME: (ptr readonly captures(none) [[P:%.*]]) #[[ATTR9:[0-9]+]] {
368; FNATTRS-NEXT:    call void @external(ptr [[P]])
369; FNATTRS-NEXT:    ret void
370;
371; ATTRIBUTOR: Function Attrs: nosync nounwind memory(read)
372; ATTRIBUTOR-LABEL: define void @nc4
373; ATTRIBUTOR-SAME: (ptr readonly captures(none) [[P:%.*]]) #[[ATTR7:[0-9]+]] {
374; ATTRIBUTOR-NEXT:    call void @external(ptr readonly captures(none) [[P]]) #[[ATTR4]]
375; ATTRIBUTOR-NEXT:    ret void
376;
377  call void @external(ptr %p)
378  ret void
379}
380
381define void @nc5(ptr %f, ptr %p) {
382; FNATTRS-LABEL: define void @nc5
383; FNATTRS-SAME: (ptr readonly captures(none) [[F:%.*]], ptr captures(none) [[P:%.*]]) {
384; FNATTRS-NEXT:    call void [[F]](ptr [[P]]) #[[ATTR8:[0-9]+]]
385; FNATTRS-NEXT:    call void [[F]](ptr captures(none) [[P]])
386; FNATTRS-NEXT:    ret void
387;
388; ATTRIBUTOR-LABEL: define void @nc5
389; ATTRIBUTOR-SAME: (ptr nofree nonnull captures(none) [[F:%.*]], ptr captures(none) [[P:%.*]]) {
390; ATTRIBUTOR-NEXT:    call void [[F]](ptr [[P]]) #[[ATTR6:[0-9]+]]
391; ATTRIBUTOR-NEXT:    call void [[F]](ptr captures(none) [[P]])
392; ATTRIBUTOR-NEXT:    ret void
393;
394  call void %f(ptr %p) readonly nounwind
395  call void %f(ptr nocapture %p)
396  ret void
397}
398
399; It would be acceptable to add readnone to %y1_1 and %y1_2.
400define void @test1_1(ptr %x1_1, ptr %y1_1, i1 %c) {
401; FNATTRS: Function Attrs: nofree nosync nounwind memory(write, argmem: none, inaccessiblemem: none)
402; FNATTRS-LABEL: define void @test1_1
403; FNATTRS-SAME: (ptr readnone captures(none) [[X1_1:%.*]], ptr [[Y1_1:%.*]], i1 [[C:%.*]]) #[[ATTR10:[0-9]+]] {
404; FNATTRS-NEXT:    [[TMP1:%.*]] = call ptr @test1_2(ptr [[X1_1]], ptr [[Y1_1]], i1 [[C]])
405; FNATTRS-NEXT:    store ptr null, ptr @g, align 8
406; FNATTRS-NEXT:    ret void
407;
408; ATTRIBUTOR: Function Attrs: nofree nosync nounwind memory(write)
409; ATTRIBUTOR-LABEL: define void @test1_1
410; ATTRIBUTOR-SAME: (ptr nofree readnone captures(none) [[X1_1:%.*]], ptr nofree readnone captures(none) [[Y1_1:%.*]], i1 [[C:%.*]]) #[[ATTR8:[0-9]+]] {
411; ATTRIBUTOR-NEXT:    [[TMP1:%.*]] = call ptr @test1_2(ptr nofree readnone captures(none) [[X1_1]], ptr nofree readnone [[Y1_1]], i1 [[C]]) #[[ATTR8]]
412; ATTRIBUTOR-NEXT:    store ptr null, ptr @g, align 8
413; ATTRIBUTOR-NEXT:    ret void
414;
415  call ptr @test1_2(ptr %x1_1, ptr %y1_1, i1 %c)
416  store ptr null, ptr @g
417  ret void
418}
419
420define ptr @test1_2(ptr %x1_2, ptr %y1_2, i1 %c) {
421; FNATTRS: Function Attrs: nofree nosync nounwind memory(write, argmem: none, inaccessiblemem: none)
422; FNATTRS-LABEL: define ptr @test1_2
423; FNATTRS-SAME: (ptr readnone captures(none) [[X1_2:%.*]], ptr returned [[Y1_2:%.*]], i1 [[C:%.*]]) #[[ATTR10]] {
424; FNATTRS-NEXT:    br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
425; FNATTRS:       t:
426; FNATTRS-NEXT:    call void @test1_1(ptr [[X1_2]], ptr [[Y1_2]], i1 [[C]])
427; FNATTRS-NEXT:    store ptr null, ptr @g, align 8
428; FNATTRS-NEXT:    br label [[F]]
429; FNATTRS:       f:
430; FNATTRS-NEXT:    ret ptr [[Y1_2]]
431;
432; ATTRIBUTOR: Function Attrs: nofree nosync nounwind memory(write)
433; ATTRIBUTOR-LABEL: define ptr @test1_2
434; ATTRIBUTOR-SAME: (ptr nofree readnone captures(none) [[X1_2:%.*]], ptr nofree readnone [[Y1_2:%.*]], i1 [[C:%.*]]) #[[ATTR8]] {
435; ATTRIBUTOR-NEXT:    br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
436; ATTRIBUTOR:       t:
437; ATTRIBUTOR-NEXT:    call void @test1_1(ptr nofree readnone captures(none) [[X1_2]], ptr nofree readnone captures(none) [[Y1_2]], i1 [[C]]) #[[ATTR8]]
438; ATTRIBUTOR-NEXT:    store ptr null, ptr @g, align 8
439; ATTRIBUTOR-NEXT:    br label [[F]]
440; ATTRIBUTOR:       f:
441; ATTRIBUTOR-NEXT:    ret ptr [[Y1_2]]
442;
443  br i1 %c, label %t, label %f
444t:
445  call void @test1_1(ptr %x1_2, ptr %y1_2, i1 %c)
446  store ptr null, ptr @g
447  br label %f
448f:
449  ret ptr %y1_2
450}
451
452define void @test2(ptr %x2) {
453; FNATTRS: Function Attrs: nofree nosync nounwind memory(write, argmem: none, inaccessiblemem: none)
454; FNATTRS-LABEL: define void @test2
455; FNATTRS-SAME: (ptr readnone captures(none) [[X2:%.*]]) #[[ATTR10]] {
456; FNATTRS-NEXT:    call void @test2(ptr [[X2]])
457; FNATTRS-NEXT:    store ptr null, ptr @g, align 8
458; FNATTRS-NEXT:    ret void
459;
460; ATTRIBUTOR: Function Attrs: nofree nosync nounwind memory(write)
461; ATTRIBUTOR-LABEL: define void @test2
462; ATTRIBUTOR-SAME: (ptr nofree readnone captures(none) [[X2:%.*]]) #[[ATTR8]] {
463; ATTRIBUTOR-NEXT:    call void @test2(ptr nofree readnone captures(none) [[X2]]) #[[ATTR8]]
464; ATTRIBUTOR-NEXT:    store ptr null, ptr @g, align 8
465; ATTRIBUTOR-NEXT:    ret void
466;
467  call void @test2(ptr %x2)
468  store ptr null, ptr @g
469  ret void
470}
471
472define void @test3(ptr %x3, ptr %y3, ptr %z3) {
473; FNATTRS: Function Attrs: nofree nosync nounwind memory(write, argmem: none, inaccessiblemem: none)
474; FNATTRS-LABEL: define void @test3
475; FNATTRS-SAME: (ptr readnone captures(none) [[X3:%.*]], ptr readnone captures(none) [[Y3:%.*]], ptr readnone captures(none) [[Z3:%.*]]) #[[ATTR10]] {
476; FNATTRS-NEXT:    call void @test3(ptr [[Z3]], ptr [[Y3]], ptr [[X3]])
477; FNATTRS-NEXT:    store ptr null, ptr @g, align 8
478; FNATTRS-NEXT:    ret void
479;
480; ATTRIBUTOR: Function Attrs: nofree nosync nounwind memory(write)
481; ATTRIBUTOR-LABEL: define void @test3
482; ATTRIBUTOR-SAME: (ptr nofree readnone captures(none) [[X3:%.*]], ptr nofree readnone captures(none) [[Y3:%.*]], ptr nofree readnone captures(none) [[Z3:%.*]]) #[[ATTR8]] {
483; ATTRIBUTOR-NEXT:    call void @test3(ptr nofree readnone captures(none) [[Z3]], ptr nofree readnone captures(none) [[Y3]], ptr nofree readnone captures(none) [[X3]]) #[[ATTR8]]
484; ATTRIBUTOR-NEXT:    store ptr null, ptr @g, align 8
485; ATTRIBUTOR-NEXT:    ret void
486;
487  call void @test3(ptr %z3, ptr %y3, ptr %x3)
488  store ptr null, ptr @g
489  ret void
490}
491
492define void @test4_1(ptr %x4_1, i1 %c) {
493; FNATTRS: Function Attrs: nofree nosync nounwind memory(write, argmem: none, inaccessiblemem: none)
494; FNATTRS-LABEL: define void @test4_1
495; FNATTRS-SAME: (ptr [[X4_1:%.*]], i1 [[C:%.*]]) #[[ATTR10]] {
496; FNATTRS-NEXT:    [[TMP1:%.*]] = call ptr @test4_2(ptr [[X4_1]], ptr [[X4_1]], ptr [[X4_1]], i1 [[C]])
497; FNATTRS-NEXT:    store ptr null, ptr @g, align 8
498; FNATTRS-NEXT:    ret void
499;
500; ATTRIBUTOR: Function Attrs: nofree nosync nounwind memory(write)
501; ATTRIBUTOR-LABEL: define void @test4_1
502; ATTRIBUTOR-SAME: (ptr nofree readnone captures(none) [[X4_1:%.*]], i1 [[C:%.*]]) #[[ATTR8]] {
503; ATTRIBUTOR-NEXT:    [[TMP1:%.*]] = call ptr @test4_2(ptr nofree readnone captures(none) [[X4_1]], ptr nofree readnone [[X4_1]], ptr nofree readnone captures(none) [[X4_1]], i1 [[C]]) #[[ATTR8]]
504; ATTRIBUTOR-NEXT:    store ptr null, ptr @g, align 8
505; ATTRIBUTOR-NEXT:    ret void
506;
507  call ptr @test4_2(ptr %x4_1, ptr %x4_1, ptr %x4_1, i1 %c)
508  store ptr null, ptr @g
509  ret void
510}
511
512define ptr @test4_2(ptr %x4_2, ptr %y4_2, ptr %z4_2, i1 %c) {
513; FNATTRS: Function Attrs: nofree nosync nounwind memory(write, argmem: none, inaccessiblemem: none)
514; FNATTRS-LABEL: define ptr @test4_2
515; FNATTRS-SAME: (ptr readnone captures(none) [[X4_2:%.*]], ptr readnone returned [[Y4_2:%.*]], ptr readnone captures(none) [[Z4_2:%.*]], i1 [[C:%.*]]) #[[ATTR10]] {
516; FNATTRS-NEXT:    br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
517; FNATTRS:       t:
518; FNATTRS-NEXT:    call void @test4_1(ptr null, i1 [[C]])
519; FNATTRS-NEXT:    store ptr null, ptr @g, align 8
520; FNATTRS-NEXT:    br label [[F]]
521; FNATTRS:       f:
522; FNATTRS-NEXT:    ret ptr [[Y4_2]]
523;
524; ATTRIBUTOR: Function Attrs: nofree nosync nounwind memory(write)
525; ATTRIBUTOR-LABEL: define ptr @test4_2
526; ATTRIBUTOR-SAME: (ptr nofree readnone captures(none) [[X4_2:%.*]], ptr nofree readnone [[Y4_2:%.*]], ptr nofree readnone captures(none) [[Z4_2:%.*]], i1 [[C:%.*]]) #[[ATTR8]] {
527; ATTRIBUTOR-NEXT:    br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
528; ATTRIBUTOR:       t:
529; ATTRIBUTOR-NEXT:    call void @test4_1(ptr nofree readnone null, i1 [[C]]) #[[ATTR8]]
530; ATTRIBUTOR-NEXT:    store ptr null, ptr @g, align 8
531; ATTRIBUTOR-NEXT:    br label [[F]]
532; ATTRIBUTOR:       f:
533; ATTRIBUTOR-NEXT:    ret ptr [[Y4_2]]
534;
535  br i1 %c, label %t, label %f
536t:
537  call void @test4_1(ptr null, i1 %c)
538  store ptr null, ptr @g
539  br label %f
540f:
541  ret ptr %y4_2
542}
543
544declare ptr @test5_1(ptr %x5_1)
545
546define void @test5_2(ptr %x5_2) {
547; COMMON-LABEL: define void @test5_2
548; COMMON-SAME: (ptr [[X5_2:%.*]]) {
549; COMMON-NEXT:    [[TMP1:%.*]] = call ptr @test5_1(ptr [[X5_2]])
550; COMMON-NEXT:    store ptr null, ptr @g, align 8
551; COMMON-NEXT:    ret void
552;
553  call ptr @test5_1(ptr %x5_2)
554  store ptr null, ptr @g
555  ret void
556}
557
558declare void @test6_1(ptr %x6_1, ptr nocapture %y6_1, ...)
559
560define void @test6_2(ptr %x6_2, ptr %y6_2, ptr %z6_2) {
561; FNATTRS-LABEL: define void @test6_2
562; FNATTRS-SAME: (ptr [[X6_2:%.*]], ptr captures(none) [[Y6_2:%.*]], ptr [[Z6_2:%.*]]) {
563; FNATTRS-NEXT:    call void (ptr, ptr, ...) @test6_1(ptr [[X6_2]], ptr [[Y6_2]], ptr [[Z6_2]])
564; FNATTRS-NEXT:    store ptr null, ptr @g, align 8
565; FNATTRS-NEXT:    ret void
566;
567; ATTRIBUTOR-LABEL: define void @test6_2
568; ATTRIBUTOR-SAME: (ptr [[X6_2:%.*]], ptr captures(none) [[Y6_2:%.*]], ptr [[Z6_2:%.*]]) {
569; ATTRIBUTOR-NEXT:    call void (ptr, ptr, ...) @test6_1(ptr [[X6_2]], ptr captures(none) [[Y6_2]], ptr [[Z6_2]])
570; ATTRIBUTOR-NEXT:    store ptr null, ptr @g, align 8
571; ATTRIBUTOR-NEXT:    ret void
572;
573  call void (ptr, ptr, ...) @test6_1(ptr %x6_2, ptr %y6_2, ptr %z6_2)
574  store ptr null, ptr @g
575  ret void
576}
577
578define void @test_cmpxchg(ptr %p) {
579; FNATTRS: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite)
580; FNATTRS-LABEL: define void @test_cmpxchg
581; FNATTRS-SAME: (ptr captures(none) [[P:%.*]]) #[[ATTR11:[0-9]+]] {
582; FNATTRS-NEXT:    [[TMP1:%.*]] = cmpxchg ptr [[P]], i32 0, i32 1 acquire monotonic, align 4
583; FNATTRS-NEXT:    ret void
584;
585; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite)
586; ATTRIBUTOR-LABEL: define void @test_cmpxchg
587; ATTRIBUTOR-SAME: (ptr nofree nonnull captures(none) [[P:%.*]]) #[[ATTR9:[0-9]+]] {
588; ATTRIBUTOR-NEXT:    [[TMP1:%.*]] = cmpxchg ptr [[P]], i32 0, i32 1 acquire monotonic, align 4
589; ATTRIBUTOR-NEXT:    ret void
590;
591  cmpxchg ptr %p, i32 0, i32 1 acquire monotonic
592  ret void
593}
594
595define void @test_cmpxchg_ptr(ptr %p, ptr %q) {
596; FNATTRS: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite)
597; FNATTRS-LABEL: define void @test_cmpxchg_ptr
598; FNATTRS-SAME: (ptr captures(none) [[P:%.*]], ptr [[Q:%.*]]) #[[ATTR11]] {
599; FNATTRS-NEXT:    [[TMP1:%.*]] = cmpxchg ptr [[P]], ptr null, ptr [[Q]] acquire monotonic, align 8
600; FNATTRS-NEXT:    ret void
601;
602; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite)
603; ATTRIBUTOR-LABEL: define void @test_cmpxchg_ptr
604; ATTRIBUTOR-SAME: (ptr nofree nonnull captures(none) [[P:%.*]], ptr nofree [[Q:%.*]]) #[[ATTR9]] {
605; ATTRIBUTOR-NEXT:    [[TMP1:%.*]] = cmpxchg ptr [[P]], ptr null, ptr [[Q]] acquire monotonic, align 8
606; ATTRIBUTOR-NEXT:    ret void
607;
608  cmpxchg ptr %p, ptr null, ptr %q acquire monotonic
609  ret void
610}
611
612define void @test_atomicrmw(ptr %p) {
613; FNATTRS: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite)
614; FNATTRS-LABEL: define void @test_atomicrmw
615; FNATTRS-SAME: (ptr captures(none) [[P:%.*]]) #[[ATTR11]] {
616; FNATTRS-NEXT:    [[TMP1:%.*]] = atomicrmw add ptr [[P]], i32 1 seq_cst, align 4
617; FNATTRS-NEXT:    ret void
618;
619; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite)
620; ATTRIBUTOR-LABEL: define void @test_atomicrmw
621; ATTRIBUTOR-SAME: (ptr nofree nonnull captures(none) [[P:%.*]]) #[[ATTR9]] {
622; ATTRIBUTOR-NEXT:    [[TMP1:%.*]] = atomicrmw add ptr [[P]], i32 1 seq_cst, align 4
623; ATTRIBUTOR-NEXT:    ret void
624;
625  atomicrmw add ptr %p, i32 1 seq_cst
626  ret void
627}
628
629define void @test_volatile(ptr %x) {
630; FNATTRS: Function Attrs: nofree norecurse nounwind memory(argmem: readwrite, inaccessiblemem: readwrite)
631; FNATTRS-LABEL: define void @test_volatile
632; FNATTRS-SAME: (ptr [[X:%.*]]) #[[ATTR12:[0-9]+]] {
633; FNATTRS-NEXT:  entry:
634; FNATTRS-NEXT:    [[GEP:%.*]] = getelementptr i32, ptr [[X]], i64 1
635; FNATTRS-NEXT:    store volatile i32 0, ptr [[GEP]], align 4
636; FNATTRS-NEXT:    ret void
637;
638; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite)
639; ATTRIBUTOR-LABEL: define void @test_volatile
640; ATTRIBUTOR-SAME: (ptr nofree [[X:%.*]]) #[[ATTR9]] {
641; ATTRIBUTOR-NEXT:  entry:
642; ATTRIBUTOR-NEXT:    [[GEP:%.*]] = getelementptr i32, ptr [[X]], i64 1
643; ATTRIBUTOR-NEXT:    store volatile i32 0, ptr [[GEP]], align 4
644; ATTRIBUTOR-NEXT:    ret void
645;
646entry:
647  %gep = getelementptr i32, ptr %x, i64 1
648  store volatile i32 0, ptr %gep, align 4
649  ret void
650}
651
652define void @nocaptureLaunder(ptr %p) {
653; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write, inaccessiblemem: readwrite)
654; FNATTRS-LABEL: define void @nocaptureLaunder
655; FNATTRS-SAME: (ptr writeonly captures(none) [[P:%.*]]) #[[ATTR13:[0-9]+]] {
656; FNATTRS-NEXT:  entry:
657; FNATTRS-NEXT:    [[B:%.*]] = call ptr @llvm.launder.invariant.group.p0(ptr [[P]])
658; FNATTRS-NEXT:    store i8 42, ptr [[B]], align 1
659; FNATTRS-NEXT:    ret void
660;
661; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite, inaccessiblemem: readwrite)
662; ATTRIBUTOR-LABEL: define void @nocaptureLaunder
663; ATTRIBUTOR-SAME: (ptr nofree captures(none) [[P:%.*]]) #[[ATTR10:[0-9]+]] {
664; ATTRIBUTOR-NEXT:  entry:
665; ATTRIBUTOR-NEXT:    [[B:%.*]] = call ptr @llvm.launder.invariant.group.p0(ptr [[P]]) #[[ATTR19:[0-9]+]]
666; ATTRIBUTOR-NEXT:    store i8 42, ptr [[B]], align 1
667; ATTRIBUTOR-NEXT:    ret void
668;
669entry:
670  %b = call ptr @llvm.launder.invariant.group.p0(ptr %p)
671  store i8 42, ptr %b
672  ret void
673}
674
675@g2 = global ptr null
676define void @captureLaunder(ptr %p) {
677; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(write, argmem: none, inaccessiblemem: readwrite)
678; FNATTRS-LABEL: define void @captureLaunder
679; FNATTRS-SAME: (ptr [[P:%.*]]) #[[ATTR14:[0-9]+]] {
680; FNATTRS-NEXT:    [[B:%.*]] = call ptr @llvm.launder.invariant.group.p0(ptr [[P]])
681; FNATTRS-NEXT:    store ptr [[B]], ptr @g2, align 8
682; FNATTRS-NEXT:    ret void
683;
684; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn
685; ATTRIBUTOR-LABEL: define void @captureLaunder
686; ATTRIBUTOR-SAME: (ptr nofree [[P:%.*]]) #[[ATTR5]] {
687; ATTRIBUTOR-NEXT:    [[B:%.*]] = call ptr @llvm.launder.invariant.group.p0(ptr [[P]]) #[[ATTR19]]
688; ATTRIBUTOR-NEXT:    store ptr [[B]], ptr @g2, align 8
689; ATTRIBUTOR-NEXT:    ret void
690;
691  %b = call ptr @llvm.launder.invariant.group.p0(ptr %p)
692  store ptr %b, ptr @g2
693  ret void
694}
695
696define void @nocaptureStrip(ptr %p) {
697; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write)
698; FNATTRS-LABEL: define void @nocaptureStrip
699; FNATTRS-SAME: (ptr writeonly captures(none) [[P:%.*]]) #[[ATTR15:[0-9]+]] {
700; FNATTRS-NEXT:  entry:
701; FNATTRS-NEXT:    [[B:%.*]] = call ptr @llvm.strip.invariant.group.p0(ptr [[P]])
702; FNATTRS-NEXT:    store i8 42, ptr [[B]], align 1
703; FNATTRS-NEXT:    ret void
704;
705; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write)
706; ATTRIBUTOR-LABEL: define void @nocaptureStrip
707; ATTRIBUTOR-SAME: (ptr nofree writeonly captures(none) [[P:%.*]]) #[[ATTR11:[0-9]+]] {
708; ATTRIBUTOR-NEXT:  entry:
709; ATTRIBUTOR-NEXT:    [[B:%.*]] = call ptr @llvm.strip.invariant.group.p0(ptr [[P]]) #[[ATTR17]]
710; ATTRIBUTOR-NEXT:    store i8 42, ptr [[B]], align 1
711; ATTRIBUTOR-NEXT:    ret void
712;
713entry:
714  %b = call ptr @llvm.strip.invariant.group.p0(ptr %p)
715  store i8 42, ptr %b
716  ret void
717}
718
719@g3 = global ptr null
720define void @captureStrip(ptr %p) {
721; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(write, argmem: none, inaccessiblemem: none)
722; FNATTRS-LABEL: define void @captureStrip
723; FNATTRS-SAME: (ptr [[P:%.*]]) #[[ATTR1]] {
724; FNATTRS-NEXT:    [[B:%.*]] = call ptr @llvm.strip.invariant.group.p0(ptr [[P]])
725; FNATTRS-NEXT:    store ptr [[B]], ptr @g3, align 8
726; FNATTRS-NEXT:    ret void
727;
728; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(write)
729; ATTRIBUTOR-LABEL: define void @captureStrip
730; ATTRIBUTOR-SAME: (ptr nofree writeonly [[P:%.*]]) #[[ATTR1]] {
731; ATTRIBUTOR-NEXT:    [[B:%.*]] = call ptr @llvm.strip.invariant.group.p0(ptr [[P]]) #[[ATTR17]]
732; ATTRIBUTOR-NEXT:    store ptr [[B]], ptr @g3, align 8
733; ATTRIBUTOR-NEXT:    ret void
734;
735  %b = call ptr @llvm.strip.invariant.group.p0(ptr %p)
736  store ptr %b, ptr @g3
737  ret void
738}
739
740define i1 @captureICmp(ptr %x) {
741; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
742; FNATTRS-LABEL: define i1 @captureICmp
743; FNATTRS-SAME: (ptr readnone [[X:%.*]]) #[[ATTR0]] {
744; FNATTRS-NEXT:    [[TMP1:%.*]] = icmp eq ptr [[X]], null
745; FNATTRS-NEXT:    ret i1 [[TMP1]]
746;
747; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
748; ATTRIBUTOR-LABEL: define i1 @captureICmp
749; ATTRIBUTOR-SAME: (ptr nofree readnone [[X:%.*]]) #[[ATTR0]] {
750; ATTRIBUTOR-NEXT:    [[TMP1:%.*]] = icmp eq ptr [[X]], null
751; ATTRIBUTOR-NEXT:    ret i1 [[TMP1]]
752;
753  %1 = icmp eq ptr %x, null
754  ret i1 %1
755}
756
757define i1 @captureICmpRev(ptr %x) {
758; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
759; FNATTRS-LABEL: define i1 @captureICmpRev
760; FNATTRS-SAME: (ptr readnone [[X:%.*]]) #[[ATTR0]] {
761; FNATTRS-NEXT:    [[TMP1:%.*]] = icmp eq ptr null, [[X]]
762; FNATTRS-NEXT:    ret i1 [[TMP1]]
763;
764; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
765; ATTRIBUTOR-LABEL: define i1 @captureICmpRev
766; ATTRIBUTOR-SAME: (ptr nofree readnone [[X:%.*]]) #[[ATTR0]] {
767; ATTRIBUTOR-NEXT:    [[TMP1:%.*]] = icmp eq ptr null, [[X]]
768; ATTRIBUTOR-NEXT:    ret i1 [[TMP1]]
769;
770  %1 = icmp eq ptr null, %x
771  ret i1 %1
772}
773
774define i1 @nocaptureInboundsGEPICmp(ptr %x) {
775; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
776; FNATTRS-LABEL: define i1 @nocaptureInboundsGEPICmp
777; FNATTRS-SAME: (ptr readnone [[X:%.*]]) #[[ATTR0]] {
778; FNATTRS-NEXT:    [[TMP1:%.*]] = getelementptr inbounds i32, ptr [[X]], i32 5
779; FNATTRS-NEXT:    [[TMP2:%.*]] = icmp eq ptr [[TMP1]], null
780; FNATTRS-NEXT:    ret i1 [[TMP2]]
781;
782; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
783; ATTRIBUTOR-LABEL: define i1 @nocaptureInboundsGEPICmp
784; ATTRIBUTOR-SAME: (ptr nofree readnone [[X:%.*]]) #[[ATTR0]] {
785; ATTRIBUTOR-NEXT:    [[TMP1:%.*]] = getelementptr inbounds i32, ptr [[X]], i32 5
786; ATTRIBUTOR-NEXT:    [[TMP2:%.*]] = icmp eq ptr [[TMP1]], null
787; ATTRIBUTOR-NEXT:    ret i1 [[TMP2]]
788;
789  %1 = getelementptr inbounds i32, ptr %x, i32 5
790  %2 = icmp eq ptr %1, null
791  ret i1 %2
792}
793
794define i1 @nocaptureInboundsGEPICmpRev(ptr %x) {
795; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
796; FNATTRS-LABEL: define i1 @nocaptureInboundsGEPICmpRev
797; FNATTRS-SAME: (ptr readnone [[X:%.*]]) #[[ATTR0]] {
798; FNATTRS-NEXT:    [[TMP1:%.*]] = getelementptr inbounds i32, ptr [[X]], i32 5
799; FNATTRS-NEXT:    [[TMP2:%.*]] = icmp eq ptr null, [[TMP1]]
800; FNATTRS-NEXT:    ret i1 [[TMP2]]
801;
802; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
803; ATTRIBUTOR-LABEL: define i1 @nocaptureInboundsGEPICmpRev
804; ATTRIBUTOR-SAME: (ptr nofree readnone [[X:%.*]]) #[[ATTR0]] {
805; ATTRIBUTOR-NEXT:    [[TMP1:%.*]] = getelementptr inbounds i32, ptr [[X]], i32 5
806; ATTRIBUTOR-NEXT:    [[TMP2:%.*]] = icmp eq ptr null, [[TMP1]]
807; ATTRIBUTOR-NEXT:    ret i1 [[TMP2]]
808;
809  %1 = getelementptr inbounds i32, ptr %x, i32 5
810  %2 = icmp eq ptr null, %1
811  ret i1 %2
812}
813
814define i1 @nocaptureDereferenceableOrNullICmp(ptr dereferenceable_or_null(4) %x) {
815; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
816; FNATTRS-LABEL: define noundef i1 @nocaptureDereferenceableOrNullICmp
817; FNATTRS-SAME: (ptr readnone captures(none) dereferenceable_or_null(4) [[X:%.*]]) #[[ATTR0]] {
818; FNATTRS-NEXT:    [[TMP1:%.*]] = icmp eq ptr [[X]], null
819; FNATTRS-NEXT:    ret i1 [[TMP1]]
820;
821; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
822; ATTRIBUTOR-LABEL: define i1 @nocaptureDereferenceableOrNullICmp
823; ATTRIBUTOR-SAME: (ptr nofree readnone dereferenceable_or_null(4) [[X:%.*]]) #[[ATTR0]] {
824; ATTRIBUTOR-NEXT:    [[TMP1:%.*]] = icmp eq ptr [[X]], null
825; ATTRIBUTOR-NEXT:    ret i1 [[TMP1]]
826;
827  %1 = icmp eq ptr %x, null
828  ret i1 %1
829}
830
831define i1 @captureDereferenceableOrNullICmp(ptr dereferenceable_or_null(4) %x) null_pointer_is_valid {
832; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind null_pointer_is_valid willreturn memory(none)
833; FNATTRS-LABEL: define noundef i1 @captureDereferenceableOrNullICmp
834; FNATTRS-SAME: (ptr readnone dereferenceable_or_null(4) [[X:%.*]]) #[[ATTR16:[0-9]+]] {
835; FNATTRS-NEXT:    [[TMP1:%.*]] = icmp eq ptr [[X]], null
836; FNATTRS-NEXT:    ret i1 [[TMP1]]
837;
838; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind null_pointer_is_valid willreturn memory(none)
839; ATTRIBUTOR-LABEL: define i1 @captureDereferenceableOrNullICmp
840; ATTRIBUTOR-SAME: (ptr nofree readnone dereferenceable_or_null(4) [[X:%.*]]) #[[ATTR12:[0-9]+]] {
841; ATTRIBUTOR-NEXT:    [[TMP1:%.*]] = icmp eq ptr [[X]], null
842; ATTRIBUTOR-NEXT:    ret i1 [[TMP1]]
843;
844  %1 = icmp eq ptr %x, null
845  ret i1 %1
846}
847
848declare void @capture(ptr)
849
850define void @nocapture_fptr(ptr %f, ptr %p) {
851; FNATTRS-LABEL: define void @nocapture_fptr
852; FNATTRS-SAME: (ptr readonly captures(none) [[F:%.*]], ptr [[P:%.*]]) {
853; FNATTRS-NEXT:    [[RES:%.*]] = call ptr [[F]](ptr [[P]])
854; FNATTRS-NEXT:    call void @capture(ptr [[RES]])
855; FNATTRS-NEXT:    ret void
856;
857; ATTRIBUTOR-LABEL: define void @nocapture_fptr
858; ATTRIBUTOR-SAME: (ptr nofree nonnull captures(none) [[F:%.*]], ptr [[P:%.*]]) {
859; ATTRIBUTOR-NEXT:    [[RES:%.*]] = call ptr [[F]](ptr [[P]])
860; ATTRIBUTOR-NEXT:    call void @capture(ptr [[RES]])
861; ATTRIBUTOR-NEXT:    ret void
862;
863  %res = call ptr %f(ptr %p)
864  call void @capture(ptr %res)
865  ret void
866}
867
868define void @recurse_fptr(ptr %f, ptr %p) {
869; FNATTRS-LABEL: define void @recurse_fptr
870; FNATTRS-SAME: (ptr readonly captures(none) [[F:%.*]], ptr [[P:%.*]]) {
871; FNATTRS-NEXT:    [[RES:%.*]] = call ptr [[F]](ptr [[P]])
872; FNATTRS-NEXT:    store i8 0, ptr [[RES]], align 1
873; FNATTRS-NEXT:    ret void
874;
875; ATTRIBUTOR-LABEL: define void @recurse_fptr
876; ATTRIBUTOR-SAME: (ptr nofree nonnull captures(none) [[F:%.*]], ptr [[P:%.*]]) {
877; ATTRIBUTOR-NEXT:    [[RES:%.*]] = call ptr [[F]](ptr [[P]])
878; ATTRIBUTOR-NEXT:    store i8 0, ptr [[RES]], align 1
879; ATTRIBUTOR-NEXT:    ret void
880;
881  %res = call ptr %f(ptr %p)
882  store i8 0, ptr %res
883  ret void
884}
885
886define void @readnone_indirec(ptr %f, ptr %p) {
887; FNATTRS: Function Attrs: nofree nosync memory(none)
888; FNATTRS-LABEL: define void @readnone_indirec
889; FNATTRS-SAME: (ptr readonly captures(none) [[F:%.*]], ptr readnone [[P:%.*]]) #[[ATTR17:[0-9]+]] {
890; FNATTRS-NEXT:    call void [[F]](ptr [[P]]) #[[ATTR20:[0-9]+]]
891; FNATTRS-NEXT:    ret void
892;
893; ATTRIBUTOR: Function Attrs: nosync memory(none)
894; ATTRIBUTOR-LABEL: define void @readnone_indirec
895; ATTRIBUTOR-SAME: (ptr nofree nonnull readnone captures(none) [[F:%.*]], ptr readnone [[P:%.*]]) #[[ATTR13:[0-9]+]] {
896; ATTRIBUTOR-NEXT:    call void [[F]](ptr [[P]]) #[[ATTR20:[0-9]+]]
897; ATTRIBUTOR-NEXT:    ret void
898;
899  call void %f(ptr %p) readnone
900  ret void
901}
902
903
904declare ptr @llvm.launder.invariant.group.p0(ptr)
905declare ptr @llvm.strip.invariant.group.p0(ptr)
906