1; RUN: llc -verify-machineinstrs -mtriple=aarch64-none-linux-gnu < %s | FileCheck %s
2
3; This test aims to check basic correctness of frame layout &
4; frame access code. There are 8 functions in this test file,
5; each function implements one element in the cartesian product
6; of:
7; . a function having a VLA/noVLA
8; . a function with dynamic stack realignment/no dynamic stack realignment.
9; . a function needing a frame pionter/no frame pointer,
10; since the presence/absence of these has influence on the frame
11; layout and which pointer to use to access various part of the
12; frame (bp,sp,fp).
13;
14; Furthermore: in every test function:
15; . there is always one integer and 1 floating point argument to be able
16;   to check those are accessed correctly.
17; . there is always one local variable to check that is accessed
18;   correctly
19;
20; The LLVM-IR below was produced by clang on the following C++ code:
21;extern "C" int g();
22;extern "C" int novla_nodynamicrealign_call(int i1, int i2, int i3, int i4, int i5, int i6, int i7, int i8, int i9, int i10,
23;                                             double d1, double d2, double d3, double d4, double d5, double d6, double d7, double d8, double d9, double d10)
24;{
25;  // use an argument passed on the stack.
26;  volatile int l1;
27;  return i10 + (int)d10 + l1 + g();
28;}
29;extern "C" int novla_nodynamicrealign_nocall(int i1, int i2, int i3, int i4, int i5, int i6, int i7, int i8, int i9, int i10,
30;                                             double d1, double d2, double d3, double d4, double d5, double d6, double d7, double d8, double d9, double d10)
31;{
32;  // use an argument passed on the stack.
33;  volatile int l1;
34;  return i10 + (int)d10 + l1;
35;}
36;extern "C" int novla_dynamicrealign_call(int i1, int i2, int i3, int i4, int i5, int i6, int i7, int i8, int i9, int i10,
37;                                         double d1, double d2, double d3, double d4, double d5, double d6, double d7, double d8, double d9, double d10)
38;{
39;  // use an argument passed on the stack.
40;  alignas(128) volatile int l1;
41;  return i10 + (int)d10 + l1 + g();
42;}
43;extern "C" int novla_dynamicrealign_nocall(int i1, int i2, int i3, int i4, int i5, int i6, int i7, int i8, int i9, int i10,
44;                                           double d1, double d2, double d3, double d4, double d5, double d6, double d7, double d8, double d9, double d10)
45;{
46;  // use an argument passed on the stack.
47;  alignas(128) volatile int l1;
48;  return i10 + (int)d10 + l1;
49;}
50;
51;extern "C" int vla_nodynamicrealign_call(int i1, int i2, int i3, int i4, int i5, int i6, int i7, int i8, int i9, int i10,
52;                                         double d1, double d2, double d3, double d4, double d5, double d6, double d7, double d8, double d9, double d10)
53;{
54;  // use an argument passed on the stack.
55;  volatile int l1;
56;  volatile int vla[i1];
57;  return i10 + (int)d10 + l1 + g() + vla[0];
58;}
59;extern "C" int vla_nodynamicrealign_nocall(int i1, int i2, int i3, int i4, int i5, int i6, int i7, int i8, int i9, int i10,
60;                                           double d1, double d2, double d3, double d4, double d5, double d6, double d7, double d8, double d9, double d10)
61;{
62;  // use an argument passed on the stack.
63;  volatile int l1;
64;  volatile int vla[i1];
65;  return i10 + (int)d10 + l1 + vla[0];
66;}
67;extern "C" int vla_dynamicrealign_call(int i1, int i2, int i3, int i4, int i5, int i6, int i7, int i8, int i9, int i10,
68;                                       double d1, double d2, double d3, double d4, double d5, double d6, double d7, double d8, double d9, double d10)
69;{
70;  // use an argument passed on the stack.
71;  alignas(128) volatile int l1;
72;  volatile int vla[i1];
73;  return i10 + (int)d10 + l1 + g() + vla[0];
74;}
75;extern "C" int vla_dynamicrealign_nocall(int i1, int i2, int i3, int i4, int i5, int i6, int i7, int i8, int i9, int i10,
76;                                         double d1, double d2, double d3, double d4, double d5, double d6, double d7, double d8, double d9, double d10)
77;{
78;  // use an argument passed on the stack.
79;  alignas(128) volatile int l1;
80;  volatile int vla[i1];
81;  return i10 + (int)d10 + l1 + vla[0];
82;}
83
84
85
86define i32 @novla_nodynamicrealign_call(i32 %i1, i32 %i2, i32 %i3, i32 %i4, i32 %i5, i32 %i6, i32 %i7, i32 %i8, i32 %i9, i32 %i10, double %d1, double %d2, double %d3, double %d4, double %d5, double %d6, double %d7, double %d8, double %d9, double %d10) #0 {
87entry:
88  %l1 = alloca i32, align 4
89  %conv = fptosi double %d10 to i32
90  %add = add nsw i32 %conv, %i10
91  %l1.0.l1.0. = load volatile i32, i32* %l1, align 4
92  %add1 = add nsw i32 %add, %l1.0.l1.0.
93  %call = tail call i32 @g()
94  %add2 = add nsw i32 %add1, %call
95  ret i32 %add2
96}
97; CHECK-LABEL: novla_nodynamicrealign_call
98; CHECK: .cfi_startproc
99;   Check that used callee-saved registers are saved
100; CHECK: stp	x20, x19, [sp, #-32]!
101;   Check that the frame pointer is created:
102; CHECK: stp	x29, x30, [sp, #16]
103; CHECK: add	x29, sp, #16
104;   Check correctness of cfi pseudo-instructions
105; CHECK: .cfi_def_cfa w29, 16
106; CHECK: .cfi_offset w30, -8
107; CHECK: .cfi_offset w29, -16
108; CHECK: .cfi_offset w19, -24
109; CHECK: .cfi_offset w20, -32
110;   Check correct access to arguments passed on the stack, through frame pointer
111; CHECK: ldr	d[[DARG:[0-9]+]], [x29, #40]
112; CHECK: ldr	w[[IARG:[0-9]+]], [x29, #24]
113;   Check correct access to local variable on the stack, through stack pointer
114; CHECK: ldr	w[[ILOC:[0-9]+]], [sp, #12]
115;   Check epilogue:
116; CHECK: ldp	x29, x30, [sp, #16]
117; CHECK: ldp	x20, x19, [sp], #32
118; CHECK: ret
119; CHECK: .cfi_endproc
120
121
122declare i32 @g() #0
123
124; Function Attrs: nounwind
125define i32 @novla_nodynamicrealign_nocall(i32 %i1, i32 %i2, i32 %i3, i32 %i4, i32 %i5, i32 %i6, i32 %i7, i32 %i8, i32 %i9, i32 %i10, double %d1, double %d2, double %d3, double %d4, double %d5, double %d6, double %d7, double %d8, double %d9, double %d10) #1 {
126entry:
127  %l1 = alloca i32, align 4
128  %conv = fptosi double %d10 to i32
129  %add = add nsw i32 %conv, %i10
130  %l1.0.l1.0. = load volatile i32, i32* %l1, align 4
131  %add1 = add nsw i32 %add, %l1.0.l1.0.
132  ret i32 %add1
133}
134; CHECK-LABEL: novla_nodynamicrealign_nocall
135;   Check that space is reserved for one local variable on the stack.
136; CHECK:	sub	sp, sp, #16             // =16
137;   Check correct access to arguments passed on the stack, through stack pointer
138; CHECK: ldr	d[[DARG:[0-9]+]], [sp, #40]
139; CHECK: ldr	w[[IARG:[0-9]+]], [sp, #24]
140;   Check correct access to local variable on the stack, through stack pointer
141; CHECK: ldr	w[[ILOC:[0-9]+]], [sp, #12]
142;   Check epilogue:
143; CHECK: add	sp, sp, #16             // =16
144; CHECK: ret
145
146
147define i32 @novla_dynamicrealign_call(i32 %i1, i32 %i2, i32 %i3, i32 %i4, i32 %i5, i32 %i6, i32 %i7, i32 %i8, i32 %i9, i32 %i10, double %d1, double %d2, double %d3, double %d4, double %d5, double %d6, double %d7, double %d8, double %d9, double %d10) #0 {
148entry:
149  %l1 = alloca i32, align 128
150  %conv = fptosi double %d10 to i32
151  %add = add nsw i32 %conv, %i10
152  %l1.0.l1.0. = load volatile i32, i32* %l1, align 128
153  %add1 = add nsw i32 %add, %l1.0.l1.0.
154  %call = tail call i32 @g()
155  %add2 = add nsw i32 %add1, %call
156  ret i32 %add2
157}
158
159; CHECK-LABEL: novla_dynamicrealign_call
160; CHECK: .cfi_startproc
161;   Check that used callee-saved registers are saved
162; CHECK: stp	x20, x19, [sp, #-32]!
163;   Check that the frame pointer is created:
164; CHECK: stp	x29, x30, [sp, #16]
165; CHECK: add	x29, sp, #16
166;   Check the dynamic realignment of the stack pointer to a 128-byte boundary
167; CHECK: sub	x9, sp, #96
168; CHECK: and	sp, x9, #0xffffffffffffff80
169;   Check correctness of cfi pseudo-instructions
170; CHECK: .cfi_def_cfa w29, 16
171; CHECK: .cfi_offset w30, -8
172; CHECK: .cfi_offset w29, -16
173; CHECK: .cfi_offset w19, -24
174; CHECK: .cfi_offset w20, -32
175;   Check correct access to arguments passed on the stack, through frame pointer
176; CHECK: ldr	d[[DARG:[0-9]+]], [x29, #40]
177; CHECK: ldr	w[[IARG:[0-9]+]], [x29, #24]
178;   Check correct access to local variable on the stack, through re-aligned stack pointer
179; CHECK: ldr	w[[ILOC:[0-9]+]], [sp]
180;   Check epilogue:
181;     Check that stack pointer get restored from frame pointer.
182; CHECK: sub	sp, x29, #16            // =16
183; CHECK: ldp	x29, x30, [sp, #16]
184; CHECK: ldp	x20, x19, [sp], #32
185; CHECK: ret
186; CHECK: .cfi_endproc
187
188
189; Function Attrs: nounwind
190define i32 @novla_dynamicrealign_nocall(i32 %i1, i32 %i2, i32 %i3, i32 %i4, i32 %i5, i32 %i6, i32 %i7, i32 %i8, i32 %i9, i32 %i10, double %d1, double %d2, double %d3, double %d4, double %d5, double %d6, double %d7, double %d8, double %d9, double %d10) #1 {
191entry:
192  %l1 = alloca i32, align 128
193  %conv = fptosi double %d10 to i32
194  %add = add nsw i32 %conv, %i10
195  %l1.0.l1.0. = load volatile i32, i32* %l1, align 128
196  %add1 = add nsw i32 %add, %l1.0.l1.0.
197  ret i32 %add1
198}
199
200; CHECK-LABEL: novla_dynamicrealign_nocall
201;   Check that the frame pointer is created:
202; CHECK: stp	x29, x30, [sp, #-16]!
203; CHECK: mov	x29, sp
204;   Check the dynamic realignment of the stack pointer to a 128-byte boundary
205; CHECK: sub	x9, sp, #112
206; CHECK: and	sp, x9, #0xffffffffffffff80
207;   Check correct access to arguments passed on the stack, through frame pointer
208; CHECK: ldr	d[[DARG:[0-9]+]], [x29, #40]
209; CHECK: ldr	w[[IARG:[0-9]+]], [x29, #24]
210;   Check correct access to local variable on the stack, through re-aligned stack pointer
211; CHECK: ldr	w[[ILOC:[0-9]+]], [sp]
212;   Check epilogue:
213;     Check that stack pointer get restored from frame pointer.
214; CHECK: mov	sp, x29
215; CHECK: ldp	x29, x30, [sp], #16
216; CHECK: ret
217
218
219define i32 @vla_nodynamicrealign_call(i32 %i1, i32 %i2, i32 %i3, i32 %i4, i32 %i5, i32 %i6, i32 %i7, i32 %i8, i32 %i9, i32 %i10, double %d1, double %d2, double %d3, double %d4, double %d5, double %d6, double %d7, double %d8, double %d9, double %d10) #0 {
220entry:
221  %l1 = alloca i32, align 4
222  %0 = zext i32 %i1 to i64
223  %vla = alloca i32, i64 %0, align 4
224  %conv = fptosi double %d10 to i32
225  %add = add nsw i32 %conv, %i10
226  %l1.0.l1.0. = load volatile i32, i32* %l1, align 4
227  %add1 = add nsw i32 %add, %l1.0.l1.0.
228  %call = tail call i32 @g()
229  %add2 = add nsw i32 %add1, %call
230  %1 = load volatile i32, i32* %vla, align 4, !tbaa !1
231  %add3 = add nsw i32 %add2, %1
232  ret i32 %add3
233}
234
235; CHECK-LABEL: vla_nodynamicrealign_call
236; CHECK: .cfi_startproc
237;   Check that used callee-saved registers are saved
238; CHECK: stp	x20, x19, [sp, #-32]!
239;   Check that the frame pointer is created:
240; CHECK: stp	x29, x30, [sp, #16]
241; CHECK: add	x29, sp, #16
242;   Check that space is reserved on the stack for the local variable,
243;   rounded up to a multiple of 16 to keep the stack pointer 16-byte aligned.
244; CHECK: sub	sp, sp, #16
245;   Check correctness of cfi pseudo-instructions
246; CHECK: .cfi_def_cfa w29, 16
247; CHECK: .cfi_offset w30, -8
248; CHECK: .cfi_offset w29, -16
249; CHECK: .cfi_offset w19, -24
250; CHECK: .cfi_offset w20, -32
251;   Check correct access to arguments passed on the stack, through frame pointer
252; CHECK: ldr	w[[IARG:[0-9]+]], [x29, #24]
253; CHECK: ldr	d[[DARG:[0-9]+]], [x29, #40]
254;   Check correct reservation of 16-byte aligned VLA (size in w0) on stack
255; CHECK: ubfx	x9, x0, #0, #32
256; CHECK: lsl	x9, x9, #2
257; CHECK: add	x9, x9, #15
258; CHECK: and	x9, x9, #0xfffffffffffffff0
259; CHECK: mov	 x10, sp
260; CHECK: sub	 x[[VLASPTMP:[0-9]+]], x10, x9
261; CHECK: mov	 sp, x[[VLASPTMP]]
262;   Check correct access to local variable, through frame pointer
263; CHECK: ldur	w[[ILOC:[0-9]+]], [x29, #-20]
264;   Check correct accessing of the VLA variable through the base pointer
265; CHECK: ldr	w[[VLA:[0-9]+]], [x[[VLASPTMP]]]
266;   Check epilogue:
267;     Check that stack pointer get restored from frame pointer.
268; CHECK: sub	sp, x29, #16            // =16
269; CHECK: ldp	x29, x30, [sp, #16]
270; CHECK: ldp	x20, x19, [sp], #32
271; CHECK: ret
272; CHECK: .cfi_endproc
273
274
275; Function Attrs: nounwind
276define i32 @vla_nodynamicrealign_nocall(i32 %i1, i32 %i2, i32 %i3, i32 %i4, i32 %i5, i32 %i6, i32 %i7, i32 %i8, i32 %i9, i32 %i10, double %d1, double %d2, double %d3, double %d4, double %d5, double %d6, double %d7, double %d8, double %d9, double %d10) #1 {
277entry:
278  %l1 = alloca i32, align 4
279  %0 = zext i32 %i1 to i64
280  %vla = alloca i32, i64 %0, align 4
281  %conv = fptosi double %d10 to i32
282  %add = add nsw i32 %conv, %i10
283  %l1.0.l1.0. = load volatile i32, i32* %l1, align 4
284  %add1 = add nsw i32 %add, %l1.0.l1.0.
285  %1 = load volatile i32, i32* %vla, align 4, !tbaa !1
286  %add2 = add nsw i32 %add1, %1
287  ret i32 %add2
288}
289
290; CHECK-LABEL: vla_nodynamicrealign_nocall
291;   Check that the frame pointer is created:
292; CHECK: stp	x29, x30, [sp, #-16]!
293; CHECK: mov	x29, sp
294;   Check that space is reserved on the stack for the local variable,
295;   rounded up to a multiple of 16 to keep the stack pointer 16-byte aligned.
296; CHECK: sub	sp, sp, #16
297;   Check correctness of cfi pseudo-instructions
298;   Check correct access to arguments passed on the stack, through frame pointer
299; CHECK: ldr	w[[IARG:[0-9]+]], [x29, #24]
300; CHECK: ldr	d[[DARG:[0-9]+]], [x29, #40]
301;   Check correct reservation of 16-byte aligned VLA (size in w0) on stack
302; CHECK: ubfx	x9, x0, #0, #32
303; CHECK: lsl	x9, x9, #2
304; CHECK: add	x9, x9, #15
305; CHECK: and	x9, x9, #0xfffffffffffffff0
306; CHECK: mov	 x10, sp
307; CHECK: sub	 x[[VLASPTMP:[0-9]+]], x10, x9
308; CHECK: mov	 sp, x[[VLASPTMP]]
309;   Check correct access to local variable, through frame pointer
310; CHECK: ldur	w[[ILOC:[0-9]+]], [x29, #-4]
311;   Check correct accessing of the VLA variable through the base pointer
312; CHECK: ldr	w[[VLA:[0-9]+]], [x[[VLASPTMP]]]
313;   Check epilogue:
314;     Check that stack pointer get restored from frame pointer.
315; CHECK: mov    sp, x29
316; CHECK: ldp	x29, x30, [sp], #16
317; CHECK: ret
318
319
320define i32 @vla_dynamicrealign_call(i32 %i1, i32 %i2, i32 %i3, i32 %i4, i32 %i5, i32 %i6, i32 %i7, i32 %i8, i32 %i9, i32 %i10, double %d1, double %d2, double %d3, double %d4, double %d5, double %d6, double %d7, double %d8, double %d9, double %d10) #0 {
321entry:
322  %l1 = alloca i32, align 128
323  %0 = zext i32 %i1 to i64
324  %vla = alloca i32, i64 %0, align 4
325  %conv = fptosi double %d10 to i32
326  %add = add nsw i32 %conv, %i10
327  %l1.0.l1.0. = load volatile i32, i32* %l1, align 128
328  %add1 = add nsw i32 %add, %l1.0.l1.0.
329  %call = tail call i32 @g()
330  %add2 = add nsw i32 %add1, %call
331  %1 = load volatile i32, i32* %vla, align 4, !tbaa !1
332  %add3 = add nsw i32 %add2, %1
333  ret i32 %add3
334}
335
336; CHECK-LABEL: vla_dynamicrealign_call
337; CHECK: .cfi_startproc
338;   Check that used callee-saved registers are saved
339; CHECK: stp	x22, x21, [sp, #-48]!
340; CHECK: stp	x20, x19, [sp, #16]
341;   Check that the frame pointer is created:
342; CHECK: stp	x29, x30, [sp, #32]
343; CHECK: add	x29, sp, #32
344;   Check that the stack pointer gets re-aligned to 128
345;   bytes & the base pointer (x19) gets initialized to
346;   this 128-byte aligned area for local variables &
347;   spill slots
348; CHECK: sub	x9, sp, #80            // =80
349; CHECK: and	sp, x9, #0xffffffffffffff80
350; CHECK: mov    x19, sp
351;   Check correctness of cfi pseudo-instructions
352; CHECK: .cfi_def_cfa w29, 16
353; CHECK: .cfi_offset w30, -8
354; CHECK: .cfi_offset w29, -16
355; CHECK: .cfi_offset w19, -24
356; CHECK: .cfi_offset w20, -32
357; CHECK: .cfi_offset w21, -40
358; CHECK: .cfi_offset w22, -48
359;   Check correct access to arguments passed on the stack, through frame pointer
360; CHECK: ldr	w[[IARG:[0-9]+]], [x29, #24]
361; CHECK: ldr	d[[DARG:[0-9]+]], [x29, #40]
362;   Check correct reservation of 16-byte aligned VLA (size in w0) on stack
363;   and set-up of base pointer (x19).
364; CHECK: ubfx	x9, x0, #0, #32
365; CHECK: lsl	x9, x9, #2
366; CHECK: add	x9, x9, #15
367; CHECK: and	x9, x9, #0xfffffffffffffff0
368; CHECK: mov	 x10, sp
369; CHECK: sub	 x[[VLASPTMP:[0-9]+]], x10, x9
370; CHECK: mov	 sp, x[[VLASPTMP]]
371;   Check correct access to local variable, through base pointer
372; CHECK: ldr	w[[ILOC:[0-9]+]], [x19]
373; CHECK: ldr	 w[[VLA:[0-9]+]], [x[[VLASPTMP]]]
374;   Check epilogue:
375;     Check that stack pointer get restored from frame pointer.
376; CHECK: sub	sp, x29, #32
377; CHECK: ldp	x29, x30, [sp, #32]
378; CHECK: ldp	x20, x19, [sp, #16]
379; CHECK: ldp	x22, x21, [sp], #48
380; CHECK: ret
381; CHECK: .cfi_endproc
382
383
384; Function Attrs: nounwind
385define i32 @vla_dynamicrealign_nocall(i32 %i1, i32 %i2, i32 %i3, i32 %i4, i32 %i5, i32 %i6, i32 %i7, i32 %i8, i32 %i9, i32 %i10, double %d1, double %d2, double %d3, double %d4, double %d5, double %d6, double %d7, double %d8, double %d9, double %d10) #1 {
386entry:
387  %l1 = alloca i32, align 128
388  %0 = zext i32 %i1 to i64
389  %vla = alloca i32, i64 %0, align 4
390  %conv = fptosi double %d10 to i32
391  %add = add nsw i32 %conv, %i10
392  %l1.0.l1.0. = load volatile i32, i32* %l1, align 128
393  %add1 = add nsw i32 %add, %l1.0.l1.0.
394  %1 = load volatile i32, i32* %vla, align 4, !tbaa !1
395  %add2 = add nsw i32 %add1, %1
396  ret i32 %add2
397}
398
399; CHECK-LABEL: vla_dynamicrealign_nocall
400;   Check that used callee-saved registers are saved
401; CHECK: stp	x20, x19, [sp, #-32]!
402;   Check that the frame pointer is created:
403; CHECK: stp	x29, x30, [sp, #16]
404; CHECK: add	x29, sp, #16
405;   Check that the stack pointer gets re-aligned to 128
406;   bytes & the base pointer (x19) gets initialized to
407;   this 128-byte aligned area for local variables &
408;   spill slots
409; CHECK: sub	x9, sp, #96
410; CHECK: and	sp, x9, #0xffffffffffffff80
411; CHECK: mov    x19, sp
412;   Check correct access to arguments passed on the stack, through frame pointer
413; CHECK: ldr	w[[IARG:[0-9]+]], [x29, #24]
414; CHECK: ldr	d[[DARG:[0-9]+]], [x29, #40]
415;   Check correct reservation of 16-byte aligned VLA (size in w0) on stack
416;   and set-up of base pointer (x19).
417; CHECK: ubfx	x9, x0, #0, #32
418; CHECK: lsl	x9, x9, #2
419; CHECK: add	x9, x9, #15
420; CHECK: and	x9, x9, #0xfffffffffffffff0
421; CHECK: mov	 x10, sp
422; CHECK: sub	 x[[VLASPTMP:[0-9]+]], x10, x9
423; CHECK: mov	 sp, x[[VLASPTMP]]
424;   Check correct access to local variable, through base pointer
425; CHECK: ldr	w[[ILOC:[0-9]+]], [x19]
426; CHECK: ldr	 w[[VLA:[0-9]+]], [x[[VLASPTMP]]]
427;   Check epilogue:
428;     Check that stack pointer get restored from frame pointer.
429; CHECK: sub	sp, x29, #16
430; CHECK: ldp	x29, x30, [sp, #16]
431; CHECK: ldp	x20, x19, [sp], #32
432; CHECK: ret
433
434
435; Function Attrs: nounwind
436define i32 @vla_dynamicrealign_nocall_large_align(i32 %i1, i32 %i2, i32 %i3, i32 %i4, i32 %i5, i32 %i6, i32 %i7, i32 %i8, i32 %i9, i32 %i10, double %d1, double %d2, double %d3, double %d4, double %d5, double %d6, double %d7, double %d8, double %d9, double %d10) #1 {
437entry:
438  %l1 = alloca i32, align 32768
439  %0 = zext i32 %i1 to i64
440  %vla = alloca i32, i64 %0, align 4
441  %conv = fptosi double %d10 to i32
442  %add = add nsw i32 %conv, %i10
443  %l1.0.l1.0. = load volatile i32, i32* %l1, align 32768
444  %add1 = add nsw i32 %add, %l1.0.l1.0.
445  %1 = load volatile i32, i32* %vla, align 4, !tbaa !1
446  %add2 = add nsw i32 %add1, %1
447  ret i32 %add2
448}
449
450; CHECK-LABEL: vla_dynamicrealign_nocall_large_align
451;   Check that used callee-saved registers are saved
452; CHECK: stp	x20, x19, [sp, #-32]!
453;   Check that the frame pointer is created:
454; CHECK: stp	x29, x30, [sp, #16]
455; CHECK: add	x29, sp, #16
456;   Check that the stack pointer gets re-aligned to 128
457;   bytes & the base pointer (x19) gets initialized to
458;   this 128-byte aligned area for local variables &
459;   spill slots
460; CHECK: sub	x9, sp, #7, lsl #12
461; CHECK: and	sp, x9, #0xffffffffffff8000
462; CHECK: mov    x19, sp
463;   Check correct access to arguments passed on the stack, through frame pointer
464; CHECK: ldr	w[[IARG:[0-9]+]], [x29, #24]
465; CHECK: ldr	d[[DARG:[0-9]+]], [x29, #40]
466;   Check correct reservation of 16-byte aligned VLA (size in w0) on stack
467;   and set-up of base pointer (x19).
468; CHECK: ubfx	x9, x0, #0, #32
469; CHECK: lsl	x9, x9, #2
470; CHECK: add	x9, x9, #15
471; CHECK: and	x9, x9, #0xfffffffffffffff0
472; CHECK: mov	 x10, sp
473; CHECK: sub	 x[[VLASPTMP:[0-9]+]], x10, x9
474; CHECK: mov	 sp, x[[VLASPTMP]]
475;   Check correct access to local variable, through base pointer
476; CHECK: ldr	w[[ILOC:[0-9]+]], [x19]
477; CHECK: ldr	 w[[VLA:[0-9]+]], [x[[VLASPTMP]]]
478;   Check epilogue:
479;     Check that stack pointer get restored from frame pointer.
480; CHECK: sub	sp, x29, #16
481; CHECK: ldp	x29, x30, [sp, #16]
482; CHECK: ldp	x20, x19, [sp], #32
483; CHECK: ret
484
485attributes #0 = { "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
486attributes #1 = { nounwind "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
487
488!1 = !{!2, !2, i64 0}
489!2 = !{!"int", !3, i64 0}
490!3 = !{!"omnipotent char", !4, i64 0}
491!4 = !{!"Simple C/C++ TBAA"}
492