xref: /llvm-project/llvm/test/CodeGen/Thumb/frame-access.ll (revision 1a5239251ead73ee57f4e2f7fc93433ac7cf18b1)
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
5
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);
11
12%struct.S = type { [128 x i32] }
13%struct.__va_list = type { ptr }
14
15@s = common dso_local global %struct.S zeroinitializer, align 4
16
17declare void @llvm.va_start(ptr)
18declare dso_local i32 @i(i32) local_unnamed_addr
19declare dso_local i32 @g(ptr, i32, i32, i32, i32, i32) local_unnamed_addr
20declare dso_local i32 @f(ptr, i32, i32, i32, ptr byval(%struct.S) align 4) local_unnamed_addr
21declare dso_local i32 @h(ptr, ptr, ptr) local_unnamed_addr
22declare dso_local i32 @u(ptr, ptr, ptr, ptr byval(%struct.S) align 4, ptr byval(%struct.S) align 4) local_unnamed_addr
23
24;
25; Test access to arguments, passed on stack (including varargs)
26;
27
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; }
33define dso_local i32 @test_args_sp(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e) local_unnamed_addr {
34entry:
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
38}
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
49
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; }
56define dso_local i32 @test_varargs_sp(i32 %a, ...) local_unnamed_addr  {
57entry:
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
63}
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
84define dso_local i32 @test_args_realign(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e) local_unnamed_addr  {
85entry:
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
89}
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
107
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; }
114define dso_local i32 @test_varargs_realign(i32 %a, ...) local_unnamed_addr  {
115entry:
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
121}
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; }
146define dso_local i32 @test_args_vla(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e) local_unnamed_addr  {
147entry:
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
151}
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
166
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; }
173define dso_local i32 @test_varargs_vla(i32 %a, ...) local_unnamed_addr  {
174entry:
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
180}
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]
197
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; }
203define dso_local i32 @test_args_moving_sp(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e) local_unnamed_addr  {
204entry:
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
214}
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
247
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; }
254define dso_local i32 @test_varargs_moving_sp(i32 %a, ...) local_unnamed_addr  {
255entry:
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
265}
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}
293
294; struct S { int x[128]; } s;
295; int test(S a, int b) {
296;   return i(b);
297; }
298define 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
304}
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
314
315;
316; Access to locals
317;
318
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; }
326define dso_local i32 @test_local(i32 %n) local_unnamed_addr  {
327entry:
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
338}
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
350
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; }
358define dso_local i32 @test_local_realign(i32 %n) local_unnamed_addr  {
359entry:
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
370}
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
390
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; }
398define dso_local i32 @test_local_vla(i32 %n) local_unnamed_addr  {
399entry:
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
410}
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
438
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; }
445define dso_local i32 @test_local_moving_sp(i32 %n) local_unnamed_addr {
446entry:
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
455}
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
492