1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 3
2 ; RUN: opt -S -passes=function-attrs -enable-nonnull-arg-prop %s | FileCheck %s --check-prefixes=COMMON,FNATTRS
3 ; RUN: opt -S -passes=attributor-light %s | FileCheck %s --check-prefixes=COMMON,ATTRIBUTOR
5 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
7 declare nonnull ptr @ret_nonnull()
9 ; Return a pointer trivially nonnull (call return attribute)
11 ; COMMON-LABEL: define nonnull ptr @test1() {
12 ; COMMON-NEXT: [[RET:%.*]] = call ptr @ret_nonnull()
13 ; COMMON-NEXT: ret ptr [[RET]]
15 %ret = call ptr @ret_nonnull()
19 ; Return a pointer trivially nonnull (argument attribute)
20 define ptr @test2(ptr nonnull %p) {
21 ; FNATTRS-LABEL: define nonnull ptr @test2(
22 ; FNATTRS-SAME: ptr nonnull readnone returned [[P:%.*]]) #[[ATTR0:[0-9]+]] {
23 ; FNATTRS-NEXT: ret ptr [[P]]
25 ; ATTRIBUTOR-LABEL: define nonnull ptr @test2(
26 ; ATTRIBUTOR-SAME: ptr nofree nonnull readnone [[P:%.*]]) #[[ATTR0:[0-9]+]] {
27 ; ATTRIBUTOR-NEXT: ret ptr [[P]]
32 ; Given an SCC where one of the functions can not be marked nonnull,
33 ; can we still mark the other one which is trivially nonnull
34 define ptr @scc_binder(i1 %c) {
35 ; FNATTRS-LABEL: define noundef ptr @scc_binder(
36 ; FNATTRS-SAME: i1 [[C:%.*]]) {
37 ; FNATTRS-NEXT: br i1 [[C]], label [[REC:%.*]], label [[END:%.*]]
39 ; FNATTRS-NEXT: [[TMP1:%.*]] = call ptr @test3(i1 [[C]])
40 ; FNATTRS-NEXT: br label [[END]]
42 ; FNATTRS-NEXT: ret ptr null
44 ; ATTRIBUTOR-LABEL: define ptr @scc_binder(
45 ; ATTRIBUTOR-SAME: i1 [[C:%.*]]) {
46 ; ATTRIBUTOR-NEXT: br i1 [[C]], label [[REC:%.*]], label [[END:%.*]]
48 ; ATTRIBUTOR-NEXT: [[TMP1:%.*]] = call ptr @test3(i1 [[C]])
49 ; ATTRIBUTOR-NEXT: br label [[END]]
51 ; ATTRIBUTOR-NEXT: ret ptr null
53 br i1 %c, label %rec, label %end
55 call ptr @test3(i1 %c)
61 define ptr @test3(i1 %c) {
62 ; COMMON-LABEL: define nonnull ptr @test3(
63 ; COMMON-SAME: i1 [[C:%.*]]) {
64 ; COMMON-NEXT: [[TMP1:%.*]] = call ptr @scc_binder(i1 [[C]])
65 ; COMMON-NEXT: [[RET:%.*]] = call ptr @ret_nonnull()
66 ; COMMON-NEXT: ret ptr [[RET]]
68 call ptr @scc_binder(i1 %c)
69 %ret = call ptr @ret_nonnull()
73 ; Given a mutual recursive set of functions, we can mark them
74 ; nonnull if neither can ever return null. (In this case, they
75 ; just never return period.)
76 define ptr @test4_helper() {
77 ; FNATTRS-LABEL: define noalias nonnull ptr @test4_helper(
78 ; FNATTRS-SAME: ) #[[ATTR1:[0-9]+]] {
79 ; FNATTRS-NEXT: [[RET:%.*]] = call ptr @test4()
80 ; FNATTRS-NEXT: ret ptr [[RET]]
82 ; ATTRIBUTOR-LABEL: define ptr @test4_helper(
83 ; ATTRIBUTOR-SAME: ) #[[ATTR1:[0-9]+]] {
84 ; ATTRIBUTOR-NEXT: [[RET:%.*]] = call ptr @test4() #[[ATTR1]]
85 ; ATTRIBUTOR-NEXT: ret ptr [[RET]]
87 %ret = call ptr @test4()
92 ; FNATTRS-LABEL: define noalias nonnull ptr @test4(
93 ; FNATTRS-SAME: ) #[[ATTR1]] {
94 ; FNATTRS-NEXT: [[RET:%.*]] = call ptr @test4_helper()
95 ; FNATTRS-NEXT: ret ptr [[RET]]
97 ; ATTRIBUTOR-LABEL: define ptr @test4(
98 ; ATTRIBUTOR-SAME: ) #[[ATTR1]] {
99 ; ATTRIBUTOR-NEXT: [[RET:%.*]] = call ptr @test4_helper() #[[ATTR1]]
100 ; ATTRIBUTOR-NEXT: ret ptr [[RET]]
102 %ret = call ptr @test4_helper()
106 ; Given a mutual recursive set of functions which *can* return null
107 ; make sure we haven't marked them as nonnull.
108 define ptr @test5_helper(i1 %c) {
109 ; FNATTRS-LABEL: define noalias noundef ptr @test5_helper(
110 ; FNATTRS-SAME: i1 [[C:%.*]]) #[[ATTR1]] {
111 ; FNATTRS-NEXT: br i1 [[C]], label [[REC:%.*]], label [[END:%.*]]
113 ; FNATTRS-NEXT: [[RET:%.*]] = call ptr @test5(i1 [[C]])
114 ; FNATTRS-NEXT: br label [[END]]
116 ; FNATTRS-NEXT: ret ptr null
118 ; ATTRIBUTOR-LABEL: define ptr @test5_helper(
119 ; ATTRIBUTOR-SAME: i1 [[C:%.*]]) #[[ATTR1]] {
120 ; ATTRIBUTOR-NEXT: br i1 [[C]], label [[REC:%.*]], label [[END:%.*]]
122 ; ATTRIBUTOR-NEXT: [[RET:%.*]] = call ptr @test5(i1 [[C]]) #[[ATTR1]]
123 ; ATTRIBUTOR-NEXT: br label [[END]]
125 ; ATTRIBUTOR-NEXT: ret ptr null
127 br i1 %c, label %rec, label %end
129 %ret = call ptr @test5(i1 %c)
135 define ptr @test5(i1 %c) {
136 ; FNATTRS-LABEL: define noalias noundef ptr @test5(
137 ; FNATTRS-SAME: i1 [[C:%.*]]) #[[ATTR1]] {
138 ; FNATTRS-NEXT: [[RET:%.*]] = call ptr @test5_helper(i1 [[C]])
139 ; FNATTRS-NEXT: ret ptr [[RET]]
141 ; ATTRIBUTOR-LABEL: define ptr @test5(
142 ; ATTRIBUTOR-SAME: i1 [[C:%.*]]) #[[ATTR1]] {
143 ; ATTRIBUTOR-NEXT: [[RET:%.*]] = call ptr @test5_helper(i1 [[C]]) #[[ATTR1]]
144 ; ATTRIBUTOR-NEXT: ret ptr [[RET]]
146 %ret = call ptr @test5_helper(i1 %c)
150 ; Local analysis, but going through a self recursive phi
151 define ptr @test6a(i1 %arg) {
152 ; COMMON-LABEL: define nonnull ptr @test6a(
153 ; COMMON-SAME: i1 [[ARG:%.*]]) {
154 ; COMMON-NEXT: entry:
155 ; COMMON-NEXT: [[RET:%.*]] = call ptr @ret_nonnull()
156 ; COMMON-NEXT: br label [[LOOP:%.*]]
158 ; COMMON-NEXT: [[PHI:%.*]] = phi ptr [ [[RET]], [[ENTRY:%.*]] ], [ [[PHI]], [[LOOP]] ]
159 ; COMMON-NEXT: br i1 [[ARG]], label [[LOOP]], label [[EXIT:%.*]]
161 ; COMMON-NEXT: ret ptr [[PHI]]
164 %ret = call ptr @ret_nonnull()
167 %phi = phi ptr [%ret, %entry], [%phi, %loop]
168 br i1 %arg, label %loop, label %exit
173 define ptr @test6b(i1 %c) {
174 ; COMMON-LABEL: define nonnull ptr @test6b(
175 ; COMMON-SAME: i1 [[C:%.*]]) {
176 ; COMMON-NEXT: entry:
177 ; COMMON-NEXT: [[RET:%.*]] = call ptr @ret_nonnull()
178 ; COMMON-NEXT: br label [[LOOP:%.*]]
180 ; COMMON-NEXT: [[PHI:%.*]] = phi ptr [ [[RET]], [[ENTRY:%.*]] ], [ [[PHI]], [[LOOP]] ]
181 ; COMMON-NEXT: br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]]
183 ; COMMON-NEXT: ret ptr [[PHI]]
186 %ret = call ptr @ret_nonnull()
189 %phi = phi ptr [%ret, %entry], [%phi, %loop]
190 br i1 %c, label %loop, label %exit
195 define ptr @test7(ptr %a) {
196 ; FNATTRS-LABEL: define ptr @test7(
197 ; FNATTRS-SAME: ptr readnone returned [[A:%.*]]) #[[ATTR0]] {
198 ; FNATTRS-NEXT: ret ptr [[A]]
200 ; ATTRIBUTOR-LABEL: define ptr @test7(
201 ; ATTRIBUTOR-SAME: ptr nofree readnone [[A:%.*]]) #[[ATTR0]] {
202 ; ATTRIBUTOR-NEXT: ret ptr [[A]]
207 define ptr @test8(ptr %a) {
208 ; FNATTRS-LABEL: define nonnull ptr @test8(
209 ; FNATTRS-SAME: ptr readnone [[A:%.*]]) #[[ATTR0]] {
210 ; FNATTRS-NEXT: [[B:%.*]] = getelementptr inbounds i8, ptr [[A]], i64 1
211 ; FNATTRS-NEXT: ret ptr [[B]]
213 ; ATTRIBUTOR-LABEL: define nonnull ptr @test8(
214 ; ATTRIBUTOR-SAME: ptr nofree readnone [[A:%.*]]) #[[ATTR0]] {
215 ; ATTRIBUTOR-NEXT: [[B:%.*]] = getelementptr inbounds i8, ptr [[A]], i64 1
216 ; ATTRIBUTOR-NEXT: ret ptr [[B]]
218 %b = getelementptr inbounds i8, ptr %a, i64 1
222 define ptr @test9(ptr %a, i64 %n) {
223 ; FNATTRS-LABEL: define ptr @test9(
224 ; FNATTRS-SAME: ptr readnone [[A:%.*]], i64 [[N:%.*]]) #[[ATTR0]] {
225 ; FNATTRS-NEXT: [[B:%.*]] = getelementptr inbounds i8, ptr [[A]], i64 [[N]]
226 ; FNATTRS-NEXT: ret ptr [[B]]
228 ; ATTRIBUTOR-LABEL: define ptr @test9(
229 ; ATTRIBUTOR-SAME: ptr nofree readnone [[A:%.*]], i64 [[N:%.*]]) #[[ATTR0]] {
230 ; ATTRIBUTOR-NEXT: [[B:%.*]] = getelementptr inbounds i8, ptr [[A]], i64 [[N]]
231 ; ATTRIBUTOR-NEXT: ret ptr [[B]]
233 %b = getelementptr inbounds i8, ptr %a, i64 %n
237 declare void @llvm.assume(i1)
238 ; FIXME: missing nonnull
239 define ptr @test10(ptr %a, i64 %n) {
240 ; FNATTRS-LABEL: define ptr @test10(
241 ; FNATTRS-SAME: ptr readnone [[A:%.*]], i64 [[N:%.*]]) #[[ATTR3:[0-9]+]] {
242 ; FNATTRS-NEXT: [[CMP:%.*]] = icmp ne i64 [[N]], 0
243 ; FNATTRS-NEXT: call void @llvm.assume(i1 [[CMP]])
244 ; FNATTRS-NEXT: [[B:%.*]] = getelementptr inbounds i8, ptr [[A]], i64 [[N]]
245 ; FNATTRS-NEXT: ret ptr [[B]]
247 ; ATTRIBUTOR-LABEL: define ptr @test10(
248 ; ATTRIBUTOR-SAME: ptr nofree readnone [[A:%.*]], i64 [[N:%.*]]) #[[ATTR3:[0-9]+]] {
249 ; ATTRIBUTOR-NEXT: [[CMP:%.*]] = icmp ne i64 [[N]], 0
250 ; ATTRIBUTOR-NEXT: call void @llvm.assume(i1 [[CMP]]) #[[ATTR13:[0-9]+]]
251 ; ATTRIBUTOR-NEXT: [[B:%.*]] = getelementptr inbounds i8, ptr [[A]], i64 [[N]]
252 ; ATTRIBUTOR-NEXT: ret ptr [[B]]
254 %cmp = icmp ne i64 %n, 0
255 call void @llvm.assume(i1 %cmp)
256 %b = getelementptr inbounds i8, ptr %a, i64 %n
261 ; char* test11(char *p) {
262 ; return p? p: nonnull();
264 define ptr @test11(ptr) local_unnamed_addr {
265 ; FNATTRS-LABEL: define nonnull ptr @test11(
266 ; FNATTRS-SAME: ptr readnone [[TMP0:%.*]]) local_unnamed_addr {
267 ; FNATTRS-NEXT: [[TMP2:%.*]] = icmp eq ptr [[TMP0]], null
268 ; FNATTRS-NEXT: br i1 [[TMP2]], label [[TMP3:%.*]], label [[TMP5:%.*]]
270 ; FNATTRS-NEXT: [[TMP4:%.*]] = tail call ptr @ret_nonnull()
271 ; FNATTRS-NEXT: br label [[TMP5]]
273 ; FNATTRS-NEXT: [[TMP6:%.*]] = phi ptr [ [[TMP4]], [[TMP3]] ], [ [[TMP0]], [[TMP1:%.*]] ]
274 ; FNATTRS-NEXT: ret ptr [[TMP6]]
276 ; ATTRIBUTOR-LABEL: define nonnull ptr @test11(
277 ; ATTRIBUTOR-SAME: ptr [[TMP0:%.*]]) local_unnamed_addr {
278 ; ATTRIBUTOR-NEXT: [[TMP2:%.*]] = icmp eq ptr [[TMP0]], null
279 ; ATTRIBUTOR-NEXT: br i1 [[TMP2]], label [[TMP3:%.*]], label [[TMP5:%.*]]
281 ; ATTRIBUTOR-NEXT: [[TMP4:%.*]] = tail call ptr @ret_nonnull()
282 ; ATTRIBUTOR-NEXT: br label [[TMP5]]
284 ; ATTRIBUTOR-NEXT: [[TMP6:%.*]] = phi ptr [ [[TMP4]], [[TMP3]] ], [ [[TMP0]], [[TMP1:%.*]] ]
285 ; ATTRIBUTOR-NEXT: ret ptr [[TMP6]]
287 %2 = icmp eq ptr %0, null
288 br i1 %2, label %3, label %5
290 ; <label>:3: ; preds = %1
291 %4 = tail call ptr @ret_nonnull()
294 ; <label>:5: ; preds = %3, %1
295 %6 = phi ptr [ %4, %3 ], [ %0, %1 ]
300 ; Simple CallSite Test
301 declare void @test12_helper(ptr)
302 define void @test12(ptr nonnull %a) {
303 ; COMMON-LABEL: define void @test12(
304 ; COMMON-SAME: ptr nonnull [[A:%.*]]) {
305 ; COMMON-NEXT: tail call void @test12_helper(ptr [[A]])
306 ; COMMON-NEXT: ret void
308 tail call void @test12_helper(ptr %a)
313 ; Simple Argument Tests
314 declare ptr @unknown()
315 define void @test13_helper() {
316 ; FNATTRS-LABEL: define void @test13_helper() {
317 ; FNATTRS-NEXT: [[NONNULLPTR:%.*]] = tail call ptr @ret_nonnull()
318 ; FNATTRS-NEXT: [[MAYBENULLPTR:%.*]] = tail call ptr @unknown()
319 ; FNATTRS-NEXT: tail call void @test13(ptr [[NONNULLPTR]], ptr [[NONNULLPTR]], ptr [[MAYBENULLPTR]])
320 ; FNATTRS-NEXT: tail call void @test13(ptr [[NONNULLPTR]], ptr [[MAYBENULLPTR]], ptr [[NONNULLPTR]])
321 ; FNATTRS-NEXT: ret void
323 ; ATTRIBUTOR-LABEL: define void @test13_helper() {
324 ; ATTRIBUTOR-NEXT: [[NONNULLPTR:%.*]] = tail call ptr @ret_nonnull()
325 ; ATTRIBUTOR-NEXT: [[MAYBENULLPTR:%.*]] = tail call ptr @unknown()
326 ; ATTRIBUTOR-NEXT: tail call void @test13(ptr nocapture nofree nonnull readnone [[NONNULLPTR]], ptr nocapture nofree nonnull readnone [[NONNULLPTR]], ptr nocapture nofree readnone [[MAYBENULLPTR]])
327 ; ATTRIBUTOR-NEXT: tail call void @test13(ptr nocapture nofree nonnull readnone [[NONNULLPTR]], ptr nocapture nofree readnone [[MAYBENULLPTR]], ptr nocapture nofree nonnull readnone [[NONNULLPTR]])
328 ; ATTRIBUTOR-NEXT: ret void
330 %nonnullptr = tail call ptr @ret_nonnull()
331 %maybenullptr = tail call ptr @unknown()
332 tail call void @test13(ptr %nonnullptr, ptr %nonnullptr, ptr %maybenullptr)
333 tail call void @test13(ptr %nonnullptr, ptr %maybenullptr, ptr %nonnullptr)
336 define internal void @test13(ptr %a, ptr %b, ptr %c) {
337 ; FNATTRS-LABEL: define internal void @test13(
338 ; FNATTRS-SAME: ptr nocapture readnone [[A:%.*]], ptr nocapture readnone [[B:%.*]], ptr nocapture readnone [[C:%.*]]) #[[ATTR0]] {
339 ; FNATTRS-NEXT: ret void
341 ; ATTRIBUTOR-LABEL: define internal void @test13(
342 ; ATTRIBUTOR-SAME: ptr nocapture nofree nonnull readnone [[A:%.*]], ptr nocapture nofree readnone [[B:%.*]], ptr nocapture nofree readnone [[C:%.*]]) #[[ATTR0]] {
343 ; ATTRIBUTOR-NEXT: ret void
348 declare nonnull ptr @nonnull()
351 ; Complex propagation
352 ; Argument of f1, f2, f3 can be marked with nonnull.
355 ; 1. In f1:bb6, %arg can be marked with nonnull because of the comparison in bb1
356 ; 2. Because f2 is internal function, f2(ptr %arg) -> @f2(ptr nonnull %arg)
357 ; 3. In f1:bb4 %tmp5 is nonnull and f3 is internal function.
358 ; Then, f3(ptr %arg) -> @f3(ptr nonnull %arg)
359 ; 4. We get nonnull in whole f1 call sites so f1(ptr %arg) -> @f1(ptr nonnull %arg)
362 define internal ptr @f1(ptr %arg) {
363 ; FIXME: missing nonnull It should be nonnull @f1(ptr nonnull readonly %arg)
364 ; FNATTRS-LABEL: define internal nonnull ptr @f1(
365 ; FNATTRS-SAME: ptr readonly [[ARG:%.*]]) #[[ATTR4:[0-9]+]] {
367 ; FNATTRS-NEXT: [[TMP:%.*]] = icmp eq ptr [[ARG]], null
368 ; FNATTRS-NEXT: br i1 [[TMP]], label [[BB9:%.*]], label [[BB1:%.*]]
370 ; FNATTRS-NEXT: [[TMP2:%.*]] = load i32, ptr [[ARG]], align 4
371 ; FNATTRS-NEXT: [[TMP3:%.*]] = icmp eq i32 [[TMP2]], 0
372 ; FNATTRS-NEXT: br i1 [[TMP3]], label [[BB6:%.*]], label [[BB4:%.*]]
374 ; FNATTRS-NEXT: [[TMP5:%.*]] = getelementptr inbounds i32, ptr [[ARG]], i64 1
375 ; FNATTRS-NEXT: [[TMP5B:%.*]] = tail call ptr @f3(ptr [[TMP5]])
376 ; FNATTRS-NEXT: [[TMP5C:%.*]] = getelementptr inbounds i32, ptr [[TMP5B]], i64 -1
377 ; FNATTRS-NEXT: br label [[BB9]]
379 ; FNATTRS-NEXT: [[TMP7:%.*]] = tail call ptr @f2(ptr [[ARG]])
380 ; FNATTRS-NEXT: ret ptr [[TMP7]]
382 ; FNATTRS-NEXT: [[TMP10:%.*]] = phi ptr [ [[TMP5C]], [[BB4]] ], [ inttoptr (i64 4 to ptr), [[BB:%.*]] ]
383 ; FNATTRS-NEXT: ret ptr [[TMP10]]
385 ; ATTRIBUTOR-LABEL: define internal ptr @f1(
386 ; ATTRIBUTOR-SAME: ptr nofree readonly [[ARG:%.*]]) #[[ATTR4:[0-9]+]] {
387 ; ATTRIBUTOR-NEXT: bb:
388 ; ATTRIBUTOR-NEXT: [[TMP:%.*]] = icmp eq ptr [[ARG]], null
389 ; ATTRIBUTOR-NEXT: br i1 [[TMP]], label [[BB9:%.*]], label [[BB1:%.*]]
391 ; ATTRIBUTOR-NEXT: [[TMP2:%.*]] = load i32, ptr [[ARG]], align 4
392 ; ATTRIBUTOR-NEXT: [[TMP3:%.*]] = icmp eq i32 [[TMP2]], 0
393 ; ATTRIBUTOR-NEXT: br i1 [[TMP3]], label [[BB6:%.*]], label [[BB4:%.*]]
395 ; ATTRIBUTOR-NEXT: [[TMP5:%.*]] = getelementptr inbounds i32, ptr [[ARG]], i64 1
396 ; ATTRIBUTOR-NEXT: [[TMP5B:%.*]] = tail call ptr @f3(ptr nofree nonnull readonly [[TMP5]]) #[[ATTR14:[0-9]+]]
397 ; ATTRIBUTOR-NEXT: [[TMP5C:%.*]] = getelementptr inbounds i32, ptr [[TMP5B]], i64 -1
398 ; ATTRIBUTOR-NEXT: br label [[BB9]]
400 ; ATTRIBUTOR-NEXT: [[TMP7:%.*]] = tail call ptr @f2(ptr nofree nonnull readonly [[ARG]]) #[[ATTR14]]
401 ; ATTRIBUTOR-NEXT: ret ptr [[TMP7]]
403 ; ATTRIBUTOR-NEXT: [[TMP10:%.*]] = phi ptr [ [[TMP5C]], [[BB4]] ], [ inttoptr (i64 4 to ptr), [[BB:%.*]] ]
404 ; ATTRIBUTOR-NEXT: ret ptr [[TMP10]]
407 %tmp = icmp eq ptr %arg, null
408 br i1 %tmp, label %bb9, label %bb1
411 %tmp2 = load i32, ptr %arg, align 4
412 %tmp3 = icmp eq i32 %tmp2, 0
413 br i1 %tmp3, label %bb6, label %bb4
416 %tmp5 = getelementptr inbounds i32, ptr %arg, i64 1
417 %tmp5b = tail call ptr @f3(ptr %tmp5)
418 %tmp5c = getelementptr inbounds i32, ptr %tmp5b, i64 -1
422 ; FIXME: missing nonnull. It should be @f2(ptr nonnull %arg)
423 %tmp7 = tail call ptr @f2(ptr %arg)
426 bb9: ; preds = %bb4, %bb
427 %tmp10 = phi ptr [ %tmp5c, %bb4 ], [ inttoptr (i64 4 to ptr), %bb ]
431 define internal ptr @f2(ptr %arg) {
432 ; FIXME: missing nonnull. It should be nonnull @f2(ptr nonnull %arg)
433 ; FNATTRS-LABEL: define internal nonnull ptr @f2(
434 ; FNATTRS-SAME: ptr [[ARG:%.*]]) #[[ATTR4]] {
436 ; FNATTRS-NEXT: [[TMP:%.*]] = tail call ptr @f1(ptr [[ARG]])
437 ; FNATTRS-NEXT: ret ptr [[TMP]]
439 ; ATTRIBUTOR-LABEL: define internal ptr @f2(
440 ; ATTRIBUTOR-SAME: ptr nofree nonnull readonly [[ARG:%.*]]) #[[ATTR4]] {
441 ; ATTRIBUTOR-NEXT: bb:
442 ; ATTRIBUTOR-NEXT: [[TMP:%.*]] = tail call ptr @f1(ptr nofree nonnull readonly [[ARG]]) #[[ATTR14]]
443 ; ATTRIBUTOR-NEXT: ret ptr [[TMP]]
447 ; FIXME: missing nonnull. It should be @f1(ptr nonnull readonly %arg)
448 %tmp = tail call ptr @f1(ptr %arg)
452 define dso_local noalias ptr @f3(ptr %arg) {
453 ; FIXME: missing nonnull. It should be nonnull @f3(ptr nonnull readonly %arg)
454 ; FNATTRS-LABEL: define dso_local noalias nonnull ptr @f3(
455 ; FNATTRS-SAME: ptr [[ARG:%.*]]) #[[ATTR4]] {
457 ; FNATTRS-NEXT: [[TMP:%.*]] = call ptr @f1(ptr [[ARG]])
458 ; FNATTRS-NEXT: ret ptr [[TMP]]
460 ; ATTRIBUTOR-LABEL: define dso_local noalias ptr @f3(
461 ; ATTRIBUTOR-SAME: ptr nofree readonly [[ARG:%.*]]) #[[ATTR4]] {
462 ; ATTRIBUTOR-NEXT: bb:
463 ; ATTRIBUTOR-NEXT: [[TMP:%.*]] = call ptr @f1(ptr nofree readonly [[ARG]]) #[[ATTR14]]
464 ; ATTRIBUTOR-NEXT: ret ptr [[TMP]]
467 ; FIXME: missing nonnull. It should be @f1(ptr nonnull readonly %arg)
468 %tmp = call ptr @f1(ptr %arg)
473 define void @f15(ptr %arg) {
474 ; FNATTRS-LABEL: define void @f15(
475 ; FNATTRS-SAME: ptr [[ARG:%.*]]) {
476 ; FNATTRS-NEXT: tail call void @use1(ptr dereferenceable(4) [[ARG]])
477 ; FNATTRS-NEXT: ret void
479 ; ATTRIBUTOR-LABEL: define void @f15(
480 ; ATTRIBUTOR-SAME: ptr nonnull [[ARG:%.*]]) {
481 ; ATTRIBUTOR-NEXT: tail call void @use1(ptr nonnull dereferenceable(4) [[ARG]])
482 ; ATTRIBUTOR-NEXT: ret void
484 tail call void @use1(ptr dereferenceable(4) %arg)
488 declare void @fun0() #1
489 declare void @fun1(ptr) #1
490 declare void @fun2(ptr, ptr) #1
491 declare void @fun3(ptr, ptr, ptr) #1
492 ; TEST 16 simple path test
494 ; fun2(nonnull %a, nonnull %b)
496 ; fun2(nonnull %a, %b)
497 ; We can say that %a is nonnull but %b is not.
498 define void @f16(ptr %a, ptr %b, i8 %c) {
499 ; FIXME: missing nonnull on %a
500 ; FNATTRS-LABEL: define void @f16(
501 ; FNATTRS-SAME: ptr [[A:%.*]], ptr [[B:%.*]], i8 [[C:%.*]]) #[[ATTR6:[0-9]+]] {
502 ; FNATTRS-NEXT: [[CMP:%.*]] = icmp eq i8 [[C]], 0
503 ; FNATTRS-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
505 ; FNATTRS-NEXT: tail call void @fun2(ptr nonnull [[A]], ptr nonnull [[B]])
506 ; FNATTRS-NEXT: ret void
508 ; FNATTRS-NEXT: tail call void @fun2(ptr nonnull [[A]], ptr [[B]])
509 ; FNATTRS-NEXT: ret void
511 ; ATTRIBUTOR-LABEL: define void @f16(
512 ; ATTRIBUTOR-SAME: ptr nonnull [[A:%.*]], ptr [[B:%.*]], i8 [[C:%.*]]) #[[ATTR6:[0-9]+]] {
513 ; ATTRIBUTOR-NEXT: [[CMP:%.*]] = icmp eq i8 [[C]], 0
514 ; ATTRIBUTOR-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
515 ; ATTRIBUTOR: if.then:
516 ; ATTRIBUTOR-NEXT: tail call void @fun2(ptr nonnull [[A]], ptr nonnull [[B]]) #[[ATTR15:[0-9]+]]
517 ; ATTRIBUTOR-NEXT: ret void
518 ; ATTRIBUTOR: if.else:
519 ; ATTRIBUTOR-NEXT: tail call void @fun2(ptr nonnull [[A]], ptr [[B]]) #[[ATTR15]]
520 ; ATTRIBUTOR-NEXT: ret void
522 %cmp = icmp eq i8 %c, 0
523 br i1 %cmp, label %if.then, label %if.else
525 tail call void @fun2(ptr nonnull %a, ptr nonnull %b)
528 tail call void @fun2(ptr nonnull %a, ptr %b)
531 ; TEST 17 explore child BB test
533 ; ... (willreturn & nounwind)
535 ; ... (willreturn & nounwind)
537 ; We can say that %a is nonnull
538 define void @f17(ptr %a, i8 %c) {
539 ; FNATTRS-LABEL: define void @f17(
540 ; FNATTRS-SAME: ptr [[A:%.*]], i8 [[C:%.*]]) #[[ATTR6]] {
541 ; FNATTRS-NEXT: [[CMP:%.*]] = icmp eq i8 [[C]], 0
542 ; FNATTRS-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
544 ; FNATTRS-NEXT: tail call void @fun0()
545 ; FNATTRS-NEXT: br label [[CONT:%.*]]
547 ; FNATTRS-NEXT: tail call void @fun0()
548 ; FNATTRS-NEXT: br label [[CONT]]
550 ; FNATTRS-NEXT: tail call void @fun1(ptr nonnull [[A]])
551 ; FNATTRS-NEXT: ret void
553 ; ATTRIBUTOR-LABEL: define void @f17(
554 ; ATTRIBUTOR-SAME: ptr nonnull [[A:%.*]], i8 [[C:%.*]]) #[[ATTR6]] {
555 ; ATTRIBUTOR-NEXT: [[CMP:%.*]] = icmp eq i8 [[C]], 0
556 ; ATTRIBUTOR-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
557 ; ATTRIBUTOR: if.then:
558 ; ATTRIBUTOR-NEXT: tail call void @fun0() #[[ATTR15]]
559 ; ATTRIBUTOR-NEXT: br label [[CONT:%.*]]
560 ; ATTRIBUTOR: if.else:
561 ; ATTRIBUTOR-NEXT: tail call void @fun0() #[[ATTR15]]
562 ; ATTRIBUTOR-NEXT: br label [[CONT]]
564 ; ATTRIBUTOR-NEXT: tail call void @fun1(ptr nonnull [[A]]) #[[ATTR15]]
565 ; ATTRIBUTOR-NEXT: ret void
567 %cmp = icmp eq i8 %c, 0
568 br i1 %cmp, label %if.then, label %if.else
570 tail call void @fun0()
573 tail call void @fun0()
576 tail call void @fun1(ptr nonnull %a)
579 ; TEST 18 More complex test
581 ; ... (willreturn & nounwind)
583 ; ... (willreturn & nounwind)
585 ; ... (willreturn & nounwind)
587 ; ... (willreturn & nounwind)
590 define void @f18(ptr %a, ptr %b, i8 %c) {
591 ; FNATTRS-LABEL: define void @f18(
592 ; FNATTRS-SAME: ptr [[A:%.*]], ptr [[B:%.*]], i8 [[C:%.*]]) #[[ATTR6]] {
593 ; FNATTRS-NEXT: [[CMP1:%.*]] = icmp eq i8 [[C]], 0
594 ; FNATTRS-NEXT: br i1 [[CMP1]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
596 ; FNATTRS-NEXT: tail call void @fun0()
597 ; FNATTRS-NEXT: br label [[CONT:%.*]]
599 ; FNATTRS-NEXT: tail call void @fun0()
600 ; FNATTRS-NEXT: br label [[CONT]]
602 ; FNATTRS-NEXT: [[CMP2:%.*]] = icmp eq i8 [[C]], 1
603 ; FNATTRS-NEXT: br i1 [[CMP2]], label [[CONT_THEN:%.*]], label [[CONT_ELSE:%.*]]
604 ; FNATTRS: cont.then:
605 ; FNATTRS-NEXT: tail call void @fun1(ptr nonnull [[B]])
606 ; FNATTRS-NEXT: br label [[CONT2:%.*]]
607 ; FNATTRS: cont.else:
608 ; FNATTRS-NEXT: tail call void @fun0()
609 ; FNATTRS-NEXT: br label [[CONT2]]
611 ; FNATTRS-NEXT: tail call void @fun1(ptr nonnull [[A]])
612 ; FNATTRS-NEXT: ret void
614 ; ATTRIBUTOR-LABEL: define void @f18(
615 ; ATTRIBUTOR-SAME: ptr nonnull [[A:%.*]], ptr [[B:%.*]], i8 [[C:%.*]]) #[[ATTR6]] {
616 ; ATTRIBUTOR-NEXT: [[CMP1:%.*]] = icmp eq i8 [[C]], 0
617 ; ATTRIBUTOR-NEXT: br i1 [[CMP1]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
618 ; ATTRIBUTOR: if.then:
619 ; ATTRIBUTOR-NEXT: tail call void @fun0() #[[ATTR15]]
620 ; ATTRIBUTOR-NEXT: br label [[CONT:%.*]]
621 ; ATTRIBUTOR: if.else:
622 ; ATTRIBUTOR-NEXT: tail call void @fun0() #[[ATTR15]]
623 ; ATTRIBUTOR-NEXT: br label [[CONT]]
625 ; ATTRIBUTOR-NEXT: [[CMP2:%.*]] = icmp eq i8 [[C]], 1
626 ; ATTRIBUTOR-NEXT: br i1 [[CMP2]], label [[CONT_THEN:%.*]], label [[CONT_ELSE:%.*]]
627 ; ATTRIBUTOR: cont.then:
628 ; ATTRIBUTOR-NEXT: tail call void @fun1(ptr nonnull [[B]]) #[[ATTR15]]
629 ; ATTRIBUTOR-NEXT: br label [[CONT2:%.*]]
630 ; ATTRIBUTOR: cont.else:
631 ; ATTRIBUTOR-NEXT: tail call void @fun0() #[[ATTR15]]
632 ; ATTRIBUTOR-NEXT: br label [[CONT2]]
634 ; ATTRIBUTOR-NEXT: tail call void @fun1(ptr nonnull [[A]]) #[[ATTR15]]
635 ; ATTRIBUTOR-NEXT: ret void
637 %cmp1 = icmp eq i8 %c, 0
638 br i1 %cmp1, label %if.then, label %if.else
640 tail call void @fun0()
643 tail call void @fun0()
646 %cmp2 = icmp eq i8 %c, 1
647 br i1 %cmp2, label %cont.then, label %cont.else
649 tail call void @fun1(ptr nonnull %b)
652 tail call void @fun0()
655 tail call void @fun1(ptr nonnull %a)
661 define void @f19(ptr %a, ptr %b, i8 %c) {
662 ; FIXME: missing nonnull on %b
663 ; FNATTRS-LABEL: define void @f19(
664 ; FNATTRS-SAME: ptr [[A:%.*]], ptr [[B:%.*]], i8 [[C:%.*]]) #[[ATTR7:[0-9]+]] {
665 ; FNATTRS-NEXT: br label [[LOOP_HEADER:%.*]]
666 ; FNATTRS: loop.header:
667 ; FNATTRS-NEXT: [[CMP2:%.*]] = icmp eq i8 [[C]], 0
668 ; FNATTRS-NEXT: br i1 [[CMP2]], label [[LOOP_BODY:%.*]], label [[LOOP_EXIT:%.*]]
669 ; FNATTRS: loop.body:
670 ; FNATTRS-NEXT: tail call void @fun1(ptr nonnull [[B]])
671 ; FNATTRS-NEXT: tail call void @fun1(ptr nonnull [[A]])
672 ; FNATTRS-NEXT: br label [[LOOP_HEADER]]
673 ; FNATTRS: loop.exit:
674 ; FNATTRS-NEXT: tail call void @fun1(ptr nonnull [[B]])
675 ; FNATTRS-NEXT: ret void
677 ; ATTRIBUTOR-LABEL: define void @f19(
678 ; ATTRIBUTOR-SAME: ptr [[A:%.*]], ptr nonnull [[B:%.*]], i8 [[C:%.*]]) #[[ATTR7:[0-9]+]] {
679 ; ATTRIBUTOR-NEXT: br label [[LOOP_HEADER:%.*]]
680 ; ATTRIBUTOR: loop.header:
681 ; ATTRIBUTOR-NEXT: [[CMP2:%.*]] = icmp eq i8 [[C]], 0
682 ; ATTRIBUTOR-NEXT: br i1 [[CMP2]], label [[LOOP_BODY:%.*]], label [[LOOP_EXIT:%.*]]
683 ; ATTRIBUTOR: loop.body:
684 ; ATTRIBUTOR-NEXT: tail call void @fun1(ptr nonnull [[B]])
685 ; ATTRIBUTOR-NEXT: tail call void @fun1(ptr nonnull [[A]])
686 ; ATTRIBUTOR-NEXT: br label [[LOOP_HEADER]]
687 ; ATTRIBUTOR: loop.exit:
688 ; ATTRIBUTOR-NEXT: tail call void @fun1(ptr nonnull [[B]])
689 ; ATTRIBUTOR-NEXT: ret void
691 br label %loop.header
693 %cmp2 = icmp eq i8 %c, 0
694 br i1 %cmp2, label %loop.body, label %loop.exit
696 tail call void @fun1(ptr nonnull %b)
697 tail call void @fun1(ptr nonnull %a)
698 br label %loop.header
700 tail call void @fun1(ptr nonnull %b)
704 ; Test propagation of nonnull callsite args back to caller.
706 declare void @use1(ptr %x)
707 declare void @use2(ptr %x, ptr %y);
708 declare void @use3(ptr %x, ptr %y, ptr %z);
710 declare void @use1nonnull(ptr nonnull noundef %x);
711 declare void @use1nonnull_without_noundef(ptr nonnull %x);
712 declare void @use2nonnull(ptr nonnull noundef %x, ptr nonnull noundef %y);
713 declare void @use3nonnull(ptr nonnull noundef %x, ptr nonnull noundef %y, ptr nonnull noundef %z);
715 declare i8 @use1safecall(ptr %x) nounwind willreturn ; nounwind+willreturn guarantees that execution continues to successor
717 ; Without noundef, nonnull cannot be propagated to the parent
719 define void @parent_poison(ptr %a) {
720 ; FNATTR-LABEL: @parent_poison(ptr %a)
721 ; FNATTRS-LABEL: define void @parent_poison(
722 ; FNATTRS-SAME: ptr [[A:%.*]]) {
723 ; FNATTRS-NEXT: call void @use1nonnull_without_noundef(ptr [[A]])
724 ; FNATTRS-NEXT: ret void
726 ; ATTRIBUTOR-LABEL: define void @parent_poison(
727 ; ATTRIBUTOR-SAME: ptr nonnull [[A:%.*]]) {
728 ; ATTRIBUTOR-NEXT: call void @use1nonnull_without_noundef(ptr nonnull [[A]])
729 ; ATTRIBUTOR-NEXT: ret void
731 call void @use1nonnull_without_noundef(ptr %a)
735 ; Can't extend non-null to parent for any argument because the 2nd call is not guaranteed to execute.
737 define void @parent1(ptr %a, ptr %b, ptr %c) {
738 ; COMMON-LABEL: define void @parent1(
739 ; COMMON-SAME: ptr [[A:%.*]], ptr [[B:%.*]], ptr [[C:%.*]]) {
740 ; COMMON-NEXT: call void @use3(ptr [[C]], ptr [[A]], ptr [[B]])
741 ; COMMON-NEXT: call void @use3nonnull(ptr [[B]], ptr [[C]], ptr [[A]])
742 ; COMMON-NEXT: ret void
744 call void @use3(ptr %c, ptr %a, ptr %b)
745 call void @use3nonnull(ptr %b, ptr %c, ptr %a)
749 ; Extend non-null to parent for all arguments.
751 define void @parent2(ptr %a, ptr %b, ptr %c) {
752 ; FNATTRS-LABEL: define void @parent2(
753 ; FNATTRS-SAME: ptr nonnull [[A:%.*]], ptr nonnull [[B:%.*]], ptr nonnull [[C:%.*]]) {
754 ; FNATTRS-NEXT: call void @use3nonnull(ptr [[B]], ptr [[C]], ptr [[A]])
755 ; FNATTRS-NEXT: call void @use3(ptr [[C]], ptr [[A]], ptr [[B]])
756 ; FNATTRS-NEXT: ret void
758 ; ATTRIBUTOR-LABEL: define void @parent2(
759 ; ATTRIBUTOR-SAME: ptr nonnull [[A:%.*]], ptr nonnull [[B:%.*]], ptr nonnull [[C:%.*]]) {
760 ; ATTRIBUTOR-NEXT: call void @use3nonnull(ptr nonnull [[B]], ptr nonnull [[C]], ptr nonnull [[A]])
761 ; ATTRIBUTOR-NEXT: call void @use3(ptr [[C]], ptr [[A]], ptr [[B]])
762 ; ATTRIBUTOR-NEXT: ret void
766 call void @use3nonnull(ptr %b, ptr %c, ptr %a)
767 call void @use3(ptr %c, ptr %a, ptr %b)
771 ; Extend non-null to parent for 1st argument.
773 define void @parent3(ptr %a, ptr %b, ptr %c) {
774 ; FNATTRS-LABEL: define void @parent3(
775 ; FNATTRS-SAME: ptr nonnull [[A:%.*]], ptr [[B:%.*]], ptr [[C:%.*]]) {
776 ; FNATTRS-NEXT: call void @use1nonnull(ptr [[A]])
777 ; FNATTRS-NEXT: call void @use3(ptr [[C]], ptr [[B]], ptr [[A]])
778 ; FNATTRS-NEXT: ret void
780 ; ATTRIBUTOR-LABEL: define void @parent3(
781 ; ATTRIBUTOR-SAME: ptr nonnull [[A:%.*]], ptr [[B:%.*]], ptr [[C:%.*]]) {
782 ; ATTRIBUTOR-NEXT: call void @use1nonnull(ptr nonnull [[A]])
783 ; ATTRIBUTOR-NEXT: call void @use3(ptr [[C]], ptr [[B]], ptr [[A]])
784 ; ATTRIBUTOR-NEXT: ret void
789 call void @use1nonnull(ptr %a)
790 call void @use3(ptr %c, ptr %b, ptr %a)
794 ; Extend non-null to parent for last 2 arguments.
796 define void @parent4(ptr %a, ptr %b, ptr %c) {
797 ; CHECK-LABEL: @parent4(ptr %a, ptr nonnull %b, ptr nonnull %c)
798 ; CHECK-NEXT: call void @use2nonnull(ptr %c, ptr %b)
799 ; CHECK-NEXT: call void @use2(ptr %a, ptr %c)
800 ; CHECK-NEXT: call void @use1(ptr %b)
801 ; FNATTRS-LABEL: define void @parent4(
802 ; FNATTRS-SAME: ptr [[A:%.*]], ptr nonnull [[B:%.*]], ptr nonnull [[C:%.*]]) {
803 ; FNATTRS-NEXT: call void @use2nonnull(ptr [[C]], ptr [[B]])
804 ; FNATTRS-NEXT: call void @use2(ptr [[A]], ptr [[C]])
805 ; FNATTRS-NEXT: call void @use1(ptr [[B]])
806 ; FNATTRS-NEXT: ret void
808 ; ATTRIBUTOR-LABEL: define void @parent4(
809 ; ATTRIBUTOR-SAME: ptr [[A:%.*]], ptr nonnull [[B:%.*]], ptr nonnull [[C:%.*]]) {
810 ; ATTRIBUTOR-NEXT: call void @use2nonnull(ptr nonnull [[C]], ptr nonnull [[B]])
811 ; ATTRIBUTOR-NEXT: call void @use2(ptr [[A]], ptr [[C]])
812 ; ATTRIBUTOR-NEXT: call void @use1(ptr [[B]])
813 ; ATTRIBUTOR-NEXT: ret void
816 call void @use2nonnull(ptr %c, ptr %b)
817 call void @use2(ptr %a, ptr %c)
818 call void @use1(ptr %b)
822 ; The callsite must execute in order for the attribute to transfer to the parent.
823 ; It appears benign to extend non-null to the parent in this case, but we can't do that
824 ; because it would incorrectly propagate the wrong information to its callers.
826 define void @parent5(ptr %a, i1 %a_is_notnull) {
827 ; FNATTRS-LABEL: define void @parent5(
828 ; FNATTRS-SAME: ptr [[A:%.*]], i1 [[A_IS_NOTNULL:%.*]]) {
829 ; FNATTRS-NEXT: br i1 [[A_IS_NOTNULL]], label [[T:%.*]], label [[F:%.*]]
831 ; FNATTRS-NEXT: call void @use1nonnull(ptr [[A]])
832 ; FNATTRS-NEXT: ret void
834 ; FNATTRS-NEXT: ret void
836 ; ATTRIBUTOR-LABEL: define void @parent5(
837 ; ATTRIBUTOR-SAME: ptr [[A:%.*]], i1 [[A_IS_NOTNULL:%.*]]) {
838 ; ATTRIBUTOR-NEXT: br i1 [[A_IS_NOTNULL]], label [[T:%.*]], label [[F:%.*]]
840 ; ATTRIBUTOR-NEXT: call void @use1nonnull(ptr nonnull [[A]])
841 ; ATTRIBUTOR-NEXT: ret void
843 ; ATTRIBUTOR-NEXT: ret void
846 br i1 %a_is_notnull, label %t, label %f
848 call void @use1nonnull(ptr %a)
854 ; The callsite must execute in order for the attribute to transfer to the parent.
855 ; The volatile load can't trap, so we can guarantee that we'll get to the call.
857 define i8 @parent6(ptr %a, ptr %b) {
858 ; FNATTRS-LABEL: define i8 @parent6(
859 ; FNATTRS-SAME: ptr nonnull [[A:%.*]], ptr [[B:%.*]]) {
860 ; FNATTRS-NEXT: [[C:%.*]] = load volatile i8, ptr [[B]], align 1
861 ; FNATTRS-NEXT: call void @use1nonnull(ptr [[A]])
862 ; FNATTRS-NEXT: ret i8 [[C]]
864 ; ATTRIBUTOR-LABEL: define i8 @parent6(
865 ; ATTRIBUTOR-SAME: ptr nonnull [[A:%.*]], ptr nofree [[B:%.*]]) {
866 ; ATTRIBUTOR-NEXT: [[C:%.*]] = load volatile i8, ptr [[B]], align 1
867 ; ATTRIBUTOR-NEXT: call void @use1nonnull(ptr nonnull [[A]])
868 ; ATTRIBUTOR-NEXT: ret i8 [[C]]
871 %c = load volatile i8, ptr %b
872 call void @use1nonnull(ptr %a)
876 ; The nonnull callsite is guaranteed to execute, so the argument must be nonnull throughout the parent.
878 define i8 @parent7(ptr %a) {
879 ; FNATTRS-LABEL: define i8 @parent7(
880 ; FNATTRS-SAME: ptr nonnull [[A:%.*]]) {
881 ; FNATTRS-NEXT: [[RET:%.*]] = call i8 @use1safecall(ptr [[A]])
882 ; FNATTRS-NEXT: call void @use1nonnull(ptr [[A]])
883 ; FNATTRS-NEXT: ret i8 [[RET]]
885 ; ATTRIBUTOR-LABEL: define i8 @parent7(
886 ; ATTRIBUTOR-SAME: ptr nonnull [[A:%.*]]) {
887 ; ATTRIBUTOR-NEXT: [[RET:%.*]] = call i8 @use1safecall(ptr nonnull [[A]]) #[[ATTR15]]
888 ; ATTRIBUTOR-NEXT: call void @use1nonnull(ptr nonnull [[A]])
889 ; ATTRIBUTOR-NEXT: ret i8 [[RET]]
895 %ret = call i8 @use1safecall(ptr %a)
896 call void @use1nonnull(ptr %a)
900 ; Make sure that an invoke works similarly to a call.
902 declare i32 @esfp(...)
904 define i1 @parent8(ptr %a, ptr %bogus1, ptr %b) personality ptr @esfp{
905 ; FNATTRS-LABEL: define noundef i1 @parent8(
906 ; FNATTRS-SAME: ptr nonnull [[A:%.*]], ptr nocapture readnone [[BOGUS1:%.*]], ptr nonnull [[B:%.*]]) #[[ATTR7]] personality ptr @esfp {
907 ; FNATTRS-NEXT: entry:
908 ; FNATTRS-NEXT: invoke void @use2nonnull(ptr [[A]], ptr [[B]])
909 ; FNATTRS-NEXT: to label [[CONT:%.*]] unwind label [[EXC:%.*]]
911 ; FNATTRS-NEXT: [[NULL_CHECK:%.*]] = icmp eq ptr [[B]], null
912 ; FNATTRS-NEXT: ret i1 [[NULL_CHECK]]
914 ; FNATTRS-NEXT: [[LP:%.*]] = landingpad { ptr, i32 }
915 ; FNATTRS-NEXT: filter [0 x ptr] zeroinitializer
916 ; FNATTRS-NEXT: unreachable
918 ; ATTRIBUTOR-LABEL: define i1 @parent8(
919 ; ATTRIBUTOR-SAME: ptr nonnull [[A:%.*]], ptr nocapture nofree readnone [[BOGUS1:%.*]], ptr nonnull [[B:%.*]]) #[[ATTR7]] personality ptr @esfp {
920 ; ATTRIBUTOR-NEXT: entry:
921 ; ATTRIBUTOR-NEXT: invoke void @use2nonnull(ptr nonnull [[A]], ptr nonnull [[B]])
922 ; ATTRIBUTOR-NEXT: to label [[CONT:%.*]] unwind label [[EXC:%.*]]
924 ; ATTRIBUTOR-NEXT: [[NULL_CHECK:%.*]] = icmp eq ptr [[B]], null
925 ; ATTRIBUTOR-NEXT: ret i1 [[NULL_CHECK]]
927 ; ATTRIBUTOR-NEXT: [[LP:%.*]] = landingpad { ptr, i32 }
928 ; ATTRIBUTOR-NEXT: filter [0 x ptr] zeroinitializer
929 ; ATTRIBUTOR-NEXT: unreachable
933 invoke void @use2nonnull(ptr %a, ptr %b)
934 to label %cont unwind label %exc
937 %null_check = icmp eq ptr %b, null
941 %lp = landingpad { ptr, i32 }
942 filter [0 x ptr] zeroinitializer
946 define ptr @gep1(ptr %p) {
947 ; FNATTRS-LABEL: define nonnull ptr @gep1(
948 ; FNATTRS-SAME: ptr readnone [[P:%.*]]) #[[ATTR0]] {
949 ; FNATTRS-NEXT: [[Q:%.*]] = getelementptr inbounds i32, ptr [[P]], i32 1
950 ; FNATTRS-NEXT: ret ptr [[Q]]
952 ; ATTRIBUTOR-LABEL: define nonnull ptr @gep1(
953 ; ATTRIBUTOR-SAME: ptr nofree readnone [[P:%.*]]) #[[ATTR0]] {
954 ; ATTRIBUTOR-NEXT: [[Q:%.*]] = getelementptr inbounds i32, ptr [[P]], i32 1
955 ; ATTRIBUTOR-NEXT: ret ptr [[Q]]
957 %q = getelementptr inbounds i32, ptr %p, i32 1
961 define ptr @gep1_no_null_opt(ptr %p) #0 {
962 ; Should't be able to derive nonnull based on gep.
963 ; FNATTRS-LABEL: define ptr @gep1_no_null_opt(
964 ; FNATTRS-SAME: ptr readnone [[P:%.*]]) #[[ATTR8:[0-9]+]] {
965 ; FNATTRS-NEXT: [[Q:%.*]] = getelementptr inbounds i32, ptr [[P]], i32 1
966 ; FNATTRS-NEXT: ret ptr [[Q]]
968 ; ATTRIBUTOR-LABEL: define ptr @gep1_no_null_opt(
969 ; ATTRIBUTOR-SAME: ptr nofree readnone [[P:%.*]]) #[[ATTR8:[0-9]+]] {
970 ; ATTRIBUTOR-NEXT: [[Q:%.*]] = getelementptr inbounds i32, ptr [[P]], i32 1
971 ; ATTRIBUTOR-NEXT: ret ptr [[Q]]
973 %q = getelementptr inbounds i32, ptr %p, i32 1
977 define ptr addrspace(3) @gep2(ptr addrspace(3) %p) {
978 ; FNATTRS-LABEL: define ptr addrspace(3) @gep2(
979 ; FNATTRS-SAME: ptr addrspace(3) readnone [[P:%.*]]) #[[ATTR0]] {
980 ; FNATTRS-NEXT: [[Q:%.*]] = getelementptr inbounds i32, ptr addrspace(3) [[P]], i32 1
981 ; FNATTRS-NEXT: ret ptr addrspace(3) [[Q]]
983 ; ATTRIBUTOR-LABEL: define ptr addrspace(3) @gep2(
984 ; ATTRIBUTOR-SAME: ptr addrspace(3) nofree readnone [[P:%.*]]) #[[ATTR0]] {
985 ; ATTRIBUTOR-NEXT: [[Q:%.*]] = getelementptr inbounds i32, ptr addrspace(3) [[P]], i32 1
986 ; ATTRIBUTOR-NEXT: ret ptr addrspace(3) [[Q]]
988 %q = getelementptr inbounds i32, ptr addrspace(3) %p, i32 1
989 ret ptr addrspace(3) %q
992 ; FIXME: We should propagate dereferenceable here but *not* nonnull
993 define ptr addrspace(3) @as(ptr addrspace(3) dereferenceable(4) %p) {
994 ; FNATTRS-LABEL: define noundef ptr addrspace(3) @as(
995 ; FNATTRS-SAME: ptr addrspace(3) readnone returned dereferenceable(4) [[P:%.*]]) #[[ATTR0]] {
996 ; FNATTRS-NEXT: ret ptr addrspace(3) [[P]]
998 ; ATTRIBUTOR-LABEL: define ptr addrspace(3) @as(
999 ; ATTRIBUTOR-SAME: ptr addrspace(3) nofree readnone dereferenceable(4) [[P:%.*]]) #[[ATTR0]] {
1000 ; ATTRIBUTOR-NEXT: ret ptr addrspace(3) [[P]]
1002 ret ptr addrspace(3) %p
1005 define internal ptr @g2() {
1006 ; FNATTRS-LABEL: define internal noundef nonnull ptr @g2(
1007 ; FNATTRS-SAME: ) #[[ATTR0]] {
1008 ; FNATTRS-NEXT: ret ptr inttoptr (i64 4 to ptr)
1010 ; ATTRIBUTOR-LABEL: define internal nonnull ptr @g2(
1011 ; ATTRIBUTOR-SAME: ) #[[ATTR0]] {
1012 ; ATTRIBUTOR-NEXT: ret ptr inttoptr (i64 4 to ptr)
1014 ret ptr inttoptr (i64 4 to ptr)
1018 ; FNATTRS-LABEL: define noundef nonnull ptr @g1(
1019 ; FNATTRS-SAME: ) #[[ATTR0]] {
1020 ; FNATTRS-NEXT: [[C:%.*]] = call ptr @g2()
1021 ; FNATTRS-NEXT: ret ptr [[C]]
1023 ; ATTRIBUTOR-LABEL: define ptr @g1(
1024 ; ATTRIBUTOR-SAME: ) #[[ATTR0]] {
1025 ; ATTRIBUTOR-NEXT: [[C:%.*]] = call ptr @g2() #[[ATTR16:[0-9]+]]
1026 ; ATTRIBUTOR-NEXT: ret ptr [[C]]
1032 declare void @use_i32_ptr(ptr) readnone nounwind
1033 define internal void @called_by_weak(ptr %a) {
1034 ; FNATTRS-LABEL: define internal void @called_by_weak(
1035 ; FNATTRS-SAME: ptr nocapture readnone [[A:%.*]]) #[[ATTR1]] {
1036 ; FNATTRS-NEXT: call void @use_i32_ptr(ptr [[A]])
1037 ; FNATTRS-NEXT: ret void
1039 ; ATTRIBUTOR-LABEL: define internal void @called_by_weak(
1040 ; ATTRIBUTOR-SAME: ptr nocapture nonnull readnone [[A:%.*]]) #[[ATTR10:[0-9]+]] {
1041 ; ATTRIBUTOR-NEXT: call void @use_i32_ptr(ptr nonnull [[A]]) #[[ATTR17:[0-9]+]]
1042 ; ATTRIBUTOR-NEXT: ret void
1044 call void @use_i32_ptr(ptr %a)
1048 ; Check we do not annotate the function interface of this weak function.
1049 define weak_odr void @weak_caller(ptr nonnull %a) {
1050 ; FNATTRS-LABEL: define weak_odr void @weak_caller(
1051 ; FNATTRS-SAME: ptr nonnull [[A:%.*]]) {
1052 ; FNATTRS-NEXT: call void @called_by_weak(ptr [[A]])
1053 ; FNATTRS-NEXT: ret void
1055 ; ATTRIBUTOR-LABEL: define weak_odr void @weak_caller(
1056 ; ATTRIBUTOR-SAME: ptr nonnull [[A:%.*]]) {
1057 ; ATTRIBUTOR-NEXT: call void @called_by_weak(ptr nocapture nonnull readnone [[A]])
1058 ; ATTRIBUTOR-NEXT: ret void
1060 call void @called_by_weak(ptr %a)
1065 define internal void @control(ptr dereferenceable(4) %a) {
1066 ; FNATTRS-LABEL: define internal void @control(
1067 ; FNATTRS-SAME: ptr nocapture readnone dereferenceable(4) [[A:%.*]]) #[[ATTR1]] {
1068 ; FNATTRS-NEXT: call void @use_i32_ptr(ptr [[A]])
1069 ; FNATTRS-NEXT: ret void
1071 ; ATTRIBUTOR-LABEL: define internal void @control(
1072 ; ATTRIBUTOR-SAME: ptr nocapture nonnull readnone dereferenceable(4) [[A:%.*]]) #[[ATTR10]] {
1073 ; ATTRIBUTOR-NEXT: call void @use_i32_ptr(ptr [[A]]) #[[ATTR17]]
1074 ; ATTRIBUTOR-NEXT: ret void
1076 call void @use_i32_ptr(ptr %a)
1079 ; Avoid nonnull as we do not touch naked functions
1080 define internal void @naked(ptr dereferenceable(4) %a) naked {
1081 ; FNATTRS-LABEL: define internal void @naked(
1082 ; FNATTRS-SAME: ptr dereferenceable(4) [[A:%.*]]) #[[ATTR10:[0-9]+]] {
1083 ; FNATTRS-NEXT: ret void
1085 ; ATTRIBUTOR-LABEL: define internal void @naked(
1086 ; ATTRIBUTOR-SAME: ptr nonnull dereferenceable(4) [[A:%.*]]) #[[ATTR11:[0-9]+]] {
1087 ; ATTRIBUTOR-NEXT: ret void
1091 ; Avoid nonnull as we do not touch optnone
1092 define internal void @optnone(ptr dereferenceable(4) %a) optnone noinline {
1093 ; FNATTRS-LABEL: define internal void @optnone(
1094 ; FNATTRS-SAME: ptr dereferenceable(4) [[A:%.*]]) #[[ATTR11:[0-9]+]] {
1095 ; FNATTRS-NEXT: call void @use_i32_ptr(ptr [[A]])
1096 ; FNATTRS-NEXT: ret void
1098 ; ATTRIBUTOR-LABEL: define internal void @optnone(
1099 ; ATTRIBUTOR-SAME: ptr nonnull dereferenceable(4) [[A:%.*]]) #[[ATTR12:[0-9]+]] {
1100 ; ATTRIBUTOR-NEXT: call void @use_i32_ptr(ptr [[A]])
1101 ; ATTRIBUTOR-NEXT: ret void
1103 call void @use_i32_ptr(ptr %a)
1106 define void @make_live(ptr nonnull dereferenceable(8) %a) {
1107 ; FNATTRS-LABEL: define void @make_live(
1108 ; FNATTRS-SAME: ptr nonnull dereferenceable(8) [[A:%.*]]) {
1109 ; FNATTRS-NEXT: call void @naked(ptr nonnull align 16 dereferenceable(8) [[A]])
1110 ; FNATTRS-NEXT: call void @control(ptr nonnull align 16 dereferenceable(8) [[A]])
1111 ; FNATTRS-NEXT: call void @optnone(ptr nonnull align 16 dereferenceable(8) [[A]])
1112 ; FNATTRS-NEXT: ret void
1114 ; ATTRIBUTOR-LABEL: define void @make_live(
1115 ; ATTRIBUTOR-SAME: ptr nonnull dereferenceable(8) [[A:%.*]]) {
1116 ; ATTRIBUTOR-NEXT: call void @naked(ptr nonnull align 16 dereferenceable(8) [[A]])
1117 ; ATTRIBUTOR-NEXT: call void @control(ptr nocapture nonnull readnone align 16 dereferenceable(8) [[A]])
1118 ; ATTRIBUTOR-NEXT: call void @optnone(ptr nonnull align 16 dereferenceable(8) [[A]])
1119 ; ATTRIBUTOR-NEXT: ret void
1121 call void @naked(ptr nonnull dereferenceable(8) align 16 %a)
1122 call void @control(ptr nonnull dereferenceable(8) align 16 %a)
1123 call void @optnone(ptr nonnull dereferenceable(8) align 16 %a)
1127 ;int f(int *u, int n){
1128 ; for(int i = 0;i<n;i++){
1131 ; return g(nonnull u);
1133 declare void @h(ptr) willreturn nounwind
1134 declare i32 @g(ptr) willreturn nounwind
1135 define i32 @nonnull_exec_ctx_1(ptr %a, i32 %b) {
1136 ; COMMON-LABEL: define i32 @nonnull_exec_ctx_1(
1137 ; COMMON-SAME: ptr [[A:%.*]], i32 [[B:%.*]]) #[[ATTR7:[0-9]+]] {
1139 ; COMMON-NEXT: [[TMP3:%.*]] = icmp eq i32 [[B]], 0
1140 ; COMMON-NEXT: br i1 [[TMP3]], label [[EX:%.*]], label [[HD:%.*]]
1142 ; COMMON-NEXT: [[TMP5:%.*]] = tail call i32 @g(ptr nonnull [[A]])
1143 ; COMMON-NEXT: ret i32 [[TMP5]]
1145 ; COMMON-NEXT: [[TMP7:%.*]] = phi i32 [ [[TMP8:%.*]], [[HD]] ], [ 0, [[EN:%.*]] ]
1146 ; COMMON-NEXT: tail call void @h(ptr [[A]])
1147 ; COMMON-NEXT: [[TMP8]] = add nuw i32 [[TMP7]], 1
1148 ; COMMON-NEXT: [[TMP9:%.*]] = icmp eq i32 [[TMP8]], [[B]]
1149 ; COMMON-NEXT: br i1 [[TMP9]], label [[EX]], label [[HD]]
1152 %tmp3 = icmp eq i32 %b, 0
1153 br i1 %tmp3, label %ex, label %hd
1156 %tmp5 = tail call i32 @g(ptr nonnull %a)
1160 %tmp7 = phi i32 [ %tmp8, %hd ], [ 0, %en ]
1161 tail call void @h(ptr %a)
1162 %tmp8 = add nuw i32 %tmp7, 1
1163 %tmp9 = icmp eq i32 %tmp8, %b
1164 br i1 %tmp9, label %ex, label %hd
1167 define i32 @nonnull_exec_ctx_1b(ptr %a, i32 %b) {
1168 ; COMMON-LABEL: define i32 @nonnull_exec_ctx_1b(
1169 ; COMMON-SAME: ptr [[A:%.*]], i32 [[B:%.*]]) #[[ATTR7]] {
1171 ; COMMON-NEXT: [[TMP3:%.*]] = icmp eq i32 [[B]], 0
1172 ; COMMON-NEXT: br i1 [[TMP3]], label [[EX:%.*]], label [[HD:%.*]]
1174 ; COMMON-NEXT: [[TMP5:%.*]] = tail call i32 @g(ptr nonnull [[A]])
1175 ; COMMON-NEXT: ret i32 [[TMP5]]
1177 ; COMMON-NEXT: [[TMP7:%.*]] = phi i32 [ [[TMP8:%.*]], [[HD2:%.*]] ], [ 0, [[EN:%.*]] ]
1178 ; COMMON-NEXT: tail call void @h(ptr [[A]])
1179 ; COMMON-NEXT: br label [[HD2]]
1181 ; COMMON-NEXT: [[TMP8]] = add nuw i32 [[TMP7]], 1
1182 ; COMMON-NEXT: [[TMP9:%.*]] = icmp eq i32 [[TMP8]], [[B]]
1183 ; COMMON-NEXT: br i1 [[TMP9]], label [[EX]], label [[HD]]
1186 %tmp3 = icmp eq i32 %b, 0
1187 br i1 %tmp3, label %ex, label %hd
1190 %tmp5 = tail call i32 @g(ptr nonnull %a)
1194 %tmp7 = phi i32 [ %tmp8, %hd2 ], [ 0, %en ]
1195 tail call void @h(ptr %a)
1199 %tmp8 = add nuw i32 %tmp7, 1
1200 %tmp9 = icmp eq i32 %tmp8, %b
1201 br i1 %tmp9, label %ex, label %hd
1204 define i32 @nonnull_exec_ctx_2(ptr %a, i32 %b) willreturn nounwind {
1205 ; FNATTRS-LABEL: define i32 @nonnull_exec_ctx_2(
1206 ; FNATTRS-SAME: ptr [[A:%.*]], i32 [[B:%.*]]) #[[ATTR6]] {
1208 ; FNATTRS-NEXT: [[TMP3:%.*]] = icmp eq i32 [[B]], 0
1209 ; FNATTRS-NEXT: br i1 [[TMP3]], label [[EX:%.*]], label [[HD:%.*]]
1211 ; FNATTRS-NEXT: [[TMP5:%.*]] = tail call i32 @g(ptr nonnull [[A]])
1212 ; FNATTRS-NEXT: ret i32 [[TMP5]]
1214 ; FNATTRS-NEXT: [[TMP7:%.*]] = phi i32 [ [[TMP8:%.*]], [[HD]] ], [ 0, [[EN:%.*]] ]
1215 ; FNATTRS-NEXT: tail call void @h(ptr [[A]])
1216 ; FNATTRS-NEXT: [[TMP8]] = add nuw i32 [[TMP7]], 1
1217 ; FNATTRS-NEXT: [[TMP9:%.*]] = icmp eq i32 [[TMP8]], [[B]]
1218 ; FNATTRS-NEXT: br i1 [[TMP9]], label [[EX]], label [[HD]]
1220 ; ATTRIBUTOR-LABEL: define i32 @nonnull_exec_ctx_2(
1221 ; ATTRIBUTOR-SAME: ptr nonnull [[A:%.*]], i32 [[B:%.*]]) #[[ATTR6]] {
1222 ; ATTRIBUTOR-NEXT: en:
1223 ; ATTRIBUTOR-NEXT: [[TMP3:%.*]] = icmp eq i32 [[B]], 0
1224 ; ATTRIBUTOR-NEXT: br i1 [[TMP3]], label [[EX:%.*]], label [[HD:%.*]]
1226 ; ATTRIBUTOR-NEXT: [[TMP5:%.*]] = tail call i32 @g(ptr nonnull [[A]])
1227 ; ATTRIBUTOR-NEXT: ret i32 [[TMP5]]
1229 ; ATTRIBUTOR-NEXT: [[TMP7:%.*]] = phi i32 [ [[TMP8:%.*]], [[HD]] ], [ 0, [[EN:%.*]] ]
1230 ; ATTRIBUTOR-NEXT: tail call void @h(ptr nonnull [[A]])
1231 ; ATTRIBUTOR-NEXT: [[TMP8]] = add nuw i32 [[TMP7]], 1
1232 ; ATTRIBUTOR-NEXT: [[TMP9:%.*]] = icmp eq i32 [[TMP8]], [[B]]
1233 ; ATTRIBUTOR-NEXT: br i1 [[TMP9]], label [[EX]], label [[HD]]
1236 %tmp3 = icmp eq i32 %b, 0
1237 br i1 %tmp3, label %ex, label %hd
1240 %tmp5 = tail call i32 @g(ptr nonnull %a)
1244 %tmp7 = phi i32 [ %tmp8, %hd ], [ 0, %en ]
1245 tail call void @h(ptr %a)
1246 %tmp8 = add nuw i32 %tmp7, 1
1247 %tmp9 = icmp eq i32 %tmp8, %b
1248 br i1 %tmp9, label %ex, label %hd
1251 define i32 @nonnull_exec_ctx_2b(ptr %a, i32 %b) willreturn nounwind {
1252 ; FNATTRS-LABEL: define i32 @nonnull_exec_ctx_2b(
1253 ; FNATTRS-SAME: ptr [[A:%.*]], i32 [[B:%.*]]) #[[ATTR6]] {
1255 ; FNATTRS-NEXT: [[TMP3:%.*]] = icmp eq i32 [[B]], 0
1256 ; FNATTRS-NEXT: br i1 [[TMP3]], label [[EX:%.*]], label [[HD:%.*]]
1258 ; FNATTRS-NEXT: [[TMP5:%.*]] = tail call i32 @g(ptr nonnull [[A]])
1259 ; FNATTRS-NEXT: ret i32 [[TMP5]]
1261 ; FNATTRS-NEXT: [[TMP7:%.*]] = phi i32 [ [[TMP8:%.*]], [[HD2:%.*]] ], [ 0, [[EN:%.*]] ]
1262 ; FNATTRS-NEXT: tail call void @h(ptr [[A]])
1263 ; FNATTRS-NEXT: br label [[HD2]]
1265 ; FNATTRS-NEXT: [[TMP8]] = add nuw i32 [[TMP7]], 1
1266 ; FNATTRS-NEXT: [[TMP9:%.*]] = icmp eq i32 [[TMP8]], [[B]]
1267 ; FNATTRS-NEXT: br i1 [[TMP9]], label [[EX]], label [[HD]]
1269 ; ATTRIBUTOR-LABEL: define i32 @nonnull_exec_ctx_2b(
1270 ; ATTRIBUTOR-SAME: ptr nonnull [[A:%.*]], i32 [[B:%.*]]) #[[ATTR6]] {
1271 ; ATTRIBUTOR-NEXT: en:
1272 ; ATTRIBUTOR-NEXT: [[TMP3:%.*]] = icmp eq i32 [[B]], 0
1273 ; ATTRIBUTOR-NEXT: br i1 [[TMP3]], label [[EX:%.*]], label [[HD:%.*]]
1275 ; ATTRIBUTOR-NEXT: [[TMP5:%.*]] = tail call i32 @g(ptr nonnull [[A]])
1276 ; ATTRIBUTOR-NEXT: ret i32 [[TMP5]]
1278 ; ATTRIBUTOR-NEXT: [[TMP7:%.*]] = phi i32 [ [[TMP8:%.*]], [[HD2:%.*]] ], [ 0, [[EN:%.*]] ]
1279 ; ATTRIBUTOR-NEXT: tail call void @h(ptr nonnull [[A]])
1280 ; ATTRIBUTOR-NEXT: br label [[HD2]]
1282 ; ATTRIBUTOR-NEXT: [[TMP8]] = add nuw i32 [[TMP7]], 1
1283 ; ATTRIBUTOR-NEXT: [[TMP9:%.*]] = icmp eq i32 [[TMP8]], [[B]]
1284 ; ATTRIBUTOR-NEXT: br i1 [[TMP9]], label [[EX]], label [[HD]]
1287 %tmp3 = icmp eq i32 %b, 0
1288 br i1 %tmp3, label %ex, label %hd
1291 %tmp5 = tail call i32 @g(ptr nonnull %a)
1295 %tmp7 = phi i32 [ %tmp8, %hd2 ], [ 0, %en ]
1296 tail call void @h(ptr %a)
1300 %tmp8 = add nuw i32 %tmp7, 1
1301 %tmp9 = icmp eq i32 %tmp8, %b
1302 br i1 %tmp9, label %ex, label %hd
1305 ; Original from PR43833
1306 declare void @sink(ptr)
1308 ; FIXME: the sink argument should be marked nonnull as in @PR43833_simple.
1309 define void @PR43833(ptr %0, i32 %1) {
1310 ; COMMON-LABEL: define void @PR43833(
1311 ; COMMON-SAME: ptr [[TMP0:%.*]], i32 [[TMP1:%.*]]) {
1312 ; COMMON-NEXT: [[TMP3:%.*]] = icmp sgt i32 [[TMP1]], 1
1313 ; COMMON-NEXT: br i1 [[TMP3]], label [[TMP4:%.*]], label [[TMP7:%.*]]
1315 ; COMMON-NEXT: [[TMP5:%.*]] = zext i32 [[TMP1]] to i64
1316 ; COMMON-NEXT: [[TMP6:%.*]] = getelementptr inbounds i32, ptr [[TMP0]], i64 [[TMP5]]
1317 ; COMMON-NEXT: br label [[TMP8:%.*]]
1319 ; COMMON-NEXT: ret void
1321 ; COMMON-NEXT: [[TMP9:%.*]] = phi i32 [ 1, [[TMP4]] ], [ [[TMP10:%.*]], [[TMP8]] ]
1322 ; COMMON-NEXT: tail call void @sink(ptr [[TMP6]])
1323 ; COMMON-NEXT: [[TMP10]] = add nuw nsw i32 [[TMP9]], 1
1324 ; COMMON-NEXT: [[TMP11:%.*]] = icmp eq i32 [[TMP10]], [[TMP1]]
1325 ; COMMON-NEXT: br i1 [[TMP11]], label [[TMP7]], label [[TMP8]]
1327 %3 = icmp sgt i32 %1, 1
1328 br i1 %3, label %4, label %7
1331 %5 = zext i32 %1 to i64
1332 %6 = getelementptr inbounds i32, ptr %0, i64 %5
1339 %9 = phi i32 [ 1, %4 ], [ %10, %8 ]
1340 tail call void @sink(ptr %6)
1341 %10 = add nuw nsw i32 %9, 1
1342 %11 = icmp eq i32 %10, %1
1343 br i1 %11, label %7, label %8
1346 ; Adjusted from PR43833
1347 define void @PR43833_simple(ptr %0, i32 %1) {
1348 ; COMMON-LABEL: define void @PR43833_simple(
1349 ; COMMON-SAME: ptr [[TMP0:%.*]], i32 [[TMP1:%.*]]) {
1350 ; COMMON-NEXT: [[TMP3:%.*]] = icmp ne i32 [[TMP1]], 0
1351 ; COMMON-NEXT: br i1 [[TMP3]], label [[TMP4:%.*]], label [[TMP7:%.*]]
1353 ; COMMON-NEXT: [[TMP5:%.*]] = zext i32 [[TMP1]] to i64
1354 ; COMMON-NEXT: [[TMP6:%.*]] = getelementptr inbounds i32, ptr [[TMP0]], i64 [[TMP5]]
1355 ; COMMON-NEXT: br label [[TMP8:%.*]]
1357 ; COMMON-NEXT: ret void
1359 ; COMMON-NEXT: [[TMP9:%.*]] = phi i32 [ 1, [[TMP4]] ], [ [[TMP10:%.*]], [[TMP8]] ]
1360 ; COMMON-NEXT: tail call void @sink(ptr [[TMP6]])
1361 ; COMMON-NEXT: [[TMP10]] = add nuw nsw i32 [[TMP9]], 1
1362 ; COMMON-NEXT: [[TMP11:%.*]] = icmp eq i32 [[TMP10]], [[TMP1]]
1363 ; COMMON-NEXT: br i1 [[TMP11]], label [[TMP7]], label [[TMP8]]
1365 %3 = icmp ne i32 %1, 0
1366 br i1 %3, label %4, label %7
1369 %5 = zext i32 %1 to i64
1370 %6 = getelementptr inbounds i32, ptr %0, i64 %5
1377 %9 = phi i32 [ 1, %4 ], [ %10, %8 ]
1378 tail call void @sink(ptr %6)
1379 %10 = add nuw nsw i32 %9, 1
1380 %11 = icmp eq i32 %10, %1
1381 br i1 %11, label %7, label %8
1384 define ptr @pr91177_non_inbounds_gep(ptr nonnull %arg) {
1385 ; FNATTRS-LABEL: define ptr @pr91177_non_inbounds_gep(
1386 ; FNATTRS-SAME: ptr nonnull readnone [[ARG:%.*]]) #[[ATTR0]] {
1387 ; FNATTRS-NEXT: [[RES:%.*]] = getelementptr i8, ptr [[ARG]], i64 -8
1388 ; FNATTRS-NEXT: ret ptr [[RES]]
1390 ; ATTRIBUTOR-LABEL: define ptr @pr91177_non_inbounds_gep(
1391 ; ATTRIBUTOR-SAME: ptr nofree nonnull readnone [[ARG:%.*]]) #[[ATTR0]] {
1392 ; ATTRIBUTOR-NEXT: [[RES:%.*]] = getelementptr i8, ptr [[ARG]], i64 -8
1393 ; ATTRIBUTOR-NEXT: ret ptr [[RES]]
1395 %res = getelementptr i8, ptr %arg, i64 -8
1399 attributes #0 = { null_pointer_is_valid }
1400 attributes #1 = { nounwind willreturn}