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
64; FIXME: We could handle this case even though we don't know %M.  The
65; faulting instruction is already outside the loop!
66define void @icmp_zero_urem_invariant(i64 %N, i64 %M, ptr %p) {
67; CHECK-LABEL: @icmp_zero_urem_invariant(
68; CHECK-NEXT:  entry:
69; CHECK-NEXT:    [[UREM:%.*]] = urem i64 [[N:%.*]], [[M:%.*]]
70; CHECK-NEXT:    br label [[VECTOR_BODY:%.*]]
71; CHECK:       vector.body:
72; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[VECTOR_BODY]] ]
73; CHECK-NEXT:    store i64 0, ptr [[P:%.*]], align 8
74; CHECK-NEXT:    [[IV_NEXT]] = add i64 [[IV]], 2
75; CHECK-NEXT:    [[DONE:%.*]] = icmp eq i64 [[IV_NEXT]], [[UREM]]
76; CHECK-NEXT:    br i1 [[DONE]], label [[EXIT:%.*]], label [[VECTOR_BODY]]
77; CHECK:       exit:
78; CHECK-NEXT:    ret void
79;
80entry:
81  %urem = urem i64 %N, %M
82  br label %vector.body
83
84vector.body:
85  %iv = phi i64 [ 0, %entry ], [ %iv.next, %vector.body ]
86  store i64 0, ptr %p
87  %iv.next = add i64 %iv, 2
88  %done = icmp eq i64 %iv.next, %urem
89  br i1 %done, label %exit, label %vector.body
90
91exit:
92  ret void
93}
94
95; Negative test - We can not hoist because we don't know value of %M.
96define void @icmp_zero_urem_nohoist(i64 %N, i64 %M, ptr %p) {
97; CHECK-LABEL: @icmp_zero_urem_nohoist(
98; CHECK-NEXT:  entry:
99; CHECK-NEXT:    br label [[VECTOR_BODY:%.*]]
100; CHECK:       vector.body:
101; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[VECTOR_BODY]] ]
102; CHECK-NEXT:    store i64 0, ptr [[P:%.*]], align 8
103; CHECK-NEXT:    [[IV_NEXT]] = add i64 [[IV]], 2
104; CHECK-NEXT:    [[UREM:%.*]] = urem i64 [[N:%.*]], [[M:%.*]]
105; CHECK-NEXT:    [[DONE:%.*]] = icmp eq i64 [[IV_NEXT]], [[UREM]]
106; CHECK-NEXT:    br i1 [[DONE]], label [[EXIT:%.*]], label [[VECTOR_BODY]]
107; CHECK:       exit:
108; CHECK-NEXT:    ret void
109;
110entry:
111  br label %vector.body
112
113vector.body:
114  %iv = phi i64 [ 0, %entry ], [ %iv.next, %vector.body ]
115  store i64 0, ptr %p
116  %iv.next = add i64 %iv, 2
117  %urem = urem i64 %N, %M
118  %done = icmp eq i64 %iv.next, %urem
119  br i1 %done, label %exit, label %vector.body
120
121exit:
122  ret void
123}
124
125define void @icmp_zero_urem_nonzero(i64 %N, i64 %M, ptr %p) {
126; CHECK-LABEL: @icmp_zero_urem_nonzero(
127; CHECK-NEXT:  entry:
128; CHECK-NEXT:    [[NONZERO:%.*]] = add nuw i64 [[M:%.*]], 1
129; CHECK-NEXT:    [[UREM:%.*]] = urem i64 [[N:%.*]], [[NONZERO]]
130; CHECK-NEXT:    br label [[VECTOR_BODY:%.*]]
131; CHECK:       vector.body:
132; CHECK-NEXT:    [[LSR_IV:%.*]] = phi i64 [ [[LSR_IV_NEXT:%.*]], [[VECTOR_BODY]] ], [ [[UREM]], [[ENTRY:%.*]] ]
133; CHECK-NEXT:    store i64 0, ptr [[P:%.*]], align 8
134; CHECK-NEXT:    [[LSR_IV_NEXT]] = add i64 [[LSR_IV]], -2
135; CHECK-NEXT:    [[DONE:%.*]] = icmp eq i64 [[LSR_IV_NEXT]], 0
136; CHECK-NEXT:    br i1 [[DONE]], label [[EXIT:%.*]], label [[VECTOR_BODY]]
137; CHECK:       exit:
138; CHECK-NEXT:    ret void
139;
140entry:
141  %nonzero = add nuw i64 %M, 1
142  %urem = urem i64 %N, %nonzero
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  %done = icmp eq i64 %iv.next, %urem
150  br i1 %done, label %exit, label %vector.body
151
152exit:
153  ret void
154}
155
156define void @icmp_zero_urem_vscale(i64 %N, ptr %p) {
157; CHECK-LABEL: @icmp_zero_urem_vscale(
158; CHECK-NEXT:  entry:
159; CHECK-NEXT:    [[VSCALE:%.*]] = call i64 @llvm.vscale.i64()
160; CHECK-NEXT:    [[UREM:%.*]] = urem i64 [[N:%.*]], [[VSCALE]]
161; CHECK-NEXT:    br label [[VECTOR_BODY:%.*]]
162; CHECK:       vector.body:
163; CHECK-NEXT:    [[LSR_IV:%.*]] = phi i64 [ [[LSR_IV_NEXT:%.*]], [[VECTOR_BODY]] ], [ [[UREM]], [[ENTRY:%.*]] ]
164; CHECK-NEXT:    store i64 0, ptr [[P:%.*]], align 8
165; CHECK-NEXT:    [[LSR_IV_NEXT]] = add i64 [[LSR_IV]], -2
166; CHECK-NEXT:    [[DONE:%.*]] = icmp eq i64 [[LSR_IV_NEXT]], 0
167; CHECK-NEXT:    br i1 [[DONE]], label [[EXIT:%.*]], label [[VECTOR_BODY]]
168; CHECK:       exit:
169; CHECK-NEXT:    ret void
170;
171entry:
172  %vscale = call i64 @llvm.vscale.i64()
173  %urem = urem i64 %N, %vscale
174  br label %vector.body
175
176vector.body:
177  %iv = phi i64 [ 0, %entry ], [ %iv.next, %vector.body ]
178  store i64 0, ptr %p
179  %iv.next = add i64 %iv, 2
180  %done = icmp eq i64 %iv.next, %urem
181  br i1 %done, label %exit, label %vector.body
182
183exit:
184  ret void
185}
186
187define void @icmp_zero_urem_vscale_mul8(i64 %N, ptr %p) {
188; CHECK-LABEL: @icmp_zero_urem_vscale_mul8(
189; CHECK-NEXT:  entry:
190; CHECK-NEXT:    [[VSCALE:%.*]] = call i64 @llvm.vscale.i64()
191; CHECK-NEXT:    [[MUL:%.*]] = mul nuw nsw i64 [[VSCALE]], 8
192; CHECK-NEXT:    [[UREM:%.*]] = urem i64 [[N:%.*]], [[MUL]]
193; CHECK-NEXT:    br label [[VECTOR_BODY:%.*]]
194; CHECK:       vector.body:
195; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[VECTOR_BODY]] ]
196; CHECK-NEXT:    store i64 0, ptr [[P:%.*]], align 8
197; CHECK-NEXT:    [[IV_NEXT]] = add i64 [[IV]], 2
198; CHECK-NEXT:    [[DONE:%.*]] = icmp eq i64 [[IV_NEXT]], [[UREM]]
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  %mul = mul nuw nsw i64 %vscale, 8
206  %urem = urem i64 %N, %mul
207  br label %vector.body
208
209vector.body:
210  %iv = phi i64 [ 0, %entry ], [ %iv.next, %vector.body ]
211  store i64 0, ptr %p
212  %iv.next = add i64 %iv, 2
213  %done = icmp eq i64 %iv.next, %urem
214  br i1 %done, label %exit, label %vector.body
215
216exit:
217  ret void
218}
219
220
221define void @icmp_zero_urem_vscale_mul64(i64 %N, ptr %p) {
222; CHECK-LABEL: @icmp_zero_urem_vscale_mul64(
223; CHECK-NEXT:  entry:
224; CHECK-NEXT:    [[VSCALE:%.*]] = call i64 @llvm.vscale.i64()
225; CHECK-NEXT:    [[MUL:%.*]] = mul nuw nsw i64 [[VSCALE]], 64
226; CHECK-NEXT:    [[UREM:%.*]] = urem i64 [[N:%.*]], [[MUL]]
227; CHECK-NEXT:    br label [[VECTOR_BODY:%.*]]
228; CHECK:       vector.body:
229; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[VECTOR_BODY]] ]
230; CHECK-NEXT:    store i64 0, ptr [[P:%.*]], align 8
231; CHECK-NEXT:    [[IV_NEXT]] = add i64 [[IV]], 2
232; CHECK-NEXT:    [[DONE:%.*]] = icmp eq i64 [[IV_NEXT]], [[UREM]]
233; CHECK-NEXT:    br i1 [[DONE]], label [[EXIT:%.*]], label [[VECTOR_BODY]]
234; CHECK:       exit:
235; CHECK-NEXT:    ret void
236;
237entry:
238  %vscale = call i64 @llvm.vscale.i64()
239  %mul = mul nuw nsw i64 %vscale, 64
240  %urem = urem i64 %N, %mul
241  br label %vector.body
242
243vector.body:
244  %iv = phi i64 [ 0, %entry ], [ %iv.next, %vector.body ]
245  store i64 0, ptr %p
246  %iv.next = add i64 %iv, 2
247  %done = icmp eq i64 %iv.next, %urem
248  br i1 %done, label %exit, label %vector.body
249
250exit:
251  ret void
252}
253
254define void @icmp_zero_urem_vscale_shl3(i64 %N, ptr %p) {
255; CHECK-LABEL: @icmp_zero_urem_vscale_shl3(
256; CHECK-NEXT:  entry:
257; CHECK-NEXT:    [[VSCALE:%.*]] = call i64 @llvm.vscale.i64()
258; CHECK-NEXT:    [[SHL:%.*]] = shl i64 [[VSCALE]], 3
259; CHECK-NEXT:    [[UREM:%.*]] = urem i64 [[N:%.*]], [[SHL]]
260; CHECK-NEXT:    br label [[VECTOR_BODY:%.*]]
261; CHECK:       vector.body:
262; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[VECTOR_BODY]] ]
263; CHECK-NEXT:    store i64 0, ptr [[P:%.*]], align 8
264; CHECK-NEXT:    [[IV_NEXT]] = add i64 [[IV]], 2
265; CHECK-NEXT:    [[DONE:%.*]] = icmp eq i64 [[IV_NEXT]], [[UREM]]
266; CHECK-NEXT:    br i1 [[DONE]], label [[EXIT:%.*]], label [[VECTOR_BODY]]
267; CHECK:       exit:
268; CHECK-NEXT:    ret void
269;
270entry:
271  %vscale = call i64 @llvm.vscale.i64()
272  %shl = shl i64 %vscale, 3
273  %urem = urem i64 %N, %shl
274  br label %vector.body
275
276vector.body:
277  %iv = phi i64 [ 0, %entry ], [ %iv.next, %vector.body ]
278  store i64 0, ptr %p
279  %iv.next = add i64 %iv, 2
280  %done = icmp eq i64 %iv.next, %urem
281  br i1 %done, label %exit, label %vector.body
282
283exit:
284  ret void
285}
286
287define void @icmp_zero_urem_vscale_shl6(i64 %N, ptr %p) {
288; CHECK-LABEL: @icmp_zero_urem_vscale_shl6(
289; CHECK-NEXT:  entry:
290; CHECK-NEXT:    [[VSCALE:%.*]] = call i64 @llvm.vscale.i64()
291; CHECK-NEXT:    [[SHL:%.*]] = shl i64 [[VSCALE]], 6
292; CHECK-NEXT:    [[UREM:%.*]] = urem i64 [[N:%.*]], [[SHL]]
293; CHECK-NEXT:    br label [[VECTOR_BODY:%.*]]
294; CHECK:       vector.body:
295; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[VECTOR_BODY]] ]
296; CHECK-NEXT:    store i64 0, ptr [[P:%.*]], align 8
297; CHECK-NEXT:    [[IV_NEXT]] = add i64 [[IV]], 2
298; CHECK-NEXT:    [[DONE:%.*]] = icmp eq i64 [[IV_NEXT]], [[UREM]]
299; CHECK-NEXT:    br i1 [[DONE]], label [[EXIT:%.*]], label [[VECTOR_BODY]]
300; CHECK:       exit:
301; CHECK-NEXT:    ret void
302;
303entry:
304  %vscale = call i64 @llvm.vscale.i64()
305  %shl = shl i64 %vscale, 6
306  %urem = urem i64 %N, %shl
307  br label %vector.body
308
309vector.body:
310  %iv = phi i64 [ 0, %entry ], [ %iv.next, %vector.body ]
311  store i64 0, ptr %p
312  %iv.next = add i64 %iv, 2
313  %done = icmp eq i64 %iv.next, %urem
314  br i1 %done, label %exit, label %vector.body
315
316exit:
317  ret void
318}
319
320declare i64 @llvm.vscale.i64()
321