1# RUN: llc -O0 -run-pass=arm-low-overhead-loops -o - -verify-machineinstrs %s | FileCheck %s
2# CHECK-NOT: WLS
3# CHECK-NOT: WhileLoopStart
4
5--- |
6  target datalayout = "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64"
7  target triple = "thumbv8.1m.main"
8
9  define void @size_limit(i32* nocapture %a, i32* nocapture readonly %b, i32* nocapture readonly %c, i32 %N) #0 {
10  entry:
11    br label %while
12
13  for.cond.cleanup:                                 ; preds = %while, %for.body
14    ret void
15
16  for.body.preheader:                               ; preds = %while
17    %scevgep = getelementptr i32, i32* %a, i32 -1
18    %scevgep4 = getelementptr i32, i32* %c, i32 -1
19    %scevgep8 = getelementptr i32, i32* %b, i32 -1
20    br label %for.body
21
22  for.body:                                         ; preds = %for.body, %for.body.preheader
23    %lsr.iv9 = phi i32* [ %scevgep8, %for.body.preheader ], [ %scevgep10, %for.body ]
24    %lsr.iv5 = phi i32* [ %scevgep4, %for.body.preheader ], [ %scevgep6, %for.body ]
25    %lsr.iv1 = phi i32* [ %scevgep, %for.body.preheader ], [ %scevgep2, %for.body ]
26    %0 = phi i32 [ %N, %for.body.preheader ], [ %3, %for.body ]
27    %scevgep11 = getelementptr i32, i32* %lsr.iv9, i32 1
28    %1 = load i32, i32* %scevgep11, align 4
29    %scevgep7 = getelementptr i32, i32* %lsr.iv5, i32 1
30    %2 = load i32, i32* %scevgep7, align 4
31    %mul = mul nsw i32 %2, %1
32    %scevgep3 = getelementptr i32, i32* %lsr.iv1, i32 1
33    store i32 %mul, i32* %scevgep3, align 4
34    %scevgep2 = getelementptr i32, i32* %lsr.iv1, i32 1
35    %scevgep6 = getelementptr i32, i32* %lsr.iv5, i32 1
36    %scevgep10 = getelementptr i32, i32* %lsr.iv9, i32 1
37    %3 = call i32 @llvm.loop.decrement.reg.i32.i32.i32(i32 %0, i32 1)
38    %4 = icmp ne i32 %3, 0
39    br i1 %4, label %for.body, label %for.cond.cleanup
40
41  while:                                            ; preds = %entry
42    %cmp8 = call i1 @llvm.test.set.loop.iterations.i32(i32 %N)
43    br i1 %cmp8, label %for.body.preheader, label %for.cond.cleanup
44  }
45
46  ; Function Attrs: nounwind
47  declare i32 @llvm.arm.space(i32 immarg, i32) #1
48
49  ; Function Attrs: noduplicate nounwind
50  declare i1 @llvm.test.set.loop.iterations.i32(i32) #2
51
52  ; Function Attrs: noduplicate nounwind
53  declare i32 @llvm.loop.decrement.reg.i32.i32.i32(i32, i32) #2
54
55  attributes #0 = { "target-features"="+lob" }
56  attributes #1 = { nounwind }
57  attributes #2 = { noduplicate nounwind }
58
59...
60---
61name:            size_limit
62alignment:       2
63exposesReturnsTwice: false
64legalized:       false
65regBankSelected: false
66selected:        false
67failedISel:      false
68tracksRegLiveness: true
69hasWinCFI:       false
70registers:       []
71liveins:
72  - { reg: '$r0', virtual-reg: '' }
73  - { reg: '$r1', virtual-reg: '' }
74  - { reg: '$r2', virtual-reg: '' }
75  - { reg: '$r3', virtual-reg: '' }
76frameInfo:
77  isFrameAddressTaken: false
78  isReturnAddressTaken: false
79  hasStackMap:     false
80  hasPatchPoint:   false
81  stackSize:       40
82  offsetAdjustment: 0
83  maxAlignment:    4
84  adjustsStack:    false
85  hasCalls:        false
86  stackProtector:  ''
87  maxCallFrameSize: 0
88  cvBytesOfCalleeSavedRegisters: 0
89  hasOpaqueSPAdjustment: false
90  hasVAStart:      false
91  hasMustTailInVarArgFunc: false
92  localFrameSize:  0
93  savePoint:       ''
94  restorePoint:    ''
95fixedStack:      []
96stack:
97  - { id: 0, name: '', type: spill-slot, offset: -12, size: 4, alignment: 4,
98      stack-id: default, callee-saved-register: '', callee-saved-restored: true,
99      debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
100  - { id: 1, name: '', type: spill-slot, offset: -16, size: 4, alignment: 4,
101      stack-id: default, callee-saved-register: '', callee-saved-restored: true,
102      debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
103  - { id: 2, name: '', type: spill-slot, offset: -20, size: 4, alignment: 4,
104      stack-id: default, callee-saved-register: '', callee-saved-restored: true,
105      debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
106  - { id: 3, name: '', type: spill-slot, offset: -24, size: 4, alignment: 4,
107      stack-id: default, callee-saved-register: '', callee-saved-restored: true,
108      debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
109  - { id: 4, name: '', type: spill-slot, offset: -28, size: 4, alignment: 4,
110      stack-id: default, callee-saved-register: '', callee-saved-restored: true,
111      debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
112  - { id: 5, name: '', type: spill-slot, offset: -32, size: 4, alignment: 4,
113      stack-id: default, callee-saved-register: '', callee-saved-restored: true,
114      debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
115  - { id: 6, name: '', type: spill-slot, offset: -36, size: 4, alignment: 4,
116      stack-id: default, callee-saved-register: '', callee-saved-restored: true,
117      debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
118  - { id: 7, name: '', type: spill-slot, offset: -40, size: 4, alignment: 4,
119      stack-id: default, callee-saved-register: '', callee-saved-restored: true,
120      debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
121  - { id: 8, name: '', type: spill-slot, offset: -4, size: 4, alignment: 4,
122      stack-id: default, callee-saved-register: '$lr', callee-saved-restored: false,
123      debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
124  - { id: 9, name: '', type: spill-slot, offset: -8, size: 4, alignment: 4,
125      stack-id: default, callee-saved-register: '$r4', callee-saved-restored: true,
126      debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
127callSites:       []
128constants:       []
129machineFunctionInfo: {}
130body:             |
131  bb.0.entry:
132    successors: %bb.4(0x80000000)
133    liveins: $r0, $r1, $r2, $r3, $r4, $lr
134
135    frame-setup tPUSH 14, $noreg, killed $r4, killed $lr, implicit-def $sp, implicit $sp
136    frame-setup CFI_INSTRUCTION def_cfa_offset 8
137    frame-setup CFI_INSTRUCTION offset $lr, -4
138    frame-setup CFI_INSTRUCTION offset $r4, -8
139    $sp = frame-setup tSUBspi $sp, 8, 14, $noreg
140    frame-setup CFI_INSTRUCTION def_cfa_offset 40
141    tSTRspi killed $r3, $sp, 7, 14, $noreg :: (store (s32) into %stack.0)
142    tSTRspi killed $r2, $sp, 6, 14, $noreg :: (store (s32) into %stack.1)
143    tSTRspi killed $r1, $sp, 5, 14, $noreg :: (store (s32) into %stack.2)
144    tSTRspi killed $r0, $sp, 4, 14, $noreg :: (store (s32) into %stack.3)
145    tB %bb.4, 14, $noreg
146
147  bb.1.for.cond.cleanup:
148    $sp = tADDspi $sp, 8, 14, $noreg
149    tPOP_RET 14, $noreg, def $r4, def $pc
150
151  bb.2.for.body.preheader:
152    successors: %bb.3(0x80000000)
153
154    $r0 = tLDRspi $sp, 4, 14, $noreg :: (load (s32) from %stack.3)
155    renamable $r1, dead $cpsr = tSUBi3 killed renamable $r0, 4, 14, $noreg
156    $r2 = tLDRspi $sp, 6, 14, $noreg :: (load (s32) from %stack.1)
157    renamable $r3, dead $cpsr = tSUBi3 killed renamable $r2, 4, 14, $noreg
158    $r12 = t2LDRi12 $sp, 20, 14, $noreg :: (load (s32) from %stack.2)
159    renamable $lr = t2SUBri killed renamable $r12, 4, 14, $noreg, $noreg
160    $r4 = tLDRspi $sp, 7, 14, $noreg :: (load (s32) from %stack.0)
161    t2STRi12 killed $lr, $sp, 12, 14, $noreg :: (store (s32) into %stack.4)
162    tSTRspi killed $r3, $sp, 2, 14, $noreg :: (store (s32) into %stack.5)
163    tSTRspi killed $r1, $sp, 1, 14, $noreg :: (store (s32) into %stack.6)
164    tSTRspi killed $r4, $sp, 0, 14, $noreg :: (store (s32) into %stack.7)
165    tB %bb.3, 14, $noreg
166
167  bb.3.for.body:
168    successors: %bb.3(0x40000000), %bb.1(0x40000000)
169
170    $r0 = tLDRspi $sp, 0, 14, $noreg :: (load (s32) from %stack.7)
171    $r1 = tLDRspi $sp, 1, 14, $noreg :: (load (s32) from %stack.6)
172    $r2 = tLDRspi $sp, 2, 14, $noreg :: (load (s32) from %stack.5)
173    $r3 = tLDRspi $sp, 3, 14, $noreg :: (load (s32) from %stack.4)
174    renamable $r12, renamable $r3 = t2LDR_PRE renamable $r3, 4, 14, $noreg :: (load (s32) from %ir.scevgep11)
175    renamable $lr, renamable $r2 = t2LDR_PRE renamable $r2, 4, 14, $noreg :: (load (s32) from %ir.scevgep7)
176    renamable $r12 = nsw t2MUL killed renamable $lr, killed renamable $r12, 14, $noreg
177    early-clobber renamable $r1 = t2STR_PRE killed renamable $r12, renamable $r1, 4, 14, $noreg :: (store (s32) into %ir.scevgep3)
178    $lr = tMOVr killed $r0, 14, $noreg
179    renamable $lr = t2LoopDec killed renamable $lr, 1
180    $r0 = tMOVr $lr, 14, $noreg
181    tSTRspi killed $r0, $sp, 0, 14, $noreg :: (store (s32) into %stack.7)
182    tSTRspi killed $r1, $sp, 1, 14, $noreg :: (store (s32) into %stack.6)
183    tSTRspi killed $r2, $sp, 2, 14, $noreg :: (store (s32) into %stack.5)
184    tSTRspi killed $r3, $sp, 3, 14, $noreg :: (store (s32) into %stack.4)
185    t2LoopEnd killed renamable $lr, %bb.3, implicit-def dead $cpsr
186    tB %bb.1, 14, $noreg
187
188  bb.4.while:
189    successors: %bb.2(0x40000000), %bb.1(0x40000000)
190
191    $r0 = tLDRspi $sp, 7, 14, $noreg :: (load (s32) from %stack.0)
192    $lr = t2WhileLoopStartLR killed renamable $r0, %bb.1, implicit-def dead $cpsr
193    tB %bb.2, 14, $noreg
194
195...
196