• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes
2; RUN: opt -attributor -enable-new-pm=0 -attributor-manifest-internal  -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=19 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
3; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal  -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=21 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
4; RUN: opt -attributor-cgscc -enable-new-pm=0 -attributor-manifest-internal  -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
5; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal  -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
6; FIXME: Figure out why we need 16 iterations here.
7
8declare void @deref_phi_user(i32* %a);
9
10; TEST 1
11; take mininimum of return values
12;
13define i32* @test1(i32* dereferenceable(4) %0, double* dereferenceable(8) %1, i1 zeroext %2) local_unnamed_addr {
14; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone willreturn
15; IS__TUNIT____-LABEL: define {{[^@]+}}@test1
16; IS__TUNIT____-SAME: (i32* nofree nonnull readnone dereferenceable(4) "no-capture-maybe-returned" [[TMP0:%.*]], double* nofree nonnull readnone dereferenceable(8) "no-capture-maybe-returned" [[TMP1:%.*]], i1 zeroext [[TMP2:%.*]]) local_unnamed_addr [[ATTR0:#.*]] {
17; IS__TUNIT____-NEXT:    [[TMP4:%.*]] = bitcast double* [[TMP1]] to i32*
18; IS__TUNIT____-NEXT:    [[TMP5:%.*]] = select i1 [[TMP2]], i32* [[TMP0]], i32* [[TMP4]]
19; IS__TUNIT____-NEXT:    ret i32* [[TMP5]]
20;
21; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
22; IS__CGSCC____-LABEL: define {{[^@]+}}@test1
23; IS__CGSCC____-SAME: (i32* nofree nonnull readnone dereferenceable(4) "no-capture-maybe-returned" [[TMP0:%.*]], double* nofree nonnull readnone dereferenceable(8) "no-capture-maybe-returned" [[TMP1:%.*]], i1 zeroext [[TMP2:%.*]]) local_unnamed_addr [[ATTR0:#.*]] {
24; IS__CGSCC____-NEXT:    [[TMP4:%.*]] = bitcast double* [[TMP1]] to i32*
25; IS__CGSCC____-NEXT:    [[TMP5:%.*]] = select i1 [[TMP2]], i32* [[TMP0]], i32* [[TMP4]]
26; IS__CGSCC____-NEXT:    ret i32* [[TMP5]]
27;
28  %4 = bitcast double* %1 to i32*
29  %5 = select i1 %2, i32* %0, i32* %4
30  ret i32* %5
31}
32
33; TEST 2
34define i32* @test2(i32* dereferenceable_or_null(4) %0, double* dereferenceable(8) %1, i1 zeroext %2) local_unnamed_addr {
35; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone willreturn
36; IS__TUNIT____-LABEL: define {{[^@]+}}@test2
37; IS__TUNIT____-SAME: (i32* nofree readnone dereferenceable_or_null(4) "no-capture-maybe-returned" [[TMP0:%.*]], double* nofree nonnull readnone dereferenceable(8) "no-capture-maybe-returned" [[TMP1:%.*]], i1 zeroext [[TMP2:%.*]]) local_unnamed_addr [[ATTR0]] {
38; IS__TUNIT____-NEXT:    [[TMP4:%.*]] = bitcast double* [[TMP1]] to i32*
39; IS__TUNIT____-NEXT:    [[TMP5:%.*]] = select i1 [[TMP2]], i32* [[TMP0]], i32* [[TMP4]]
40; IS__TUNIT____-NEXT:    ret i32* [[TMP5]]
41;
42; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
43; IS__CGSCC____-LABEL: define {{[^@]+}}@test2
44; IS__CGSCC____-SAME: (i32* nofree readnone dereferenceable_or_null(4) "no-capture-maybe-returned" [[TMP0:%.*]], double* nofree nonnull readnone dereferenceable(8) "no-capture-maybe-returned" [[TMP1:%.*]], i1 zeroext [[TMP2:%.*]]) local_unnamed_addr [[ATTR0]] {
45; IS__CGSCC____-NEXT:    [[TMP4:%.*]] = bitcast double* [[TMP1]] to i32*
46; IS__CGSCC____-NEXT:    [[TMP5:%.*]] = select i1 [[TMP2]], i32* [[TMP0]], i32* [[TMP4]]
47; IS__CGSCC____-NEXT:    ret i32* [[TMP5]]
48;
49  %4 = bitcast double* %1 to i32*
50  %5 = select i1 %2, i32* %0, i32* %4
51  ret i32* %5
52}
53
54; TEST 3
55; GEP inbounds
56define i32* @test3_1(i32* dereferenceable(8) %0) local_unnamed_addr {
57; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone willreturn
58; IS__TUNIT____-LABEL: define {{[^@]+}}@test3_1
59; IS__TUNIT____-SAME: (i32* nofree nonnull readnone dereferenceable(8) "no-capture-maybe-returned" [[TMP0:%.*]]) local_unnamed_addr [[ATTR0]] {
60; IS__TUNIT____-NEXT:    [[RET:%.*]] = getelementptr inbounds i32, i32* [[TMP0]], i64 1
61; IS__TUNIT____-NEXT:    ret i32* [[RET]]
62;
63; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
64; IS__CGSCC____-LABEL: define {{[^@]+}}@test3_1
65; IS__CGSCC____-SAME: (i32* nofree nonnull readnone dereferenceable(8) "no-capture-maybe-returned" [[TMP0:%.*]]) local_unnamed_addr [[ATTR0]] {
66; IS__CGSCC____-NEXT:    [[RET:%.*]] = getelementptr inbounds i32, i32* [[TMP0]], i64 1
67; IS__CGSCC____-NEXT:    ret i32* [[RET]]
68;
69  %ret = getelementptr inbounds i32, i32* %0, i64 1
70  ret i32* %ret
71}
72
73define i32* @test3_2(i32* dereferenceable_or_null(32) %0) local_unnamed_addr {
74; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone willreturn
75; IS__TUNIT____-LABEL: define {{[^@]+}}@test3_2
76; IS__TUNIT____-SAME: (i32* nofree readnone dereferenceable_or_null(32) "no-capture-maybe-returned" [[TMP0:%.*]]) local_unnamed_addr [[ATTR0]] {
77; IS__TUNIT____-NEXT:    [[RET:%.*]] = getelementptr inbounds i32, i32* [[TMP0]], i64 4
78; IS__TUNIT____-NEXT:    ret i32* [[RET]]
79;
80; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
81; IS__CGSCC____-LABEL: define {{[^@]+}}@test3_2
82; IS__CGSCC____-SAME: (i32* nofree readnone dereferenceable_or_null(32) "no-capture-maybe-returned" [[TMP0:%.*]]) local_unnamed_addr [[ATTR0]] {
83; IS__CGSCC____-NEXT:    [[RET:%.*]] = getelementptr inbounds i32, i32* [[TMP0]], i64 4
84; IS__CGSCC____-NEXT:    ret i32* [[RET]]
85;
86  %ret = getelementptr inbounds i32, i32* %0, i64 4
87  ret i32* %ret
88}
89
90define i32* @test3_3(i32* dereferenceable(8) %0, i32* dereferenceable(16) %1, i1 %2) local_unnamed_addr {
91; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone willreturn
92; IS__TUNIT____-LABEL: define {{[^@]+}}@test3_3
93; IS__TUNIT____-SAME: (i32* nofree nonnull readnone dereferenceable(8) "no-capture-maybe-returned" [[TMP0:%.*]], i32* nofree nonnull readnone dereferenceable(16) "no-capture-maybe-returned" [[TMP1:%.*]], i1 [[TMP2:%.*]]) local_unnamed_addr [[ATTR0]] {
94; IS__TUNIT____-NEXT:    [[RET1:%.*]] = getelementptr inbounds i32, i32* [[TMP0]], i64 1
95; IS__TUNIT____-NEXT:    [[RET2:%.*]] = getelementptr inbounds i32, i32* [[TMP1]], i64 2
96; IS__TUNIT____-NEXT:    [[RET:%.*]] = select i1 [[TMP2]], i32* [[RET1]], i32* [[RET2]]
97; IS__TUNIT____-NEXT:    ret i32* [[RET]]
98;
99; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
100; IS__CGSCC____-LABEL: define {{[^@]+}}@test3_3
101; IS__CGSCC____-SAME: (i32* nofree nonnull readnone dereferenceable(8) "no-capture-maybe-returned" [[TMP0:%.*]], i32* nofree nonnull readnone dereferenceable(16) "no-capture-maybe-returned" [[TMP1:%.*]], i1 [[TMP2:%.*]]) local_unnamed_addr [[ATTR0]] {
102; IS__CGSCC____-NEXT:    [[RET1:%.*]] = getelementptr inbounds i32, i32* [[TMP0]], i64 1
103; IS__CGSCC____-NEXT:    [[RET2:%.*]] = getelementptr inbounds i32, i32* [[TMP1]], i64 2
104; IS__CGSCC____-NEXT:    [[RET:%.*]] = select i1 [[TMP2]], i32* [[RET1]], i32* [[RET2]]
105; IS__CGSCC____-NEXT:    ret i32* [[RET]]
106;
107  %ret1 = getelementptr inbounds i32, i32* %0, i64 1
108  %ret2 = getelementptr inbounds i32, i32* %1, i64 2
109  %ret = select i1 %2, i32* %ret1, i32* %ret2
110  ret i32* %ret
111}
112
113; TEST 4
114; Better than known in IR.
115
116define dereferenceable(4) i32* @test4(i32* dereferenceable(8) %0) local_unnamed_addr {
117; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone willreturn
118; IS__TUNIT____-LABEL: define {{[^@]+}}@test4
119; IS__TUNIT____-SAME: (i32* nofree nonnull readnone returned dereferenceable(8) "no-capture-maybe-returned" [[TMP0:%.*]]) local_unnamed_addr [[ATTR0]] {
120; IS__TUNIT____-NEXT:    ret i32* [[TMP0]]
121;
122; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
123; IS__CGSCC____-LABEL: define {{[^@]+}}@test4
124; IS__CGSCC____-SAME: (i32* nofree nonnull readnone returned dereferenceable(8) "no-capture-maybe-returned" [[TMP0:%.*]]) local_unnamed_addr [[ATTR0]] {
125; IS__CGSCC____-NEXT:    ret i32* [[TMP0]]
126;
127  ret i32* %0
128}
129
130; TEST 5
131; loop in which dereferenceabily "grows"
132define void @deref_phi_growing(i32* dereferenceable(4000) %a) {
133; CHECK-LABEL: define {{[^@]+}}@deref_phi_growing
134; CHECK-SAME: (i32* nonnull dereferenceable(4000) [[A:%.*]]) {
135; CHECK-NEXT:  entry:
136; CHECK-NEXT:    br label [[FOR_COND:%.*]]
137; CHECK:       for.cond:
138; CHECK-NEXT:    [[I_0:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_INC:%.*]] ]
139; CHECK-NEXT:    [[A_ADDR_0:%.*]] = phi i32* [ [[A]], [[ENTRY]] ], [ [[INCDEC_PTR:%.*]], [[FOR_INC]] ]
140; CHECK-NEXT:    call void @deref_phi_user(i32* nonnull dereferenceable(4000) [[A_ADDR_0]])
141; CHECK-NEXT:    [[TMP:%.*]] = load i32, i32* [[A_ADDR_0]], align 4
142; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[I_0]], [[TMP]]
143; CHECK-NEXT:    br i1 [[CMP]], label [[FOR_BODY:%.*]], label [[FOR_COND_CLEANUP:%.*]]
144; CHECK:       for.cond.cleanup:
145; CHECK-NEXT:    br label [[FOR_END:%.*]]
146; CHECK:       for.body:
147; CHECK-NEXT:    br label [[FOR_INC]]
148; CHECK:       for.inc:
149; CHECK-NEXT:    [[INCDEC_PTR]] = getelementptr inbounds i32, i32* [[A_ADDR_0]], i64 -1
150; CHECK-NEXT:    [[INC]] = add nuw nsw i32 [[I_0]], 1
151; CHECK-NEXT:    br label [[FOR_COND]]
152; CHECK:       for.end:
153; CHECK-NEXT:    ret void
154;
155entry:
156  br label %for.cond
157
158for.cond:                                         ; preds = %for.inc, %entry
159  %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
160  %a.addr.0 = phi i32* [ %a, %entry ], [ %incdec.ptr, %for.inc ]
161  call void @deref_phi_user(i32* %a.addr.0)
162  %tmp = load i32, i32* %a.addr.0, align 4
163  %cmp = icmp slt i32 %i.0, %tmp
164  br i1 %cmp, label %for.body, label %for.cond.cleanup
165
166for.cond.cleanup:                                 ; preds = %for.cond
167  br label %for.end
168
169for.body:                                         ; preds = %for.cond
170  br label %for.inc
171
172for.inc:                                          ; preds = %for.body
173  %incdec.ptr = getelementptr inbounds i32, i32* %a.addr.0, i64 -1
174  %inc = add nuw nsw i32 %i.0, 1
175  br label %for.cond
176
177for.end:                                          ; preds = %for.cond.cleanup
178  ret void
179}
180
181; TEST 6
182; loop in which dereferenceabily "shrinks"
183define void @deref_phi_shrinking(i32* dereferenceable(4000) %a) {
184; CHECK-LABEL: define {{[^@]+}}@deref_phi_shrinking
185; CHECK-SAME: (i32* nonnull dereferenceable(4000) [[A:%.*]]) {
186; CHECK-NEXT:  entry:
187; CHECK-NEXT:    br label [[FOR_COND:%.*]]
188; CHECK:       for.cond:
189; CHECK-NEXT:    [[I_0:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_INC:%.*]] ]
190; CHECK-NEXT:    [[A_ADDR_0:%.*]] = phi i32* [ [[A]], [[ENTRY]] ], [ [[INCDEC_PTR:%.*]], [[FOR_INC]] ]
191; CHECK-NEXT:    call void @deref_phi_user(i32* nonnull [[A_ADDR_0]])
192; CHECK-NEXT:    [[TMP:%.*]] = load i32, i32* [[A_ADDR_0]], align 4
193; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[I_0]], [[TMP]]
194; CHECK-NEXT:    br i1 [[CMP]], label [[FOR_BODY:%.*]], label [[FOR_COND_CLEANUP:%.*]]
195; CHECK:       for.cond.cleanup:
196; CHECK-NEXT:    br label [[FOR_END:%.*]]
197; CHECK:       for.body:
198; CHECK-NEXT:    br label [[FOR_INC]]
199; CHECK:       for.inc:
200; CHECK-NEXT:    [[INCDEC_PTR]] = getelementptr inbounds i32, i32* [[A_ADDR_0]], i64 1
201; CHECK-NEXT:    [[INC]] = add nuw nsw i32 [[I_0]], 1
202; CHECK-NEXT:    br label [[FOR_COND]]
203; CHECK:       for.end:
204; CHECK-NEXT:    ret void
205;
206entry:
207  br label %for.cond
208
209for.cond:                                         ; preds = %for.inc, %entry
210  %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
211  %a.addr.0 = phi i32* [ %a, %entry ], [ %incdec.ptr, %for.inc ]
212  call void @deref_phi_user(i32* %a.addr.0)
213  %tmp = load i32, i32* %a.addr.0, align 4
214  %cmp = icmp slt i32 %i.0, %tmp
215  br i1 %cmp, label %for.body, label %for.cond.cleanup
216
217for.cond.cleanup:                                 ; preds = %for.cond
218  br label %for.end
219
220for.body:                                         ; preds = %for.cond
221  br label %for.inc
222
223for.inc:                                          ; preds = %for.body
224  %incdec.ptr = getelementptr inbounds i32, i32* %a.addr.0, i64 1
225  %inc = add nuw nsw i32 %i.0, 1
226  br label %for.cond
227
228for.end:                                          ; preds = %for.cond.cleanup
229  ret void
230}
231
232; TEST 7
233; share known infomation in must-be-executed-context
234declare i32* @unkown_ptr() willreturn nounwind
235declare i32 @unkown_f(i32*) willreturn nounwind
236define i32* @f7_0(i32* %ptr) {
237; CHECK: Function Attrs: nounwind willreturn
238; CHECK-LABEL: define {{[^@]+}}@f7_0
239; CHECK-SAME: (i32* nonnull returned dereferenceable(8) [[PTR:%.*]]) [[ATTR1:#.*]] {
240; CHECK-NEXT:    [[T:%.*]] = tail call i32 @unkown_f(i32* nonnull dereferenceable(8) [[PTR]]) [[ATTR1]]
241; CHECK-NEXT:    ret i32* [[PTR]]
242;
243  %T = tail call i32 @unkown_f(i32* dereferenceable(8) %ptr)
244  ret i32* %ptr
245}
246
247define void @f7_1(i32* %ptr, i1 %c) {
248; CHECK: Function Attrs: nounwind willreturn
249; CHECK-LABEL: define {{[^@]+}}@f7_1
250; CHECK-SAME: (i32* nonnull align 4 dereferenceable(4) [[PTR:%.*]], i1 [[C:%.*]]) [[ATTR1]] {
251; CHECK-NEXT:    [[A:%.*]] = tail call i32 @unkown_f(i32* nonnull align 4 dereferenceable(4) [[PTR]]) [[ATTR1]]
252; CHECK-NEXT:    [[B:%.*]] = tail call i32 @unkown_f(i32* nonnull align 4 dereferenceable(4) [[PTR]]) [[ATTR1]]
253; CHECK-NEXT:    br i1 [[C]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
254; CHECK:       if.true:
255; CHECK-NEXT:    [[C:%.*]] = tail call i32 @unkown_f(i32* nonnull align 4 dereferenceable(8) [[PTR]]) [[ATTR1]]
256; CHECK-NEXT:    [[D:%.*]] = tail call i32 @unkown_f(i32* nonnull align 4 dereferenceable(8) [[PTR]]) [[ATTR1]]
257; CHECK-NEXT:    [[E:%.*]] = tail call i32 @unkown_f(i32* nonnull align 4 dereferenceable(8) [[PTR]]) [[ATTR1]]
258; CHECK-NEXT:    ret void
259; CHECK:       if.false:
260; CHECK-NEXT:    ret void
261;
262  %A = tail call i32 @unkown_f(i32* %ptr)
263  %ptr.0 = load i32, i32* %ptr
264  ; deref 4 hold
265; FIXME: this should be %B = tail call i32 @unkown_f(i32* nonnull dereferenceable(4) %ptr)
266  %B = tail call i32 @unkown_f(i32* dereferenceable(1) %ptr)
267  br i1%c, label %if.true, label %if.false
268if.true:
269  %C = tail call i32 @unkown_f(i32* %ptr)
270  %D = tail call i32 @unkown_f(i32* dereferenceable(8) %ptr)
271  %E = tail call i32 @unkown_f(i32* %ptr)
272  ret void
273if.false:
274  ret void
275}
276
277define void @f7_2(i1 %c) {
278; CHECK: Function Attrs: nounwind willreturn
279; CHECK-LABEL: define {{[^@]+}}@f7_2
280; CHECK-SAME: (i1 [[C:%.*]]) [[ATTR1]] {
281; CHECK-NEXT:    [[PTR:%.*]] = tail call nonnull align 4 dereferenceable(4) i32* @unkown_ptr() [[ATTR1]]
282; CHECK-NEXT:    [[A:%.*]] = tail call i32 @unkown_f(i32* nonnull align 4 dereferenceable(4) [[PTR]]) [[ATTR1]]
283; CHECK-NEXT:    [[ARG_A_0:%.*]] = load i32, i32* [[PTR]], align 4
284; CHECK-NEXT:    [[B:%.*]] = tail call i32 @unkown_f(i32* nonnull align 4 dereferenceable(4) [[PTR]]) [[ATTR1]]
285; CHECK-NEXT:    br i1 [[C]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
286; CHECK:       if.true:
287; CHECK-NEXT:    [[C:%.*]] = tail call i32 @unkown_f(i32* nonnull align 4 dereferenceable(8) [[PTR]]) [[ATTR1]]
288; CHECK-NEXT:    [[D:%.*]] = tail call i32 @unkown_f(i32* nonnull align 4 dereferenceable(8) [[PTR]]) [[ATTR1]]
289; CHECK-NEXT:    [[E:%.*]] = tail call i32 @unkown_f(i32* nonnull align 4 dereferenceable(8) [[PTR]]) [[ATTR1]]
290; CHECK-NEXT:    ret void
291; CHECK:       if.false:
292; CHECK-NEXT:    ret void
293;
294  %ptr =  tail call i32* @unkown_ptr()
295  %A = tail call i32 @unkown_f(i32* %ptr)
296  %arg_a.0 = load i32, i32* %ptr
297  ; deref 4 hold
298  %B = tail call i32 @unkown_f(i32* dereferenceable(1) %ptr)
299  br i1%c, label %if.true, label %if.false
300if.true:
301  %C = tail call i32 @unkown_f(i32* %ptr)
302  %D = tail call i32 @unkown_f(i32* dereferenceable(8) %ptr)
303  %E = tail call i32 @unkown_f(i32* %ptr)
304  ret void
305if.false:
306  ret void
307}
308
309define i32* @f7_3() {
310; CHECK: Function Attrs: nounwind willreturn
311; CHECK-LABEL: define {{[^@]+}}@f7_3
312; CHECK-SAME: () [[ATTR1]] {
313; CHECK-NEXT:    [[PTR:%.*]] = tail call nonnull align 16 dereferenceable(4) i32* @unkown_ptr() [[ATTR1]]
314; CHECK-NEXT:    store i32 10, i32* [[PTR]], align 16
315; CHECK-NEXT:    ret i32* [[PTR]]
316;
317  %ptr = tail call i32* @unkown_ptr()
318  store i32 10, i32* %ptr, align 16
319  ret i32* %ptr
320}
321
322; FIXME: This should have a return dereferenceable(8) but we need to make sure it will work in loops as well.
323define i32* @test_for_minus_index(i32* %p) {
324; IS__TUNIT____: Function Attrs: argmemonly nofree nosync nounwind willreturn writeonly
325; IS__TUNIT____-LABEL: define {{[^@]+}}@test_for_minus_index
326; IS__TUNIT____-SAME: (i32* nofree nonnull writeonly align 4 "no-capture-maybe-returned" [[P:%.*]]) [[ATTR2:#.*]] {
327; IS__TUNIT____-NEXT:    [[Q:%.*]] = getelementptr inbounds i32, i32* [[P]], i32 -2
328; IS__TUNIT____-NEXT:    store i32 1, i32* [[Q]], align 4
329; IS__TUNIT____-NEXT:    ret i32* [[Q]]
330;
331; IS__CGSCC____: Function Attrs: argmemonly nofree norecurse nosync nounwind willreturn writeonly
332; IS__CGSCC____-LABEL: define {{[^@]+}}@test_for_minus_index
333; IS__CGSCC____-SAME: (i32* nofree nonnull writeonly align 4 "no-capture-maybe-returned" [[P:%.*]]) [[ATTR2:#.*]] {
334; IS__CGSCC____-NEXT:    [[Q:%.*]] = getelementptr inbounds i32, i32* [[P]], i32 -2
335; IS__CGSCC____-NEXT:    store i32 1, i32* [[Q]], align 4
336; IS__CGSCC____-NEXT:    ret i32* [[Q]]
337;
338  %q = getelementptr inbounds i32, i32* %p, i32 -2
339  store i32 1, i32* %q
340  ret i32* %q
341}
342
343define void @deref_or_null_and_nonnull(i32* dereferenceable_or_null(100) %0) {
344; IS__TUNIT____: Function Attrs: argmemonly nofree nosync nounwind willreturn writeonly
345; IS__TUNIT____-LABEL: define {{[^@]+}}@deref_or_null_and_nonnull
346; IS__TUNIT____-SAME: (i32* nocapture nofree nonnull writeonly align 4 dereferenceable(100) [[TMP0:%.*]]) [[ATTR2]] {
347; IS__TUNIT____-NEXT:    store i32 1, i32* [[TMP0]], align 4
348; IS__TUNIT____-NEXT:    ret void
349;
350; IS__CGSCC____: Function Attrs: argmemonly nofree norecurse nosync nounwind willreturn writeonly
351; IS__CGSCC____-LABEL: define {{[^@]+}}@deref_or_null_and_nonnull
352; IS__CGSCC____-SAME: (i32* nocapture nofree nonnull writeonly align 4 dereferenceable(100) [[TMP0:%.*]]) [[ATTR2]] {
353; IS__CGSCC____-NEXT:    store i32 1, i32* [[TMP0]], align 4
354; IS__CGSCC____-NEXT:    ret void
355;
356  store i32 1, i32* %0
357  ret void
358}
359
360; TEST 8
361; Use Constant range in deereferenceable
362; void g(int *p, long long int *range){
363;   int r = *range ; // [10, 99]
364;   fill_range(p, *range);
365; }
366
367; FIXME: %ptr should be dereferenceable(31)
368define void @test8(i8* %ptr) #0 {
369; IS__TUNIT_OPM: Function Attrs: argmemonly nofree nosync nounwind writeonly
370; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@test8
371; IS__TUNIT_OPM-SAME: (i8* nocapture nofree nonnull writeonly [[PTR:%.*]]) [[ATTR3:#.*]] {
372; IS__TUNIT_OPM-NEXT:    br label [[TMP1:%.*]]
373; IS__TUNIT_OPM:       1:
374; IS__TUNIT_OPM-NEXT:    [[I_0:%.*]] = phi i32 [ 20, [[TMP0:%.*]] ], [ [[TMP4:%.*]], [[TMP5:%.*]] ]
375; IS__TUNIT_OPM-NEXT:    [[TMP2:%.*]] = sext i32 [[I_0]] to i64
376; IS__TUNIT_OPM-NEXT:    [[TMP3:%.*]] = getelementptr inbounds i8, i8* [[PTR]], i64 [[TMP2]]
377; IS__TUNIT_OPM-NEXT:    store i8 32, i8* [[TMP3]], align 1
378; IS__TUNIT_OPM-NEXT:    [[TMP4]] = add nsw i32 [[I_0]], 1
379; IS__TUNIT_OPM-NEXT:    br label [[TMP5]]
380; IS__TUNIT_OPM:       5:
381; IS__TUNIT_OPM-NEXT:    [[TMP6:%.*]] = icmp slt i32 [[TMP4]], 30
382; IS__TUNIT_OPM-NEXT:    br i1 [[TMP6]], label [[TMP1]], label [[TMP7:%.*]]
383; IS__TUNIT_OPM:       7:
384; IS__TUNIT_OPM-NEXT:    ret void
385;
386; IS__TUNIT_NPM: Function Attrs: argmemonly nofree nosync nounwind willreturn writeonly
387; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@test8
388; IS__TUNIT_NPM-SAME: (i8* nocapture nofree nonnull writeonly dereferenceable(21) [[PTR:%.*]]) [[ATTR2:#.*]] {
389; IS__TUNIT_NPM-NEXT:    br label [[TMP1:%.*]]
390; IS__TUNIT_NPM:       1:
391; IS__TUNIT_NPM-NEXT:    [[I_0:%.*]] = phi i32 [ 20, [[TMP0:%.*]] ], [ [[TMP4:%.*]], [[TMP5:%.*]] ]
392; IS__TUNIT_NPM-NEXT:    [[TMP2:%.*]] = sext i32 [[I_0]] to i64
393; IS__TUNIT_NPM-NEXT:    [[TMP3:%.*]] = getelementptr inbounds i8, i8* [[PTR]], i64 [[TMP2]]
394; IS__TUNIT_NPM-NEXT:    store i8 32, i8* [[TMP3]], align 1
395; IS__TUNIT_NPM-NEXT:    [[TMP4]] = add nsw i32 [[I_0]], 1
396; IS__TUNIT_NPM-NEXT:    br label [[TMP5]]
397; IS__TUNIT_NPM:       5:
398; IS__TUNIT_NPM-NEXT:    [[TMP6:%.*]] = icmp slt i32 [[TMP4]], 30
399; IS__TUNIT_NPM-NEXT:    br i1 [[TMP6]], label [[TMP1]], label [[TMP7:%.*]]
400; IS__TUNIT_NPM:       7:
401; IS__TUNIT_NPM-NEXT:    ret void
402;
403; IS__CGSCC_OPM: Function Attrs: argmemonly nofree norecurse nosync nounwind writeonly
404; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@test8
405; IS__CGSCC_OPM-SAME: (i8* nocapture nofree nonnull writeonly [[PTR:%.*]]) [[ATTR3:#.*]] {
406; IS__CGSCC_OPM-NEXT:    br label [[TMP1:%.*]]
407; IS__CGSCC_OPM:       1:
408; IS__CGSCC_OPM-NEXT:    [[I_0:%.*]] = phi i32 [ 20, [[TMP0:%.*]] ], [ [[TMP4:%.*]], [[TMP5:%.*]] ]
409; IS__CGSCC_OPM-NEXT:    [[TMP2:%.*]] = sext i32 [[I_0]] to i64
410; IS__CGSCC_OPM-NEXT:    [[TMP3:%.*]] = getelementptr inbounds i8, i8* [[PTR]], i64 [[TMP2]]
411; IS__CGSCC_OPM-NEXT:    store i8 32, i8* [[TMP3]], align 1
412; IS__CGSCC_OPM-NEXT:    [[TMP4]] = add nsw i32 [[I_0]], 1
413; IS__CGSCC_OPM-NEXT:    br label [[TMP5]]
414; IS__CGSCC_OPM:       5:
415; IS__CGSCC_OPM-NEXT:    [[TMP6:%.*]] = icmp slt i32 [[TMP4]], 30
416; IS__CGSCC_OPM-NEXT:    br i1 [[TMP6]], label [[TMP1]], label [[TMP7:%.*]]
417; IS__CGSCC_OPM:       7:
418; IS__CGSCC_OPM-NEXT:    ret void
419;
420; IS__CGSCC_NPM: Function Attrs: argmemonly nofree norecurse nosync nounwind willreturn writeonly
421; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@test8
422; IS__CGSCC_NPM-SAME: (i8* nocapture nofree nonnull writeonly dereferenceable(21) [[PTR:%.*]]) [[ATTR2:#.*]] {
423; IS__CGSCC_NPM-NEXT:    br label [[TMP1:%.*]]
424; IS__CGSCC_NPM:       1:
425; IS__CGSCC_NPM-NEXT:    [[I_0:%.*]] = phi i32 [ 20, [[TMP0:%.*]] ], [ [[TMP4:%.*]], [[TMP5:%.*]] ]
426; IS__CGSCC_NPM-NEXT:    [[TMP2:%.*]] = sext i32 [[I_0]] to i64
427; IS__CGSCC_NPM-NEXT:    [[TMP3:%.*]] = getelementptr inbounds i8, i8* [[PTR]], i64 [[TMP2]]
428; IS__CGSCC_NPM-NEXT:    store i8 32, i8* [[TMP3]], align 1
429; IS__CGSCC_NPM-NEXT:    [[TMP4]] = add nsw i32 [[I_0]], 1
430; IS__CGSCC_NPM-NEXT:    br label [[TMP5]]
431; IS__CGSCC_NPM:       5:
432; IS__CGSCC_NPM-NEXT:    [[TMP6:%.*]] = icmp slt i32 [[TMP4]], 30
433; IS__CGSCC_NPM-NEXT:    br i1 [[TMP6]], label [[TMP1]], label [[TMP7:%.*]]
434; IS__CGSCC_NPM:       7:
435; IS__CGSCC_NPM-NEXT:    ret void
436;
437  br label %1
4381:                                                ; preds = %5, %0
439  %i.0 = phi i32 [ 20, %0 ], [ %4, %5 ]
440  %2 = sext i32 %i.0 to i64
441  %3 = getelementptr inbounds i8, i8* %ptr, i64 %2
442  store i8 32, i8* %3, align 1
443  %4 = add nsw i32 %i.0, 1
444  br label %5
4455:                                                ; preds = %1
446  %6 = icmp slt i32 %4, 30
447  br i1 %6, label %1, label %7
448
4497:                                                ; preds = %5
450  ret void
451}
452
453; 8.2 (negative case)
454define void @test8_neg(i32 %i, i8* %ptr) #0 {
455; IS__TUNIT____: Function Attrs: argmemonly nofree nosync nounwind willreturn writeonly
456; IS__TUNIT____-LABEL: define {{[^@]+}}@test8_neg
457; IS__TUNIT____-SAME: (i32 [[I:%.*]], i8* nocapture nofree nonnull writeonly [[PTR:%.*]]) [[ATTR2]] {
458; IS__TUNIT____-NEXT:    [[TMP1:%.*]] = sext i32 [[I]] to i64
459; IS__TUNIT____-NEXT:    [[TMP2:%.*]] = getelementptr inbounds i8, i8* [[PTR]], i64 [[TMP1]]
460; IS__TUNIT____-NEXT:    store i8 65, i8* [[TMP2]], align 1
461; IS__TUNIT____-NEXT:    ret void
462;
463; IS__CGSCC____: Function Attrs: argmemonly nofree norecurse nosync nounwind willreturn writeonly
464; IS__CGSCC____-LABEL: define {{[^@]+}}@test8_neg
465; IS__CGSCC____-SAME: (i32 [[I:%.*]], i8* nocapture nofree nonnull writeonly [[PTR:%.*]]) [[ATTR2]] {
466; IS__CGSCC____-NEXT:    [[TMP1:%.*]] = sext i32 [[I]] to i64
467; IS__CGSCC____-NEXT:    [[TMP2:%.*]] = getelementptr inbounds i8, i8* [[PTR]], i64 [[TMP1]]
468; IS__CGSCC____-NEXT:    store i8 65, i8* [[TMP2]], align 1
469; IS__CGSCC____-NEXT:    ret void
470;
471  %1 = sext i32 %i to i64
472  %2 = getelementptr inbounds i8, i8* %ptr, i64 %1
473  store i8 65, i8* %2, align 1
474  ret void
475}
476
477; void fill_range(int* p, long long int start){
478;   for(long long int i = start;i<start+10;i++){
479;     // If p[i] is inbounds, p is dereferenceable(40) at least.
480;     p[i] = i;
481;   }
482; }
483
484; NOTE: %p should not be dereferenceable
485define internal void @fill_range_not_inbounds(i32* %p, i64 %start){
486; IS__TUNIT_OPM: Function Attrs: argmemonly nofree nosync nounwind writeonly
487; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@fill_range_not_inbounds
488; IS__TUNIT_OPM-SAME: (i32* nocapture nofree writeonly [[P:%.*]], i64 [[START:%.*]]) [[ATTR3]] {
489; IS__TUNIT_OPM-NEXT:  entry:
490; IS__TUNIT_OPM-NEXT:    [[TMP0:%.*]] = add nsw i64 [[START]], 9
491; IS__TUNIT_OPM-NEXT:    br label [[FOR_BODY:%.*]]
492; IS__TUNIT_OPM:       for.cond.cleanup:
493; IS__TUNIT_OPM-NEXT:    ret void
494; IS__TUNIT_OPM:       for.body:
495; IS__TUNIT_OPM-NEXT:    [[I_06:%.*]] = phi i64 [ [[START]], [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_BODY]] ]
496; IS__TUNIT_OPM-NEXT:    [[CONV:%.*]] = trunc i64 [[I_06]] to i32
497; IS__TUNIT_OPM-NEXT:    [[ARRAYIDX:%.*]] = getelementptr i32, i32* [[P]], i64 [[I_06]]
498; IS__TUNIT_OPM-NEXT:    store i32 [[CONV]], i32* [[ARRAYIDX]], align 4
499; IS__TUNIT_OPM-NEXT:    [[INC]] = add nsw i64 [[I_06]], 1
500; IS__TUNIT_OPM-NEXT:    [[CMP:%.*]] = icmp slt i64 [[I_06]], [[TMP0]]
501; IS__TUNIT_OPM-NEXT:    br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_COND_CLEANUP:%.*]]
502;
503; IS__TUNIT_NPM: Function Attrs: argmemonly nofree nosync nounwind willreturn writeonly
504; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@fill_range_not_inbounds
505; IS__TUNIT_NPM-SAME: (i32* nocapture nofree writeonly [[P:%.*]], i64 [[START:%.*]]) [[ATTR2]] {
506; IS__TUNIT_NPM-NEXT:  entry:
507; IS__TUNIT_NPM-NEXT:    [[TMP0:%.*]] = add nsw i64 [[START]], 9
508; IS__TUNIT_NPM-NEXT:    br label [[FOR_BODY:%.*]]
509; IS__TUNIT_NPM:       for.cond.cleanup:
510; IS__TUNIT_NPM-NEXT:    ret void
511; IS__TUNIT_NPM:       for.body:
512; IS__TUNIT_NPM-NEXT:    [[I_06:%.*]] = phi i64 [ [[START]], [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_BODY]] ]
513; IS__TUNIT_NPM-NEXT:    [[CONV:%.*]] = trunc i64 [[I_06]] to i32
514; IS__TUNIT_NPM-NEXT:    [[ARRAYIDX:%.*]] = getelementptr i32, i32* [[P]], i64 [[I_06]]
515; IS__TUNIT_NPM-NEXT:    store i32 [[CONV]], i32* [[ARRAYIDX]], align 4
516; IS__TUNIT_NPM-NEXT:    [[INC]] = add nsw i64 [[I_06]], 1
517; IS__TUNIT_NPM-NEXT:    [[CMP:%.*]] = icmp slt i64 [[I_06]], [[TMP0]]
518; IS__TUNIT_NPM-NEXT:    br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_COND_CLEANUP:%.*]]
519;
520; IS__CGSCC_OPM: Function Attrs: argmemonly nofree norecurse nosync nounwind writeonly
521; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@fill_range_not_inbounds
522; IS__CGSCC_OPM-SAME: (i32* nocapture nofree writeonly [[P:%.*]], i64 [[START:%.*]]) [[ATTR3]] {
523; IS__CGSCC_OPM-NEXT:  entry:
524; IS__CGSCC_OPM-NEXT:    [[TMP0:%.*]] = add nsw i64 [[START]], 9
525; IS__CGSCC_OPM-NEXT:    br label [[FOR_BODY:%.*]]
526; IS__CGSCC_OPM:       for.cond.cleanup:
527; IS__CGSCC_OPM-NEXT:    ret void
528; IS__CGSCC_OPM:       for.body:
529; IS__CGSCC_OPM-NEXT:    [[I_06:%.*]] = phi i64 [ [[START]], [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_BODY]] ]
530; IS__CGSCC_OPM-NEXT:    [[CONV:%.*]] = trunc i64 [[I_06]] to i32
531; IS__CGSCC_OPM-NEXT:    [[ARRAYIDX:%.*]] = getelementptr i32, i32* [[P]], i64 [[I_06]]
532; IS__CGSCC_OPM-NEXT:    store i32 [[CONV]], i32* [[ARRAYIDX]], align 4
533; IS__CGSCC_OPM-NEXT:    [[INC]] = add nsw i64 [[I_06]], 1
534; IS__CGSCC_OPM-NEXT:    [[CMP:%.*]] = icmp slt i64 [[I_06]], [[TMP0]]
535; IS__CGSCC_OPM-NEXT:    br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_COND_CLEANUP:%.*]]
536;
537; IS__CGSCC_NPM: Function Attrs: argmemonly nofree norecurse nosync nounwind willreturn writeonly
538; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@fill_range_not_inbounds
539; IS__CGSCC_NPM-SAME: (i32* nocapture nofree writeonly [[P:%.*]], i64 [[START:%.*]]) [[ATTR2]] {
540; IS__CGSCC_NPM-NEXT:  entry:
541; IS__CGSCC_NPM-NEXT:    [[TMP0:%.*]] = add nsw i64 [[START]], 9
542; IS__CGSCC_NPM-NEXT:    br label [[FOR_BODY:%.*]]
543; IS__CGSCC_NPM:       for.cond.cleanup:
544; IS__CGSCC_NPM-NEXT:    ret void
545; IS__CGSCC_NPM:       for.body:
546; IS__CGSCC_NPM-NEXT:    [[I_06:%.*]] = phi i64 [ [[START]], [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_BODY]] ]
547; IS__CGSCC_NPM-NEXT:    [[CONV:%.*]] = trunc i64 [[I_06]] to i32
548; IS__CGSCC_NPM-NEXT:    [[ARRAYIDX:%.*]] = getelementptr i32, i32* [[P]], i64 [[I_06]]
549; IS__CGSCC_NPM-NEXT:    store i32 [[CONV]], i32* [[ARRAYIDX]], align 4
550; IS__CGSCC_NPM-NEXT:    [[INC]] = add nsw i64 [[I_06]], 1
551; IS__CGSCC_NPM-NEXT:    [[CMP:%.*]] = icmp slt i64 [[I_06]], [[TMP0]]
552; IS__CGSCC_NPM-NEXT:    br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_COND_CLEANUP:%.*]]
553;
554entry:
555  %0 = add nsw i64 %start, 9
556  br label %for.body
557
558for.cond.cleanup:                                 ; preds = %for.body
559  ret void
560
561for.body:                                         ; preds = %entry, %for.body
562  %i.06 = phi i64 [ %start, %entry ], [ %inc, %for.body ]
563  %conv = trunc i64 %i.06 to i32
564  %arrayidx = getelementptr i32, i32* %p, i64 %i.06
565  store i32 %conv, i32* %arrayidx, align 4
566  %inc = add nsw i64 %i.06, 1
567  %cmp = icmp slt i64 %i.06, %0
568  br i1 %cmp, label %for.body, label %for.cond.cleanup
569}
570
571; FIXME: %p should be dereferenceable(40)
572define internal void @fill_range_inbounds(i32* %p, i64 %start){
573; IS__TUNIT_OPM: Function Attrs: argmemonly nofree nosync nounwind writeonly
574; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@fill_range_inbounds
575; IS__TUNIT_OPM-SAME: (i32* nocapture nofree writeonly [[P:%.*]], i64 [[START:%.*]]) [[ATTR3]] {
576; IS__TUNIT_OPM-NEXT:  entry:
577; IS__TUNIT_OPM-NEXT:    [[TMP0:%.*]] = add nsw i64 [[START]], 9
578; IS__TUNIT_OPM-NEXT:    br label [[FOR_BODY:%.*]]
579; IS__TUNIT_OPM:       for.cond.cleanup:
580; IS__TUNIT_OPM-NEXT:    ret void
581; IS__TUNIT_OPM:       for.body:
582; IS__TUNIT_OPM-NEXT:    [[I_06:%.*]] = phi i64 [ [[START]], [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_BODY]] ]
583; IS__TUNIT_OPM-NEXT:    [[CONV:%.*]] = trunc i64 [[I_06]] to i32
584; IS__TUNIT_OPM-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds i32, i32* [[P]], i64 [[I_06]]
585; IS__TUNIT_OPM-NEXT:    store i32 [[CONV]], i32* [[ARRAYIDX]], align 4
586; IS__TUNIT_OPM-NEXT:    [[INC]] = add nsw i64 [[I_06]], 1
587; IS__TUNIT_OPM-NEXT:    [[CMP:%.*]] = icmp slt i64 [[I_06]], [[TMP0]]
588; IS__TUNIT_OPM-NEXT:    br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_COND_CLEANUP:%.*]]
589;
590; IS__TUNIT_NPM: Function Attrs: argmemonly nofree nosync nounwind willreturn writeonly
591; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@fill_range_inbounds
592; IS__TUNIT_NPM-SAME: (i32* nocapture nofree writeonly [[P:%.*]], i64 [[START:%.*]]) [[ATTR2]] {
593; IS__TUNIT_NPM-NEXT:  entry:
594; IS__TUNIT_NPM-NEXT:    [[TMP0:%.*]] = add nsw i64 [[START]], 9
595; IS__TUNIT_NPM-NEXT:    br label [[FOR_BODY:%.*]]
596; IS__TUNIT_NPM:       for.cond.cleanup:
597; IS__TUNIT_NPM-NEXT:    ret void
598; IS__TUNIT_NPM:       for.body:
599; IS__TUNIT_NPM-NEXT:    [[I_06:%.*]] = phi i64 [ [[START]], [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_BODY]] ]
600; IS__TUNIT_NPM-NEXT:    [[CONV:%.*]] = trunc i64 [[I_06]] to i32
601; IS__TUNIT_NPM-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds i32, i32* [[P]], i64 [[I_06]]
602; IS__TUNIT_NPM-NEXT:    store i32 [[CONV]], i32* [[ARRAYIDX]], align 4
603; IS__TUNIT_NPM-NEXT:    [[INC]] = add nsw i64 [[I_06]], 1
604; IS__TUNIT_NPM-NEXT:    [[CMP:%.*]] = icmp slt i64 [[I_06]], [[TMP0]]
605; IS__TUNIT_NPM-NEXT:    br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_COND_CLEANUP:%.*]]
606;
607; IS__CGSCC_OPM: Function Attrs: argmemonly nofree norecurse nosync nounwind writeonly
608; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@fill_range_inbounds
609; IS__CGSCC_OPM-SAME: (i32* nocapture nofree writeonly [[P:%.*]], i64 [[START:%.*]]) [[ATTR3]] {
610; IS__CGSCC_OPM-NEXT:  entry:
611; IS__CGSCC_OPM-NEXT:    [[TMP0:%.*]] = add nsw i64 [[START]], 9
612; IS__CGSCC_OPM-NEXT:    br label [[FOR_BODY:%.*]]
613; IS__CGSCC_OPM:       for.cond.cleanup:
614; IS__CGSCC_OPM-NEXT:    ret void
615; IS__CGSCC_OPM:       for.body:
616; IS__CGSCC_OPM-NEXT:    [[I_06:%.*]] = phi i64 [ [[START]], [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_BODY]] ]
617; IS__CGSCC_OPM-NEXT:    [[CONV:%.*]] = trunc i64 [[I_06]] to i32
618; IS__CGSCC_OPM-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds i32, i32* [[P]], i64 [[I_06]]
619; IS__CGSCC_OPM-NEXT:    store i32 [[CONV]], i32* [[ARRAYIDX]], align 4
620; IS__CGSCC_OPM-NEXT:    [[INC]] = add nsw i64 [[I_06]], 1
621; IS__CGSCC_OPM-NEXT:    [[CMP:%.*]] = icmp slt i64 [[I_06]], [[TMP0]]
622; IS__CGSCC_OPM-NEXT:    br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_COND_CLEANUP:%.*]]
623;
624; IS__CGSCC_NPM: Function Attrs: argmemonly nofree norecurse nosync nounwind willreturn writeonly
625; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@fill_range_inbounds
626; IS__CGSCC_NPM-SAME: (i32* nocapture nofree writeonly [[P:%.*]], i64 [[START:%.*]]) [[ATTR2]] {
627; IS__CGSCC_NPM-NEXT:  entry:
628; IS__CGSCC_NPM-NEXT:    [[TMP0:%.*]] = add nsw i64 [[START]], 9
629; IS__CGSCC_NPM-NEXT:    br label [[FOR_BODY:%.*]]
630; IS__CGSCC_NPM:       for.cond.cleanup:
631; IS__CGSCC_NPM-NEXT:    ret void
632; IS__CGSCC_NPM:       for.body:
633; IS__CGSCC_NPM-NEXT:    [[I_06:%.*]] = phi i64 [ [[START]], [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_BODY]] ]
634; IS__CGSCC_NPM-NEXT:    [[CONV:%.*]] = trunc i64 [[I_06]] to i32
635; IS__CGSCC_NPM-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds i32, i32* [[P]], i64 [[I_06]]
636; IS__CGSCC_NPM-NEXT:    store i32 [[CONV]], i32* [[ARRAYIDX]], align 4
637; IS__CGSCC_NPM-NEXT:    [[INC]] = add nsw i64 [[I_06]], 1
638; IS__CGSCC_NPM-NEXT:    [[CMP:%.*]] = icmp slt i64 [[I_06]], [[TMP0]]
639; IS__CGSCC_NPM-NEXT:    br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_COND_CLEANUP:%.*]]
640;
641entry:
642  %0 = add nsw i64 %start, 9
643  br label %for.body
644
645for.cond.cleanup:                                 ; preds = %for.body
646  ret void
647
648for.body:                                         ; preds = %entry, %for.body
649  %i.06 = phi i64 [ %start, %entry ], [ %inc, %for.body ]
650  %conv = trunc i64 %i.06 to i32
651  %arrayidx = getelementptr inbounds i32, i32* %p, i64 %i.06
652  store i32 %conv, i32* %arrayidx, align 4
653  %inc = add nsw i64 %i.06, 1
654  %cmp = icmp slt i64 %i.06, %0
655  br i1 %cmp, label %for.body, label %for.cond.cleanup
656}
657
658define void @call_fill_range(i32* nocapture %p, i64* nocapture readonly %range) {
659; IS__TUNIT_OPM: Function Attrs: argmemonly nofree nosync nounwind
660; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@call_fill_range
661; IS__TUNIT_OPM-SAME: (i32* nocapture nofree writeonly [[P:%.*]], i64* nocapture nofree nonnull readonly align 8 dereferenceable(8) [[RANGE:%.*]]) [[ATTR4:#.*]] {
662; IS__TUNIT_OPM-NEXT:  entry:
663; IS__TUNIT_OPM-NEXT:    [[TMP0:%.*]] = load i64, i64* [[RANGE]], align 8, [[RNG0:!range !.*]]
664; IS__TUNIT_OPM-NEXT:    tail call void @fill_range_inbounds(i32* nocapture nofree writeonly [[P]], i64 [[TMP0]]) [[ATTR6:#.*]]
665; IS__TUNIT_OPM-NEXT:    tail call void @fill_range_not_inbounds(i32* nocapture nofree writeonly [[P]], i64 [[TMP0]]) [[ATTR6]]
666; IS__TUNIT_OPM-NEXT:    ret void
667;
668; IS__TUNIT_NPM: Function Attrs: argmemonly nofree nosync nounwind willreturn
669; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@call_fill_range
670; IS__TUNIT_NPM-SAME: (i32* nocapture nofree writeonly [[P:%.*]], i64* nocapture nofree nonnull readonly align 8 dereferenceable(8) [[RANGE:%.*]]) [[ATTR3:#.*]] {
671; IS__TUNIT_NPM-NEXT:  entry:
672; IS__TUNIT_NPM-NEXT:    [[TMP0:%.*]] = load i64, i64* [[RANGE]], align 8, [[RNG0:!range !.*]]
673; IS__TUNIT_NPM-NEXT:    tail call void @fill_range_inbounds(i32* nocapture nofree writeonly [[P]], i64 [[TMP0]]) [[ATTR6:#.*]]
674; IS__TUNIT_NPM-NEXT:    tail call void @fill_range_not_inbounds(i32* nocapture nofree writeonly [[P]], i64 [[TMP0]]) [[ATTR6]]
675; IS__TUNIT_NPM-NEXT:    ret void
676;
677; IS__CGSCC_OPM: Function Attrs: argmemonly nofree norecurse nosync nounwind
678; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@call_fill_range
679; IS__CGSCC_OPM-SAME: (i32* nocapture nofree writeonly [[P:%.*]], i64* nocapture nofree nonnull readonly align 8 dereferenceable(8) [[RANGE:%.*]]) [[ATTR4:#.*]] {
680; IS__CGSCC_OPM-NEXT:  entry:
681; IS__CGSCC_OPM-NEXT:    [[TMP0:%.*]] = load i64, i64* [[RANGE]], align 8, [[RNG0:!range !.*]]
682; IS__CGSCC_OPM-NEXT:    tail call void @fill_range_inbounds(i32* nocapture nofree writeonly [[P]], i64 [[TMP0]]) [[ATTR7:#.*]]
683; IS__CGSCC_OPM-NEXT:    tail call void @fill_range_not_inbounds(i32* nocapture nofree writeonly [[P]], i64 [[TMP0]]) [[ATTR7]]
684; IS__CGSCC_OPM-NEXT:    ret void
685;
686; IS__CGSCC_NPM: Function Attrs: argmemonly nofree norecurse nosync nounwind willreturn
687; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@call_fill_range
688; IS__CGSCC_NPM-SAME: (i32* nocapture nofree writeonly [[P:%.*]], i64* nocapture nofree nonnull readonly align 8 dereferenceable(8) [[RANGE:%.*]]) [[ATTR3:#.*]] {
689; IS__CGSCC_NPM-NEXT:  entry:
690; IS__CGSCC_NPM-NEXT:    [[TMP0:%.*]] = load i64, i64* [[RANGE]], align 8, [[RNG0:!range !.*]]
691; IS__CGSCC_NPM-NEXT:    tail call void @fill_range_inbounds(i32* nocapture nofree writeonly [[P]], i64 [[TMP0]]) [[ATTR6:#.*]]
692; IS__CGSCC_NPM-NEXT:    tail call void @fill_range_not_inbounds(i32* nocapture nofree writeonly [[P]], i64 [[TMP0]]) [[ATTR6]]
693; IS__CGSCC_NPM-NEXT:    ret void
694;
695entry:
696  %0 = load i64, i64* %range, align 8, !range !0
697  tail call void @fill_range_inbounds(i32* %p, i64 %0)
698  tail call void @fill_range_not_inbounds(i32* %p, i64 %0)
699  ret void
700}
701
702declare void @use0() willreturn nounwind
703declare void @use1(i8*) willreturn nounwind
704declare void @use2(i8*, i8*) willreturn nounwind
705declare void @use3(i8*, i8*, i8*) willreturn nounwind
706
707; simple path test
708; if(..)
709;   fun2(dereferenceable(8) %a, dereferenceable(8) %b)
710; else
711;   fun2(dereferenceable(4) %a, %b)
712; We can say that %a is dereferenceable(4) but %b is not.
713define void @simple-path(i8* %a, i8 * %b, i8 %c) {
714; CHECK: Function Attrs: nounwind willreturn
715; CHECK-LABEL: define {{[^@]+}}@simple-path
716; CHECK-SAME: (i8* nonnull dereferenceable(4) [[A:%.*]], i8* [[B:%.*]], i8 [[C:%.*]]) [[ATTR1]] {
717; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 [[C]], 0
718; CHECK-NEXT:    br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
719; CHECK:       if.then:
720; CHECK-NEXT:    tail call void @use2(i8* nonnull dereferenceable(8) [[A]], i8* nonnull dereferenceable(8) [[B]]) [[ATTR1]]
721; CHECK-NEXT:    ret void
722; CHECK:       if.else:
723; CHECK-NEXT:    tail call void @use2(i8* nonnull dereferenceable(4) [[A]], i8* [[B]]) [[ATTR1]]
724; CHECK-NEXT:    ret void
725;
726  %cmp = icmp eq i8 %c, 0
727  br i1 %cmp, label %if.then, label %if.else
728if.then:
729  tail call void @use2(i8* dereferenceable(8) %a, i8* dereferenceable(8) %b)
730  ret void
731if.else:
732  tail call void @use2(i8* dereferenceable(4) %a, i8* %b)
733  ret void
734}
735
736; More complex test
737; {
738; fun1(dereferenceable(4) %a)
739; if(..)
740;    ... (willreturn & nounwind)
741;    fun1(dereferenceable(12) %a)
742; else
743;    ... (willreturn & nounwind)
744;    fun1(dereferenceable(16) %a)
745; fun1(dereferenceable(8) %a)
746; }
747; %a is dereferenceable(12)
748define void @complex-path(i8* %a, i8* %b, i8 %c) {
749; CHECK: Function Attrs: nounwind willreturn
750; CHECK-LABEL: define {{[^@]+}}@complex-path
751; CHECK-SAME: (i8* nonnull dereferenceable(12) [[A:%.*]], i8* nocapture nofree readnone [[B:%.*]], i8 [[C:%.*]]) [[ATTR1]] {
752; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 [[C]], 0
753; CHECK-NEXT:    tail call void @use1(i8* nonnull dereferenceable(12) [[A]]) [[ATTR1]]
754; CHECK-NEXT:    br i1 [[CMP]], label [[CONT_THEN:%.*]], label [[CONT_ELSE:%.*]]
755; CHECK:       cont.then:
756; CHECK-NEXT:    tail call void @use1(i8* nonnull dereferenceable(12) [[A]]) [[ATTR1]]
757; CHECK-NEXT:    br label [[CONT2:%.*]]
758; CHECK:       cont.else:
759; CHECK-NEXT:    tail call void @use1(i8* nonnull dereferenceable(16) [[A]]) [[ATTR1]]
760; CHECK-NEXT:    br label [[CONT2]]
761; CHECK:       cont2:
762; CHECK-NEXT:    tail call void @use1(i8* nonnull dereferenceable(12) [[A]]) [[ATTR1]]
763; CHECK-NEXT:    ret void
764;
765  %cmp = icmp eq i8 %c, 0
766  tail call void @use1(i8* dereferenceable(4) %a)
767  br i1 %cmp, label %cont.then, label %cont.else
768cont.then:
769  tail call void @use1(i8* dereferenceable(12) %a)
770  br label %cont2
771cont.else:
772  tail call void @use1(i8* dereferenceable(16) %a)
773  br label %cont2
774cont2:
775  tail call void @use1(i8* dereferenceable(8) %a)
776  ret void
777}
778
779;  void rec-branch-1(int a, int b, int c, int *ptr) {
780;    if (a) {
781;      if (b)
782;        *ptr = 1;
783;      else
784;        *ptr = 2;
785;    } else {
786;      if (c)
787;        *ptr = 3;
788;      else
789;        *ptr = 4;
790;    }
791;  }
792;
793; FIXME: %ptr should be dereferenceable(4)
794define dso_local void @rec-branch-1(i32 %a, i32 %b, i32 %c, i32* %ptr) {
795; IS__TUNIT____: Function Attrs: argmemonly nofree nosync nounwind willreturn writeonly
796; IS__TUNIT____-LABEL: define {{[^@]+}}@rec-branch-1
797; IS__TUNIT____-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]], i32* nocapture nofree writeonly [[PTR:%.*]]) [[ATTR2]] {
798; IS__TUNIT____-NEXT:  entry:
799; IS__TUNIT____-NEXT:    [[TOBOOL:%.*]] = icmp eq i32 [[A]], 0
800; IS__TUNIT____-NEXT:    br i1 [[TOBOOL]], label [[IF_ELSE3:%.*]], label [[IF_THEN:%.*]]
801; IS__TUNIT____:       if.then:
802; IS__TUNIT____-NEXT:    [[TOBOOL1:%.*]] = icmp eq i32 [[B]], 0
803; IS__TUNIT____-NEXT:    br i1 [[TOBOOL1]], label [[IF_ELSE:%.*]], label [[IF_THEN2:%.*]]
804; IS__TUNIT____:       if.then2:
805; IS__TUNIT____-NEXT:    store i32 1, i32* [[PTR]], align 4
806; IS__TUNIT____-NEXT:    br label [[IF_END8:%.*]]
807; IS__TUNIT____:       if.else:
808; IS__TUNIT____-NEXT:    store i32 2, i32* [[PTR]], align 4
809; IS__TUNIT____-NEXT:    br label [[IF_END8]]
810; IS__TUNIT____:       if.else3:
811; IS__TUNIT____-NEXT:    [[TOBOOL4:%.*]] = icmp eq i32 [[C]], 0
812; IS__TUNIT____-NEXT:    br i1 [[TOBOOL4]], label [[IF_ELSE6:%.*]], label [[IF_THEN5:%.*]]
813; IS__TUNIT____:       if.then5:
814; IS__TUNIT____-NEXT:    store i32 3, i32* [[PTR]], align 4
815; IS__TUNIT____-NEXT:    br label [[IF_END8]]
816; IS__TUNIT____:       if.else6:
817; IS__TUNIT____-NEXT:    store i32 4, i32* [[PTR]], align 4
818; IS__TUNIT____-NEXT:    br label [[IF_END8]]
819; IS__TUNIT____:       if.end8:
820; IS__TUNIT____-NEXT:    ret void
821;
822; IS__CGSCC____: Function Attrs: argmemonly nofree norecurse nosync nounwind willreturn writeonly
823; IS__CGSCC____-LABEL: define {{[^@]+}}@rec-branch-1
824; IS__CGSCC____-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]], i32* nocapture nofree writeonly [[PTR:%.*]]) [[ATTR2]] {
825; IS__CGSCC____-NEXT:  entry:
826; IS__CGSCC____-NEXT:    [[TOBOOL:%.*]] = icmp eq i32 [[A]], 0
827; IS__CGSCC____-NEXT:    br i1 [[TOBOOL]], label [[IF_ELSE3:%.*]], label [[IF_THEN:%.*]]
828; IS__CGSCC____:       if.then:
829; IS__CGSCC____-NEXT:    [[TOBOOL1:%.*]] = icmp eq i32 [[B]], 0
830; IS__CGSCC____-NEXT:    br i1 [[TOBOOL1]], label [[IF_ELSE:%.*]], label [[IF_THEN2:%.*]]
831; IS__CGSCC____:       if.then2:
832; IS__CGSCC____-NEXT:    store i32 1, i32* [[PTR]], align 4
833; IS__CGSCC____-NEXT:    br label [[IF_END8:%.*]]
834; IS__CGSCC____:       if.else:
835; IS__CGSCC____-NEXT:    store i32 2, i32* [[PTR]], align 4
836; IS__CGSCC____-NEXT:    br label [[IF_END8]]
837; IS__CGSCC____:       if.else3:
838; IS__CGSCC____-NEXT:    [[TOBOOL4:%.*]] = icmp eq i32 [[C]], 0
839; IS__CGSCC____-NEXT:    br i1 [[TOBOOL4]], label [[IF_ELSE6:%.*]], label [[IF_THEN5:%.*]]
840; IS__CGSCC____:       if.then5:
841; IS__CGSCC____-NEXT:    store i32 3, i32* [[PTR]], align 4
842; IS__CGSCC____-NEXT:    br label [[IF_END8]]
843; IS__CGSCC____:       if.else6:
844; IS__CGSCC____-NEXT:    store i32 4, i32* [[PTR]], align 4
845; IS__CGSCC____-NEXT:    br label [[IF_END8]]
846; IS__CGSCC____:       if.end8:
847; IS__CGSCC____-NEXT:    ret void
848;
849entry:
850  %tobool = icmp eq i32 %a, 0
851  br i1 %tobool, label %if.else3, label %if.then
852
853if.then:                                          ; preds = %entry
854  %tobool1 = icmp eq i32 %b, 0
855  br i1 %tobool1, label %if.else, label %if.then2
856
857if.then2:                                         ; preds = %if.then
858  store i32 1, i32* %ptr, align 4
859  br label %if.end8
860
861if.else:                                          ; preds = %if.then
862  store i32 2, i32* %ptr, align 4
863  br label %if.end8
864
865if.else3:                                         ; preds = %entry
866  %tobool4 = icmp eq i32 %c, 0
867  br i1 %tobool4, label %if.else6, label %if.then5
868
869if.then5:                                         ; preds = %if.else3
870  store i32 3, i32* %ptr, align 4
871  br label %if.end8
872
873if.else6:                                         ; preds = %if.else3
874  store i32 4, i32* %ptr, align 4
875  br label %if.end8
876
877if.end8:                                          ; preds = %if.then5, %if.else6, %if.then2, %if.else
878  ret void
879}
880
881;  void rec-branch-2(int a, int b, int c, int *ptr) {
882;    if (a) {
883;      if (b)
884;        *ptr = 1;
885;      else
886;        *ptr = 2;
887;    } else {
888;      if (c)
889;        *ptr = 3;
890;      else
891;        rec-branch-2(1, 1, 1, ptr);
892;    }
893;  }
894; FIXME: %ptr should be dereferenceable(4)
895define dso_local void @rec-branch-2(i32 %a, i32 %b, i32 %c, i32* %ptr) {
896; IS__TUNIT_OPM: Function Attrs: argmemonly nofree nosync nounwind writeonly
897; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@rec-branch-2
898; IS__TUNIT_OPM-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]], i32* nocapture nofree writeonly [[PTR:%.*]]) [[ATTR3]] {
899; IS__TUNIT_OPM-NEXT:  entry:
900; IS__TUNIT_OPM-NEXT:    [[TOBOOL:%.*]] = icmp eq i32 [[A]], 0
901; IS__TUNIT_OPM-NEXT:    br i1 [[TOBOOL]], label [[IF_ELSE3:%.*]], label [[IF_THEN:%.*]]
902; IS__TUNIT_OPM:       if.then:
903; IS__TUNIT_OPM-NEXT:    [[TOBOOL1:%.*]] = icmp eq i32 [[B]], 0
904; IS__TUNIT_OPM-NEXT:    br i1 [[TOBOOL1]], label [[IF_ELSE:%.*]], label [[IF_THEN2:%.*]]
905; IS__TUNIT_OPM:       if.then2:
906; IS__TUNIT_OPM-NEXT:    store i32 1, i32* [[PTR]], align 4
907; IS__TUNIT_OPM-NEXT:    br label [[IF_END8:%.*]]
908; IS__TUNIT_OPM:       if.else:
909; IS__TUNIT_OPM-NEXT:    store i32 2, i32* [[PTR]], align 4
910; IS__TUNIT_OPM-NEXT:    br label [[IF_END8]]
911; IS__TUNIT_OPM:       if.else3:
912; IS__TUNIT_OPM-NEXT:    [[TOBOOL4:%.*]] = icmp eq i32 [[C]], 0
913; IS__TUNIT_OPM-NEXT:    br i1 [[TOBOOL4]], label [[IF_ELSE6:%.*]], label [[IF_THEN5:%.*]]
914; IS__TUNIT_OPM:       if.then5:
915; IS__TUNIT_OPM-NEXT:    store i32 3, i32* [[PTR]], align 4
916; IS__TUNIT_OPM-NEXT:    br label [[IF_END8]]
917; IS__TUNIT_OPM:       if.else6:
918; IS__TUNIT_OPM-NEXT:    tail call void @rec-branch-2(i32 noundef 1, i32 noundef 1, i32 noundef 1, i32* nocapture nofree writeonly [[PTR]]) [[ATTR6]]
919; IS__TUNIT_OPM-NEXT:    br label [[IF_END8]]
920; IS__TUNIT_OPM:       if.end8:
921; IS__TUNIT_OPM-NEXT:    ret void
922;
923; IS________NPM: Function Attrs: argmemonly nofree nosync nounwind writeonly
924; IS________NPM-LABEL: define {{[^@]+}}@rec-branch-2
925; IS________NPM-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]], i32* nocapture nofree writeonly [[PTR:%.*]]) [[ATTR4:#.*]] {
926; IS________NPM-NEXT:  entry:
927; IS________NPM-NEXT:    [[TOBOOL:%.*]] = icmp eq i32 [[A]], 0
928; IS________NPM-NEXT:    br i1 [[TOBOOL]], label [[IF_ELSE3:%.*]], label [[IF_THEN:%.*]]
929; IS________NPM:       if.then:
930; IS________NPM-NEXT:    [[TOBOOL1:%.*]] = icmp eq i32 [[B]], 0
931; IS________NPM-NEXT:    br i1 [[TOBOOL1]], label [[IF_ELSE:%.*]], label [[IF_THEN2:%.*]]
932; IS________NPM:       if.then2:
933; IS________NPM-NEXT:    store i32 1, i32* [[PTR]], align 4
934; IS________NPM-NEXT:    br label [[IF_END8:%.*]]
935; IS________NPM:       if.else:
936; IS________NPM-NEXT:    store i32 2, i32* [[PTR]], align 4
937; IS________NPM-NEXT:    br label [[IF_END8]]
938; IS________NPM:       if.else3:
939; IS________NPM-NEXT:    [[TOBOOL4:%.*]] = icmp eq i32 [[C]], 0
940; IS________NPM-NEXT:    br i1 [[TOBOOL4]], label [[IF_ELSE6:%.*]], label [[IF_THEN5:%.*]]
941; IS________NPM:       if.then5:
942; IS________NPM-NEXT:    store i32 3, i32* [[PTR]], align 4
943; IS________NPM-NEXT:    br label [[IF_END8]]
944; IS________NPM:       if.else6:
945; IS________NPM-NEXT:    tail call void @rec-branch-2(i32 noundef 1, i32 noundef 1, i32 noundef 1, i32* nocapture nofree writeonly [[PTR]]) [[ATTR7:#.*]]
946; IS________NPM-NEXT:    br label [[IF_END8]]
947; IS________NPM:       if.end8:
948; IS________NPM-NEXT:    ret void
949;
950; IS__CGSCC_OPM: Function Attrs: argmemonly nofree nosync nounwind writeonly
951; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@rec-branch-2
952; IS__CGSCC_OPM-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]], i32* nocapture nofree writeonly [[PTR:%.*]]) [[ATTR5:#.*]] {
953; IS__CGSCC_OPM-NEXT:  entry:
954; IS__CGSCC_OPM-NEXT:    [[TOBOOL:%.*]] = icmp eq i32 [[A]], 0
955; IS__CGSCC_OPM-NEXT:    br i1 [[TOBOOL]], label [[IF_ELSE3:%.*]], label [[IF_THEN:%.*]]
956; IS__CGSCC_OPM:       if.then:
957; IS__CGSCC_OPM-NEXT:    [[TOBOOL1:%.*]] = icmp eq i32 [[B]], 0
958; IS__CGSCC_OPM-NEXT:    br i1 [[TOBOOL1]], label [[IF_ELSE:%.*]], label [[IF_THEN2:%.*]]
959; IS__CGSCC_OPM:       if.then2:
960; IS__CGSCC_OPM-NEXT:    store i32 1, i32* [[PTR]], align 4
961; IS__CGSCC_OPM-NEXT:    br label [[IF_END8:%.*]]
962; IS__CGSCC_OPM:       if.else:
963; IS__CGSCC_OPM-NEXT:    store i32 2, i32* [[PTR]], align 4
964; IS__CGSCC_OPM-NEXT:    br label [[IF_END8]]
965; IS__CGSCC_OPM:       if.else3:
966; IS__CGSCC_OPM-NEXT:    [[TOBOOL4:%.*]] = icmp eq i32 [[C]], 0
967; IS__CGSCC_OPM-NEXT:    br i1 [[TOBOOL4]], label [[IF_ELSE6:%.*]], label [[IF_THEN5:%.*]]
968; IS__CGSCC_OPM:       if.then5:
969; IS__CGSCC_OPM-NEXT:    store i32 3, i32* [[PTR]], align 4
970; IS__CGSCC_OPM-NEXT:    br label [[IF_END8]]
971; IS__CGSCC_OPM:       if.else6:
972; IS__CGSCC_OPM-NEXT:    tail call void @rec-branch-2(i32 noundef 1, i32 noundef 1, i32 noundef 1, i32* nocapture nofree writeonly [[PTR]]) [[ATTR8:#.*]]
973; IS__CGSCC_OPM-NEXT:    br label [[IF_END8]]
974; IS__CGSCC_OPM:       if.end8:
975; IS__CGSCC_OPM-NEXT:    ret void
976;
977entry:
978  %tobool = icmp eq i32 %a, 0
979  br i1 %tobool, label %if.else3, label %if.then
980
981if.then:                                          ; preds = %entry
982  %tobool1 = icmp eq i32 %b, 0
983  br i1 %tobool1, label %if.else, label %if.then2
984
985if.then2:                                         ; preds = %if.then
986  store i32 1, i32* %ptr, align 4
987  br label %if.end8
988
989if.else:                                          ; preds = %if.then
990  store i32 2, i32* %ptr, align 4
991  br label %if.end8
992
993if.else3:                                         ; preds = %entry
994  %tobool4 = icmp eq i32 %c, 0
995  br i1 %tobool4, label %if.else6, label %if.then5
996
997if.then5:                                         ; preds = %if.else3
998  store i32 3, i32* %ptr, align 4
999  br label %if.end8
1000
1001if.else6:                                         ; preds = %if.else3
1002  tail call void @rec-branch-2(i32 1, i32 1, i32 1, i32* %ptr)
1003  br label %if.end8
1004
1005if.end8:                                          ; preds = %if.then5, %if.else6, %if.then2, %if.else
1006  ret void
1007}
1008
1009declare void @unknown()
1010define void @nonnull_assume_pos(i8* %arg1, i8* %arg2, i8* %arg3, i8* %arg4) {
1011; ATTRIBUTOR-LABEL: define {{[^@]+}}@nonnull_assume_pos
1012; ATTRIBUTOR-SAME: (i8* nocapture nofree nonnull readnone dereferenceable(101) [[ARG1:%.*]], i8* nocapture nofree readnone dereferenceable_or_null(31) [[ARG2:%.*]], i8* nocapture nofree nonnull readnone [[ARG3:%.*]], i8* nocapture nofree readnone dereferenceable_or_null(42) [[ARG4:%.*]])
1013; ATTRIBUTOR-NEXT:    call void @llvm.assume(i1 true) #6 [ "nonnull"(i8* undef), "dereferenceable"(i8* undef, i64 1), "dereferenceable"(i8* undef, i64 2), "dereferenceable"(i8* undef, i64 101), "dereferenceable_or_null"(i8* undef, i64 31), "dereferenceable_or_null"(i8* undef, i64 42) ]
1014; ATTRIBUTOR-NEXT:    call void @unknown()
1015; ATTRIBUTOR-NEXT:    ret void
1016;
1017; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@nonnull_assume_pos
1018; IS__TUNIT_OPM-SAME: (i8* nocapture nofree nonnull readnone dereferenceable(101) [[ARG1:%.*]], i8* nocapture nofree readnone dereferenceable_or_null(31) [[ARG2:%.*]], i8* nocapture nofree nonnull readnone [[ARG3:%.*]], i8* nocapture nofree readnone dereferenceable_or_null(42) [[ARG4:%.*]]) {
1019; IS__TUNIT_OPM-NEXT:    call void @llvm.assume(i1 noundef true) [[ATTR7:#.*]] [ "nonnull"(i8* [[ARG3]]), "dereferenceable"(i8* [[ARG1]], i64 1), "dereferenceable"(i8* [[ARG1]], i64 2), "dereferenceable"(i8* [[ARG1]], i64 101), "dereferenceable_or_null"(i8* [[ARG2]], i64 31), "dereferenceable_or_null"(i8* [[ARG4]], i64 42) ]
1020; IS__TUNIT_OPM-NEXT:    call void @unknown()
1021; IS__TUNIT_OPM-NEXT:    ret void
1022;
1023; IS________NPM-LABEL: define {{[^@]+}}@nonnull_assume_pos
1024; IS________NPM-SAME: (i8* nocapture nofree nonnull readnone dereferenceable(101) [[ARG1:%.*]], i8* nocapture nofree readnone dereferenceable_or_null(31) [[ARG2:%.*]], i8* nocapture nofree nonnull readnone [[ARG3:%.*]], i8* nocapture nofree readnone dereferenceable_or_null(42) [[ARG4:%.*]]) {
1025; IS________NPM-NEXT:    call void @llvm.assume(i1 noundef true) [[ATTR8:#.*]] [ "nonnull"(i8* [[ARG3]]), "dereferenceable"(i8* [[ARG1]], i64 1), "dereferenceable"(i8* [[ARG1]], i64 2), "dereferenceable"(i8* [[ARG1]], i64 101), "dereferenceable_or_null"(i8* [[ARG2]], i64 31), "dereferenceable_or_null"(i8* [[ARG4]], i64 42) ]
1026; IS________NPM-NEXT:    call void @unknown()
1027; IS________NPM-NEXT:    ret void
1028;
1029; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@nonnull_assume_pos
1030; IS__CGSCC_OPM-SAME: (i8* nocapture nofree nonnull readnone dereferenceable(101) [[ARG1:%.*]], i8* nocapture nofree readnone dereferenceable_or_null(31) [[ARG2:%.*]], i8* nocapture nofree nonnull readnone [[ARG3:%.*]], i8* nocapture nofree readnone dereferenceable_or_null(42) [[ARG4:%.*]]) {
1031; IS__CGSCC_OPM-NEXT:    call void @llvm.assume(i1 noundef true) [[ATTR9:#.*]] [ "nonnull"(i8* [[ARG3]]), "dereferenceable"(i8* [[ARG1]], i64 1), "dereferenceable"(i8* [[ARG1]], i64 2), "dereferenceable"(i8* [[ARG1]], i64 101), "dereferenceable_or_null"(i8* [[ARG2]], i64 31), "dereferenceable_or_null"(i8* [[ARG4]], i64 42) ]
1032; IS__CGSCC_OPM-NEXT:    call void @unknown()
1033; IS__CGSCC_OPM-NEXT:    ret void
1034;
1035  call void @llvm.assume(i1 true) [ "nonnull"(i8* %arg3), "dereferenceable"(i8* %arg1, i64 1), "dereferenceable"(i8* %arg1, i64 2), "dereferenceable"(i8* %arg1, i64 101), "dereferenceable_or_null"(i8* %arg2, i64 31), "dereferenceable_or_null"(i8* %arg4, i64 42)]
1036  call void @unknown()
1037  ret void
1038}
1039define void @nonnull_assume_neg(i8* %arg1, i8* %arg2, i8* %arg3) {
1040; ATTRIBUTOR-LABEL: define {{[^@]+}}@nonnull_assume_neg
1041; ATTRIBUTOR-SAME: (i8* nocapture nofree readnone [[ARG1:%.*]], i8* nocapture nofree readnone [[ARG2:%.*]], i8* nocapture nofree readnone [[ARG3:%.*]])
1042; ATTRIBUTOR-NEXT:    call void @unknown()
1043; ATTRIBUTOR-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(i8* undef, i64 101), "dereferenceable"(i8* undef, i64 -2), "dereferenceable_or_null"(i8* undef, i64 31) ]
1044; ATTRIBUTOR-NEXT:    ret void
1045;
1046; CHECK-LABEL: define {{[^@]+}}@nonnull_assume_neg
1047; CHECK-SAME: (i8* nocapture nofree readnone [[ARG1:%.*]], i8* nocapture nofree readnone [[ARG2:%.*]], i8* nocapture nofree readnone [[ARG3:%.*]]) {
1048; CHECK-NEXT:    call void @unknown()
1049; CHECK-NEXT:    call void @llvm.assume(i1 noundef true) [ "dereferenceable"(i8* [[ARG1]], i64 101), "dereferenceable"(i8* [[ARG2]], i64 -2), "dereferenceable_or_null"(i8* [[ARG3]], i64 31) ]
1050; CHECK-NEXT:    ret void
1051;
1052  call void @unknown()
1053  call void @llvm.assume(i1 true) ["dereferenceable"(i8* %arg1, i64 101), "dereferenceable"(i8* %arg2, i64 -2), "dereferenceable_or_null"(i8* %arg3, i64 31)]
1054  ret void
1055}
1056define void @nonnull_assume_call(i8* %arg1, i8* %arg2, i8* %arg3, i8* %arg4) {
1057; ATTRIBUTOR-LABEL: define {{[^@]+}}@nonnull_assume_call
1058; ATTRIBUTOR-SAME: (i8* [[ARG1:%.*]], i8* [[ARG2:%.*]], i8* [[ARG3:%.*]], i8* [[ARG4:%.*]])
1059; ATTRIBUTOR-NEXT:    call void @unknown()
1060; ATTRIBUTOR-NEXT:    [[P:%.*]] = call nonnull dereferenceable(101) i32* @unkown_ptr()
1061; ATTRIBUTOR-NEXT:    call void @unknown_use32(i32* nonnull dereferenceable(101) [[P]])
1062; ATTRIBUTOR-NEXT:    call void @unknown_use8(i8* nonnull dereferenceable(42) [[ARG4]])
1063; ATTRIBUTOR-NEXT:    call void @unknown_use8(i8* nonnull [[ARG3]])
1064; ATTRIBUTOR-NEXT:    call void @unknown_use8(i8* nonnull dereferenceable(31) [[ARG2]])
1065; ATTRIBUTOR-NEXT:    call void @unknown_use8(i8* nonnull dereferenceable(2) [[ARG1]])
1066; ATTRIBUTOR-NEXT:    call void @llvm.assume(i1 true) [ "nonnull"(i8* [[ARG3]]), "dereferenceable"(i8* [[ARG1]], i64 1), "dereferenceable"(i8* [[ARG1]], i64 2), "dereferenceable"(i32* [[P]], i64 101), "dereferenceable_or_null"(i8* [[ARG2]], i64 31), "dereferenceable_or_null"(i8* [[ARG4]], i64 42) ]
1067; ATTRIBUTOR-NEXT:    call void @unknown_use8(i8* nonnull dereferenceable(2) [[ARG1]])
1068; ATTRIBUTOR-NEXT:    call void @unknown_use8(i8* nonnull dereferenceable(31) [[ARG2]])
1069; ATTRIBUTOR-NEXT:    call void @unknown_use8(i8* nonnull [[ARG3]])
1070; ATTRIBUTOR-NEXT:    call void @unknown_use8(i8* nonnull dereferenceable(42) [[ARG4]])
1071; ATTRIBUTOR-NEXT:    call void @unknown_use32(i32* nonnull dereferenceable(101) [[P]])
1072; ATTRIBUTOR-NEXT:    call void @unknown()
1073; ATTRIBUTOR-NEXT:    ret void
1074;
1075; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@nonnull_assume_call
1076; IS__TUNIT_OPM-SAME: (i8* [[ARG1:%.*]], i8* [[ARG2:%.*]], i8* [[ARG3:%.*]], i8* [[ARG4:%.*]]) {
1077; IS__TUNIT_OPM-NEXT:    call void @unknown()
1078; IS__TUNIT_OPM-NEXT:    [[P:%.*]] = call nonnull dereferenceable(101) i32* @unkown_ptr() [[ATTR8:#.*]]
1079; IS__TUNIT_OPM-NEXT:    call void @unknown_use32(i32* nonnull dereferenceable(101) [[P]]) [[ATTR8]]
1080; IS__TUNIT_OPM-NEXT:    call void @unknown_use8(i8* dereferenceable_or_null(42) [[ARG4]]) [[ATTR8]]
1081; IS__TUNIT_OPM-NEXT:    call void @unknown_use8(i8* nonnull [[ARG3]]) [[ATTR8]]
1082; IS__TUNIT_OPM-NEXT:    call void @unknown_use8(i8* dereferenceable_or_null(31) [[ARG2]]) [[ATTR8]]
1083; IS__TUNIT_OPM-NEXT:    call void @unknown_use8(i8* nonnull dereferenceable(2) [[ARG1]]) [[ATTR8]]
1084; IS__TUNIT_OPM-NEXT:    call void @llvm.assume(i1 noundef true) [ "nonnull"(i8* [[ARG3]]), "dereferenceable"(i8* [[ARG1]], i64 1), "dereferenceable"(i8* [[ARG1]], i64 2), "dereferenceable"(i32* [[P]], i64 101), "dereferenceable_or_null"(i8* [[ARG2]], i64 31), "dereferenceable_or_null"(i8* [[ARG4]], i64 42) ]
1085; IS__TUNIT_OPM-NEXT:    call void @unknown_use8(i8* nonnull dereferenceable(2) [[ARG1]]) [[ATTR8]]
1086; IS__TUNIT_OPM-NEXT:    call void @unknown_use8(i8* dereferenceable_or_null(31) [[ARG2]]) [[ATTR8]]
1087; IS__TUNIT_OPM-NEXT:    call void @unknown_use8(i8* nonnull [[ARG3]]) [[ATTR8]]
1088; IS__TUNIT_OPM-NEXT:    call void @unknown_use8(i8* dereferenceable_or_null(42) [[ARG4]]) [[ATTR8]]
1089; IS__TUNIT_OPM-NEXT:    call void @unknown_use32(i32* nonnull dereferenceable(101) [[P]]) [[ATTR8]]
1090; IS__TUNIT_OPM-NEXT:    call void @unknown()
1091; IS__TUNIT_OPM-NEXT:    ret void
1092;
1093; IS________NPM-LABEL: define {{[^@]+}}@nonnull_assume_call
1094; IS________NPM-SAME: (i8* [[ARG1:%.*]], i8* [[ARG2:%.*]], i8* [[ARG3:%.*]], i8* [[ARG4:%.*]]) {
1095; IS________NPM-NEXT:    call void @unknown()
1096; IS________NPM-NEXT:    [[P:%.*]] = call nonnull dereferenceable(101) i32* @unkown_ptr() [[ATTR9:#.*]]
1097; IS________NPM-NEXT:    call void @unknown_use32(i32* nonnull dereferenceable(101) [[P]]) [[ATTR9]]
1098; IS________NPM-NEXT:    call void @unknown_use8(i8* dereferenceable_or_null(42) [[ARG4]]) [[ATTR9]]
1099; IS________NPM-NEXT:    call void @unknown_use8(i8* nonnull [[ARG3]]) [[ATTR9]]
1100; IS________NPM-NEXT:    call void @unknown_use8(i8* dereferenceable_or_null(31) [[ARG2]]) [[ATTR9]]
1101; IS________NPM-NEXT:    call void @unknown_use8(i8* nonnull dereferenceable(2) [[ARG1]]) [[ATTR9]]
1102; IS________NPM-NEXT:    call void @llvm.assume(i1 noundef true) [ "nonnull"(i8* [[ARG3]]), "dereferenceable"(i8* [[ARG1]], i64 1), "dereferenceable"(i8* [[ARG1]], i64 2), "dereferenceable"(i32* [[P]], i64 101), "dereferenceable_or_null"(i8* [[ARG2]], i64 31), "dereferenceable_or_null"(i8* [[ARG4]], i64 42) ]
1103; IS________NPM-NEXT:    call void @unknown_use8(i8* nonnull dereferenceable(2) [[ARG1]]) [[ATTR9]]
1104; IS________NPM-NEXT:    call void @unknown_use8(i8* dereferenceable_or_null(31) [[ARG2]]) [[ATTR9]]
1105; IS________NPM-NEXT:    call void @unknown_use8(i8* nonnull [[ARG3]]) [[ATTR9]]
1106; IS________NPM-NEXT:    call void @unknown_use8(i8* dereferenceable_or_null(42) [[ARG4]]) [[ATTR9]]
1107; IS________NPM-NEXT:    call void @unknown_use32(i32* nonnull dereferenceable(101) [[P]]) [[ATTR9]]
1108; IS________NPM-NEXT:    call void @unknown()
1109; IS________NPM-NEXT:    ret void
1110;
1111; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@nonnull_assume_call
1112; IS__CGSCC_OPM-SAME: (i8* [[ARG1:%.*]], i8* [[ARG2:%.*]], i8* [[ARG3:%.*]], i8* [[ARG4:%.*]]) {
1113; IS__CGSCC_OPM-NEXT:    call void @unknown()
1114; IS__CGSCC_OPM-NEXT:    [[P:%.*]] = call nonnull dereferenceable(101) i32* @unkown_ptr() [[ATTR10:#.*]]
1115; IS__CGSCC_OPM-NEXT:    call void @unknown_use32(i32* nonnull dereferenceable(101) [[P]]) [[ATTR10]]
1116; IS__CGSCC_OPM-NEXT:    call void @unknown_use8(i8* dereferenceable_or_null(42) [[ARG4]]) [[ATTR10]]
1117; IS__CGSCC_OPM-NEXT:    call void @unknown_use8(i8* nonnull [[ARG3]]) [[ATTR10]]
1118; IS__CGSCC_OPM-NEXT:    call void @unknown_use8(i8* dereferenceable_or_null(31) [[ARG2]]) [[ATTR10]]
1119; IS__CGSCC_OPM-NEXT:    call void @unknown_use8(i8* nonnull dereferenceable(2) [[ARG1]]) [[ATTR10]]
1120; IS__CGSCC_OPM-NEXT:    call void @llvm.assume(i1 noundef true) [ "nonnull"(i8* [[ARG3]]), "dereferenceable"(i8* [[ARG1]], i64 1), "dereferenceable"(i8* [[ARG1]], i64 2), "dereferenceable"(i32* [[P]], i64 101), "dereferenceable_or_null"(i8* [[ARG2]], i64 31), "dereferenceable_or_null"(i8* [[ARG4]], i64 42) ]
1121; IS__CGSCC_OPM-NEXT:    call void @unknown_use8(i8* nonnull dereferenceable(2) [[ARG1]]) [[ATTR10]]
1122; IS__CGSCC_OPM-NEXT:    call void @unknown_use8(i8* dereferenceable_or_null(31) [[ARG2]]) [[ATTR10]]
1123; IS__CGSCC_OPM-NEXT:    call void @unknown_use8(i8* nonnull [[ARG3]]) [[ATTR10]]
1124; IS__CGSCC_OPM-NEXT:    call void @unknown_use8(i8* dereferenceable_or_null(42) [[ARG4]]) [[ATTR10]]
1125; IS__CGSCC_OPM-NEXT:    call void @unknown_use32(i32* nonnull dereferenceable(101) [[P]]) [[ATTR10]]
1126; IS__CGSCC_OPM-NEXT:    call void @unknown()
1127; IS__CGSCC_OPM-NEXT:    ret void
1128;
1129  call void @unknown()
1130  %p = call i32* @unkown_ptr()
1131  call void @unknown_use32(i32* %p)
1132  call void @unknown_use8(i8* %arg4)
1133  call void @unknown_use8(i8* %arg3)
1134  call void @unknown_use8(i8* %arg2)
1135  call void @unknown_use8(i8* %arg1)
1136  call void @llvm.assume(i1 true) [ "nonnull"(i8* %arg3), "dereferenceable"(i8* %arg1, i64 1), "dereferenceable"(i8* %arg1, i64 2), "dereferenceable"(i32* %p, i64 101), "dereferenceable_or_null"(i8* %arg2, i64 31), "dereferenceable_or_null"(i8* %arg4, i64 42)]
1137  call void @unknown_use8(i8* %arg1)
1138  call void @unknown_use8(i8* %arg2)
1139  call void @unknown_use8(i8* %arg3)
1140  call void @unknown_use8(i8* %arg4)
1141  call void @unknown_use32(i32* %p)
1142  call void @unknown()
1143  ret void
1144}
1145declare void @unknown_use8(i8*) willreturn nounwind
1146declare void @unknown_use32(i32*) willreturn nounwind
1147declare void @llvm.assume(i1)
1148
1149!0 = !{i64 10, i64 100}
1150
1151