; RUN: llc -verify-machineinstrs -mtriple=aarch64-none-linux-gnu -disable-post-ra < %s | FileCheck %s ; RUN: llc -verify-machineinstrs -mtriple=arm64-apple-ios -frame-pointer=all -disable-post-ra < %s | FileCheck %s --check-prefix=CHECK-MACHO ; This test aims to check basic correctness of frame layout & ; frame access code. There are 8 functions in this test file, ; each function implements one element in the cartesian product ; of: ; . a function having a VLA/noVLA ; . a function with dynamic stack realignment/no dynamic stack realignment. ; . a function needing a frame pionter/no frame pointer, ; since the presence/absence of these has influence on the frame ; layout and which pointer to use to access various part of the ; frame (bp,sp,fp). ; ; Furthermore: in every test function: ; . there is always one integer and 1 floating point argument to be able ; to check those are accessed correctly. ; . there is always one local variable to check that is accessed ; correctly ; ; The LLVM-IR below was produced by clang on the following C++ code: ;extern "C" int g(); ;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, ; double d1, double d2, double d3, double d4, double d5, double d6, double d7, double d8, double d9, double d10) ;{ ; // use an argument passed on the stack. ; volatile int l1; ; return i10 + (int)d10 + l1 + g(); ;} ;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, ; double d1, double d2, double d3, double d4, double d5, double d6, double d7, double d8, double d9, double d10) ;{ ; // use an argument passed on the stack. ; volatile int l1; ; return i10 + (int)d10 + l1; ;} ;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, ; double d1, double d2, double d3, double d4, double d5, double d6, double d7, double d8, double d9, double d10) ;{ ; // use an argument passed on the stack. ; alignas(128) volatile int l1; ; return i10 + (int)d10 + l1 + g(); ;} ;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, ; double d1, double d2, double d3, double d4, double d5, double d6, double d7, double d8, double d9, double d10) ;{ ; // use an argument passed on the stack. ; alignas(128) volatile int l1; ; return i10 + (int)d10 + l1; ;} ; ;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, ; double d1, double d2, double d3, double d4, double d5, double d6, double d7, double d8, double d9, double d10) ;{ ; // use an argument passed on the stack. ; volatile int l1; ; volatile int vla[i1]; ; return i10 + (int)d10 + l1 + g() + vla[0]; ;} ;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, ; double d1, double d2, double d3, double d4, double d5, double d6, double d7, double d8, double d9, double d10) ;{ ; // use an argument passed on the stack. ; volatile int l1; ; volatile int vla[i1]; ; return i10 + (int)d10 + l1 + vla[0]; ;} ;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, ; double d1, double d2, double d3, double d4, double d5, double d6, double d7, double d8, double d9, double d10) ;{ ; // use an argument passed on the stack. ; alignas(128) volatile int l1; ; volatile int vla[i1]; ; return i10 + (int)d10 + l1 + g() + vla[0]; ;} ;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, ; double d1, double d2, double d3, double d4, double d5, double d6, double d7, double d8, double d9, double d10) ;{ ; // use an argument passed on the stack. ; alignas(128) volatile int l1; ; volatile int vla[i1]; ; return i10 + (int)d10 + l1 + vla[0]; ;} define 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 { entry: %l1 = alloca i32, align 4 %conv = fptosi double %d10 to i32 %add = add nsw i32 %conv, %i10 %l1.0.l1.0. = load volatile i32, i32* %l1, align 4 %add1 = add nsw i32 %add, %l1.0.l1.0. %call = tail call i32 @g() %add2 = add nsw i32 %add1, %call ret i32 %add2 } ; CHECK-LABEL: novla_nodynamicrealign_call ; CHECK: .cfi_startproc ; Check that used callee-saved registers are saved ; CHECK: sub sp, sp, #32 ; CHECK: stp x30, x19, [sp, #16] ; Check correctness of cfi pseudo-instructions ; CHECK: .cfi_def_cfa_offset 32 ; CHECK: .cfi_offset w19, -8 ; CHECK: .cfi_offset w30, -16 ; Check correct access to arguments passed on the stack, through stack pointer ; CHECK: ldr d[[DARG:[0-9]+]], [sp, #56] ; CHECK: ldr w[[IARG:[0-9]+]], [sp, #40] ; Check correct access to local variable on the stack, through stack pointer ; CHECK: ldr w[[ILOC:[0-9]+]], [sp, #12] ; Check epilogue: ; CHECK: ldp x30, x19, [sp, #16] ; CHECK: ret ; CHECK: .cfi_endproc ; CHECK-MACHO-LABEL: _novla_nodynamicrealign_call: ; CHECK-MACHO: .cfi_startproc ; Check that used callee-saved registers are saved ; CHECK-MACHO: sub sp, sp, #48 ; CHECK-MACHO: stp x20, x19, [sp, #16] ; Check that the frame pointer is created: ; CHECK-MACHO: stp x29, x30, [sp, #32] ; CHECK-MACHO: add x29, sp, #32 ; Check correctness of cfi pseudo-instructions ; CHECK-MACHO: .cfi_def_cfa w29, 16 ; CHECK-MACHO: .cfi_offset w30, -8 ; CHECK-MACHO: .cfi_offset w29, -16 ; CHECK-MACHO: .cfi_offset w19, -24 ; CHECK-MACHO: .cfi_offset w20, -32 ; Check correct access to arguments passed on the stack, through frame pointer ; CHECK-MACHO: ldr d[[DARG:[0-9]+]], [x29, #32] ; CHECK-MACHO: ldr w[[IARG:[0-9]+]], [x29, #20] ; Check correct access to local variable on the stack, through stack pointer ; CHECK-MACHO: ldr w[[ILOC:[0-9]+]], [sp, #12] ; Check epilogue: ; CHECK-MACHO: ldp x29, x30, [sp, #32] ; CHECK-MACHO: ldp x20, x19, [sp, #16] ; CHECK-MACHO: ret ; CHECK-MACHO: .cfi_endproc declare i32 @g() #0 ; Function Attrs: nounwind define 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 { entry: %l1 = alloca i32, align 4 %conv = fptosi double %d10 to i32 %add = add nsw i32 %conv, %i10 %l1.0.l1.0. = load volatile i32, i32* %l1, align 4 %add1 = add nsw i32 %add, %l1.0.l1.0. ret i32 %add1 } ; CHECK-LABEL: novla_nodynamicrealign_nocall ; Check that space is reserved for one local variable on the stack. ; CHECK: sub sp, sp, #16 // =16 ; Check correct access to arguments passed on the stack, through stack pointer ; CHECK: ldr d[[DARG:[0-9]+]], [sp, #40] ; CHECK: ldr w[[IARG:[0-9]+]], [sp, #24] ; Check correct access to local variable on the stack, through stack pointer ; CHECK: ldr w[[ILOC:[0-9]+]], [sp, #12] ; Check epilogue: ; CHECK: add sp, sp, #16 // =16 ; CHECK: ret define 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 { entry: %l1 = alloca i32, align 128 %conv = fptosi double %d10 to i32 %add = add nsw i32 %conv, %i10 %l1.0.l1.0. = load volatile i32, i32* %l1, align 128 %add1 = add nsw i32 %add, %l1.0.l1.0. %call = tail call i32 @g() %add2 = add nsw i32 %add1, %call ret i32 %add2 } ; CHECK-LABEL: novla_dynamicrealign_call ; CHECK: .cfi_startproc ; Check that used callee-saved registers are saved ; CHECK: stp x29, x30, [sp, #-32]! ; Check that the frame pointer is created: ; CHECK: str x19, [sp, #16] ; CHECK: mov x29, sp ; Check the dynamic realignment of the stack pointer to a 128-byte boundary ; CHECK: sub x9, sp, #96 ; CHECK: and sp, x9, #0xffffffffffffff80 ; Check correctness of cfi pseudo-instructions ; CHECK: .cfi_def_cfa w29, 32 ; CHECK: .cfi_offset w19, -16 ; CHECK: .cfi_offset w30, -24 ; CHECK: .cfi_offset w29, -32 ; Check correct access to arguments passed on the stack, through frame pointer ; CHECK: ldr d[[DARG:[0-9]+]], [x29, #56] ; CHECK: ldr w[[IARG:[0-9]+]], [x29, #40] ; Check correct access to local variable on the stack, through re-aligned stack pointer ; CHECK: ldr w[[ILOC:[0-9]+]], [sp] ; Check epilogue: ; Check that stack pointer get restored from frame pointer. ; CHECK: mov sp, x29 ; CHECK: ldr x19, [sp, #16] ; CHECK: ldp x29, x30, [sp], #32 ; CHECK: ret ; CHECK: .cfi_endproc ; CHECK-MACHO-LABEL: _novla_dynamicrealign_call: ; CHECK-MACHO: .cfi_startproc ; Check that used callee-saved registers are saved ; CHECK-MACHO: stp x20, x19, [sp, #-32]! ; Check that the frame pointer is created: ; CHECK-MACHO: stp x29, x30, [sp, #16] ; CHECK-MACHO: add x29, sp, #16 ; Check the dynamic realignment of the stack pointer to a 128-byte boundary ; CHECK-MACHO: sub x9, sp, #96 ; CHECK-MACHO: and sp, x9, #0xffffffffffffff80 ; Check correctness of cfi pseudo-instructions ; CHECK-MACHO: .cfi_def_cfa w29, 16 ; CHECK-MACHO: .cfi_offset w30, -8 ; CHECK-MACHO: .cfi_offset w29, -16 ; CHECK-MACHO: .cfi_offset w19, -24 ; CHECK-MACHO: .cfi_offset w20, -32 ; Check correct access to arguments passed on the stack, through frame pointer ; CHECK-MACHO: ldr d[[DARG:[0-9]+]], [x29, #32] ; CHECK-MACHO: ldr w[[IARG:[0-9]+]], [x29, #20] ; Check correct access to local variable on the stack, through re-aligned stack pointer ; CHECK-MACHO: ldr w[[ILOC:[0-9]+]], [sp] ; Check epilogue: ; Check that stack pointer get restored from frame pointer. ; CHECK-MACHO: sub sp, x29, #16 ; CHECK-MACHO: ldp x29, x30, [sp, #16] ; CHECK-MACHO: ldp x20, x19, [sp], #32 ; CHECK-MACHO: ret ; CHECK-MACHO: .cfi_endproc ; Function Attrs: nounwind define 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 { entry: %l1 = alloca i32, align 128 %conv = fptosi double %d10 to i32 %add = add nsw i32 %conv, %i10 %l1.0.l1.0. = load volatile i32, i32* %l1, align 128 %add1 = add nsw i32 %add, %l1.0.l1.0. ret i32 %add1 } ; CHECK-LABEL: novla_dynamicrealign_nocall ; Check that the frame pointer is created: ; CHECK: stp x29, x30, [sp, #-16]! ; CHECK: mov x29, sp ; Check the dynamic realignment of the stack pointer to a 128-byte boundary ; CHECK: sub x9, sp, #112 ; CHECK: and sp, x9, #0xffffffffffffff80 ; Check correct access to arguments passed on the stack, through frame pointer ; CHECK: ldr d[[DARG:[0-9]+]], [x29, #40] ; CHECK: ldr w[[IARG:[0-9]+]], [x29, #24] ; Check correct access to local variable on the stack, through re-aligned stack pointer ; CHECK: ldr w[[ILOC:[0-9]+]], [sp] ; Check epilogue: ; Check that stack pointer get restored from frame pointer. ; CHECK: mov sp, x29 ; CHECK: ldp x29, x30, [sp], #16 ; CHECK: ret define 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 { entry: %l1 = alloca i32, align 4 %0 = zext i32 %i1 to i64 %vla = alloca i32, i64 %0, align 4 %conv = fptosi double %d10 to i32 %add = add nsw i32 %conv, %i10 %l1.0.l1.0. = load volatile i32, i32* %l1, align 4 %add1 = add nsw i32 %add, %l1.0.l1.0. %call = tail call i32 @g() %add2 = add nsw i32 %add1, %call %1 = load volatile i32, i32* %vla, align 4, !tbaa !1 %add3 = add nsw i32 %add2, %1 ret i32 %add3 } ; CHECK-LABEL: vla_nodynamicrealign_call ; CHECK: .cfi_startproc ; Check that used callee-saved registers are saved ; CHECK: stp x29, x30, [sp, #-32]! ; Check that the frame pointer is created: ; CHECK: stp x20, x19, [sp, #16] ; CHECK: mov x29, sp ; Check that space is reserved on the stack for the local variable, ; rounded up to a multiple of 16 to keep the stack pointer 16-byte aligned. ; CHECK: sub sp, sp, #16 ; Check correctness of cfi pseudo-instructions ; CHECK: .cfi_def_cfa w29, 32 ; CHECK: .cfi_offset w19, -8 ; CHECK: .cfi_offset w20, -16 ; CHECK: .cfi_offset w30, -24 ; CHECK: .cfi_offset w29, -32 ; Check correct access to arguments passed on the stack, through frame pointer ; CHECK: ldr w[[IARG:[0-9]+]], [x29, #40] ; CHECK: ldr d[[DARG:[0-9]+]], [x29, #56] ; Check correct reservation of 16-byte aligned VLA (size in w0) on stack ; CHECK: mov w9, w0 ; CHECK: mov x10, sp ; CHECK: lsl x9, x9, #2 ; CHECK: add x9, x9, #15 ; CHECK: and x9, x9, #0x7fffffff0 ; CHECK: sub x[[VLASPTMP:[0-9]+]], x10, x9 ; CHECK: mov sp, x[[VLASPTMP]] ; Check correct access to local variable, through frame pointer ; CHECK: ldur w[[ILOC:[0-9]+]], [x29, #-4] ; Check correct accessing of the VLA variable through the base pointer ; CHECK: ldr w[[VLA:[0-9]+]], [x[[VLASPTMP]]] ; Check epilogue: ; Check that stack pointer get restored from frame pointer. ; CHECK: mov sp, x29 ; CHECK: ldp x20, x19, [sp, #16] ; CHECK: ldp x29, x30, [sp], #32 ; CHECK: ret ; CHECK: .cfi_endproc ; Function Attrs: nounwind define 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 { entry: %l1 = alloca i32, align 4 %0 = zext i32 %i1 to i64 %vla = alloca i32, i64 %0, align 4 %conv = fptosi double %d10 to i32 %add = add nsw i32 %conv, %i10 %l1.0.l1.0. = load volatile i32, i32* %l1, align 4 %add1 = add nsw i32 %add, %l1.0.l1.0. %1 = load volatile i32, i32* %vla, align 4, !tbaa !1 %add2 = add nsw i32 %add1, %1 ret i32 %add2 } ; CHECK-LABEL: vla_nodynamicrealign_nocall ; Check that the frame pointer is created: ; CHECK: stp x29, x30, [sp, #-16]! ; CHECK: mov x29, sp ; Check that space is reserved on the stack for the local variable, ; rounded up to a multiple of 16 to keep the stack pointer 16-byte aligned. ; CHECK: sub sp, sp, #16 ; Check correctness of cfi pseudo-instructions ; Check correct access to arguments passed on the stack, through frame pointer ; CHECK: ldr w[[IARG:[0-9]+]], [x29, #24] ; CHECK: ldr d[[DARG:[0-9]+]], [x29, #40] ; Check correct reservation of 16-byte aligned VLA (size in w0) on stack ; CHECK: mov w9, w0 ; CHECK: mov x10, sp ; CHECK: lsl x9, x9, #2 ; CHECK: add x9, x9, #15 ; CHECK: and x9, x9, #0x7fffffff0 ; CHECK: sub x[[VLASPTMP:[0-9]+]], x10, x9 ; CHECK: mov sp, x[[VLASPTMP]] ; Check correct access to local variable, through frame pointer ; CHECK: ldur w[[ILOC:[0-9]+]], [x29, #-4] ; Check correct accessing of the VLA variable through the base pointer ; CHECK: ldr w[[VLA:[0-9]+]], [x[[VLASPTMP]]] ; Check epilogue: ; Check that stack pointer get restored from frame pointer. ; CHECK: mov sp, x29 ; CHECK: ldp x29, x30, [sp], #16 ; CHECK: ret define 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 { entry: %l1 = alloca i32, align 128 %0 = zext i32 %i1 to i64 %vla = alloca i32, i64 %0, align 4 %conv = fptosi double %d10 to i32 %add = add nsw i32 %conv, %i10 %l1.0.l1.0. = load volatile i32, i32* %l1, align 128 %add1 = add nsw i32 %add, %l1.0.l1.0. %call = tail call i32 @g() %add2 = add nsw i32 %add1, %call %1 = load volatile i32, i32* %vla, align 4, !tbaa !1 %add3 = add nsw i32 %add2, %1 ret i32 %add3 } ; CHECK-LABEL: vla_dynamicrealign_call ; CHECK: .cfi_startproc ; Check that used callee-saved registers are saved ; CHECK: stp x29, x30, [sp, #-48]! ; CHECK: str x21, [sp, #16] ; CHECK: stp x20, x19, [sp, #32] ; Check that the frame pointer is created: ; CHECK: mov x29, sp ; Check that the stack pointer gets re-aligned to 128 ; bytes & the base pointer (x19) gets initialized to ; this 128-byte aligned area for local variables & ; spill slots ; CHECK: sub x9, sp, #80 // =80 ; CHECK: and sp, x9, #0xffffffffffffff80 ; CHECK: mov x19, sp ; Check correctness of cfi pseudo-instructions ; CHECK: .cfi_def_cfa w29, 48 ; CHECK: .cfi_offset w19, -8 ; CHECK: .cfi_offset w20, -16 ; CHECK: .cfi_offset w21, -32 ; CHECK: .cfi_offset w30, -40 ; CHECK: .cfi_offset w29, -48 ; Check correct access to arguments passed on the stack, through frame pointer ; CHECK: ldr w[[IARG:[0-9]+]], [x29, #56] ; CHECK: ldr d[[DARG:[0-9]+]], [x29, #72] ; Check correct reservation of 16-byte aligned VLA (size in w0) on stack ; and set-up of base pointer (x19). ; CHECK: mov w9, w0 ; CHECK: mov x10, sp ; CHECK: lsl x9, x9, #2 ; CHECK: add x9, x9, #15 ; CHECK: and x9, x9, #0x7fffffff0 ; CHECK: sub x[[VLASPTMP:[0-9]+]], x10, x9 ; CHECK: mov sp, x[[VLASPTMP]] ; Check correct access to local variable, through base pointer ; CHECK: ldr w[[ILOC:[0-9]+]], [x19] ; CHECK: ldr w[[VLA:[0-9]+]], [x[[VLASPTMP]]] ; Check epilogue: ; Check that stack pointer get restored from frame pointer. ; CHECK: mov sp, x29 ; CHECK: ldp x20, x19, [sp, #32] ; CHECK: ldr x21, [sp, #16] ; CHECK: ldp x29, x30, [sp], #48 ; CHECK: ret ; CHECK: .cfi_endproc ; CHECK-MACHO-LABEL: _vla_dynamicrealign_call: ; CHECK-MACHO: .cfi_startproc ; Check that used callee-saved registers are saved ; CHECK-MACHO: stp x22, x21, [sp, #-48]! ; CHECK-MACHO: stp x20, x19, [sp, #16] ; Check that the frame pointer is created: ; CHECK-MACHO: stp x29, x30, [sp, #32] ; CHECK-MACHO: add x29, sp, #32 ; Check that the stack pointer gets re-aligned to 128 ; bytes & the base pointer (x19) gets initialized to ; this 128-byte aligned area for local variables & ; spill slots ; CHECK-MACHO: sub x9, sp, #80 ; CHECK-MACHO: and sp, x9, #0xffffffffffffff80 ; CHECK-MACHO: mov x19, sp ; Check correctness of cfi pseudo-instructions ; CHECK-MACHO: .cfi_def_cfa w29, 16 ; CHECK-MACHO: .cfi_offset w30, -8 ; CHECK-MACHO: .cfi_offset w29, -16 ; CHECK-MACHO: .cfi_offset w19, -24 ; CHECK-MACHO: .cfi_offset w20, -32 ; CHECK-MACHO: .cfi_offset w21, -40 ; CHECK-MACHO: .cfi_offset w22, -48 ; Check correct access to arguments passed on the stack, through frame pointer ; CHECK-MACHO: ldr w[[IARG:[0-9]+]], [x29, #20] ; CHECK-MACHO: ldr d[[DARG:[0-9]+]], [x29, #32] ; Check correct reservation of 16-byte aligned VLA (size in w0) on stack ; and set-up of base pointer (x19). ; CHECK-MACHO: mov w9, w0 ; CHECK-MACHO: mov x10, sp ; CHECK-MACHO: lsl x9, x9, #2 ; CHECK-MACHO: add x9, x9, #15 ; CHECK-MACHO: and x9, x9, #0x7fffffff0 ; CHECK-MACHO: sub x[[VLASPTMP:[0-9]+]], x10, x9 ; CHECK-MACHO: mov sp, x[[VLASPTMP]] ; Check correct access to local variable, through base pointer ; CHECK-MACHO: ldr w[[ILOC:[0-9]+]], [x19] ; CHECK-MACHO: ldr w[[VLA:[0-9]+]], [x[[VLASPTMP]]] ; Check epilogue: ; Check that stack pointer get restored from frame pointer. ; CHECK-MACHO: sub sp, x29, #32 ; CHECK-MACHO: ldp x29, x30, [sp, #32] ; CHECK-MACHO: ldp x20, x19, [sp, #16] ; CHECK-MACHO: ldp x22, x21, [sp], #48 ; CHECK-MACHO: ret ; CHECK-MACHO: .cfi_endproc ; Function Attrs: nounwind define 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 { entry: %l1 = alloca i32, align 128 %0 = zext i32 %i1 to i64 %vla = alloca i32, i64 %0, align 4 %conv = fptosi double %d10 to i32 %add = add nsw i32 %conv, %i10 %l1.0.l1.0. = load volatile i32, i32* %l1, align 128 %add1 = add nsw i32 %add, %l1.0.l1.0. %1 = load volatile i32, i32* %vla, align 4, !tbaa !1 %add2 = add nsw i32 %add1, %1 ret i32 %add2 } ; CHECK-LABEL: vla_dynamicrealign_nocall ; Check that used callee-saved registers are saved ; CHECK: stp x29, x30, [sp, #-32]! ; CHECK: str x19, [sp, #16] ; Check that the frame pointer is created: ; CHECK: mov x29, sp ; Check that the stack pointer gets re-aligned to 128 ; bytes & the base pointer (x19) gets initialized to ; this 128-byte aligned area for local variables & ; spill slots ; CHECK: sub x9, sp, #96 ; CHECK: and sp, x9, #0xffffffffffffff80 ; CHECK: mov x19, sp ; Check correct access to arguments passed on the stack, through frame pointer ; CHECK: ldr w[[IARG:[0-9]+]], [x29, #40] ; CHECK: ldr d[[DARG:[0-9]+]], [x29, #56] ; Check correct reservation of 16-byte aligned VLA (size in w0) on stack ; and set-up of base pointer (x19). ; CHECK: mov w9, w0 ; CHECK: mov x10, sp ; CHECK: lsl x9, x9, #2 ; CHECK: add x9, x9, #15 ; CHECK: and x9, x9, #0x7fffffff0 ; CHECK: sub x[[VLASPTMP:[0-9]+]], x10, x9 ; CHECK: mov sp, x[[VLASPTMP]] ; Check correct access to local variable, through base pointer ; CHECK: ldr w[[ILOC:[0-9]+]], [x19] ; CHECK: ldr w[[VLA:[0-9]+]], [x[[VLASPTMP]]] ; Check epilogue: ; Check that stack pointer get restored from frame pointer. ; CHECK: mov sp, x29 ; CHECK: ldr x19, [sp, #16] ; CHECK: ldp x29, x30, [sp], #32 ; CHECK: ret ; CHECK-MACHO-LABEL: _vla_dynamicrealign_nocall: ; Check that used callee-saved registers are saved ; CHECK-MACHO: stp x20, x19, [sp, #-32]! ; Check that the frame pointer is created: ; CHECK-MACHO: stp x29, x30, [sp, #16] ; CHECK-MACHO: add x29, sp, #16 ; Check that the stack pointer gets re-aligned to 128 ; bytes & the base pointer (x19) gets initialized to ; this 128-byte aligned area for local variables & ; spill slots ; CHECK-MACHO: sub x9, sp, #96 ; CHECK-MACHO: and sp, x9, #0xffffffffffffff80 ; CHECK-MACHO: mov x19, sp ; Check correct access to arguments passed on the stack, through frame pointer ; CHECK-MACHO: ldr w[[IARG:[0-9]+]], [x29, #20] ; CHECK-MACHO: ldr d[[DARG:[0-9]+]], [x29, #32] ; Check correct reservation of 16-byte aligned VLA (size in w0) on stack ; and set-up of base pointer (x19). ; CHECK-MACHO: mov w9, w0 ; CHECK-MACHO: mov x10, sp ; CHECK-MACHO: lsl x9, x9, #2 ; CHECK-MACHO: add x9, x9, #15 ; CHECK-MACHO: and x9, x9, #0x7fffffff0 ; CHECK-MACHO: sub x[[VLASPTMP:[0-9]+]], x10, x9 ; CHECK-MACHO: mov sp, x[[VLASPTMP]] ; Check correct access to local variable, through base pointer ; CHECK-MACHO: ldr w[[ILOC:[0-9]+]], [x19] ; CHECK-MACHO: ldr w[[VLA:[0-9]+]], [x[[VLASPTMP]]] ; Check epilogue: ; Check that stack pointer get restored from frame pointer. ; CHECK-MACHO: sub sp, x29, #16 ; CHECK-MACHO: ldp x29, x30, [sp, #16] ; CHECK-MACHO: ldp x20, x19, [sp], #32 ; CHECK-MACHO: ret ; Function Attrs: nounwind define 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 { entry: %l1 = alloca i32, align 32768 %0 = zext i32 %i1 to i64 %vla = alloca i32, i64 %0, align 4 %conv = fptosi double %d10 to i32 %add = add nsw i32 %conv, %i10 %l1.0.l1.0. = load volatile i32, i32* %l1, align 32768 %add1 = add nsw i32 %add, %l1.0.l1.0. %1 = load volatile i32, i32* %vla, align 4, !tbaa !1 %add2 = add nsw i32 %add1, %1 ret i32 %add2 } ; CHECK-LABEL: vla_dynamicrealign_nocall_large_align ; Check that used callee-saved registers are saved ; CHECK: stp x29, x30, [sp, #-32]! ; CHECK: str x19, [sp, #16] ; Check that the frame pointer is created: ; CHECK: mov x29, sp ; Check that the stack pointer gets re-aligned to 128 ; bytes & the base pointer (x19) gets initialized to ; this 128-byte aligned area for local variables & ; spill slots ; CHECK: sub x9, sp, #7, lsl #12 ; CHECK: and sp, x9, #0xffffffffffff8000 ; CHECK: mov x19, sp ; Check correct access to arguments passed on the stack, through frame pointer ; CHECK: ldr w[[IARG:[0-9]+]], [x29, #40] ; CHECK: ldr d[[DARG:[0-9]+]], [x29, #56] ; Check correct reservation of 16-byte aligned VLA (size in w0) on stack ; and set-up of base pointer (x19). ; CHECK: mov w9, w0 ; CHECK: mov x10, sp ; CHECK: lsl x9, x9, #2 ; CHECK: add x9, x9, #15 ; CHECK: and x9, x9, #0x7fffffff0 ; CHECK: sub x[[VLASPTMP:[0-9]+]], x10, x9 ; CHECK: mov sp, x[[VLASPTMP]] ; Check correct access to local variable, through base pointer ; CHECK: ldr w[[ILOC:[0-9]+]], [x19] ; CHECK: ldr w[[VLA:[0-9]+]], [x[[VLASPTMP]]] ; Check epilogue: ; Check that stack pointer get restored from frame pointer. ; CHECK: mov sp, x29 ; CHECK: ldr x19, [sp, #16] ; CHECK: ldp x29, x30, [sp], #32 ; CHECK: ret ; CHECK-MACHO-LABEL: _vla_dynamicrealign_nocall_large_align: ; Check that used callee-saved registers are saved ; CHECK-MACHO: stp x20, x19, [sp, #-32]! ; Check that the frame pointer is created: ; CHECK-MACHO: stp x29, x30, [sp, #16] ; CHECK-MACHO: add x29, sp, #16 ; Check that the stack pointer gets re-aligned to 128 ; bytes & the base pointer (x19) gets initialized to ; this 128-byte aligned area for local variables & ; spill slots ; CHECK-MACHO: sub x9, sp, #7, lsl #12 ; CHECK-MACHO: and sp, x9, #0xffffffffffff8000 ; CHECK-MACHO: mov x19, sp ; Check correct access to arguments passed on the stack, through frame pointer ; CHECK-MACHO: ldr w[[IARG:[0-9]+]], [x29, #20] ; CHECK-MACHO: ldr d[[DARG:[0-9]+]], [x29, #32] ; Check correct reservation of 16-byte aligned VLA (size in w0) on stack ; and set-up of base pointer (x19). ; CHECK-MACHO: mov w9, w0 ; CHECK-MACHO: mov x10, sp ; CHECK-MACHO: lsl x9, x9, #2 ; CHECK-MACHO: add x9, x9, #15 ; CHECK-MACHO: and x9, x9, #0x7fffffff0 ; CHECK-MACHO: sub x[[VLASPTMP:[0-9]+]], x10, x9 ; CHECK-MACHO: mov sp, x[[VLASPTMP]] ; Check correct access to local variable, through base pointer ; CHECK-MACHO: ldr w[[ILOC:[0-9]+]], [x19] ; CHECK-MACHO: ldr w[[VLA:[0-9]+]], [x[[VLASPTMP]]] ; Check epilogue: ; Check that stack pointer get restored from frame pointer. ; CHECK-MACHO: sub sp, x29, #16 ; CHECK-MACHO: ldp x29, x30, [sp, #16] ; CHECK-MACHO: ldp x20, x19, [sp], #32 ; CHECK-MACHO: ret define void @realign_conditional(i1 %b) { entry: br i1 %b, label %bb0, label %bb1 bb0: %MyAlloca = alloca i8, i64 64, align 32 br label %bb1 bb1: ret void } ; CHECK-LABEL: realign_conditional ; No realignment in the prologue. ; CHECK-NOT: and ; CHECK-NOT: 0xffffffffffffffe0 ; CHECK: tbz {{.*}} .[[LABEL:.*]] ; Stack is realigned in a non-entry BB. ; CHECK: sub [[REG:x[01-9]+]], sp, #64 ; CHECK: and sp, [[REG]], #0xffffffffffffffe0 ; CHECK: .[[LABEL]]: ; CHECK: ret define void @realign_conditional2(i1 %b) { entry: %tmp = alloca i8, i32 16 br i1 %b, label %bb0, label %bb1 bb0: %MyAlloca = alloca i8, i64 64, align 32 br label %bb1 bb1: ret void } ; CHECK-LABEL: realign_conditional2 ; Extra realignment in the prologue (performance issue). ; CHECK: tbz {{.*}} .[[LABEL:.*]] ; CHECK: sub x9, sp, #32 // =32 ; CHECK: and sp, x9, #0xffffffffffffffe0 ; CHECK: mov x19, sp ; Stack is realigned in a non-entry BB. ; CHECK: sub [[REG:x[01-9]+]], sp, #64 ; CHECK: and sp, [[REG]], #0xffffffffffffffe0 ; CHECK: .[[LABEL]]: ; CHECK: ret attributes #0 = { "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } !1 = !{!2, !2, i64 0} !2 = !{!"int", !3, i64 0} !3 = !{!"omnipotent char", !4, i64 0} !4 = !{!"Simple C/C++ TBAA"}