1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-attributes
2 ; RUN: opt -passes=indvars -S %s | FileCheck %s
4 ; Test cases inspired by PR48965.
6 ; %len is zero-extended before being used to compute %p.end, which guarantees
7 ; the offset is positive. %i.ult.ext can be simplified.
8 define i1 @can_simplify_ult_i32_ptr_len_zext(ptr %p.base, i32 %len) {
9 ; CHECK-LABEL: @can_simplify_ult_i32_ptr_len_zext(
11 ; CHECK-NEXT: [[EXT:%.*]] = zext i32 [[LEN:%.*]] to i64
12 ; CHECK-NEXT: [[P_END:%.*]] = getelementptr inbounds i32, ptr [[P_BASE:%.*]], i64 [[EXT]]
13 ; CHECK-NEXT: [[LEN_NONZERO:%.*]] = icmp ne i32 [[LEN]], 0
14 ; CHECK-NEXT: br i1 [[LEN_NONZERO]], label [[HEADER_PREHEADER:%.*]], label [[TRAP:%.*]]
15 ; CHECK: header.preheader:
16 ; CHECK-NEXT: br label [[HEADER:%.*]]
17 ; CHECK: trap.loopexit:
18 ; CHECK-NEXT: br label [[TRAP]]
20 ; CHECK-NEXT: ret i1 false
22 ; CHECK-NEXT: [[P:%.*]] = phi ptr [ [[P_INC:%.*]], [[LATCH:%.*]] ], [ [[P_BASE]], [[HEADER_PREHEADER]] ]
23 ; CHECK-NEXT: [[I:%.*]] = phi i64 [ [[I_INC:%.*]], [[LATCH]] ], [ 0, [[HEADER_PREHEADER]] ]
24 ; CHECK-NEXT: [[I_INC]] = add nuw nsw i64 [[I]], 1
25 ; CHECK-NEXT: [[I_ULT_EXT:%.*]] = icmp ult i64 [[I]], [[EXT]]
26 ; CHECK-NEXT: br i1 [[I_ULT_EXT]], label [[LATCH]], label [[TRAP_LOOPEXIT:%.*]]
28 ; CHECK-NEXT: [[P_INC]] = getelementptr inbounds i32, ptr [[P]], i64 1
29 ; CHECK-NEXT: [[C:%.*]] = icmp ne ptr [[P_INC]], [[P_END]]
30 ; CHECK-NEXT: store i32 0, ptr [[P]], align 4
31 ; CHECK-NEXT: br i1 [[C]], label [[HEADER]], label [[EXIT:%.*]]
33 ; CHECK-NEXT: ret i1 true
36 %ext = zext i32 %len to i64
37 %p.end = getelementptr inbounds i32, ptr %p.base, i64 %ext
38 %len.nonzero = icmp ne i32 %len, 0
39 br i1 %len.nonzero, label %header, label %trap
45 %p = phi ptr [ %p.base, %entry ], [ %p.inc, %latch ]
46 %i = phi i64 [ 0, %entry ], [ %i.inc, %latch]
47 %i.inc = add nsw nuw i64 %i, 1
48 %i.ult.ext = icmp ult i64 %i, %ext
49 br i1 %i.ult.ext, label %latch, label %trap
52 %p.inc = getelementptr inbounds i32, ptr %p, i64 1
53 %c = icmp ne ptr %p.inc, %p.end
55 br i1 %c, label %header, label %exit
61 ; %len may be (signed) negative, %i.ult.ext cannot be simplified.
62 define i1 @cannot_simplify_ult_i32_ptr_len_ult(ptr %p.base, i64 %len) {
63 ; CHECK-LABEL: @cannot_simplify_ult_i32_ptr_len_ult(
65 ; CHECK-NEXT: [[P_END:%.*]] = getelementptr inbounds i32, ptr [[P_BASE:%.*]], i64 [[LEN:%.*]]
66 ; CHECK-NEXT: [[LEN_NONZERO:%.*]] = icmp ne i64 [[LEN]], 0
67 ; CHECK-NEXT: br i1 [[LEN_NONZERO]], label [[HEADER_PREHEADER:%.*]], label [[TRAP:%.*]]
68 ; CHECK: header.preheader:
69 ; CHECK-NEXT: br label [[HEADER:%.*]]
70 ; CHECK: trap.loopexit:
71 ; CHECK-NEXT: br label [[TRAP]]
73 ; CHECK-NEXT: ret i1 false
75 ; CHECK-NEXT: [[P:%.*]] = phi ptr [ [[P_INC:%.*]], [[LATCH:%.*]] ], [ [[P_BASE]], [[HEADER_PREHEADER]] ]
76 ; CHECK-NEXT: [[I:%.*]] = phi i64 [ [[I_INC:%.*]], [[LATCH]] ], [ 0, [[HEADER_PREHEADER]] ]
77 ; CHECK-NEXT: [[I_INC]] = add nuw nsw i64 [[I]], 1
78 ; CHECK-NEXT: [[I_ULT_EXT:%.*]] = icmp ult i64 [[I]], [[LEN]]
79 ; CHECK-NEXT: br i1 [[I_ULT_EXT]], label [[LATCH]], label [[TRAP_LOOPEXIT:%.*]]
81 ; CHECK-NEXT: [[P_INC]] = getelementptr inbounds i32, ptr [[P]], i64 1
82 ; CHECK-NEXT: [[C:%.*]] = icmp ne ptr [[P_INC]], [[P_END]]
83 ; CHECK-NEXT: store i32 0, ptr [[P]], align 4
84 ; CHECK-NEXT: br i1 [[C]], label [[HEADER]], label [[EXIT:%.*]]
86 ; CHECK-NEXT: ret i1 true
89 %p.end = getelementptr inbounds i32, ptr %p.base, i64 %len
90 %len.nonzero = icmp ne i64 %len, 0
91 br i1 %len.nonzero, label %header, label %trap
97 %p = phi ptr [ %p.base, %entry ], [ %p.inc, %latch ]
98 %i = phi i64 [ 0, %entry ], [ %i.inc, %latch]
99 %i.inc = add nsw nuw i64 %i, 1
100 %i.ult.ext = icmp ult i64 %i, %len
101 br i1 %i.ult.ext, label %latch, label %trap
104 %p.inc = getelementptr inbounds i32, ptr %p, i64 1
105 %c = icmp ne ptr %p.inc, %p.end
107 br i1 %c, label %header, label %exit
113 ; Similar to can_simplify_ult_i32_ptr_len_zext, but %i has 1 as start value. %i.ult.ext cannot be simplified.
114 define i1 @cannot_simplify_ult_i32_ptr_len_zext(ptr %p.base, i32 %len) {
115 ; CHECK-LABEL: @cannot_simplify_ult_i32_ptr_len_zext(
117 ; CHECK-NEXT: [[EXT:%.*]] = zext i32 [[LEN:%.*]] to i64
118 ; CHECK-NEXT: [[P_END:%.*]] = getelementptr inbounds i32, ptr [[P_BASE:%.*]], i64 [[EXT]]
119 ; CHECK-NEXT: [[LEN_NONZERO:%.*]] = icmp ne i32 [[LEN]], 0
120 ; CHECK-NEXT: br i1 [[LEN_NONZERO]], label [[HEADER_PREHEADER:%.*]], label [[TRAP:%.*]]
121 ; CHECK: header.preheader:
122 ; CHECK-NEXT: br label [[HEADER:%.*]]
123 ; CHECK: trap.loopexit:
124 ; CHECK-NEXT: br label [[TRAP]]
126 ; CHECK-NEXT: ret i1 false
128 ; CHECK-NEXT: [[P:%.*]] = phi ptr [ [[P_INC:%.*]], [[LATCH:%.*]] ], [ [[P_BASE]], [[HEADER_PREHEADER]] ]
129 ; CHECK-NEXT: [[I:%.*]] = phi i64 [ [[I_INC:%.*]], [[LATCH]] ], [ 1, [[HEADER_PREHEADER]] ]
130 ; CHECK-NEXT: [[I_INC]] = add nuw nsw i64 [[I]], 1
131 ; CHECK-NEXT: [[I_ULT_EXT:%.*]] = icmp ult i64 [[I]], [[EXT]]
132 ; CHECK-NEXT: br i1 [[I_ULT_EXT]], label [[LATCH]], label [[TRAP_LOOPEXIT:%.*]]
134 ; CHECK-NEXT: [[P_INC]] = getelementptr inbounds i32, ptr [[P]], i64 1
135 ; CHECK-NEXT: [[C:%.*]] = icmp ne ptr [[P_INC]], [[P_END]]
136 ; CHECK-NEXT: store i32 0, ptr [[P]], align 4
137 ; CHECK-NEXT: br i1 [[C]], label [[HEADER]], label [[EXIT:%.*]]
139 ; CHECK-NEXT: ret i1 true
142 %ext = zext i32 %len to i64
143 %p.end = getelementptr inbounds i32, ptr %p.base, i64 %ext
144 %len.nonzero = icmp ne i32 %len, 0
145 br i1 %len.nonzero, label %header, label %trap
151 %p = phi ptr [ %p.base, %entry ], [ %p.inc, %latch ]
152 %i = phi i64 [ 1, %entry ], [ %i.inc, %latch]
153 %i.inc = add nsw nuw i64 %i, 1
154 %i.ult.ext = icmp ult i64 %i, %ext
155 br i1 %i.ult.ext, label %latch, label %trap
158 %p.inc = getelementptr inbounds i32, ptr %p, i64 1
159 %c = icmp ne ptr %p.inc, %p.end
161 br i1 %c, label %header, label %exit
167 define i1 @can_simplify_ule_i32_ptr_len_zext(ptr %p.base, i32 %len) {
168 ; CHECK-LABEL: @can_simplify_ule_i32_ptr_len_zext(
170 ; CHECK-NEXT: [[EXT:%.*]] = zext i32 [[LEN:%.*]] to i64
171 ; CHECK-NEXT: [[P_END:%.*]] = getelementptr inbounds i32, ptr [[P_BASE:%.*]], i64 [[EXT]]
172 ; CHECK-NEXT: [[LEN_NONZERO:%.*]] = icmp ne i32 [[LEN]], 0
173 ; CHECK-NEXT: br i1 [[LEN_NONZERO]], label [[HEADER_PREHEADER:%.*]], label [[TRAP:%.*]]
174 ; CHECK: header.preheader:
175 ; CHECK-NEXT: br label [[HEADER:%.*]]
176 ; CHECK: trap.loopexit:
177 ; CHECK-NEXT: br label [[TRAP]]
179 ; CHECK-NEXT: ret i1 false
181 ; CHECK-NEXT: [[P:%.*]] = phi ptr [ [[P_INC:%.*]], [[LATCH:%.*]] ], [ [[P_BASE]], [[HEADER_PREHEADER]] ]
182 ; CHECK-NEXT: [[I:%.*]] = phi i64 [ [[I_INC:%.*]], [[LATCH]] ], [ 1, [[HEADER_PREHEADER]] ]
183 ; CHECK-NEXT: [[I_INC]] = add nuw nsw i64 [[I]], 1
184 ; CHECK-NEXT: [[I_ULT_EXT:%.*]] = icmp ule i64 [[I]], [[EXT]]
185 ; CHECK-NEXT: br i1 [[I_ULT_EXT]], label [[LATCH]], label [[TRAP_LOOPEXIT:%.*]]
187 ; CHECK-NEXT: [[P_INC]] = getelementptr inbounds i32, ptr [[P]], i64 1
188 ; CHECK-NEXT: [[C:%.*]] = icmp ne ptr [[P_INC]], [[P_END]]
189 ; CHECK-NEXT: store i32 0, ptr [[P]], align 4
190 ; CHECK-NEXT: br i1 [[C]], label [[HEADER]], label [[EXIT:%.*]]
192 ; CHECK-NEXT: ret i1 true
195 %ext = zext i32 %len to i64
196 %p.end = getelementptr inbounds i32, ptr %p.base, i64 %ext
197 %len.nonzero = icmp ne i32 %len, 0
198 br i1 %len.nonzero, label %header, label %trap
204 %p = phi ptr [ %p.base, %entry ], [ %p.inc, %latch ]
205 %i = phi i64 [ 1, %entry ], [ %i.inc, %latch]
206 %i.inc = add nsw nuw i64 %i, 1
207 %i.ult.ext = icmp ule i64 %i, %ext
208 br i1 %i.ult.ext, label %latch, label %trap
211 %p.inc = getelementptr inbounds i32, ptr %p, i64 1
212 %c = icmp ne ptr %p.inc, %p.end
214 br i1 %c, label %header, label %exit
220 ; %len is zero-extended before being used to compute %p.end, which guarantees
221 ; the offset is positive. %i.uge.ext can be simplified.
222 define i1 @can_simplify_uge_i32_ptr_len_zext(ptr %p.base, i32 %len) {
223 ; CHECK-LABEL: @can_simplify_uge_i32_ptr_len_zext(
225 ; CHECK-NEXT: [[EXT:%.*]] = zext i32 [[LEN:%.*]] to i64
226 ; CHECK-NEXT: [[P_END:%.*]] = getelementptr inbounds i32, ptr [[P_BASE:%.*]], i64 [[EXT]]
227 ; CHECK-NEXT: [[LEN_NONZERO:%.*]] = icmp ne i32 [[LEN]], 0
228 ; CHECK-NEXT: br i1 [[LEN_NONZERO]], label [[HEADER_PREHEADER:%.*]], label [[TRAP:%.*]]
229 ; CHECK: header.preheader:
230 ; CHECK-NEXT: br label [[HEADER:%.*]]
231 ; CHECK: trap.loopexit:
232 ; CHECK-NEXT: br label [[TRAP]]
234 ; CHECK-NEXT: ret i1 false
236 ; CHECK-NEXT: [[P:%.*]] = phi ptr [ [[P_INC:%.*]], [[LATCH:%.*]] ], [ [[P_BASE]], [[HEADER_PREHEADER]] ]
237 ; CHECK-NEXT: [[I:%.*]] = phi i64 [ [[I_INC:%.*]], [[LATCH]] ], [ 0, [[HEADER_PREHEADER]] ]
238 ; CHECK-NEXT: [[I_INC]] = add nuw nsw i64 [[I]], 1
239 ; CHECK-NEXT: [[I_UGE_EXT:%.*]] = icmp uge i64 [[I]], [[EXT]]
240 ; CHECK-NEXT: br i1 [[I_UGE_EXT]], label [[TRAP_LOOPEXIT:%.*]], label [[LATCH]]
242 ; CHECK-NEXT: [[P_INC]] = getelementptr inbounds i32, ptr [[P]], i64 1
243 ; CHECK-NEXT: [[C:%.*]] = icmp ne ptr [[P_INC]], [[P_END]]
244 ; CHECK-NEXT: store i32 0, ptr [[P]], align 4
245 ; CHECK-NEXT: br i1 [[C]], label [[HEADER]], label [[EXIT:%.*]]
247 ; CHECK-NEXT: ret i1 true
250 %ext = zext i32 %len to i64
251 %p.end = getelementptr inbounds i32, ptr %p.base, i64 %ext
252 %len.nonzero = icmp ne i32 %len, 0
253 br i1 %len.nonzero, label %header, label %trap
259 %p = phi ptr [ %p.base, %entry ], [ %p.inc, %latch ]
260 %i = phi i64 [ 0, %entry ], [ %i.inc, %latch]
261 %i.inc = add nsw nuw i64 %i, 1
262 %i.uge.ext = icmp uge i64 %i, %ext
263 br i1 %i.uge.ext, label %trap, label %latch
266 %p.inc = getelementptr inbounds i32, ptr %p, i64 1
267 %c = icmp ne ptr %p.inc, %p.end
269 br i1 %c, label %header, label %exit
275 define i1 @cannot_simplify_uge_i32_ptr_len(ptr %p.base, i64 %len) {
276 ; CHECK-LABEL: @cannot_simplify_uge_i32_ptr_len(
278 ; CHECK-NEXT: [[P_END:%.*]] = getelementptr inbounds i32, ptr [[P_BASE:%.*]], i64 [[LEN:%.*]]
279 ; CHECK-NEXT: [[LEN_NONZERO:%.*]] = icmp ne i64 [[LEN]], 0
280 ; CHECK-NEXT: br i1 [[LEN_NONZERO]], label [[HEADER_PREHEADER:%.*]], label [[TRAP:%.*]]
281 ; CHECK: header.preheader:
282 ; CHECK-NEXT: br label [[HEADER:%.*]]
283 ; CHECK: trap.loopexit:
284 ; CHECK-NEXT: br label [[TRAP]]
286 ; CHECK-NEXT: ret i1 false
288 ; CHECK-NEXT: [[P:%.*]] = phi ptr [ [[P_INC:%.*]], [[LATCH:%.*]] ], [ [[P_BASE]], [[HEADER_PREHEADER]] ]
289 ; CHECK-NEXT: [[I:%.*]] = phi i64 [ [[I_INC:%.*]], [[LATCH]] ], [ 0, [[HEADER_PREHEADER]] ]
290 ; CHECK-NEXT: [[I_INC]] = add nuw nsw i64 [[I]], 1
291 ; CHECK-NEXT: [[I_UGE_EXT:%.*]] = icmp uge i64 [[I]], [[LEN]]
292 ; CHECK-NEXT: br i1 [[I_UGE_EXT]], label [[TRAP_LOOPEXIT:%.*]], label [[LATCH]]
294 ; CHECK-NEXT: [[P_INC]] = getelementptr inbounds i32, ptr [[P]], i64 1
295 ; CHECK-NEXT: [[C:%.*]] = icmp ne ptr [[P_INC]], [[P_END]]
296 ; CHECK-NEXT: store i32 0, ptr [[P]], align 4
297 ; CHECK-NEXT: br i1 [[C]], label [[HEADER]], label [[EXIT:%.*]]
299 ; CHECK-NEXT: ret i1 true
302 %p.end = getelementptr inbounds i32, ptr %p.base, i64 %len
303 %len.nonzero = icmp ne i64 %len, 0
304 br i1 %len.nonzero, label %header, label %trap
310 %p = phi ptr [ %p.base, %entry ], [ %p.inc, %latch ]
311 %i = phi i64 [ 0, %entry ], [ %i.inc, %latch]
312 %i.inc = add nsw nuw i64 %i, 1
313 %i.uge.ext = icmp uge i64 %i, %len
314 br i1 %i.uge.ext, label %trap, label %latch
317 %p.inc = getelementptr inbounds i32, ptr %p, i64 1
318 %c = icmp ne ptr %p.inc, %p.end
320 br i1 %c, label %header, label %exit
326 define i1 @cannot_simplify_uge_i32_ptr_len_zext_step_2(ptr %p.base, i32 %len) {
327 ; CHECK-LABEL: @cannot_simplify_uge_i32_ptr_len_zext_step_2(
329 ; CHECK-NEXT: [[EXT:%.*]] = zext i32 [[LEN:%.*]] to i64
330 ; CHECK-NEXT: [[P_END:%.*]] = getelementptr inbounds i32, ptr [[P_BASE:%.*]], i64 [[EXT]]
331 ; CHECK-NEXT: [[LEN_NONZERO:%.*]] = icmp ne i32 [[LEN]], 0
332 ; CHECK-NEXT: br i1 [[LEN_NONZERO]], label [[HEADER_PREHEADER:%.*]], label [[TRAP:%.*]]
333 ; CHECK: header.preheader:
334 ; CHECK-NEXT: br label [[HEADER:%.*]]
335 ; CHECK: trap.loopexit:
336 ; CHECK-NEXT: br label [[TRAP]]
338 ; CHECK-NEXT: ret i1 false
340 ; CHECK-NEXT: [[P:%.*]] = phi ptr [ [[P_INC:%.*]], [[LATCH:%.*]] ], [ [[P_BASE]], [[HEADER_PREHEADER]] ]
341 ; CHECK-NEXT: [[I:%.*]] = phi i64 [ [[I_INC:%.*]], [[LATCH]] ], [ 0, [[HEADER_PREHEADER]] ]
342 ; CHECK-NEXT: [[I_INC]] = add nuw nsw i64 [[I]], 2
343 ; CHECK-NEXT: [[I_UGE_EXT:%.*]] = icmp uge i64 [[I]], [[EXT]]
344 ; CHECK-NEXT: br i1 [[I_UGE_EXT]], label [[TRAP_LOOPEXIT:%.*]], label [[LATCH]]
346 ; CHECK-NEXT: [[P_INC]] = getelementptr inbounds i32, ptr [[P]], i64 1
347 ; CHECK-NEXT: [[C:%.*]] = icmp ne ptr [[P_INC]], [[P_END]]
348 ; CHECK-NEXT: store i32 0, ptr [[P]], align 4
349 ; CHECK-NEXT: br i1 [[C]], label [[HEADER]], label [[EXIT:%.*]]
351 ; CHECK-NEXT: ret i1 true
354 %ext = zext i32 %len to i64
355 %p.end = getelementptr inbounds i32, ptr %p.base, i64 %ext
356 %len.nonzero = icmp ne i32 %len, 0
357 br i1 %len.nonzero, label %header, label %trap
363 %p = phi ptr [ %p.base, %entry ], [ %p.inc, %latch ]
364 %i = phi i64 [ 0, %entry ], [ %i.inc, %latch]
365 %i.inc = add nsw nuw i64 %i, 2
366 %i.uge.ext = icmp uge i64 %i, %ext
367 br i1 %i.uge.ext, label %trap, label %latch
370 %p.inc = getelementptr inbounds i32, ptr %p, i64 1
371 %c = icmp ne ptr %p.inc, %p.end
373 br i1 %c, label %header, label %exit