xref: /llvm-project/llvm/test/Transforms/LoopStrengthReduce/RISCV/icmp-zero.ll (revision 6ab686eb86fb60ab63750dddd575ac92d8a1f9f9)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt < %s -loop-reduce -S | FileCheck %s
3
4target datalayout = "e-m:e-p:64:64-i64:64-i128:128-n64-S128"
5target triple = "riscv64"
6
7
8define void @icmp_zero(i64 %N, ptr %p) {
9; CHECK-LABEL: @icmp_zero(
10; CHECK-NEXT:  entry:
11; CHECK-NEXT:    br label [[VECTOR_BODY:%.*]]
12; CHECK:       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]]
18; CHECK:       exit:
19; CHECK-NEXT:    ret void
20;
21entry:
22  br label %vector.body
23
24vector.body:
25  %iv = phi i64 [ 0, %entry ], [ %iv.next, %vector.body ]
26  store i64 0, ptr %p
27  %iv.next = add i64 %iv, 2
28  %done = icmp eq i64 %iv.next, %N
29  br i1 %done, label %exit, label %vector.body
30
31exit:
32  ret void
33}
34
35define void @icmp_zero_urem_nonzero_con(i64 %N, ptr %p) {
36; CHECK-LABEL: @icmp_zero_urem_nonzero_con(
37; CHECK-NEXT:  entry:
38; CHECK-NEXT:    [[UREM:%.*]] = urem i64 [[N:%.*]], 16
39; CHECK-NEXT:    br label [[VECTOR_BODY:%.*]]
40; CHECK:       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]]
46; CHECK:       exit:
47; CHECK-NEXT:    ret void
48;
49entry:
50  %urem = urem i64 %N, 16
51  br label %vector.body
52
53vector.body:
54  %iv = phi i64 [ 0, %entry ], [ %iv.next, %vector.body ]
55  store i64 0, ptr %p
56  %iv.next = add i64 %iv, 2
57  %done = icmp eq i64 %iv.next, %urem
58  br i1 %done, label %exit, label %vector.body
59
60exit:
61  ret void
62}
63
64define void @icmp_zero_urem_invariant(i64 %N, i64 %M, ptr %p) {
65; CHECK-LABEL: @icmp_zero_urem_invariant(
66; CHECK-NEXT:  entry:
67; CHECK-NEXT:    [[UREM:%.*]] = urem i64 [[N:%.*]], [[M:%.*]]
68; CHECK-NEXT:    br label [[VECTOR_BODY:%.*]]
69; CHECK:       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]]
75; CHECK:       exit:
76; CHECK-NEXT:    ret void
77;
78entry:
79  %urem = urem i64 %N, %M
80  br label %vector.body
81
82vector.body:
83  %iv = phi i64 [ 0, %entry ], [ %iv.next, %vector.body ]
84  store i64 0, ptr %p
85  %iv.next = add i64 %iv, 2
86  %done = icmp eq i64 %iv.next, %urem
87  br i1 %done, label %exit, label %vector.body
88
89exit:
90  ret void
91}
92
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.
96define void @icmp_zero_urem_invariant_ptr(i64 %N, i64 %M, ptr %p) {
97; CHECK-LABEL: @icmp_zero_urem_invariant_ptr(
98; CHECK-NEXT:  entry:
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]]
108; CHECK:       exit:
109; CHECK-NEXT:    ret void
110;
111entry:
112  %urem = urem i64 %N, %M
113  %end = getelementptr i64, ptr %p, i64 %urem
114  br label %vector.body
115
116vector.body:
117  %iv = phi ptr [ %p, %entry ], [ %iv.next, %vector.body ]
118  store i64 0, ptr %p
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
122
123exit:
124  ret void
125}
126
127; Negative test - We can not hoist because we don't know value of %M.
128define void @icmp_zero_urem_nohoist(i64 %N, i64 %M, ptr %p) {
129; CHECK-LABEL: @icmp_zero_urem_nohoist(
130; CHECK-NEXT:  entry:
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]]
139; CHECK:       exit:
140; CHECK-NEXT:    ret void
141;
142entry:
143  br label %vector.body
144
145vector.body:
146  %iv = phi i64 [ 0, %entry ], [ %iv.next, %vector.body ]
147  store i64 0, ptr %p
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
152
153exit:
154  ret void
155}
156
157define void @icmp_zero_urem_nonzero(i64 %N, i64 %M, ptr %p) {
158; CHECK-LABEL: @icmp_zero_urem_nonzero(
159; CHECK-NEXT:  entry:
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]]
169; CHECK:       exit:
170; CHECK-NEXT:    ret void
171;
172entry:
173  %nonzero = add nuw i64 %M, 1
174  %urem = urem i64 %N, %nonzero
175  br label %vector.body
176
177vector.body:
178  %iv = phi i64 [ 0, %entry ], [ %iv.next, %vector.body ]
179  store i64 0, ptr %p
180  %iv.next = add i64 %iv, 2
181  %done = icmp eq i64 %iv.next, %urem
182  br i1 %done, label %exit, label %vector.body
183
184exit:
185  ret void
186}
187
188define void @icmp_zero_urem_vscale(i64 %N, ptr %p) {
189; CHECK-LABEL: @icmp_zero_urem_vscale(
190; CHECK-NEXT:  entry:
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]]
200; CHECK:       exit:
201; CHECK-NEXT:    ret void
202;
203entry:
204  %vscale = call i64 @llvm.vscale.i64()
205  %urem = urem i64 %N, %vscale
206  br label %vector.body
207
208vector.body:
209  %iv = phi i64 [ 0, %entry ], [ %iv.next, %vector.body ]
210  store i64 0, ptr %p
211  %iv.next = add i64 %iv, 2
212  %done = icmp eq i64 %iv.next, %urem
213  br i1 %done, label %exit, label %vector.body
214
215exit:
216  ret void
217}
218
219define void @icmp_zero_urem_vscale_mul8(i64 %N, ptr %p) {
220; CHECK-LABEL: @icmp_zero_urem_vscale_mul8(
221; CHECK-NEXT:  entry:
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]]
232; CHECK:       exit:
233; CHECK-NEXT:    ret void
234;
235entry:
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
240
241vector.body:
242  %iv = phi i64 [ 0, %entry ], [ %iv.next, %vector.body ]
243  store i64 0, ptr %p
244  %iv.next = add i64 %iv, 2
245  %done = icmp eq i64 %iv.next, %urem
246  br i1 %done, label %exit, label %vector.body
247
248exit:
249  ret void
250}
251
252
253define void @icmp_zero_urem_vscale_mul64(i64 %N, ptr %p) {
254; CHECK-LABEL: @icmp_zero_urem_vscale_mul64(
255; CHECK-NEXT:  entry:
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]]
266; CHECK:       exit:
267; CHECK-NEXT:    ret void
268;
269entry:
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
274
275vector.body:
276  %iv = phi i64 [ 0, %entry ], [ %iv.next, %vector.body ]
277  store i64 0, ptr %p
278  %iv.next = add i64 %iv, 2
279  %done = icmp eq i64 %iv.next, %urem
280  br i1 %done, label %exit, label %vector.body
281
282exit:
283  ret void
284}
285
286define void @icmp_zero_urem_vscale_shl3(i64 %N, ptr %p) {
287; CHECK-LABEL: @icmp_zero_urem_vscale_shl3(
288; CHECK-NEXT:  entry:
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]]
299; CHECK:       exit:
300; CHECK-NEXT:    ret void
301;
302entry:
303  %vscale = call i64 @llvm.vscale.i64()
304  %shl = shl i64 %vscale, 3
305  %urem = urem i64 %N, %shl
306  br label %vector.body
307
308vector.body:
309  %iv = phi i64 [ 0, %entry ], [ %iv.next, %vector.body ]
310  store i64 0, ptr %p
311  %iv.next = add i64 %iv, 2
312  %done = icmp eq i64 %iv.next, %urem
313  br i1 %done, label %exit, label %vector.body
314
315exit:
316  ret void
317}
318
319define void @icmp_zero_urem_vscale_shl6(i64 %N, ptr %p) {
320; CHECK-LABEL: @icmp_zero_urem_vscale_shl6(
321; CHECK-NEXT:  entry:
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]]
332; CHECK:       exit:
333; CHECK-NEXT:    ret void
334;
335entry:
336  %vscale = call i64 @llvm.vscale.i64()
337  %shl = shl i64 %vscale, 6
338  %urem = urem i64 %N, %shl
339  br label %vector.body
340
341vector.body:
342  %iv = phi i64 [ 0, %entry ], [ %iv.next, %vector.body ]
343  store i64 0, ptr %p
344  %iv.next = add i64 %iv, 2
345  %done = icmp eq i64 %iv.next, %urem
346  br i1 %done, label %exit, label %vector.body
347
348exit:
349  ret void
350}
351
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.
355define void @loop_invariant_definition(i64 %arg) {
356; CHECK-LABEL: @loop_invariant_definition(
357; CHECK-NEXT:  entry:
358; CHECK-NEXT:    br label [[T1:%.*]]
359; CHECK:       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]]
363; CHECK:       t4:
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
368;
369entry:
370  br label %t1
371
372t1:                                                ; preds = %1, %0
373  %t2 = phi i64 [ %t3, %t1 ], [ 0, %entry ]
374  %t3 = add nuw i64 %t2, 1
375  br i1 true, label %t4, label %t1
376
377t4:                                                ; preds = %1
378  %t5 = trunc i64 %t2 to i32
379  %t6 = add i32 %t5, 1
380  %t7 = icmp eq i32 %t5, %t6
381  ret void
382}
383
384declare i64 @llvm.vscale.i64()
385