[RISCV] Change func to funct in RISCVInstrInfoXqci.td. NFC (#119669)
[llvm-project.git] / llvm / test / CodeGen / Thumb / frame-access.ll
blob07a6b6d0b94906d468147736feb1163fc67b80b2
1 ; RUN: llc -mtriple=thumbv6m-eabi -frame-pointer=none %s -o - --verify-machineinstrs | FileCheck %s --check-prefixes=CHECK,CHECK-NOFP,CHECK-ATPCS
2 ; RUN: llc -mtriple=thumbv6m-eabi -frame-pointer=all %s -o - --verify-machineinstrs | FileCheck %s --check-prefixes=CHECK,CHECK-FP-ATPCS,CHECK-ATPCS
3 ; RUN: llc -mtriple=thumbv6m-eabi -frame-pointer=none -mattr=+aapcs-frame-chain %s -o - --verify-machineinstrs | FileCheck %s --check-prefixes=CHECK,CHECK-NOFP,CHECK-AAPCS
4 ; RUN: llc -mtriple=thumbv6m-eabi -frame-pointer=all -mattr=+aapcs-frame-chain %s -o - --verify-machineinstrs | FileCheck %s --check-prefixes=CHECK,CHECK-FP-AAPCS,CHECK-AAPCS
6 ; struct S { int x[128]; } s;
7 ; int f(int *, int, int, int, struct S);
8 ; int g(int *, int, int, int, int, int);
9 ; int h(int *, int *, int *);
10 ; int u(int *, int *, int *, struct S, struct S);
12 %struct.S = type { [128 x i32] }
13 %struct.__va_list = type { ptr }
15 @s = common dso_local global %struct.S zeroinitializer, align 4
17 declare void @llvm.va_start(ptr)
18 declare dso_local i32 @i(i32) local_unnamed_addr
19 declare dso_local i32 @g(ptr, i32, i32, i32, i32, i32) local_unnamed_addr
20 declare dso_local i32 @f(ptr, i32, i32, i32, ptr byval(%struct.S) align 4) local_unnamed_addr
21 declare dso_local i32 @h(ptr, ptr, ptr) local_unnamed_addr
22 declare dso_local i32 @u(ptr, ptr, ptr, ptr byval(%struct.S) align 4, ptr byval(%struct.S) align 4) local_unnamed_addr
25 ; Test access to arguments, passed on stack (including varargs)
28 ; Usual case, access via SP if FP is not available
29 ; int test_args_sp(int a, int b, int c, int d, int e) {
30 ;   int v[4];
31 ;   return g(v, a, b, c, d, e);
32 ; }
33 define dso_local i32 @test_args_sp(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e) local_unnamed_addr {
34 entry:
35   %v = alloca [4 x i32], align 4
36   %call = call i32 @g(ptr nonnull %v, i32 %a, i32 %b, i32 %c, i32 %d, i32 %e)
37   ret i32 %call
39 ; CHECK-LABEL: test_args_sp
40 ; Load `e`
41 ; CHECK-NOFP: ldr    r0, [sp, #32]
42 ; CHECK-FP-ATPCS: ldr  r0, [r7, #8]
43 ; CHECK-FP-AAPCS: mov    r0, r11
44 ; CHECK-FP-AAPCS: ldr    r0, [r0, #8]
45 ; CHECK-NEXT:  str    r3, [sp]
46 ; Pass `e` on stack
47 ; CHECK-NEXT:  str    r0, [sp, #4]
48 ; CHECK:       bl    g
50 ; int test_varargs_sp(int a, ...) {
51 ;   int v[4];
52 ;   __builtin_va_list ap;
53 ;   __builtin_va_start(ap, a);
54 ;   return g(v, a, 0, 0, 0, 0);
55 ; }
56 define dso_local i32 @test_varargs_sp(i32 %a, ...) local_unnamed_addr  {
57 entry:
58   %v = alloca [4 x i32], align 4
59   %ap = alloca %struct.__va_list, align 4
60   call void @llvm.va_start(ptr nonnull %ap)
61   %call = call i32 @g(ptr nonnull %v, i32 %a, i32 0, i32 0, i32 0, i32 0)
62   ret i32 %call
64 ; CHECK-LABEL: test_varargs_sp
65 ; Three incoming varargs in registers
66 ; CHECK:       sub sp, #12
67 ; CHECK:       sub sp, #28
68 ; Incoming arguments area is accessed via SP if FP is not available
69 ; CHECK-NOFP:  add r0, sp, #36
70 ; CHECK-NOFP:  stm r0!, {r1, r2, r3}
71 ; CHECK-FP-ATPCS: mov r0, r7
72 ; CHECK-FP-ATPCS: adds r0, #8
73 ; CHECK-FP-ATPCS: stm r0!, {r1, r2, r3}
74 ; CHECK-FP-AAPCS: mov r0, r11
75 ; CHECK-FP-AAPCS: mov r7, r0
76 ; CHECK-FP-AAPCS: adds r7, #8
77 ; CHECK-FP-AAPCS: stm r7!, {r1, r2, r3}
78 ; Re-aligned stack, access via FP
79 ; int test_args_realign(int a, int b, int c, int d, int e) {
80 ;   __attribute__((aligned(16))) int v[4];
81 ;   return g(v, a, b, c, d, e);
82 ; }
83 ; Function Attrs: nounwind
84 define dso_local i32 @test_args_realign(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e) local_unnamed_addr  {
85 entry:
86   %v = alloca [4 x i32], align 16
87   %call = call i32 @g(ptr nonnull %v, i32 %a, i32 %b, i32 %c, i32 %d, i32 %e)
88   ret i32 %call
90 ; CHECK-LABEL: test_args_realign
91 ; Setup frame pointer
92 ; CHECK-ATPCS: add r7, sp, #8
93 ; CHECK-AAPCS: mov r11, sp
94 ; Align stack
95 ; CHECK:       mov  r4, sp
96 ; CHECK-NEXT:  lsrs r4, r4, #4
97 ; CHECK-NEXT:  lsls r4, r4, #4
98 ; CHECK-NEXT:  mov  sp, r4
99 ; Load `e` via FP
100 ; CHECK-ATPCS: ldr r0, [r7, #8]
101 ; CHECK-AAPCS: mov r0, r11
102 ; CHECK-AAPCS: ldr r0, [r0, #8]
103 ; CHECK-NEXT:  str r3, [sp]
104 ; Pass `e` as argument
105 ; CHECK-NEXT:  str r0, [sp, #4]
106 ; CHECK:       bl    g
108 ; int test_varargs_realign(int a, ...) {
109 ;   __attribute__((aligned(16))) int v[4];
110 ;   __builtin_va_list ap;
111 ;   __builtin_va_start(ap, a);
112 ;   return g(v, a, 0, 0, 0, 0);
113 ; }
114 define dso_local i32 @test_varargs_realign(i32 %a, ...) local_unnamed_addr  {
115 entry:
116   %v = alloca [4 x i32], align 16
117   %ap = alloca %struct.__va_list, align 4
118   call void @llvm.va_start(ptr nonnull %ap)
119   %call = call i32 @g(ptr nonnull %v, i32 %a, i32 0, i32 0, i32 0, i32 0)
120   ret i32 %call
122 ; CHECK-LABEL: test_varargs_realign
123 ; Three incoming register varargs
124 ; CHECK:       sub sp, #12
125 ; Setup frame pointer
126 ; CHECK-ATPCS: add r7, sp, #8
127 ; CHECK-AAPCS: mov r11, sp
128 ; Align stack
129 ; CHECK:       mov  r4, sp
130 ; CHECK-NEXT:  lsrs r4, r4, #4
131 ; CHECK-NEXT:  lsls r4, r4, #4
132 ; CHECK-NEXT:  mov  sp, r4
133 ; Incoming register varargs stored via FP
134 ; CHECK-ATPCS: mov r0, r7
135 ; CHECK-ATPCS-NEXT: adds r0, #8
136 ; CHECK-ATPCS-NEXT: stm r0!, {r1, r2, r3}
137 ; CHECK-AAPCS: mov r0, r11
138 ; CHECK-AAPCS: mov r7, r0
139 ; CHECK-AAPCS: adds r7, #8
140 ; CHECK-AAPCS: stm r7!, {r1, r2, r3}
141 ; VLAs present, access via FP
142 ; int test_args_vla(int a, int b, int c, int d, int e) {
143 ;   int v[a];
144 ;   return g(v, a, b, c, d, e);
145 ; }
146 define dso_local i32 @test_args_vla(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e) local_unnamed_addr  {
147 entry:
148   %vla = alloca i32, i32 %a, align 4
149   %call = call i32 @g(ptr nonnull %vla, i32 %a, i32 %b, i32 %c, i32 %d, i32 %e)
150   ret i32 %call
152 ; CHECK-LABEL: test_args_vla
153 ; Setup frame pointer
154 ; CHECK-ATPCS: add r7, sp, #12
155 ; CHECK-AAPCS: mov r11, sp
156 ; Allocate outgoing stack arguments space
157 ; CHECK:       sub sp, #8
158 ; Load `e` via FP
159 ; CHECK-ATPCS: ldr r5, [r7, #8]
160 ; CHECK-AAPCS: mov r5, r11
161 ; CHECK-AAPCS: ldr r5, [r5, #8]
162 ; Pass `d` and `e` as arguments
163 ; CHECK-NEXT:  str r3, [sp]
164 ; CHECK-NEXT:  str r5, [sp, #4]
165 ; CHECK:       bl  g
167 ; int test_varargs_vla(int a, ...) {
168 ;   int v[a];
169 ;   __builtin_va_list ap;
170 ;   __builtin_va_start(ap, a);
171 ;   return g(v, a, 0, 0, 0, 0);
172 ; }
173 define dso_local i32 @test_varargs_vla(i32 %a, ...) local_unnamed_addr  {
174 entry:
175   %ap = alloca %struct.__va_list, align 4
176   %vla = alloca i32, i32 %a, align 4
177   call void @llvm.va_start(ptr nonnull %ap)
178   %call = call i32 @g(ptr nonnull %vla, i32 %a, i32 0, i32 0, i32 0, i32 0)
179   ret i32 %call
181 ; CHECK-LABEL: test_varargs_vla
182 ; Three incoming register varargs
183 ; CHECK:       sub sp, #12
184 ; Setup frame pointer
185 ; CHECK-ATPCS: add r7, sp, #8
186 ; CHECK-AAPCS: mov r11, sp
187 ; Register varargs stored via FP
188 ; CHECK-ATPCS-DAG:  str r3, [r7, #16]
189 ; CHECK-ATPCS-DAG:  str r2, [r7, #12]
190 ; CHECK-ATPCS-DAG:  str r1, [r7, #8]
191 ; CHECK-AAPCS-DAG:  mov r5, r11
192 ; CHECK-AAPCS-DAG:  str r1, [r5, #8]
193 ; CHECK-AAPCS-DAG:  mov r1, r11
194 ; CHECK-AAPCS-DAG:  str r3, [r1, #16]
195 ; CHECK-AAPCS-DAG:  mov r1, r11
196 ; CHECK-AAPCS-DAG:  str r2, [r1, #12]
198 ; Moving SP, access via SP
199 ; int test_args_moving_sp(int a, int b, int c, int d, int e) {
200 ;   int v[4];
201 ;   return f(v, a, b + c + d, e, s) + h(v, v+1, v+2);
202 ; }
203 define dso_local i32 @test_args_moving_sp(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e) local_unnamed_addr  {
204 entry:
205   %v = alloca [4 x i32], align 4
206   %add = add nsw i32 %c, %b
207   %add1 = add nsw i32 %add, %d
208   %call = call i32 @f(ptr nonnull %v, i32 %a, i32 %add1, i32 %e, ptr byval(%struct.S) nonnull align 4 @s)
209   %add.ptr = getelementptr inbounds [4 x i32], ptr %v, i32 0, i32 1
210   %add.ptr5 = getelementptr inbounds [4 x i32], ptr %v, i32 0, i32 2
211   %call6 = call i32 @h(ptr nonnull %v, ptr nonnull %add.ptr, ptr nonnull %add.ptr5)
212   %add7 = add nsw i32 %call6, %call
213   ret i32 %add7
215 ; CHECK-LABEL: test_args_moving_sp
216 ; 20 bytes callee-saved area without FP
217 ; CHECK-NOFP: push {r4, r5, r6, r7, lr}
218 ; 20 bytes callee-saved area for ATPCS
219 ; CHECK-FP-ATPCS: push {r4, r5, r6, r7, lr}
220 ; 24 bytes callee-saved area for AAPCS as codegen prefers an even number of GPRs spilled
221 ; CHECK-FP-AAPCS: push {lr}
222 ; CHECK-FP-AAPCS: mov lr, r11
223 ; CHECK-FP-AAPCS: push {lr}
224 ; CHECK-FP-AAPCS: push {r4, r5, r6, r7}
225 ; 20 bytes locals without FP
226 ; CHECK-NOFP:       sub sp, #20
227 ; 28 bytes locals with FP for ATPCS
228 ; CHECK-FP-ATPCS:       sub sp, #28
229 ; 24 bytes locals with FP for AAPCS
230 ; CHECK-FP-AAPCS:       sub sp, #24
231 ; Setup base pointer
232 ; CHECK:       mov r6, sp
233 ; Allocate outgoing arguments space
234 ; CHECK:       sub sp, #508
235 ; CHECK:       sub sp, #4
236 ; Load `e` via BP if FP is not present (40 = 20 + 20)
237 ; CHECK-NOFP:  ldr r3, [r6, #40]
238 ; Load `e` via FP otherwise
239 ; CHECK-FP-ATPCS: ldr r3, [r7, #8]
240 ; CHECK-FP-AAPCS: mov r0, r11
241 ; CHECK-FP-AAPCS: ldr r3, [r0, #8]
242 ; CHECK:       bl  f
243 ; Stack restored before next call
244 ; CHECK-NEXT:  add sp, #508
245 ; CHECK-NEXT:  add sp, #4
246 ; CHECK:       bl  h
248 ; int test_varargs_moving_sp(int a, ...) {
249 ;   int v[4];
250 ;   __builtin_va_list ap;
251 ;   __builtin_va_start(ap, a);
252 ;   return f(v, a, 0, 0, s) + h(v, v+1, v+2);
253 ; }
254 define dso_local i32 @test_varargs_moving_sp(i32 %a, ...) local_unnamed_addr  {
255 entry:
256   %v = alloca [4 x i32], align 4
257   %ap = alloca %struct.__va_list, align 4
258   call void @llvm.va_start(ptr nonnull %ap)
259   %call = call i32 @f(ptr nonnull %v, i32 %a, i32 0, i32 0, ptr byval(%struct.S) nonnull align 4 @s)
260   %add.ptr = getelementptr inbounds [4 x i32], ptr %v, i32 0, i32 1
261   %add.ptr5 = getelementptr inbounds [4 x i32], ptr %v, i32 0, i32 2
262   %call6 = call i32 @h(ptr nonnull %v, ptr nonnull %add.ptr, ptr nonnull %add.ptr5)
263   %add = add nsw i32 %call6, %call
264   ret i32 %add
266 ; CHECK-LABEL: test_varargs_moving_sp
267 ; Three incoming register varargs
268 ; CHECK:       sub sp, #12
269 ; 16 bytes callee-saves without FP
270 ; CHECK-NOFP: push {r4, r5, r6, lr}
271 ; 24 bytes callee-saves with FP
272 ; CHECK-FP-ATPCS: push {r4, r5, r6, r7, lr}
273 ; CHECK-FP-AAPCS: push {lr}
274 ; CHECK-FP-AAPCS: mov lr, r11
275 ; CHECK-FP-AAPCS: push {lr}
276 ; CHECK-FP-AAPCS: push {r4, r5, r6, r7}
277 ; Locals area
278 ; CHECK-NOFP:       sub sp, #20
279 ; CHECK-FP-ATPCS:   sub sp, #24
280 ; CHECK-FP-AAPCS:   sub sp, #20
281 ; Incoming varargs stored via BP if FP is not present (36 = 20 + 16)
282 ; CHECK-NOFP:      mov r0, r6
283 ; CHECK-NOFP-NEXT: adds r0, #36
284 ; CHECK-NOFP-NEXT: stm r0!, {r1, r2, r3}
285 ; Incoming varargs stored via FP otherwise
286 ; CHECK-FP-ATPCS:      mov r0, r7
287 ; CHECK-FP-ATPCS-NEXT: adds r0, #8
288 ; CHECK-FP-ATPCS-NEXT: stm r0!, {r1, r2, r3}
289 ; CHECK-FP-AAPCS:      mov r0, r11
290 ; CHECK-FP-AAPCS-NEXT: mov r5, r0
291 ; CHECK-FP-AAPCS-NEXT: adds r5, #8
292 ; CHECK-FP-AAPCS-NEXT: stm r5!, {r1, r2, r3}
294 ; struct S { int x[128]; } s;
295 ; int test(S a, int b) {
296 ;   return i(b);
297 ; }
298 define dso_local i32 @test_args_large_offset(ptr byval(%struct.S) align 4 %0, i32 %1) local_unnamed_addr {
299   %3 = alloca i32, align 4
300   store i32 %1, ptr %3, align 4
301   %4 = load i32, ptr %3, align 4
302   %5 = call i32 @i(i32 %4)
303   ret i32 %5
305 ; CHECK-LABEL: test_args_large_offset
306 ; Without FP: Access to large offset is made using SP
307 ; CHECK-NOFP:     ldr r0, [sp, #520]
308 ; With FP: Access to large offset is made through a const pool using FP
309 ; CHECK-FP:       ldr r0, .LCPI0_0
310 ; CHECK-FP-ATPCS: ldr r0, [r0, r7]
311 ; CHECK-FP-AAPCS: add r0, r11
312 ; CHECK-FP-AAPCS: ldr r0, [r0]
313 ; CHECK: bl i
316 ; Access to locals
319 ; Usual case, access via SP.
320 ; int test_local(int n) {
321 ;   int v[4];
322 ;   int x, y, z;
323 ;   h(&x, &y, &z);
324 ;   return g(v, x, y, z, 0, 0);
325 ; }
326 define dso_local i32 @test_local(i32 %n) local_unnamed_addr  {
327 entry:
328   %v = alloca [4 x i32], align 4
329   %x = alloca i32, align 4
330   %y = alloca i32, align 4
331   %z = alloca i32, align 4
332   %call = call i32 @h(ptr nonnull %x, ptr nonnull %y, ptr nonnull %z)
333   %0 = load i32, ptr %x, align 4
334   %1 = load i32, ptr %y, align 4
335   %2 = load i32, ptr %z, align 4
336   %call1 = call i32 @g(ptr nonnull %v, i32 %0, i32 %1, i32 %2, i32 0, i32 0)
337   ret i32 %call1
339 ; CHECK-LABEL: test_local
340 ; Arguments to `h` relative to SP
341 ; CHECK:       add r0, sp, #20
342 ; CHECK-NEXT:  add r1, sp, #16
343 ; CHECK-NEXT:  add r2, sp, #12
344 ; CHECK-NEXT:  bl  h
345 ; Load `x`, `y`, and `z` via SP
346 ; CHECK:       ldr r1, [sp, #20]
347 ; CHECK-NEXT:  ldr r2, [sp, #16]
348 ; CHECK-NEXT:  ldr r3, [sp, #12]
349 ; CHECK:       bl  g
351 ; Re-aligned stack, access via SP.
352 ; int test_local_realign(int n) {
353 ;   __attribute__((aligned(16))) int v[4];
354 ;   int x, y, z;
355 ;   h(&x, &y, &z);
356 ;   return g(v, x, y, z, 0, 0);
357 ; }
358 define dso_local i32 @test_local_realign(i32 %n) local_unnamed_addr  {
359 entry:
360   %v = alloca [4 x i32], align 16
361   %x = alloca i32, align 4
362   %y = alloca i32, align 4
363   %z = alloca i32, align 4
364   %call = call i32 @h(ptr nonnull %x, ptr nonnull %y, ptr nonnull %z)
365   %0 = load i32, ptr %x, align 4
366   %1 = load i32, ptr %y, align 4
367   %2 = load i32, ptr %z, align 4
368   %call1 = call i32 @g(ptr nonnull %v, i32 %0, i32 %1, i32 %2, i32 0, i32 0)
369   ret i32 %call1
371 ; CHECK-LABEL: test_local_realign
372 ; Setup frame pointer
373 ; CHECK-ATPCS: add r7, sp, #8
374 ; CHECK-AAPCS: mov r11, sp
375 ; Re-align stack
376 ; CHECK:       mov r4, sp
377 ; CHECK-NEXT:  lsrs r4, r4, #4
378 ; CHECK-NEXT:  lsls r4, r4, #4
379 ; CHECK-NEXT:  mov  sp, r4
380 ; Arguments to `h` computed relative to SP
381 ; CHECK:       add r0, sp, #28
382 ; CHECK-NEXT:  add r1, sp, #24
383 ; CHECK-NEXT:  add r2, sp, #20
384 ; CHECK-NEXT:  bl  h
385 ; Load `x`, `y`, and `z` via SP for passing to `g`
386 ; CHECK:       ldr r1, [sp, #28]
387 ; CHECK-NEXT:  ldr r2, [sp, #24]
388 ; CHECK-NEXT:  ldr r3, [sp, #20]
389 ; CHECK:       bl  g
391 ; VLAs, access via BP.
392 ; int test_local_vla(int n) {
393 ;   int v[n];
394 ;   int x, y, z;
395 ;   h(&x, &y, &z);
396 ;   return g(v, x, y, z, 0, 0);
397 ; }
398 define dso_local i32 @test_local_vla(i32 %n) local_unnamed_addr  {
399 entry:
400   %x = alloca i32, align 4
401   %y = alloca i32, align 4
402   %z = alloca i32, align 4
403   %vla = alloca i32, i32 %n, align 4
404   %call = call i32 @h(ptr nonnull %x, ptr nonnull %y, ptr nonnull %z)
405   %0 = load i32, ptr %x, align 4
406   %1 = load i32, ptr %y, align 4
407   %2 = load i32, ptr %z, align 4
408   %call1 = call i32 @g(ptr nonnull %vla, i32 %0, i32 %1, i32 %2, i32 0, i32 0)
409   ret i32 %call1
411 ; CHECK-LABEL: test_local_vla
412 ; Setup frame pointer
413 ; CHECK-ATPCS: add r7, sp, #12
414 ; CHECK-AAPCS: mov r11, sp
415 ; Locas area
416 ; CHECK-ATPCS: sub sp, #12
417 ; CHECK-AAPCS: sub sp, #16
418 ; Setup base pointer
419 ; CHECK:       mov  r6, sp
420 ; CHECK-ATPCS: mov  r5, r6
421 ; CHECK-AAPCS: adds  r5, r6, #4
422 ; Arguments to `h` compute relative to BP
423 ; CHECK:       adds r0, r6, #7
424 ; CHECK-ATPCS-NEXT:  adds r0, #1
425 ; CHECK-ATPCS-NEXT:  adds r1, r6, #4
426 ; CHECK-ATPCS-NEXT:  mov  r2, r6
427 ; CHECK-AAPCS-NEXT:  adds r0, #5
428 ; CHECK-AAPCS-NEXT:  adds r1, r6, #7
429 ; CHECK-AAPCS-NEXT:  adds r1, #1
430 ; CHECK-AAPCS-NEXT:  adds r2, r6, #4
431 ; CHECK-NEXT:  bl   h
432 ; Load `x`, `y`, `z` via BP (r5 should still have the value of r6 from the move
433 ; above)
434 ; CHECK:       ldr r3, [r5]
435 ; CHECK-NEXT:  ldr r2, [r5, #4]
436 ; CHECK-NEXT:  ldr r1, [r5, #8]
437 ; CHECK:       bl  g
439 ;  Moving SP, access via SP.
440 ; int test_local_moving_sp(int n) {
441 ;   int v[4];
442 ;   int x, y, z;
443 ;   return u(v, &x, &y, s, s) + u(v, &y, &z, s, s);
444 ; }
445 define dso_local i32 @test_local_moving_sp(i32 %n) local_unnamed_addr {
446 entry:
447   %v = alloca [4 x i32], align 4
448   %x = alloca i32, align 4
449   %y = alloca i32, align 4
450   %z = alloca i32, align 4
451   %call = call i32 @u(ptr nonnull %v, ptr nonnull %x, ptr nonnull %y, ptr byval(%struct.S) nonnull align 4 @s, ptr byval(%struct.S) nonnull align 4 @s)
452   %call2 = call i32 @u(ptr nonnull %v, ptr nonnull %y, ptr nonnull %z, ptr byval(%struct.S) nonnull align 4 @s, ptr byval(%struct.S) nonnull align 4 @s)
453   %add = add nsw i32 %call2, %call
454   ret i32 %add
456 ; CHECK-LABEL: test_local_moving_sp
457 ; Locals area
458 ; CHECK-NOFP: sub sp, #36
459 ; CHECK-FP-ATPCS: sub sp, #44
460 ; CHECK-FP-AAPCS: sub sp, #40
461 ; Setup BP
462 ; CHECK:      mov r6, sp
463 ; Outoging arguments
464 ; CHECK:      sub sp, #508
465 ; CHECK-NEXT: sub sp, #508
466 ; CHECK-NEXT: sub sp, #8
467 ; Argument addresses computed relative to BP
468 ; CHECK-NOFP:      adds r4, r6, #7
469 ; CHECK-NOFP-NEXT: adds r4, #13
470 ; CHECK-NOFP:      adds r1, r6, #7
471 ; CHECK-NOFP-NEXT: adds r1, #9
472 ; CHECK-NOFP:      adds r5, r6, #7
473 ; CHECK-NOFP-NEXT: adds r5, #5
474 ; CHECK-FP-ATPCS:      adds r0, r6, #7
475 ; CHECK-FP-ATPCS-NEXT: adds r0, #21
476 ; CHECK-FP-ATPCS:      adds r1, r6, #7
477 ; CHECK-FP-ATPCS-NEXT: adds r1, #17
478 ; CHECK-FP-ATPCS:      adds r5, r6, #7
479 ; CHECK-FP-ATPCS-NEXT: adds r5, #13
480 ; CHECK-FP-AAPCS:      adds r4, r6, #7
481 ; CHECK-FP-AAPCS-NEXT: adds r4, #17
482 ; CHECK-FP-AAPCS:      adds r1, r6, #7
483 ; CHECK-FP-AAPCS-NEXT: adds r1, #13
484 ; CHECK-FP-AAPCS:      adds r5, r6, #7
485 ; CHECK-FP-AAPCS-NEXT: adds r5, #9
486 ; CHECK:      bl   u
487 ; Stack restored before next call
488 ; CHECK:      add  sp, #508
489 ; CHECK-NEXT: add  sp, #508
490 ; CHECK-NEXT: add  sp, #8
491 ; CHECK:      bl   u