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; Negative test - We can not hoist because we don't know value of %M.
94define void @icmp_zero_urem_nohoist(i64 %N, i64 %M, ptr %p) {
95; CHECK-LABEL: @icmp_zero_urem_nohoist(
96; CHECK-NEXT:  entry:
97; CHECK-NEXT:    br label [[VECTOR_BODY:%.*]]
98; CHECK:       vector.body:
99; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[VECTOR_BODY]] ]
100; CHECK-NEXT:    store i64 0, ptr [[P:%.*]], align 8
101; CHECK-NEXT:    [[IV_NEXT]] = add i64 [[IV]], 2
102; CHECK-NEXT:    [[UREM:%.*]] = urem i64 [[N:%.*]], [[M:%.*]]
103; CHECK-NEXT:    [[DONE:%.*]] = icmp eq i64 [[IV_NEXT]], [[UREM]]
104; CHECK-NEXT:    br i1 [[DONE]], label [[EXIT:%.*]], label [[VECTOR_BODY]]
105; CHECK:       exit:
106; CHECK-NEXT:    ret void
107;
108entry:
109  br label %vector.body
110
111vector.body:
112  %iv = phi i64 [ 0, %entry ], [ %iv.next, %vector.body ]
113  store i64 0, ptr %p
114  %iv.next = add i64 %iv, 2
115  %urem = urem i64 %N, %M
116  %done = icmp eq i64 %iv.next, %urem
117  br i1 %done, label %exit, label %vector.body
118
119exit:
120  ret void
121}
122
123define void @icmp_zero_urem_nonzero(i64 %N, i64 %M, ptr %p) {
124; CHECK-LABEL: @icmp_zero_urem_nonzero(
125; CHECK-NEXT:  entry:
126; CHECK-NEXT:    [[NONZERO:%.*]] = add nuw i64 [[M:%.*]], 1
127; CHECK-NEXT:    [[UREM:%.*]] = urem i64 [[N:%.*]], [[NONZERO]]
128; CHECK-NEXT:    br label [[VECTOR_BODY:%.*]]
129; CHECK:       vector.body:
130; CHECK-NEXT:    [[LSR_IV:%.*]] = phi i64 [ [[LSR_IV_NEXT:%.*]], [[VECTOR_BODY]] ], [ [[UREM]], [[ENTRY:%.*]] ]
131; CHECK-NEXT:    store i64 0, ptr [[P:%.*]], align 8
132; CHECK-NEXT:    [[LSR_IV_NEXT]] = add i64 [[LSR_IV]], -2
133; CHECK-NEXT:    [[DONE:%.*]] = icmp eq i64 [[LSR_IV_NEXT]], 0
134; CHECK-NEXT:    br i1 [[DONE]], label [[EXIT:%.*]], label [[VECTOR_BODY]]
135; CHECK:       exit:
136; CHECK-NEXT:    ret void
137;
138entry:
139  %nonzero = add nuw i64 %M, 1
140  %urem = urem i64 %N, %nonzero
141  br label %vector.body
142
143vector.body:
144  %iv = phi i64 [ 0, %entry ], [ %iv.next, %vector.body ]
145  store i64 0, ptr %p
146  %iv.next = add i64 %iv, 2
147  %done = icmp eq i64 %iv.next, %urem
148  br i1 %done, label %exit, label %vector.body
149
150exit:
151  ret void
152}
153
154define void @icmp_zero_urem_vscale(i64 %N, ptr %p) {
155; CHECK-LABEL: @icmp_zero_urem_vscale(
156; CHECK-NEXT:  entry:
157; CHECK-NEXT:    [[VSCALE:%.*]] = call i64 @llvm.vscale.i64()
158; CHECK-NEXT:    [[UREM:%.*]] = urem i64 [[N:%.*]], [[VSCALE]]
159; CHECK-NEXT:    br label [[VECTOR_BODY:%.*]]
160; CHECK:       vector.body:
161; CHECK-NEXT:    [[LSR_IV:%.*]] = phi i64 [ [[LSR_IV_NEXT:%.*]], [[VECTOR_BODY]] ], [ [[UREM]], [[ENTRY:%.*]] ]
162; CHECK-NEXT:    store i64 0, ptr [[P:%.*]], align 8
163; CHECK-NEXT:    [[LSR_IV_NEXT]] = add i64 [[LSR_IV]], -2
164; CHECK-NEXT:    [[DONE:%.*]] = icmp eq i64 [[LSR_IV_NEXT]], 0
165; CHECK-NEXT:    br i1 [[DONE]], label [[EXIT:%.*]], label [[VECTOR_BODY]]
166; CHECK:       exit:
167; CHECK-NEXT:    ret void
168;
169entry:
170  %vscale = call i64 @llvm.vscale.i64()
171  %urem = urem i64 %N, %vscale
172  br label %vector.body
173
174vector.body:
175  %iv = phi i64 [ 0, %entry ], [ %iv.next, %vector.body ]
176  store i64 0, ptr %p
177  %iv.next = add i64 %iv, 2
178  %done = icmp eq i64 %iv.next, %urem
179  br i1 %done, label %exit, label %vector.body
180
181exit:
182  ret void
183}
184
185define void @icmp_zero_urem_vscale_mul8(i64 %N, ptr %p) {
186; CHECK-LABEL: @icmp_zero_urem_vscale_mul8(
187; CHECK-NEXT:  entry:
188; CHECK-NEXT:    [[VSCALE:%.*]] = call i64 @llvm.vscale.i64()
189; CHECK-NEXT:    [[MUL:%.*]] = mul nuw nsw i64 [[VSCALE]], 8
190; CHECK-NEXT:    [[UREM:%.*]] = urem i64 [[N:%.*]], [[MUL]]
191; CHECK-NEXT:    br label [[VECTOR_BODY:%.*]]
192; CHECK:       vector.body:
193; CHECK-NEXT:    [[LSR_IV:%.*]] = phi i64 [ [[LSR_IV_NEXT:%.*]], [[VECTOR_BODY]] ], [ [[UREM]], [[ENTRY:%.*]] ]
194; CHECK-NEXT:    store i64 0, ptr [[P:%.*]], align 8
195; CHECK-NEXT:    [[LSR_IV_NEXT]] = add i64 [[LSR_IV]], -2
196; CHECK-NEXT:    [[DONE:%.*]] = icmp eq i64 [[LSR_IV_NEXT]], 0
197; CHECK-NEXT:    br i1 [[DONE]], label [[EXIT:%.*]], label [[VECTOR_BODY]]
198; CHECK:       exit:
199; CHECK-NEXT:    ret void
200;
201entry:
202  %vscale = call i64 @llvm.vscale.i64()
203  %mul = mul nuw nsw i64 %vscale, 8
204  %urem = urem i64 %N, %mul
205  br label %vector.body
206
207vector.body:
208  %iv = phi i64 [ 0, %entry ], [ %iv.next, %vector.body ]
209  store i64 0, ptr %p
210  %iv.next = add i64 %iv, 2
211  %done = icmp eq i64 %iv.next, %urem
212  br i1 %done, label %exit, label %vector.body
213
214exit:
215  ret void
216}
217
218
219define void @icmp_zero_urem_vscale_mul64(i64 %N, ptr %p) {
220; CHECK-LABEL: @icmp_zero_urem_vscale_mul64(
221; CHECK-NEXT:  entry:
222; CHECK-NEXT:    [[VSCALE:%.*]] = call i64 @llvm.vscale.i64()
223; CHECK-NEXT:    [[MUL:%.*]] = mul nuw nsw i64 [[VSCALE]], 64
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, 64
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
252define void @icmp_zero_urem_vscale_shl3(i64 %N, ptr %p) {
253; CHECK-LABEL: @icmp_zero_urem_vscale_shl3(
254; CHECK-NEXT:  entry:
255; CHECK-NEXT:    [[VSCALE:%.*]] = call i64 @llvm.vscale.i64()
256; CHECK-NEXT:    [[SHL:%.*]] = shl i64 [[VSCALE]], 3
257; CHECK-NEXT:    [[UREM:%.*]] = urem i64 [[N:%.*]], [[SHL]]
258; CHECK-NEXT:    br label [[VECTOR_BODY:%.*]]
259; CHECK:       vector.body:
260; CHECK-NEXT:    [[LSR_IV:%.*]] = phi i64 [ [[LSR_IV_NEXT:%.*]], [[VECTOR_BODY]] ], [ [[UREM]], [[ENTRY:%.*]] ]
261; CHECK-NEXT:    store i64 0, ptr [[P:%.*]], align 8
262; CHECK-NEXT:    [[LSR_IV_NEXT]] = add i64 [[LSR_IV]], -2
263; CHECK-NEXT:    [[DONE:%.*]] = icmp eq i64 [[LSR_IV_NEXT]], 0
264; CHECK-NEXT:    br i1 [[DONE]], label [[EXIT:%.*]], label [[VECTOR_BODY]]
265; CHECK:       exit:
266; CHECK-NEXT:    ret void
267;
268entry:
269  %vscale = call i64 @llvm.vscale.i64()
270  %shl = shl i64 %vscale, 3
271  %urem = urem i64 %N, %shl
272  br label %vector.body
273
274vector.body:
275  %iv = phi i64 [ 0, %entry ], [ %iv.next, %vector.body ]
276  store i64 0, ptr %p
277  %iv.next = add i64 %iv, 2
278  %done = icmp eq i64 %iv.next, %urem
279  br i1 %done, label %exit, label %vector.body
280
281exit:
282  ret void
283}
284
285define void @icmp_zero_urem_vscale_shl6(i64 %N, ptr %p) {
286; CHECK-LABEL: @icmp_zero_urem_vscale_shl6(
287; CHECK-NEXT:  entry:
288; CHECK-NEXT:    [[VSCALE:%.*]] = call i64 @llvm.vscale.i64()
289; CHECK-NEXT:    [[SHL:%.*]] = shl i64 [[VSCALE]], 6
290; CHECK-NEXT:    [[UREM:%.*]] = urem i64 [[N:%.*]], [[SHL]]
291; CHECK-NEXT:    br label [[VECTOR_BODY:%.*]]
292; CHECK:       vector.body:
293; CHECK-NEXT:    [[LSR_IV:%.*]] = phi i64 [ [[LSR_IV_NEXT:%.*]], [[VECTOR_BODY]] ], [ [[UREM]], [[ENTRY:%.*]] ]
294; CHECK-NEXT:    store i64 0, ptr [[P:%.*]], align 8
295; CHECK-NEXT:    [[LSR_IV_NEXT]] = add i64 [[LSR_IV]], -2
296; CHECK-NEXT:    [[DONE:%.*]] = icmp eq i64 [[LSR_IV_NEXT]], 0
297; CHECK-NEXT:    br i1 [[DONE]], label [[EXIT:%.*]], label [[VECTOR_BODY]]
298; CHECK:       exit:
299; CHECK-NEXT:    ret void
300;
301entry:
302  %vscale = call i64 @llvm.vscale.i64()
303  %shl = shl i64 %vscale, 6
304  %urem = urem i64 %N, %shl
305  br label %vector.body
306
307vector.body:
308  %iv = phi i64 [ 0, %entry ], [ %iv.next, %vector.body ]
309  store i64 0, ptr %p
310  %iv.next = add i64 %iv, 2
311  %done = icmp eq i64 %iv.next, %urem
312  br i1 %done, label %exit, label %vector.body
313
314exit:
315  ret void
316}
317
318declare i64 @llvm.vscale.i64()
319