1; RUN: opt -mtriple=thumbv8.1m.main-none-none-eabi -hardware-loops %s -S -o - | \
2; RUN:     FileCheck %s
3; RUN: opt -mtriple=thumbv8.1m.main -loop-unroll -unroll-remainder=false -S < %s | \
4; RUN:     llc -mtriple=thumbv8.1m.main | FileCheck %s --check-prefix=CHECK-UNROLL
5; RUN: opt -mtriple=thumbv8.1m.main-none-none-eabi -hardware-loops \
6; RUN:     -pass-remarks-analysis=hardware-loops  %s -S -o - 2>&1 | \
7; RUN:     FileCheck %s --check-prefix=CHECK-REMARKS
8
9
10; CHECK-REMARKS: remark: <unknown>:0:0: hardware-loop not created: it's not profitable to create a hardware-loop
11; CHECK-REMARKS: remark: <unknown>:0:0: hardware-loop not created: nested hardware-loops not supported
12; CHECK-REMARKS: remark: <unknown>:0:0: hardware-loop not created: it's not profitable to create a hardware-loop
13; CHECK-REMARKS: remark: <unknown>:0:0: hardware-loop not created: it's not profitable to create a hardware-loop
14; CHECK-REMARKS: remark: <unknown>:0:0: hardware-loop not created: it's not profitable to create a hardware-loop
15; CHECK-REMARKS: remark: <unknown>:0:0: hardware-loop not created: it's not profitable to create a hardware-loop
16; CHECK-REMARKS: remark: <unknown>:0:0: hardware-loop not created: loop is not a candidate
17; CHECK-REMARKS: remark: <unknown>:0:0: hardware-loop not created: nested hardware-loops not supported
18; CHECK-REMARKS: remark: <unknown>:0:0: hardware-loop not created: it's not profitable to create a hardware-loop
19; CHECK-REMARKS: remark: <unknown>:0:0: hardware-loop not created: it's not profitable to create a hardware-loop
20
21
22; CHECK-LABEL: early_exit
23; CHECK-NOT: llvm.set.loop.iterations
24; CHECK-NOT: llvm.loop.decrement
25define i32 @early_exit(i32* nocapture readonly %a, i32 %max, i32 %n) {
26entry:
27  br label %do.body
28
29do.body:
30  %i.0 = phi i32 [ 0, %entry ], [ %inc, %if.end ]
31  %arrayidx = getelementptr inbounds i32, i32* %a, i32 %i.0
32  %0 = load i32, i32* %arrayidx, align 4
33  %cmp = icmp sgt i32 %0, %max
34  br i1 %cmp, label %do.end, label %if.end
35
36if.end:
37  %inc = add nuw i32 %i.0, 1
38  %cmp1 = icmp ult i32 %inc, %n
39  br i1 %cmp1, label %do.body, label %if.end.do.end_crit_edge
40
41if.end.do.end_crit_edge:
42  %arrayidx2.phi.trans.insert = getelementptr inbounds i32, i32* %a, i32 %inc
43  %.pre = load i32, i32* %arrayidx2.phi.trans.insert, align 4
44  br label %do.end
45
46do.end:
47  %1 = phi i32 [ %.pre, %if.end.do.end_crit_edge ], [ %0, %do.body ]
48  ret i32 %1
49}
50
51; CHECK-LABEL: nested
52; CHECK-NOT: call i32 @llvm.start.loop.iterations.i32(i32 %N)
53; CHECK: br i1 %cmp20, label %while.end7, label %while.cond1.preheader.us
54
55; CHECK: [[START:%[^ ]+]] = call i32 @llvm.start.loop.iterations.i32(i32 %N)
56; CHECK: br label %while.body3.us
57
58; CHECK: [[REM:%[^ ]+]] = phi i32 [ [[START]], %while.cond1.preheader.us ], [ [[LOOP_DEC:%[^ ]+]], %while.body3.us ]
59; CHECK: [[LOOP_DEC]] = call i32 @llvm.loop.decrement.reg.i32(i32 [[REM]], i32 1)
60; CHECK: [[CMP:%[^ ]+]] = icmp ne i32 [[LOOP_DEC]], 0
61; CHECK: br i1 [[CMP]], label %while.body3.us, label %while.cond1.while.end_crit_edge.us
62
63; CHECK-NOT: [[LOOP_DEC1:%[^ ]+]] = call i1 @llvm.loop.decrement.i32(i32 1)
64; CHECK-NOT: br i1 [[LOOP_DEC1]], label %while.cond1.preheader.us, label %while.end7
65
66define void @nested(i32* nocapture %A, i32 %N) {
67entry:
68  %cmp20 = icmp eq i32 %N, 0
69  br i1 %cmp20, label %while.end7, label %while.cond1.preheader.us
70
71while.cond1.preheader.us:
72  %i.021.us = phi i32 [ %inc6.us, %while.cond1.while.end_crit_edge.us ], [ 0, %entry ]
73  %mul.us = mul i32 %i.021.us, %N
74  br label %while.body3.us
75
76while.body3.us:
77  %j.019.us = phi i32 [ 0, %while.cond1.preheader.us ], [ %inc.us, %while.body3.us ]
78  %add.us = add i32 %j.019.us, %mul.us
79  %arrayidx.us = getelementptr inbounds i32, i32* %A, i32 %add.us
80  store i32 %add.us, i32* %arrayidx.us, align 4
81  %inc.us = add nuw i32 %j.019.us, 1
82  %exitcond = icmp eq i32 %inc.us, %N
83  br i1 %exitcond, label %while.cond1.while.end_crit_edge.us, label %while.body3.us
84
85while.cond1.while.end_crit_edge.us:
86  %inc6.us = add nuw i32 %i.021.us, 1
87  %exitcond23 = icmp eq i32 %inc6.us, %N
88  br i1 %exitcond23, label %while.end7, label %while.cond1.preheader.us
89
90while.end7:
91  ret void
92}
93
94; CHECK-LABEL: pre_existing
95; CHECK: llvm.start.loop.iterations
96; CHECK-NOT: llvm.start.loop.iterations
97; CHECK: call i32 @llvm.loop.decrement.reg.i32(i32 %0, i32 1)
98; CHECK-NOT: call i32 @llvm.loop.decrement.reg
99define i32 @pre_existing(i32 %n, i32* nocapture %p, i32* nocapture readonly %q) {
100entry:
101  %start = call i32 @llvm.start.loop.iterations.i32(i32 %n)
102  br label %while.body
103
104while.body:                                       ; preds = %while.body, %entry
105  %q.addr.05 = phi i32* [ %incdec.ptr, %while.body ], [ %q, %entry ]
106  %p.addr.04 = phi i32* [ %incdec.ptr1, %while.body ], [ %p, %entry ]
107  %0 = phi i32 [ %start, %entry ], [ %2, %while.body ]
108  %incdec.ptr = getelementptr inbounds i32, i32* %q.addr.05, i32 1
109  %1 = load i32, i32* %q.addr.05, align 4
110  %incdec.ptr1 = getelementptr inbounds i32, i32* %p.addr.04, i32 1
111  store i32 %1, i32* %p.addr.04, align 4
112  %2 = call i32 @llvm.loop.decrement.reg.i32(i32 %0, i32 1)
113  %3 = icmp ne i32 %2, 0
114  br i1 %3, label %while.body, label %while.end
115
116while.end:                                        ; preds = %while.body
117  ret i32 0
118}
119
120; CHECK-LABEL: pre_existing_test_set
121; CHECK: call { i32, i1 } @llvm.test.start.loop.iterations
122; CHECK-NOT: llvm.set{{.*}}.loop.iterations
123; CHECK: call i32 @llvm.loop.decrement.reg.i32(i32 %0, i32 1)
124; CHECK-NOT: call i32 @llvm.loop.decrement.reg
125define i32 @pre_existing_test_set(i32 %n, i32* nocapture %p, i32* nocapture readonly %q) {
126entry:
127  %guard = call { i32, i1 } @llvm.test.start.loop.iterations.i32(i32 %n)
128  %g0 = extractvalue { i32, i1 } %guard, 0
129  %g1 = extractvalue { i32, i1 } %guard, 1
130  br i1 %g1, label %while.preheader, label %while.end
131
132while.preheader:
133  br label %while.body
134
135while.body:                                       ; preds = %while.body, %entry
136  %q.addr.05 = phi i32* [ %incdec.ptr, %while.body ], [ %q, %while.preheader ]
137  %p.addr.04 = phi i32* [ %incdec.ptr1, %while.body ], [ %p, %while.preheader ]
138  %0 = phi i32 [ %g0, %while.preheader ], [ %2, %while.body ]
139  %incdec.ptr = getelementptr inbounds i32, i32* %q.addr.05, i32 1
140  %1 = load i32, i32* %q.addr.05, align 4
141  %incdec.ptr1 = getelementptr inbounds i32, i32* %p.addr.04, i32 1
142  store i32 %1, i32* %p.addr.04, align 4
143  %2 = call i32 @llvm.loop.decrement.reg.i32(i32 %0, i32 1)
144  %3 = icmp ne i32 %2, 0
145  br i1 %3, label %while.body, label %while.end
146
147while.end:                                        ; preds = %while.body
148  ret i32 0
149}
150
151; CHECK-LABEL: pre_existing_inner
152; CHECK-NOT: llvm.start.loop.iterations
153; CHECK: while.cond1.preheader.us:
154; CHECK: call i32 @llvm.start.loop.iterations.i32(i32 %N)
155; CHECK: call i32 @llvm.loop.decrement.reg.i32(i32 %0, i32 1)
156; CHECK: br i1
157; CHECK-NOT: call i32 @llvm.loop.decrement
158define void @pre_existing_inner(i32* nocapture %A, i32 %N) {
159entry:
160  %cmp20 = icmp eq i32 %N, 0
161  br i1 %cmp20, label %while.end7, label %while.cond1.preheader.us
162
163while.cond1.preheader.us:
164  %i.021.us = phi i32 [ %inc6.us, %while.cond1.while.end_crit_edge.us ], [ 0, %entry ]
165  %mul.us = mul i32 %i.021.us, %N
166  %start = call i32 @llvm.start.loop.iterations.i32(i32 %N)
167  br label %while.body3.us
168
169while.body3.us:
170  %j.019.us = phi i32 [ 0, %while.cond1.preheader.us ], [ %inc.us, %while.body3.us ]
171  %0 = phi i32 [ %start, %while.cond1.preheader.us ], [ %1, %while.body3.us ]
172  %add.us = add i32 %j.019.us, %mul.us
173  %arrayidx.us = getelementptr inbounds i32, i32* %A, i32 %add.us
174  store i32 %add.us, i32* %arrayidx.us, align 4
175  %inc.us = add nuw i32 %j.019.us, 1
176  %1 = call i32 @llvm.loop.decrement.reg.i32(i32 %0, i32 1)
177  %2 = icmp ne i32 %1, 0
178  br i1 %2, label %while.body3.us, label %while.cond1.while.end_crit_edge.us
179
180while.cond1.while.end_crit_edge.us:
181  %inc6.us = add nuw i32 %i.021.us, 1
182  %exitcond23 = icmp eq i32 %inc6.us, %N
183  br i1 %exitcond23, label %while.end7, label %while.cond1.preheader.us
184
185while.end7:
186  ret void
187}
188
189; CHECK-LABEL: not_rotated
190; CHECK-NOT: call i32 @llvm.start.loop.iterations
191; CHECK-NOT: call i32 @llvm.loop.decrement.i32
192define void @not_rotated(i32, i16* nocapture, i16 signext) {
193  br label %4
194
1954:
196  %5 = phi i32 [ 0, %3 ], [ %19, %18 ]
197  %6 = icmp eq i32 %5, %0
198  br i1 %6, label %20, label %7
199
2007:
201  %8 = mul i32 %5, %0
202  br label %9
203
2049:
205  %10 = phi i32 [ %17, %12 ], [ 0, %7 ]
206  %11 = icmp eq i32 %10, %0
207  br i1 %11, label %18, label %12
208
20912:
210  %13 = add i32 %10, %8
211  %14 = getelementptr inbounds i16, i16* %1, i32 %13
212  %15 = load i16, i16* %14, align 2
213  %16 = add i16 %15, %2
214  store i16 %16, i16* %14, align 2
215  %17 = add i32 %10, 1
216  br label %9
217
21818:
219  %19 = add i32 %5, 1
220  br label %4
221
22220:
223  ret void
224}
225
226; CHECK-LABEL: multi_latch
227; CHECK-NOT: call i32 @llvm.start.loop.iterations
228; CHECK-NOT: call i32 @llvm.loop.decrement
229define void @multi_latch(i32* %a, i32* %b, i32 %N) {
230entry:
231  %half = lshr i32 %N, 1
232  br label %header
233
234header:
235  %iv = phi i32 [ 0, %entry ], [ %count.next, %latch.0 ], [ %count.next, %latch.1 ]
236  %cmp = icmp ult i32 %iv, %half
237  %addr.a = getelementptr i32, i32* %a, i32 %iv
238  %addr.b = getelementptr i32, i32* %b, i32 %iv
239  br i1 %cmp, label %if.then, label %if.else
240
241if.then:
242  store i32 %iv, i32* %addr.a
243  br label %latch.0
244
245if.else:
246  store i32 %iv, i32* %addr.b
247  br label %latch.0
248
249latch.0:
250  %count.next = add nuw i32 %iv, 1
251  %cmp.1 = icmp ult i32 %count.next, %half
252  br i1 %cmp.1, label %header, label %latch.1
253
254latch.1:
255  %ld = load i32, i32* %addr.a
256  store i32 %ld, i32* %addr.b
257  %cmp.2 = icmp ult i32 %count.next, %N
258  br i1 %cmp.2, label %header, label %latch.1
259
260exit:
261  ret void
262}
263
264; CHECK-LABEL: search
265; CHECK: entry:
266; CHECK:   [[TEST1:%[^ ]+]] = call { i32, i1 } @llvm.test.start.loop.iterations.i32(i32 %N)
267; CHECK:   [[TEST:%[^ ]+]] = extractvalue { i32, i1 } [[TEST1]], 1
268; CHECK:   br i1 [[TEST]], label %for.body.preheader, label %for.cond.cleanup
269; CHECK: for.body.preheader:
270; CHECK:   br label %for.body
271; CHECK: for.body:
272; CHECK: for.inc:
273; CHECK:   [[LOOP_DEC:%[^ ]+]] = call i32 @llvm.loop.decrement.reg.i32(
274; CHECK:   [[CMP:%[^ ]+]] = icmp ne i32 [[LOOP_DEC]], 0
275; CHECK:   br i1 [[CMP]], label %for.body, label %for.cond.cleanup
276define i32 @search(i8* nocapture readonly %c, i32 %N) {
277entry:
278  %cmp11 = icmp eq i32 %N, 0
279  br i1 %cmp11, label %for.cond.cleanup, label %for.body
280
281for.cond.cleanup:
282  %found.0.lcssa = phi i32 [ 0, %entry ], [ %found.1, %for.inc ]
283  %spaces.0.lcssa = phi i32 [ 0, %entry ], [ %spaces.1, %for.inc ]
284  %sub = sub nsw i32 %found.0.lcssa, %spaces.0.lcssa
285  ret i32 %sub
286
287for.body:
288  %i.014 = phi i32 [ %inc3, %for.inc ], [ 0, %entry ]
289  %spaces.013 = phi i32 [ %spaces.1, %for.inc ], [ 0, %entry ]
290  %found.012 = phi i32 [ %found.1, %for.inc ], [ 0, %entry ]
291  %arrayidx = getelementptr inbounds i8, i8* %c, i32 %i.014
292  %0 = load i8, i8* %arrayidx, align 1
293  switch i8 %0, label %for.inc [
294    i8 108, label %sw.bb
295    i8 111, label %sw.bb
296    i8 112, label %sw.bb
297    i8 32, label %sw.bb1
298  ]
299
300sw.bb:                                            ; preds = %for.body, %for.body, %for.body
301  %inc = add nsw i32 %found.012, 1
302  br label %for.inc
303
304sw.bb1:                                           ; preds = %for.body
305  %inc2 = add nsw i32 %spaces.013, 1
306  br label %for.inc
307
308for.inc:                                          ; preds = %sw.bb, %sw.bb1, %for.body
309  %found.1 = phi i32 [ %found.012, %for.body ], [ %found.012, %sw.bb1 ], [ %inc, %sw.bb ]
310  %spaces.1 = phi i32 [ %spaces.013, %for.body ], [ %inc2, %sw.bb1 ], [ %spaces.013, %sw.bb ]
311  %inc3 = add nuw i32 %i.014, 1
312  %exitcond = icmp eq i32 %inc3, %N
313  br i1 %exitcond, label %for.cond.cleanup, label %for.body
314}
315
316; CHECK-LABEL: unroll_inc_int
317; CHECK: call i32 @llvm.start.loop.iterations.i32(i32 %N)
318; CHECK: call i32 @llvm.loop.decrement.reg.i32(
319
320; TODO: We should be able to support the unrolled loop body.
321; CHECK-UNROLL-LABEL: unroll_inc_int
322; CHECK-UNROLL:     [[PREHEADER:.LBB[0-9_]+]]: @ %for.body.preheader
323; CHECK-UNROLL-NOT: dls
324; CHECK-UNROLL:     [[LOOP:.LBB[0-9_]+]]: @ %for.body
325; CHECK-UNROLL-NOT: le lr, [[LOOP]]
326; CHECK-UNROLL:     bne [[LOOP]]
327; CHECK-UNROLL:     wls lr, r12, [[EXIT:.LBB[0-9_]+]]
328; CHECK-UNROLL:     [[EPIL:.LBB[0-9_]+]]:
329; CHECK-UNROLL:     le lr, [[EPIL]]
330; CHECK-UNROLL-NEXT: [[EXIT]]
331
332define void @unroll_inc_int(i32* nocapture %a, i32* nocapture readonly %b, i32* nocapture readonly %c, i32 %N) {
333entry:
334  %cmp8 = icmp sgt i32 %N, 0
335  br i1 %cmp8, label %for.body, label %for.cond.cleanup
336
337for.cond.cleanup:
338  ret void
339
340for.body:
341  %i.09 = phi i32 [ %inc, %for.body ], [ 0, %entry ]
342  %arrayidx = getelementptr inbounds i32, i32* %b, i32 %i.09
343  %0 = load i32, i32* %arrayidx, align 4
344  %arrayidx1 = getelementptr inbounds i32, i32* %c, i32 %i.09
345  %1 = load i32, i32* %arrayidx1, align 4
346  %mul = mul nsw i32 %1, %0
347  %arrayidx2 = getelementptr inbounds i32, i32* %a, i32 %i.09
348  store i32 %mul, i32* %arrayidx2, align 4
349  %inc = add nuw nsw i32 %i.09, 1
350  %exitcond = icmp eq i32 %inc, %N
351  br i1 %exitcond, label %for.cond.cleanup, label %for.body
352}
353
354; CHECK-LABEL: unroll_inc_unsigned
355; CHECK: call { i32, i1 } @llvm.test.start.loop.iterations.i32(i32 %N)
356; CHECK: call i32 @llvm.loop.decrement.reg.i32(
357
358; TODO: We should be able to support the unrolled loop body.
359; CHECK-UNROLL-LABEL: unroll_inc_unsigned
360; CHECK-UNROLL:     [[PREHEADER:.LBB[0-9_]+]]: @ %for.body.preheader
361; CHECK-UNROLL-NOT: dls
362; CHECK-UNROLL:     [[LOOP:.LBB[0-9_]+]]: @ %for.body
363; CHECK-UNROLL-NOT: le lr, [[LOOP]]
364; CHECK-UNROLL:     bne [[LOOP]]
365; CHECK-UNROLL:     wls lr, r12, [[EPIL_EXIT:.LBB[0-9_]+]]
366; CHECK-UNROLL: [[EPIL:.LBB[0-9_]+]]:
367; CHECK-UNROLL:     le lr, [[EPIL]]
368; CHECK-UNROLL: [[EPIL_EXIT]]:
369; CHECK-UNROLL:     pop
370define void @unroll_inc_unsigned(i32* nocapture %a, i32* nocapture readonly %b, i32* nocapture readonly %c, i32 %N) {
371entry:
372  %cmp8 = icmp eq i32 %N, 0
373  br i1 %cmp8, label %for.cond.cleanup, label %for.body
374
375for.cond.cleanup:
376  ret void
377
378for.body:
379  %i.09 = phi i32 [ %inc, %for.body ], [ 0, %entry ]
380  %arrayidx = getelementptr inbounds i32, i32* %b, i32 %i.09
381  %0 = load i32, i32* %arrayidx, align 4
382  %arrayidx1 = getelementptr inbounds i32, i32* %c, i32 %i.09
383  %1 = load i32, i32* %arrayidx1, align 4
384  %mul = mul nsw i32 %1, %0
385  %arrayidx2 = getelementptr inbounds i32, i32* %a, i32 %i.09
386  store i32 %mul, i32* %arrayidx2, align 4
387  %inc = add nuw i32 %i.09, 1
388  %exitcond = icmp eq i32 %inc, %N
389  br i1 %exitcond, label %for.cond.cleanup, label %for.body
390}
391
392; CHECK-LABEL: unroll_dec_int
393; CHECK: call i32 @llvm.start.loop.iterations.i32(i32 %N)
394; CHECK: call i32 @llvm.loop.decrement.reg.i32(
395
396; CHECK-UNROLL-LABEL: unroll_dec_int:
397; CHECK-UNROLL:         wls lr, {{.*}}, [[PROLOGUE_EXIT:.LBB[0-9_]+]]
398; CHECK-UNROLL-NEXT: [[PROLOGUE:.LBB[0-9_]+]]:
399; CHECK-UNROLL:         le lr, [[PROLOGUE]]
400; CHECK-UNROLL-NEXT: [[PROLOGUE_EXIT:.LBB[0-9_]+]]:
401; CHECK-UNROLL:      [[BODY:.LBB[0-9_]+]]:
402; CHECK-UNROLL:         le lr, [[BODY]]
403; CHECK-UNROLL-NOT:     b
404; CHECK-UNROLL:         pop
405define void @unroll_dec_int(i32* nocapture %a, i32* nocapture readonly %b, i32* nocapture readonly %c, i32 %N) {
406entry:
407  %cmp8 = icmp sgt i32 %N, 0
408  br i1 %cmp8, label %for.body, label %for.cond.cleanup
409
410for.cond.cleanup:
411  ret void
412
413for.body:
414  %i.09 = phi i32 [ %dec, %for.body ], [ %N, %entry ]
415  %arrayidx = getelementptr inbounds i32, i32* %b, i32 %i.09
416  %0 = load i32, i32* %arrayidx, align 4
417  %arrayidx1 = getelementptr inbounds i32, i32* %c, i32 %i.09
418  %1 = load i32, i32* %arrayidx1, align 4
419  %mul = mul nsw i32 %1, %0
420  %arrayidx2 = getelementptr inbounds i32, i32* %a, i32 %i.09
421  store i32 %mul, i32* %arrayidx2, align 4
422  %dec = add nsw i32 %i.09, -1
423  %cmp = icmp sgt i32 %dec, 0
424  br i1 %cmp, label %for.body, label %for.cond.cleanup
425}
426
427declare i32 @llvm.start.loop.iterations.i32(i32) #0
428declare { i32, i1 } @llvm.test.start.loop.iterations.i32(i32) #0
429declare i32 @llvm.loop.decrement.reg.i32(i32, i32) #0
430
431