[InstCombine] Signed saturation patterns
[llvm-core.git] / test / Transforms / HardwareLoops / ARM / structure.ll
blobd413e2b300618a8668cabeade5efce6b3dbc735d
1 ; RUN: opt -mtriple=thumbv8.1m.main-arm-none-eabi -hardware-loops %s -S -o - | FileCheck %s
2 ; RUN: llc -mtriple=thumbv8.1m.main-arm-none-eabi %s -o - | FileCheck %s --check-prefix=CHECK-LLC
3 ; RUN: opt -mtriple=thumbv8.1m.main -loop-unroll -unroll-remainder=false -S < %s | llc -mtriple=thumbv8.1m.main | FileCheck %s --check-prefix=CHECK-UNROLL
5 ; CHECK-LABEL: early_exit
6 ; CHECK-NOT: llvm.set.loop.iterations
7 ; CHECK-NOT: llvm.loop.decrement
8 define i32 @early_exit(i32* nocapture readonly %a, i32 %max, i32 %n) {
9 entry:
10   br label %do.body
12 do.body:
13   %i.0 = phi i32 [ 0, %entry ], [ %inc, %if.end ]
14   %arrayidx = getelementptr inbounds i32, i32* %a, i32 %i.0
15   %0 = load i32, i32* %arrayidx, align 4
16   %cmp = icmp sgt i32 %0, %max
17   br i1 %cmp, label %do.end, label %if.end
19 if.end:
20   %inc = add nuw i32 %i.0, 1
21   %cmp1 = icmp ult i32 %inc, %n
22   br i1 %cmp1, label %do.body, label %if.end.do.end_crit_edge
24 if.end.do.end_crit_edge:
25   %arrayidx2.phi.trans.insert = getelementptr inbounds i32, i32* %a, i32 %inc
26   %.pre = load i32, i32* %arrayidx2.phi.trans.insert, align 4
27   br label %do.end
29 do.end:
30   %1 = phi i32 [ %.pre, %if.end.do.end_crit_edge ], [ %0, %do.body ]
31   ret i32 %1
34 ; CHECK-LABEL: nested
35 ; CHECK-NOT: call void @llvm.set.loop.iterations.i32(i32 %N)
36 ; CHECK: br i1 %cmp20, label %while.end7, label %while.cond1.preheader.us
38 ; CHECK: call void @llvm.set.loop.iterations.i32(i32 %N)
39 ; CHECK: br label %while.body3.us
41 ; CHECK: [[REM:%[^ ]+]] = phi i32 [ %N, %while.cond1.preheader.us ], [ [[LOOP_DEC:%[^ ]+]], %while.body3.us ]
42 ; CHECK: [[LOOP_DEC]] = call i32 @llvm.loop.decrement.reg.i32.i32.i32(i32 [[REM]], i32 1)
43 ; CHECK: [[CMP:%[^ ]+]] = icmp ne i32 [[LOOP_DEC]], 0
44 ; CHECK: br i1 [[CMP]], label %while.body3.us, label %while.cond1.while.end_crit_edge.us
46 ; CHECK-NOT: [[LOOP_DEC1:%[^ ]+]] = call i1 @llvm.loop.decrement.i32(i32 1)
47 ; CHECK-NOT: br i1 [[LOOP_DEC1]], label %while.cond1.preheader.us, label %while.end7
49 ; CHECK-LLC:      nested:
50 ; CHECK-LLC-NOT:    mov lr, r1
51 ; CHECK-LLC:        dls lr, r1
52 ; CHECK-LLC-NOT:    mov lr, r1
53 ; CHECK-LLC:      [[LOOP_HEADER:\.LBB[0-9._]+]]:
54 ; CHECK-LLC:        le lr, [[LOOP_HEADER]]
55 ; CHECK-LLC-NOT:    b [[LOOP_EXIT:\.LBB[0-9._]+]]
56 ; CHECK-LLC:      [[LOOP_EXIT:\.LBB[0-9._]+]]:
58 define void @nested(i32* nocapture %A, i32 %N) {
59 entry:
60   %cmp20 = icmp eq i32 %N, 0
61   br i1 %cmp20, label %while.end7, label %while.cond1.preheader.us
63 while.cond1.preheader.us:
64   %i.021.us = phi i32 [ %inc6.us, %while.cond1.while.end_crit_edge.us ], [ 0, %entry ]
65   %mul.us = mul i32 %i.021.us, %N
66   br label %while.body3.us
68 while.body3.us:
69   %j.019.us = phi i32 [ 0, %while.cond1.preheader.us ], [ %inc.us, %while.body3.us ]
70   %add.us = add i32 %j.019.us, %mul.us
71   %arrayidx.us = getelementptr inbounds i32, i32* %A, i32 %add.us
72   store i32 %add.us, i32* %arrayidx.us, align 4
73   %inc.us = add nuw i32 %j.019.us, 1
74   %exitcond = icmp eq i32 %inc.us, %N
75   br i1 %exitcond, label %while.cond1.while.end_crit_edge.us, label %while.body3.us
77 while.cond1.while.end_crit_edge.us:
78   %inc6.us = add nuw i32 %i.021.us, 1
79   %exitcond23 = icmp eq i32 %inc6.us, %N
80   br i1 %exitcond23, label %while.end7, label %while.cond1.preheader.us
82 while.end7:
83   ret void
86 ; CHECK-LABEL: pre_existing
87 ; CHECK: llvm.set.loop.iterations
88 ; CHECK-NOT: llvm.set.loop.iterations
89 ; CHECK: call i32 @llvm.loop.decrement.reg.i32.i32.i32(i32 %0, i32 1)
90 ; CHECK-NOT: call i32 @llvm.loop.decrement.reg
91 define i32 @pre_existing(i32 %n, i32* nocapture %p, i32* nocapture readonly %q) {
92 entry:
93   call void @llvm.set.loop.iterations.i32(i32 %n)
94   br label %while.body
96 while.body:                                       ; preds = %while.body, %entry
97   %q.addr.05 = phi i32* [ %incdec.ptr, %while.body ], [ %q, %entry ]
98   %p.addr.04 = phi i32* [ %incdec.ptr1, %while.body ], [ %p, %entry ]
99   %0 = phi i32 [ %n, %entry ], [ %2, %while.body ]
100   %incdec.ptr = getelementptr inbounds i32, i32* %q.addr.05, i32 1
101   %1 = load i32, i32* %q.addr.05, align 4
102   %incdec.ptr1 = getelementptr inbounds i32, i32* %p.addr.04, i32 1
103   store i32 %1, i32* %p.addr.04, align 4
104   %2 = call i32 @llvm.loop.decrement.reg.i32.i32.i32(i32 %0, i32 1)
105   %3 = icmp ne i32 %2, 0
106   br i1 %3, label %while.body, label %while.end
108 while.end:                                        ; preds = %while.body
109   ret i32 0
112 ; CHECK-LABEL: pre_existing_test_set
113 ; CHECK: call i1 @llvm.test.set.loop.iterations
114 ; CHECK-NOT: llvm.set{{.*}}.loop.iterations
115 ; CHECK: call i32 @llvm.loop.decrement.reg.i32.i32.i32(i32 %0, i32 1)
116 ; CHECK-NOT: call i32 @llvm.loop.decrement.reg
117 define i32 @pre_existing_test_set(i32 %n, i32* nocapture %p, i32* nocapture readonly %q) {
118 entry:
119   %guard = call i1 @llvm.test.set.loop.iterations.i32(i32 %n)
120   br i1 %guard, label %while.preheader, label %while.end
122 while.preheader:
123   br label %while.body
125 while.body:                                       ; preds = %while.body, %entry
126   %q.addr.05 = phi i32* [ %incdec.ptr, %while.body ], [ %q, %while.preheader ]
127   %p.addr.04 = phi i32* [ %incdec.ptr1, %while.body ], [ %p, %while.preheader ]
128   %0 = phi i32 [ %n, %while.preheader ], [ %2, %while.body ]
129   %incdec.ptr = getelementptr inbounds i32, i32* %q.addr.05, i32 1
130   %1 = load i32, i32* %q.addr.05, align 4
131   %incdec.ptr1 = getelementptr inbounds i32, i32* %p.addr.04, i32 1
132   store i32 %1, i32* %p.addr.04, align 4
133   %2 = call i32 @llvm.loop.decrement.reg.i32.i32.i32(i32 %0, i32 1)
134   %3 = icmp ne i32 %2, 0
135   br i1 %3, label %while.body, label %while.end
137 while.end:                                        ; preds = %while.body
138   ret i32 0
141 ; CHECK-LABEL: pre_existing_inner
142 ; CHECK-NOT: llvm.set.loop.iterations
143 ; CHECK: while.cond1.preheader.us:
144 ; CHECK: call void @llvm.set.loop.iterations.i32(i32 %N)
145 ; CHECK: call i32 @llvm.loop.decrement.reg.i32.i32.i32(i32 %0, i32 1)
146 ; CHECK: br i1
147 ; CHECK-NOT: call i32 @llvm.loop.decrement
148 define void @pre_existing_inner(i32* nocapture %A, i32 %N) {
149 entry:
150   %cmp20 = icmp eq i32 %N, 0
151   br i1 %cmp20, label %while.end7, label %while.cond1.preheader.us
153 while.cond1.preheader.us:
154   %i.021.us = phi i32 [ %inc6.us, %while.cond1.while.end_crit_edge.us ], [ 0, %entry ]
155   %mul.us = mul i32 %i.021.us, %N
156   call void @llvm.set.loop.iterations.i32(i32 %N)
157   br label %while.body3.us
159 while.body3.us:
160   %j.019.us = phi i32 [ 0, %while.cond1.preheader.us ], [ %inc.us, %while.body3.us ]
161   %0 = phi i32 [ %N, %while.cond1.preheader.us ], [ %1, %while.body3.us ]
162   %add.us = add i32 %j.019.us, %mul.us
163   %arrayidx.us = getelementptr inbounds i32, i32* %A, i32 %add.us
164   store i32 %add.us, i32* %arrayidx.us, align 4
165   %inc.us = add nuw i32 %j.019.us, 1
166   %1 = call i32 @llvm.loop.decrement.reg.i32.i32.i32(i32 %0, i32 1)
167   %2 = icmp ne i32 %1, 0
168   br i1 %2, label %while.body3.us, label %while.cond1.while.end_crit_edge.us
170 while.cond1.while.end_crit_edge.us:
171   %inc6.us = add nuw i32 %i.021.us, 1
172   %exitcond23 = icmp eq i32 %inc6.us, %N
173   br i1 %exitcond23, label %while.end7, label %while.cond1.preheader.us
175 while.end7:
176   ret void
179 ; CHECK-LABEL: not_rotated
180 ; CHECK-NOT: call void @llvm.set.loop.iterations
181 ; CHECK-NOT: call i32 @llvm.loop.decrement.i32
182 define void @not_rotated(i32, i16* nocapture, i16 signext) {
183   br label %4
186   %5 = phi i32 [ 0, %3 ], [ %19, %18 ]
187   %6 = icmp eq i32 %5, %0
188   br i1 %6, label %20, label %7
191   %8 = mul i32 %5, %0
192   br label %9
195   %10 = phi i32 [ %17, %12 ], [ 0, %7 ]
196   %11 = icmp eq i32 %10, %0
197   br i1 %11, label %18, label %12
200   %13 = add i32 %10, %8
201   %14 = getelementptr inbounds i16, i16* %1, i32 %13
202   %15 = load i16, i16* %14, align 2
203   %16 = add i16 %15, %2
204   store i16 %16, i16* %14, align 2
205   %17 = add i32 %10, 1
206   br label %9
209   %19 = add i32 %5, 1
210   br label %4
213   ret void
216 ; CHECK-LABEL: multi_latch
217 ; CHECK-NOT: call void @llvm.set.loop.iterations
218 ; CHECK-NOT: call i32 @llvm.loop.decrement
219 define void @multi_latch(i32* %a, i32* %b, i32 %N) {
220 entry:
221   %half = lshr i32 %N, 1
222   br label %header
224 header:
225   %iv = phi i32 [ 0, %entry ], [ %count.next, %latch.0 ], [ %count.next, %latch.1 ]
226   %cmp = icmp ult i32 %iv, %half
227   %addr.a = getelementptr i32, i32* %a, i32 %iv
228   %addr.b = getelementptr i32, i32* %b, i32 %iv
229   br i1 %cmp, label %if.then, label %if.else
231 if.then:
232   store i32 %iv, i32* %addr.a
233   br label %latch.0
235 if.else:
236   store i32 %iv, i32* %addr.b
237   br label %latch.0
239 latch.0:
240   %count.next = add nuw i32 %iv, 1
241   %cmp.1 = icmp ult i32 %count.next, %half
242   br i1 %cmp.1, label %header, label %latch.1
244 latch.1:
245   %ld = load i32, i32* %addr.a
246   store i32 %ld, i32* %addr.b
247   %cmp.2 = icmp ult i32 %count.next, %N
248   br i1 %cmp.2, label %header, label %latch.1
250 exit:
251   ret void
254 ; CHECK-LABEL: search
255 ; CHECK: entry:
256 ; CHECK:   [[TEST:%[^ ]+]] = call i1 @llvm.test.set.loop.iterations.i32(i32 %N)
257 ; CHECK:   br i1 [[TEST]], label %for.body.preheader, label %for.cond.cleanup
258 ; CHECK: for.body.preheader:
259 ; CHECK:   br label %for.body
260 ; CHECK: for.body:
261 ; CHECK: for.inc:
262 ; CHECK:   [[LOOP_DEC:%[^ ]+]] = call i32 @llvm.loop.decrement.reg.i32.i32.i32
263 ; CHECK:   [[CMP:%[^ ]+]] = icmp ne i32 [[LOOP_DEC]], 0
264 ; CHECK:   br i1 [[CMP]], label %for.body, label %for.cond.cleanup
265 define i32 @search(i8* nocapture readonly %c, i32 %N) {
266 entry:
267   %cmp11 = icmp eq i32 %N, 0
268   br i1 %cmp11, label %for.cond.cleanup, label %for.body
270 for.cond.cleanup:
271   %found.0.lcssa = phi i32 [ 0, %entry ], [ %found.1, %for.inc ]
272   %spaces.0.lcssa = phi i32 [ 0, %entry ], [ %spaces.1, %for.inc ]
273   %sub = sub nsw i32 %found.0.lcssa, %spaces.0.lcssa
274   ret i32 %sub
276 for.body:
277   %i.014 = phi i32 [ %inc3, %for.inc ], [ 0, %entry ]
278   %spaces.013 = phi i32 [ %spaces.1, %for.inc ], [ 0, %entry ]
279   %found.012 = phi i32 [ %found.1, %for.inc ], [ 0, %entry ]
280   %arrayidx = getelementptr inbounds i8, i8* %c, i32 %i.014
281   %0 = load i8, i8* %arrayidx, align 1
282   switch i8 %0, label %for.inc [
283     i8 108, label %sw.bb
284     i8 111, label %sw.bb
285     i8 112, label %sw.bb
286     i8 32, label %sw.bb1
287   ]
289 sw.bb:                                            ; preds = %for.body, %for.body, %for.body
290   %inc = add nsw i32 %found.012, 1
291   br label %for.inc
293 sw.bb1:                                           ; preds = %for.body
294   %inc2 = add nsw i32 %spaces.013, 1
295   br label %for.inc
297 for.inc:                                          ; preds = %sw.bb, %sw.bb1, %for.body
298   %found.1 = phi i32 [ %found.012, %for.body ], [ %found.012, %sw.bb1 ], [ %inc, %sw.bb ]
299   %spaces.1 = phi i32 [ %spaces.013, %for.body ], [ %inc2, %sw.bb1 ], [ %spaces.013, %sw.bb ]
300   %inc3 = add nuw i32 %i.014, 1
301   %exitcond = icmp eq i32 %inc3, %N
302   br i1 %exitcond, label %for.cond.cleanup, label %for.body
305 ; CHECK-LABEL: unroll_inc_int
306 ; CHECK: call void @llvm.set.loop.iterations.i32(i32 %N)
307 ; CHECK: call i32 @llvm.loop.decrement.reg.i32.i32.i32(
309 ; TODO: We should be able to support the unrolled loop body.
310 ; CHECK-UNROLL-LABEL: unroll_inc_int
311 ; CHECK-UNROLL:     [[PREHEADER:.LBB[0-9_]+]]: @ %for.body.preheader
312 ; CHECK-UNROLL-NOT: dls
313 ; CHECK-UNROLL:     [[LOOP:.LBB[0-9_]+]]: @ %for.body
314 ; CHECK-UNROLL-NOT: le lr, [[LOOP]]
315 ; CHECK-UNROLL:     bne [[LOOP]]
316 ; CHECK-UNROLL:     wls lr, lr, [[EXIT:.LBB[0-9_]+]]
317 ; CHECK-UNROLL:     [[EPIL:.LBB[0-9_]+]]:
318 ; CHECK-UNROLL:     le lr, [[EPIL]]
319 ; CHECK-UNROLL-NEXT: [[EXIT]]
321 define void @unroll_inc_int(i32* nocapture %a, i32* nocapture readonly %b, i32* nocapture readonly %c, i32 %N) {
322 entry:
323   %cmp8 = icmp sgt i32 %N, 0
324   br i1 %cmp8, label %for.body, label %for.cond.cleanup
326 for.cond.cleanup:
327   ret void
329 for.body:
330   %i.09 = phi i32 [ %inc, %for.body ], [ 0, %entry ]
331   %arrayidx = getelementptr inbounds i32, i32* %b, i32 %i.09
332   %0 = load i32, i32* %arrayidx, align 4
333   %arrayidx1 = getelementptr inbounds i32, i32* %c, i32 %i.09
334   %1 = load i32, i32* %arrayidx1, align 4
335   %mul = mul nsw i32 %1, %0
336   %arrayidx2 = getelementptr inbounds i32, i32* %a, i32 %i.09
337   store i32 %mul, i32* %arrayidx2, align 4
338   %inc = add nuw nsw i32 %i.09, 1
339   %exitcond = icmp eq i32 %inc, %N
340   br i1 %exitcond, label %for.cond.cleanup, label %for.body
343 ; CHECK-LABEL: unroll_inc_unsigned
344 ; CHECK: call i1 @llvm.test.set.loop.iterations.i32(i32 %N)
345 ; CHECK: call i32 @llvm.loop.decrement.reg.i32.i32.i32(
347 ; CHECK-LLC-LABEL: unroll_inc_unsigned:
348 ; CHECK-LLC: wls lr, r3, [[EXIT:.LBB[0-9_]+]]
349 ; CHECK-LLC: [[HEADER:.LBB[0-9_]+]]:
350 ; CHECK-LLC: le lr, [[HEADER]]
351 ; CHECK-LLC-NEXT: [[EXIT]]:
353 ; TODO: We should be able to support the unrolled loop body.
354 ; CHECK-UNROLL-LABEL: unroll_inc_unsigned
355 ; CHECK-UNROLL:     [[PREHEADER:.LBB[0-9_]+]]: @ %for.body.preheader
356 ; CHECK-UNROLL-NOT: dls
357 ; CHECK-UNROLL:     [[LOOP:.LBB[0-9_]+]]: @ %for.body
358 ; CHECK-UNROLL-NOT: le lr, [[LOOP]]
359 ; CHECK-UNROLL:     bne [[LOOP]]
360 ; CHECK-UNROLL:     wls lr, lr, [[EPIL_EXIT:.LBB[0-9_]+]]
361 ; CHECK-UNROLL: [[EPIL:.LBB[0-9_]+]]:
362 ; CHECK-UNROLL:     le lr, [[EPIL]]
363 ; CHECK-UNROLL: [[EPIL_EXIT]]:
364 ; CHECK-UNROLL:     pop
365 define void @unroll_inc_unsigned(i32* nocapture %a, i32* nocapture readonly %b, i32* nocapture readonly %c, i32 %N) {
366 entry:
367   %cmp8 = icmp eq i32 %N, 0
368   br i1 %cmp8, label %for.cond.cleanup, label %for.body
370 for.cond.cleanup:
371   ret void
373 for.body:
374   %i.09 = phi i32 [ %inc, %for.body ], [ 0, %entry ]
375   %arrayidx = getelementptr inbounds i32, i32* %b, i32 %i.09
376   %0 = load i32, i32* %arrayidx, align 4
377   %arrayidx1 = getelementptr inbounds i32, i32* %c, i32 %i.09
378   %1 = load i32, i32* %arrayidx1, align 4
379   %mul = mul nsw i32 %1, %0
380   %arrayidx2 = getelementptr inbounds i32, i32* %a, i32 %i.09
381   store i32 %mul, i32* %arrayidx2, align 4
382   %inc = add nuw i32 %i.09, 1
383   %exitcond = icmp eq i32 %inc, %N
384   br i1 %exitcond, label %for.cond.cleanup, label %for.body
387 ; CHECK-LABEL: unroll_dec_int
388 ; CHECK: call void @llvm.set.loop.iterations.i32(i32 %N)
389 ; CHECK: call i32 @llvm.loop.decrement.reg.i32.i32.i32(
391 ; TODO: An unnecessary register is being held to hold COUNT, lr should just
392 ; be used instead.
393 ; CHECK-LLC-LABEL: unroll_dec_int:
394 ; CHECK-LLC: dls lr, r3
395 ; CHECK-LLC-NOT: mov lr, r3
396 ; CHECK-LLC: [[HEADER:.LBB[0-9_]+]]:
397 ; CHECK-LLC: le lr, [[HEADER]]
399 ; CHECK-UNROLL-LABEL: unroll_dec_int:
400 ; CHECK-UNROLL:         wls lr, {{.*}}, [[PROLOGUE_EXIT:.LBB[0-9_]+]]
401 ; CHECK-UNROLL-NEXT: [[PROLOGUE:.LBB[0-9_]+]]:
402 ; CHECK-UNROLL:         le lr, [[PROLOGUE]]
403 ; CHECK-UNROLL-NEXT: [[PROLOGUE_EXIT:.LBB[0-9_]+]]:
404 ; CHECK-UNROLL:         dls lr, lr
405 ; CHECK-UNROLL:      [[BODY:.LBB[0-9_]+]]:
406 ; CHECK-UNROLL:         le lr, [[BODY]]
407 ; CHECK-UNROLL-NOT:     b
408 ; CHECK-UNROLL:         pop
409 define void @unroll_dec_int(i32* nocapture %a, i32* nocapture readonly %b, i32* nocapture readonly %c, i32 %N) {
410 entry:
411   %cmp8 = icmp sgt i32 %N, 0
412   br i1 %cmp8, label %for.body, label %for.cond.cleanup
414 for.cond.cleanup:
415   ret void
417 for.body:
418   %i.09 = phi i32 [ %dec, %for.body ], [ %N, %entry ]
419   %arrayidx = getelementptr inbounds i32, i32* %b, i32 %i.09
420   %0 = load i32, i32* %arrayidx, align 4
421   %arrayidx1 = getelementptr inbounds i32, i32* %c, i32 %i.09
422   %1 = load i32, i32* %arrayidx1, align 4
423   %mul = mul nsw i32 %1, %0
424   %arrayidx2 = getelementptr inbounds i32, i32* %a, i32 %i.09
425   store i32 %mul, i32* %arrayidx2, align 4
426   %dec = add nsw i32 %i.09, -1
427   %cmp = icmp sgt i32 %dec, 0
428   br i1 %cmp, label %for.body, label %for.cond.cleanup
431 declare void @llvm.set.loop.iterations.i32(i32) #0
432 declare i1 @llvm.test.set.loop.iterations.i32(i32) #0
433 declare i32 @llvm.loop.decrement.reg.i32.i32.i32(i32, i32) #0