[Transforms] Silence a warning in SROA.cpp (NFC)
[llvm-project.git] / llvm / test / CodeGen / Thumb / callee_save.ll
blob550542cc2330cb98222f2bbded418ea3e12a471f
1 ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
2 ; RUN: llc -mtriple=thumbv6m-none-eabi < %s | FileCheck %s
4 declare ptr @llvm.returnaddress(i32)
6 ; We don't allocate high registers, so any function not using inline asm will
7 ; only need to save the low registers.
8 define void @low_regs_only() {
9 ; CHECK-LABEL: low_regs_only:
10 ; CHECK:       @ %bb.0: @ %entry
11 ; CHECK-NEXT:    .save {r4, r5, r6, r7, lr}
12 ; CHECK-NEXT:    push {r4, r5, r6, r7, lr}
13 ; CHECK-NEXT:    @APP
14 ; CHECK-NEXT:    @NO_APP
15 ; CHECK-NEXT:    pop {r4, r5, r6, r7, pc}
16 entry:
17   tail call void asm sideeffect "", "~{r4},~{r5},~{r6},~{r7}"()
18   ret void
21 ; One high reg clobbered, but no low regs, args or returns. We can use an
22 ; argument/return register to help save/restore it.
23 define void @one_high() {
24 ; CHECK-LABEL: one_high:
25 ; CHECK:       @ %bb.0: @ %entry
26 ; CHECK-NEXT:    mov r3, r8
27 ; CHECK-NEXT:    .save {r8}
28 ; CHECK-NEXT:    push {r3}
29 ; CHECK-NEXT:    @APP
30 ; CHECK-NEXT:    @NO_APP
31 ; CHECK-NEXT:    pop {r0}
32 ; CHECK-NEXT:    mov r8, r0
33 ; CHECK-NEXT:    bx lr
34 entry:
35   tail call void asm sideeffect "", "~{r8}"()
36   ret void
39 ; 4 high regs clobbered, but still no low regs, args or returns. We can use all
40 ; 4 arg/return regs for the save/restore.
41 define void @four_high() {
42 ; CHECK-LABEL: four_high:
43 ; CHECK:       @ %bb.0: @ %entry
44 ; CHECK-NEXT:    mov r3, r11
45 ; CHECK-NEXT:    mov r2, r10
46 ; CHECK-NEXT:    mov r1, r9
47 ; CHECK-NEXT:    mov r0, r8
48 ; CHECK-NEXT:    .save {r8, r9, r10, r11}
49 ; CHECK-NEXT:    push {r0, r1, r2, r3}
50 ; CHECK-NEXT:    @APP
51 ; CHECK-NEXT:    @NO_APP
52 ; CHECK-NEXT:    pop {r0, r1, r2, r3}
53 ; CHECK-NEXT:    mov r8, r0
54 ; CHECK-NEXT:    mov r9, r1
55 ; CHECK-NEXT:    mov r10, r2
56 ; CHECK-NEXT:    mov r11, r3
57 ; CHECK-NEXT:    bx lr
58 entry:
59   tail call void asm sideeffect "", "~{r8},~{r9},~{r10},~{r11}"()
60   ret void
63 ; One high and one low register clobbered. lr also gets pushed to simplify the
64 ; return, and r7 to keep the stack aligned. Here, we could use r0-r3, r4, r7 or
65 ; lr to save/restore r8.
66 define void @one_high_one_low() {
67 ; CHECK-LABEL: one_high_one_low:
68 ; CHECK:       @ %bb.0: @ %entry
69 ; CHECK-NEXT:    .save {r4, r7, lr}
70 ; CHECK-NEXT:    push {r4, r7, lr}
71 ; CHECK-NEXT:    mov lr, r8
72 ; CHECK-NEXT:    .save {r8}
73 ; CHECK-NEXT:    push {lr}
74 ; CHECK-NEXT:    @APP
75 ; CHECK-NEXT:    @NO_APP
76 ; CHECK-NEXT:    pop {r0}
77 ; CHECK-NEXT:    mov r8, r0
78 ; CHECK-NEXT:    pop {r4, r7, pc}
79 entry:
80   tail call void asm sideeffect "", "~{r4},~{r8}"()
81   ret void
84 ; All callee-saved registers clobbered, r4-r7 and lr are not live after the
85 ; first push so can be used for pushing the high registers.
86 define void @four_high_four_low() {
87 ; CHECK-LABEL: four_high_four_low:
88 ; CHECK:       @ %bb.0: @ %entry
89 ; CHECK-NEXT:    .save {r4, r5, r6, r7, lr}
90 ; CHECK-NEXT:    push {r4, r5, r6, r7, lr}
91 ; CHECK-NEXT:    mov lr, r11
92 ; CHECK-NEXT:    mov r7, r10
93 ; CHECK-NEXT:    mov r6, r9
94 ; CHECK-NEXT:    mov r5, r8
95 ; CHECK-NEXT:    .save {r8, r9, r10, r11}
96 ; CHECK-NEXT:    push {r5, r6, r7, lr}
97 ; CHECK-NEXT:    @APP
98 ; CHECK-NEXT:    @NO_APP
99 ; CHECK-NEXT:    pop {r0, r1, r2, r3}
100 ; CHECK-NEXT:    mov r8, r0
101 ; CHECK-NEXT:    mov r9, r1
102 ; CHECK-NEXT:    mov r10, r2
103 ; CHECK-NEXT:    mov r11, r3
104 ; CHECK-NEXT:    pop {r4, r5, r6, r7, pc}
105 entry:
106   tail call void asm sideeffect "", "~{r4},~{r5},~{r6},~{r7},~{r8},~{r9},~{r10},~{r11}"()
107   ret void
111 ; All callee-saved registers clobbered, and frame pointer is requested. r7 now
112 ; cannot be used while saving/restoring the high regs.
113 define void @four_high_four_low_frame_ptr() "frame-pointer"="all" {
114 ; CHECK-LABEL: four_high_four_low_frame_ptr:
115 ; CHECK:       @ %bb.0: @ %entry
116 ; CHECK-NEXT:    .save {r4, r5, r6, r7, lr}
117 ; CHECK-NEXT:    push {r4, r5, r6, r7, lr}
118 ; CHECK-NEXT:    .setfp r7, sp, #12
119 ; CHECK-NEXT:    add r7, sp, #12
120 ; CHECK-NEXT:    mov lr, r11
121 ; CHECK-NEXT:    mov r6, r10
122 ; CHECK-NEXT:    mov r5, r9
123 ; CHECK-NEXT:    mov r4, r8
124 ; CHECK-NEXT:    .save {r8, r9, r10, r11}
125 ; CHECK-NEXT:    push {r4, r5, r6, lr}
126 ; CHECK-NEXT:    @APP
127 ; CHECK-NEXT:    @NO_APP
128 ; CHECK-NEXT:    pop {r0, r1, r2, r3}
129 ; CHECK-NEXT:    mov r8, r0
130 ; CHECK-NEXT:    mov r9, r1
131 ; CHECK-NEXT:    mov r10, r2
132 ; CHECK-NEXT:    mov r11, r3
133 ; CHECK-NEXT:    pop {r4, r5, r6, r7, pc}
134 entry:
135   tail call void asm sideeffect "", "~{r4},~{r5},~{r6},~{r7},~{r8},~{r9},~{r10},~{r11}"()
136   ret void
139 ; All callee-saved registers clobbered, frame pointer is requested and
140 ; llvm.returnaddress used. r7 and lr now cannot be used while saving/restoring
141 ; the high regs.
142 define void @four_high_four_low_frame_ptr_ret_addr() "frame-pointer"="all" {
143 ; CHECK-LABEL: four_high_four_low_frame_ptr_ret_addr:
144 ; CHECK:       @ %bb.0: @ %entry
145 ; CHECK-NEXT:    .save {r4, r5, r6, r7, lr}
146 ; CHECK-NEXT:    push {r4, r5, r6, r7, lr}
147 ; CHECK-NEXT:    .setfp r7, sp, #12
148 ; CHECK-NEXT:    add r7, sp, #12
149 ; CHECK-NEXT:    mov r6, r11
150 ; CHECK-NEXT:    mov r5, r10
151 ; CHECK-NEXT:    mov r4, r9
152 ; CHECK-NEXT:    mov r3, r8
153 ; CHECK-NEXT:    .save {r8, r9, r10, r11}
154 ; CHECK-NEXT:    push {r3, r4, r5, r6}
155 ; CHECK-NEXT:    mov r0, lr
156 ; CHECK-NEXT:    @APP
157 ; CHECK-NEXT:    @NO_APP
158 ; CHECK-NEXT:    pop {r0, r1, r2, r3}
159 ; CHECK-NEXT:    mov r8, r0
160 ; CHECK-NEXT:    mov r9, r1
161 ; CHECK-NEXT:    mov r10, r2
162 ; CHECK-NEXT:    mov r11, r3
163 ; CHECK-NEXT:    pop {r4, r5, r6, r7, pc}
164 entry:
165   %a = tail call ptr @llvm.returnaddress(i32 0)
166   tail call void asm sideeffect "", "r,~{r4},~{r5},~{r6},~{r7},~{r8},~{r9},~{r10},~{r11}"(ptr %a)
167   ret void
170 ; 4 high regs clobbered, all 4 argument registers used. We push an extra 4 low
171 ; registers, so that we can use them for saving the high regs.
172 define void @four_high_four_arg(i32 %a, i32 %b, i32 %c, i32 %d) {
173 ; CHECK-LABEL: four_high_four_arg:
174 ; CHECK:       @ %bb.0: @ %entry
175 ; CHECK-NEXT:    .save {r5, r6, r7, lr}
176 ; CHECK-NEXT:    push {r5, r6, r7, lr}
177 ; CHECK-NEXT:    mov lr, r11
178 ; CHECK-NEXT:    mov r7, r10
179 ; CHECK-NEXT:    mov r6, r9
180 ; CHECK-NEXT:    mov r5, r8
181 ; CHECK-NEXT:    .save {r8, r9, r10, r11}
182 ; CHECK-NEXT:    push {r5, r6, r7, lr}
183 ; CHECK-NEXT:    @APP
184 ; CHECK-NEXT:    @NO_APP
185 ; CHECK-NEXT:    pop {r0, r1, r2, r3}
186 ; CHECK-NEXT:    mov r8, r0
187 ; CHECK-NEXT:    mov r9, r1
188 ; CHECK-NEXT:    mov r10, r2
189 ; CHECK-NEXT:    mov r11, r3
190 ; CHECK-NEXT:    pop {r5, r6, r7, pc}
191 entry:
192   tail call void asm sideeffect "", "r,r,r,r,~{r8},~{r9},~{r10},~{r11}"(i32 %a, i32 %b, i32 %c, i32 %d)
193   ret void
196 ; 4 high regs clobbered, all 4 return registers used. We push an extra 4 low
197 ; registers, so that we can use them for restoring the high regs.
198 define <4 x i32> @four_high_four_return() {
199 ; CHECK-LABEL: four_high_four_return:
200 ; CHECK:       @ %bb.0: @ %entry
201 ; CHECK-NEXT:    .save {r4, r5, r6, r7, lr}
202 ; CHECK-NEXT:    push {r4, r5, r6, r7, lr}
203 ; CHECK-NEXT:    mov lr, r11
204 ; CHECK-NEXT:    mov r7, r10
205 ; CHECK-NEXT:    mov r6, r9
206 ; CHECK-NEXT:    mov r5, r8
207 ; CHECK-NEXT:    .save {r8, r9, r10, r11}
208 ; CHECK-NEXT:    push {r5, r6, r7, lr}
209 ; CHECK-NEXT:    @APP
210 ; CHECK-NEXT:    @NO_APP
211 ; CHECK-NEXT:    movs r0, #1
212 ; CHECK-NEXT:    movs r1, #2
213 ; CHECK-NEXT:    movs r2, #3
214 ; CHECK-NEXT:    movs r3, #4
215 ; CHECK-NEXT:    pop {r4, r5, r6, r7}
216 ; CHECK-NEXT:    mov r8, r4
217 ; CHECK-NEXT:    mov r9, r5
218 ; CHECK-NEXT:    mov r10, r6
219 ; CHECK-NEXT:    mov r11, r7
220 ; CHECK-NEXT:    pop {r4, r5, r6, r7, pc}
221 entry:
222   tail call void asm sideeffect "", "~{r8},~{r9},~{r10},~{r11}"()
223   %vecinit = insertelement <4 x i32> undef, i32 1, i32 0
224   %vecinit11 = insertelement <4 x i32> %vecinit, i32 2, i32 1
225   %vecinit12 = insertelement <4 x i32> %vecinit11, i32 3, i32 2
226   %vecinit13 = insertelement <4 x i32> %vecinit12, i32 4, i32 3
227   ret <4 x i32> %vecinit13
230 ; 4 high regs clobbered, all args & returns used, frame pointer requested and
231 ; llvm.returnaddress called. This leaves us with 3 low registers available (r4,
232 ; r5, r6), with which to save 4 high registers, so we have to use two pushes
233 ; and pops.
234 define <4 x i32> @all_of_the_above(i32 %a, i32 %b, i32 %c, i32 %d) "frame-pointer"="all" {
235 ; CHECK-LABEL: all_of_the_above:
236 ; CHECK:       @ %bb.0: @ %entry
237 ; CHECK-NEXT:    .save {r4, r5, r6, r7, lr}
238 ; CHECK-NEXT:    push {r4, r5, r6, r7, lr}
239 ; CHECK-NEXT:    .setfp r7, sp, #12
240 ; CHECK-NEXT:    add r7, sp, #12
241 ; CHECK-NEXT:    mov r6, r11
242 ; CHECK-NEXT:    mov r5, r10
243 ; CHECK-NEXT:    mov r4, r9
244 ; CHECK-NEXT:    .save {r9, r10, r11}
245 ; CHECK-NEXT:    push {r4, r5, r6}
246 ; CHECK-NEXT:    mov r6, r8
247 ; CHECK-NEXT:    .save {r8}
248 ; CHECK-NEXT:    push {r6}
249 ; CHECK-NEXT:    .pad #4
250 ; CHECK-NEXT:    sub sp, #4
251 ; CHECK-NEXT:    mov r4, lr
252 ; CHECK-NEXT:    str r4, [sp] @ 4-byte Spill
253 ; CHECK-NEXT:    @APP
254 ; CHECK-NEXT:    @NO_APP
255 ; CHECK-NEXT:    movs r1, #2
256 ; CHECK-NEXT:    movs r2, #3
257 ; CHECK-NEXT:    movs r3, #4
258 ; CHECK-NEXT:    ldr r0, [sp] @ 4-byte Reload
259 ; CHECK-NEXT:    add sp, #4
260 ; CHECK-NEXT:    pop {r4, r5, r6}
261 ; CHECK-NEXT:    mov r8, r4
262 ; CHECK-NEXT:    mov r9, r5
263 ; CHECK-NEXT:    mov r10, r6
264 ; CHECK-NEXT:    pop {r4}
265 ; CHECK-NEXT:    mov r11, r4
266 ; CHECK-NEXT:    pop {r4, r5, r6, r7, pc}
267 entry:
268   tail call void asm sideeffect "", "r,r,r,r,~{r4},~{r5},~{r6},~{r7},~{r8},~{r9},~{r10},~{r11}"(i32 %a, i32 %b, i32 %c, i32 %d)
269   %e = tail call ptr @llvm.returnaddress(i32 0)
270   %f = ptrtoint ptr %e to i32
271   %vecinit = insertelement <4 x i32> undef, i32 %f, i32 0
272   %vecinit11 = insertelement <4 x i32> %vecinit, i32 2, i32 1
273   %vecinit12 = insertelement <4 x i32> %vecinit11, i32 3, i32 2
274   %vecinit13 = insertelement <4 x i32> %vecinit12, i32 4, i32 3
275   ret <4 x i32> %vecinit13
278 ; When a base pointer is being used, we can safely use it for saving/restoring
279 ; the high regs because it is set after the last push, and not used at all in the
280 ; epliogue. We can also use r4 for restoring the registers despite it also being
281 ; used when restoring sp from fp, as that happens before the first pop.
282 define <4 x i32> @base_pointer(i32 %a) {
283 ; CHECK-LABEL: base_pointer:
284 ; CHECK:       @ %bb.0: @ %entry
285 ; CHECK-NEXT:    .save {r4, r6, r7, lr}
286 ; CHECK-NEXT:    push {r4, r6, r7, lr}
287 ; CHECK-NEXT:    .setfp r7, sp, #8
288 ; CHECK-NEXT:    add r7, sp, #8
289 ; CHECK-NEXT:    mov lr, r9
290 ; CHECK-NEXT:    mov r6, r8
291 ; CHECK-NEXT:    .save {r8, r9}
292 ; CHECK-NEXT:    push {r6, lr}
293 ; CHECK-NEXT:    mov r6, sp
294 ; CHECK-NEXT:    lsls r0, r0, #2
295 ; CHECK-NEXT:    adds r0, r0, #7
296 ; CHECK-NEXT:    movs r1, #7
297 ; CHECK-NEXT:    bics r0, r1
298 ; CHECK-NEXT:    mov r1, sp
299 ; CHECK-NEXT:    subs r0, r1, r0
300 ; CHECK-NEXT:    mov sp, r0
301 ; CHECK-NEXT:    @APP
302 ; CHECK-NEXT:    @NO_APP
303 ; CHECK-NEXT:    movs r0, #1
304 ; CHECK-NEXT:    movs r1, #2
305 ; CHECK-NEXT:    movs r2, #3
306 ; CHECK-NEXT:    movs r3, #4
307 ; CHECK-NEXT:    subs r6, r7, #7
308 ; CHECK-NEXT:    subs r6, #9
309 ; CHECK-NEXT:    mov sp, r6
310 ; CHECK-NEXT:    pop {r4, r6}
311 ; CHECK-NEXT:    mov r8, r4
312 ; CHECK-NEXT:    mov r9, r6
313 ; CHECK-NEXT:    pop {r4, r6, r7, pc}
314 entry:
315   %b = alloca i32, i32 %a
316   call void asm sideeffect "", "r,~{r8},~{r9}"(ptr %b)
317   %vecinit = insertelement <4 x i32> undef, i32 1, i32 0
318   %vecinit11 = insertelement <4 x i32> %vecinit, i32 2, i32 1
319   %vecinit12 = insertelement <4 x i32> %vecinit11, i32 3, i32 2
320   %vecinit13 = insertelement <4 x i32> %vecinit12, i32 4, i32 3
321   ret <4 x i32> %vecinit13