1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2 ; RUN: opt < %s -loop-reduce -S | FileCheck %s
4 target datalayout = "e-m:e-p:64:64-i64:64-i128:128-n64-S128"
5 target triple = "riscv64"
8 define void @icmp_zero(i64 %N, ptr %p) {
9 ; CHECK-LABEL: @icmp_zero(
11 ; CHECK-NEXT: br label [[VECTOR_BODY:%.*]]
13 ; CHECK-NEXT: [[LSR_IV:%.*]] = phi i64 [ [[LSR_IV_NEXT:%.*]], [[VECTOR_BODY]] ], [ [[N:%.*]], [[ENTRY:%.*]] ]
14 ; CHECK-NEXT: store i64 0, ptr [[P:%.*]], align 8
15 ; CHECK-NEXT: [[LSR_IV_NEXT]] = add i64 [[LSR_IV]], -2
16 ; CHECK-NEXT: [[DONE:%.*]] = icmp eq i64 [[LSR_IV_NEXT]], 0
17 ; CHECK-NEXT: br i1 [[DONE]], label [[EXIT:%.*]], label [[VECTOR_BODY]]
19 ; CHECK-NEXT: ret void
25 %iv = phi i64 [ 0, %entry ], [ %iv.next, %vector.body ]
27 %iv.next = add i64 %iv, 2
28 %done = icmp eq i64 %iv.next, %N
29 br i1 %done, label %exit, label %vector.body
35 define void @icmp_zero_urem_nonzero_con(i64 %N, ptr %p) {
36 ; CHECK-LABEL: @icmp_zero_urem_nonzero_con(
38 ; CHECK-NEXT: [[UREM:%.*]] = urem i64 [[N:%.*]], 16
39 ; CHECK-NEXT: br label [[VECTOR_BODY:%.*]]
41 ; CHECK-NEXT: [[LSR_IV:%.*]] = phi i64 [ [[LSR_IV_NEXT:%.*]], [[VECTOR_BODY]] ], [ [[UREM]], [[ENTRY:%.*]] ]
42 ; CHECK-NEXT: store i64 0, ptr [[P:%.*]], align 8
43 ; CHECK-NEXT: [[LSR_IV_NEXT]] = add i64 [[LSR_IV]], -2
44 ; CHECK-NEXT: [[DONE:%.*]] = icmp eq i64 [[LSR_IV_NEXT]], 0
45 ; CHECK-NEXT: br i1 [[DONE]], label [[EXIT:%.*]], label [[VECTOR_BODY]]
47 ; CHECK-NEXT: ret void
50 %urem = urem i64 %N, 16
54 %iv = phi i64 [ 0, %entry ], [ %iv.next, %vector.body ]
56 %iv.next = add i64 %iv, 2
57 %done = icmp eq i64 %iv.next, %urem
58 br i1 %done, label %exit, label %vector.body
64 define void @icmp_zero_urem_invariant(i64 %N, i64 %M, ptr %p) {
65 ; CHECK-LABEL: @icmp_zero_urem_invariant(
67 ; CHECK-NEXT: [[UREM:%.*]] = urem i64 [[N:%.*]], [[M:%.*]]
68 ; CHECK-NEXT: br label [[VECTOR_BODY:%.*]]
70 ; CHECK-NEXT: [[LSR_IV:%.*]] = phi i64 [ [[LSR_IV_NEXT:%.*]], [[VECTOR_BODY]] ], [ [[UREM]], [[ENTRY:%.*]] ]
71 ; CHECK-NEXT: store i64 0, ptr [[P:%.*]], align 8
72 ; CHECK-NEXT: [[LSR_IV_NEXT]] = add i64 [[LSR_IV]], -2
73 ; CHECK-NEXT: [[DONE:%.*]] = icmp eq i64 [[LSR_IV_NEXT]], 0
74 ; CHECK-NEXT: br i1 [[DONE]], label [[EXIT:%.*]], label [[VECTOR_BODY]]
76 ; CHECK-NEXT: ret void
79 %urem = urem i64 %N, %M
83 %iv = phi i64 [ 0, %entry ], [ %iv.next, %vector.body ]
85 %iv.next = add i64 %iv, 2
86 %done = icmp eq i64 %iv.next, %urem
87 br i1 %done, label %exit, label %vector.body
93 ; We have to be careful here as SCEV can only compute a subtraction from
94 ; two pointers with the same base. If we hide %end inside a unknown, we
95 ; can no longer compute the subtract.
96 define void @icmp_zero_urem_invariant_ptr(i64 %N, i64 %M, ptr %p) {
97 ; CHECK-LABEL: @icmp_zero_urem_invariant_ptr(
99 ; CHECK-NEXT: [[UREM:%.*]] = urem i64 [[N:%.*]], [[M:%.*]]
100 ; CHECK-NEXT: [[END:%.*]] = getelementptr i64, ptr [[P:%.*]], i64 [[UREM]]
101 ; CHECK-NEXT: br label [[VECTOR_BODY:%.*]]
102 ; CHECK: vector.body:
103 ; CHECK-NEXT: [[IV:%.*]] = phi ptr [ [[P]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[VECTOR_BODY]] ]
104 ; CHECK-NEXT: store i64 0, ptr [[P]], align 8
105 ; CHECK-NEXT: [[IV_NEXT]] = getelementptr i64, ptr [[IV]], i64 1
106 ; CHECK-NEXT: [[DONE:%.*]] = icmp eq ptr [[IV_NEXT]], [[END]]
107 ; CHECK-NEXT: br i1 [[DONE]], label [[EXIT:%.*]], label [[VECTOR_BODY]]
109 ; CHECK-NEXT: ret void
112 %urem = urem i64 %N, %M
113 %end = getelementptr i64, ptr %p, i64 %urem
114 br label %vector.body
117 %iv = phi ptr [ %p, %entry ], [ %iv.next, %vector.body ]
119 %iv.next = getelementptr i64, ptr %iv, i64 1
120 %done = icmp eq ptr %iv.next, %end
121 br i1 %done, label %exit, label %vector.body
127 ; Negative test - We can not hoist because we don't know value of %M.
128 define void @icmp_zero_urem_nohoist(i64 %N, i64 %M, ptr %p) {
129 ; CHECK-LABEL: @icmp_zero_urem_nohoist(
131 ; CHECK-NEXT: br label [[VECTOR_BODY:%.*]]
132 ; CHECK: vector.body:
133 ; CHECK-NEXT: [[IV:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[VECTOR_BODY]] ]
134 ; CHECK-NEXT: store i64 0, ptr [[P:%.*]], align 8
135 ; CHECK-NEXT: [[IV_NEXT]] = add i64 [[IV]], 2
136 ; CHECK-NEXT: [[UREM:%.*]] = urem i64 [[N:%.*]], [[M:%.*]]
137 ; CHECK-NEXT: [[DONE:%.*]] = icmp eq i64 [[IV_NEXT]], [[UREM]]
138 ; CHECK-NEXT: br i1 [[DONE]], label [[EXIT:%.*]], label [[VECTOR_BODY]]
140 ; CHECK-NEXT: ret void
143 br label %vector.body
146 %iv = phi i64 [ 0, %entry ], [ %iv.next, %vector.body ]
148 %iv.next = add i64 %iv, 2
149 %urem = urem i64 %N, %M
150 %done = icmp eq i64 %iv.next, %urem
151 br i1 %done, label %exit, label %vector.body
157 define void @icmp_zero_urem_nonzero(i64 %N, i64 %M, ptr %p) {
158 ; CHECK-LABEL: @icmp_zero_urem_nonzero(
160 ; CHECK-NEXT: [[NONZERO:%.*]] = add nuw i64 [[M:%.*]], 1
161 ; CHECK-NEXT: [[UREM:%.*]] = urem i64 [[N:%.*]], [[NONZERO]]
162 ; CHECK-NEXT: br label [[VECTOR_BODY:%.*]]
163 ; CHECK: vector.body:
164 ; CHECK-NEXT: [[LSR_IV:%.*]] = phi i64 [ [[LSR_IV_NEXT:%.*]], [[VECTOR_BODY]] ], [ [[UREM]], [[ENTRY:%.*]] ]
165 ; CHECK-NEXT: store i64 0, ptr [[P:%.*]], align 8
166 ; CHECK-NEXT: [[LSR_IV_NEXT]] = add i64 [[LSR_IV]], -2
167 ; CHECK-NEXT: [[DONE:%.*]] = icmp eq i64 [[LSR_IV_NEXT]], 0
168 ; CHECK-NEXT: br i1 [[DONE]], label [[EXIT:%.*]], label [[VECTOR_BODY]]
170 ; CHECK-NEXT: ret void
173 %nonzero = add nuw i64 %M, 1
174 %urem = urem i64 %N, %nonzero
175 br label %vector.body
178 %iv = phi i64 [ 0, %entry ], [ %iv.next, %vector.body ]
180 %iv.next = add i64 %iv, 2
181 %done = icmp eq i64 %iv.next, %urem
182 br i1 %done, label %exit, label %vector.body
188 define void @icmp_zero_urem_vscale(i64 %N, ptr %p) {
189 ; CHECK-LABEL: @icmp_zero_urem_vscale(
191 ; CHECK-NEXT: [[VSCALE:%.*]] = call i64 @llvm.vscale.i64()
192 ; CHECK-NEXT: [[UREM:%.*]] = urem i64 [[N:%.*]], [[VSCALE]]
193 ; CHECK-NEXT: br label [[VECTOR_BODY:%.*]]
194 ; CHECK: vector.body:
195 ; CHECK-NEXT: [[LSR_IV:%.*]] = phi i64 [ [[LSR_IV_NEXT:%.*]], [[VECTOR_BODY]] ], [ [[UREM]], [[ENTRY:%.*]] ]
196 ; CHECK-NEXT: store i64 0, ptr [[P:%.*]], align 8
197 ; CHECK-NEXT: [[LSR_IV_NEXT]] = add i64 [[LSR_IV]], -2
198 ; CHECK-NEXT: [[DONE:%.*]] = icmp eq i64 [[LSR_IV_NEXT]], 0
199 ; CHECK-NEXT: br i1 [[DONE]], label [[EXIT:%.*]], label [[VECTOR_BODY]]
201 ; CHECK-NEXT: ret void
204 %vscale = call i64 @llvm.vscale.i64()
205 %urem = urem i64 %N, %vscale
206 br label %vector.body
209 %iv = phi i64 [ 0, %entry ], [ %iv.next, %vector.body ]
211 %iv.next = add i64 %iv, 2
212 %done = icmp eq i64 %iv.next, %urem
213 br i1 %done, label %exit, label %vector.body
219 define void @icmp_zero_urem_vscale_mul8(i64 %N, ptr %p) {
220 ; CHECK-LABEL: @icmp_zero_urem_vscale_mul8(
222 ; CHECK-NEXT: [[VSCALE:%.*]] = call i64 @llvm.vscale.i64()
223 ; CHECK-NEXT: [[MUL:%.*]] = mul nuw nsw i64 [[VSCALE]], 8
224 ; CHECK-NEXT: [[UREM:%.*]] = urem i64 [[N:%.*]], [[MUL]]
225 ; CHECK-NEXT: br label [[VECTOR_BODY:%.*]]
226 ; CHECK: vector.body:
227 ; CHECK-NEXT: [[LSR_IV:%.*]] = phi i64 [ [[LSR_IV_NEXT:%.*]], [[VECTOR_BODY]] ], [ [[UREM]], [[ENTRY:%.*]] ]
228 ; CHECK-NEXT: store i64 0, ptr [[P:%.*]], align 8
229 ; CHECK-NEXT: [[LSR_IV_NEXT]] = add i64 [[LSR_IV]], -2
230 ; CHECK-NEXT: [[DONE:%.*]] = icmp eq i64 [[LSR_IV_NEXT]], 0
231 ; CHECK-NEXT: br i1 [[DONE]], label [[EXIT:%.*]], label [[VECTOR_BODY]]
233 ; CHECK-NEXT: ret void
236 %vscale = call i64 @llvm.vscale.i64()
237 %mul = mul nuw nsw i64 %vscale, 8
238 %urem = urem i64 %N, %mul
239 br label %vector.body
242 %iv = phi i64 [ 0, %entry ], [ %iv.next, %vector.body ]
244 %iv.next = add i64 %iv, 2
245 %done = icmp eq i64 %iv.next, %urem
246 br i1 %done, label %exit, label %vector.body
253 define void @icmp_zero_urem_vscale_mul64(i64 %N, ptr %p) {
254 ; CHECK-LABEL: @icmp_zero_urem_vscale_mul64(
256 ; CHECK-NEXT: [[VSCALE:%.*]] = call i64 @llvm.vscale.i64()
257 ; CHECK-NEXT: [[MUL:%.*]] = mul nuw nsw i64 [[VSCALE]], 64
258 ; CHECK-NEXT: [[UREM:%.*]] = urem i64 [[N:%.*]], [[MUL]]
259 ; CHECK-NEXT: br label [[VECTOR_BODY:%.*]]
260 ; CHECK: vector.body:
261 ; CHECK-NEXT: [[LSR_IV:%.*]] = phi i64 [ [[LSR_IV_NEXT:%.*]], [[VECTOR_BODY]] ], [ [[UREM]], [[ENTRY:%.*]] ]
262 ; CHECK-NEXT: store i64 0, ptr [[P:%.*]], align 8
263 ; CHECK-NEXT: [[LSR_IV_NEXT]] = add i64 [[LSR_IV]], -2
264 ; CHECK-NEXT: [[DONE:%.*]] = icmp eq i64 [[LSR_IV_NEXT]], 0
265 ; CHECK-NEXT: br i1 [[DONE]], label [[EXIT:%.*]], label [[VECTOR_BODY]]
267 ; CHECK-NEXT: ret void
270 %vscale = call i64 @llvm.vscale.i64()
271 %mul = mul nuw nsw i64 %vscale, 64
272 %urem = urem i64 %N, %mul
273 br label %vector.body
276 %iv = phi i64 [ 0, %entry ], [ %iv.next, %vector.body ]
278 %iv.next = add i64 %iv, 2
279 %done = icmp eq i64 %iv.next, %urem
280 br i1 %done, label %exit, label %vector.body
286 define void @icmp_zero_urem_vscale_shl3(i64 %N, ptr %p) {
287 ; CHECK-LABEL: @icmp_zero_urem_vscale_shl3(
289 ; CHECK-NEXT: [[VSCALE:%.*]] = call i64 @llvm.vscale.i64()
290 ; CHECK-NEXT: [[SHL:%.*]] = shl i64 [[VSCALE]], 3
291 ; CHECK-NEXT: [[UREM:%.*]] = urem i64 [[N:%.*]], [[SHL]]
292 ; CHECK-NEXT: br label [[VECTOR_BODY:%.*]]
293 ; CHECK: vector.body:
294 ; CHECK-NEXT: [[LSR_IV:%.*]] = phi i64 [ [[LSR_IV_NEXT:%.*]], [[VECTOR_BODY]] ], [ [[UREM]], [[ENTRY:%.*]] ]
295 ; CHECK-NEXT: store i64 0, ptr [[P:%.*]], align 8
296 ; CHECK-NEXT: [[LSR_IV_NEXT]] = add i64 [[LSR_IV]], -2
297 ; CHECK-NEXT: [[DONE:%.*]] = icmp eq i64 [[LSR_IV_NEXT]], 0
298 ; CHECK-NEXT: br i1 [[DONE]], label [[EXIT:%.*]], label [[VECTOR_BODY]]
300 ; CHECK-NEXT: ret void
303 %vscale = call i64 @llvm.vscale.i64()
304 %shl = shl i64 %vscale, 3
305 %urem = urem i64 %N, %shl
306 br label %vector.body
309 %iv = phi i64 [ 0, %entry ], [ %iv.next, %vector.body ]
311 %iv.next = add i64 %iv, 2
312 %done = icmp eq i64 %iv.next, %urem
313 br i1 %done, label %exit, label %vector.body
319 define void @icmp_zero_urem_vscale_shl6(i64 %N, ptr %p) {
320 ; CHECK-LABEL: @icmp_zero_urem_vscale_shl6(
322 ; CHECK-NEXT: [[VSCALE:%.*]] = call i64 @llvm.vscale.i64()
323 ; CHECK-NEXT: [[SHL:%.*]] = shl i64 [[VSCALE]], 6
324 ; CHECK-NEXT: [[UREM:%.*]] = urem i64 [[N:%.*]], [[SHL]]
325 ; CHECK-NEXT: br label [[VECTOR_BODY:%.*]]
326 ; CHECK: vector.body:
327 ; CHECK-NEXT: [[LSR_IV:%.*]] = phi i64 [ [[LSR_IV_NEXT:%.*]], [[VECTOR_BODY]] ], [ [[UREM]], [[ENTRY:%.*]] ]
328 ; CHECK-NEXT: store i64 0, ptr [[P:%.*]], align 8
329 ; CHECK-NEXT: [[LSR_IV_NEXT]] = add i64 [[LSR_IV]], -2
330 ; CHECK-NEXT: [[DONE:%.*]] = icmp eq i64 [[LSR_IV_NEXT]], 0
331 ; CHECK-NEXT: br i1 [[DONE]], label [[EXIT:%.*]], label [[VECTOR_BODY]]
333 ; CHECK-NEXT: ret void
336 %vscale = call i64 @llvm.vscale.i64()
337 %shl = shl i64 %vscale, 6
338 %urem = urem i64 %N, %shl
339 br label %vector.body
342 %iv = phi i64 [ 0, %entry ], [ %iv.next, %vector.body ]
344 %iv.next = add i64 %iv, 2
345 %done = icmp eq i64 %iv.next, %urem
346 br i1 %done, label %exit, label %vector.body
352 ; Loop invariant does not neccessarily mean dominating the loop. Forming
353 ; an ICmpZero from this example would be illegal even though the operands
354 ; to the compare are loop invariant.
355 define void @loop_invariant_definition(i64 %arg) {
356 ; CHECK-LABEL: @loop_invariant_definition(
358 ; CHECK-NEXT: br label [[T1:%.*]]
360 ; CHECK-NEXT: [[LSR_IV:%.*]] = phi i64 [ [[LSR_IV_NEXT:%.*]], [[T1]] ], [ -1, [[ENTRY:%.*]] ]
361 ; CHECK-NEXT: [[LSR_IV_NEXT]] = add nsw i64 [[LSR_IV]], 1
362 ; CHECK-NEXT: br i1 true, label [[T4:%.*]], label [[T1]]
364 ; CHECK-NEXT: [[T5:%.*]] = trunc i64 [[LSR_IV_NEXT]] to i32
365 ; CHECK-NEXT: [[T6:%.*]] = add i32 [[T5]], 1
366 ; CHECK-NEXT: [[T7:%.*]] = icmp eq i32 [[T5]], [[T6]]
367 ; CHECK-NEXT: ret void
373 %t2 = phi i64 [ %t3, %t1 ], [ 0, %entry ]
374 %t3 = add nuw i64 %t2, 1
375 br i1 true, label %t4, label %t1
378 %t5 = trunc i64 %t2 to i32
380 %t7 = icmp eq i32 %t5, %t6
384 declare i64 @llvm.vscale.i64()