| ; RUN: llc -verify-machineinstrs -mtriple=aarch64-none-linux-gnu -disable-post-ra < %s | FileCheck %s | |
| ; RUN: llc -verify-machineinstrs -mtriple=arm64-apple-ios -disable-fp-elim -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 x19, x30, [sp, #16] | |
| ; Check correctness of cfi pseudo-instructions | |
| ; CHECK: .cfi_def_cfa_offset 32 | |
| ; CHECK: .cfi_offset w30, -8 | |
| ; CHECK: .cfi_offset w19, -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 x19, x30, [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: str x19, [sp, #-32]! | |
| ; Check that the frame pointer is created: | |
| ; CHECK: stp x29, x30, [sp, #16] | |
| ; CHECK: add x29, sp, #16 | |
| ; 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, 16 | |
| ; CHECK: .cfi_offset w30, -8 | |
| ; CHECK: .cfi_offset w29, -16 | |
| ; CHECK: .cfi_offset w19, -32 | |
| ; 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: sub sp, x29, #16 // =16 | |
| ; CHECK: ldp x29, x30, [sp, #16] | |
| ; CHECK: ldr x19, [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 x20, x19, [sp, #-32]! | |
| ; Check that the frame pointer is created: | |
| ; CHECK: stp x29, x30, [sp, #16] | |
| ; CHECK: add x29, sp, #16 | |
| ; 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, 16 | |
| ; CHECK: .cfi_offset w30, -8 | |
| ; CHECK: .cfi_offset w29, -16 | |
| ; CHECK: .cfi_offset w19, -24 | |
| ; CHECK: .cfi_offset w20, -32 | |
| ; 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, #-20] | |
| ; 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: sub sp, x29, #16 // =16 | |
| ; CHECK: ldp x29, x30, [sp, #16] | |
| ; CHECK: ldp x20, x19, [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: str x21, [sp, #-48]! | |
| ; CHECK: stp x20, x19, [sp, #16] | |
| ; Check that the frame pointer is created: | |
| ; CHECK: stp x29, x30, [sp, #32] | |
| ; CHECK: 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: 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, 16 | |
| ; CHECK: .cfi_offset w30, -8 | |
| ; CHECK: .cfi_offset w29, -16 | |
| ; CHECK: .cfi_offset w19, -24 | |
| ; CHECK: .cfi_offset w20, -32 | |
| ; CHECK: .cfi_offset w21, -48 | |
| ; 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 | |
| ; 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: sub sp, x29, #32 | |
| ; CHECK: ldp x29, x30, [sp, #32] | |
| ; CHECK: ldp x20, x19, [sp, #16] | |
| ; CHECK: ldr x21, [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: str x19, [sp, #-32]! | |
| ; Check that the frame pointer is created: | |
| ; CHECK: stp x29, x30, [sp, #16] | |
| ; CHECK: 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: 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, #24] | |
| ; CHECK: ldr d[[DARG:[0-9]+]], [x29, #40] | |
| ; 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: sub sp, x29, #16 | |
| ; CHECK: ldp x29, x30, [sp, #16] | |
| ; CHECK: ldr x19, [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 x28, x19, [sp, #-32]! | |
| ; Check that the frame pointer is created: | |
| ; CHECK: stp x29, x30, [sp, #16] | |
| ; CHECK: 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: 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, #24] | |
| ; CHECK: ldr d[[DARG:[0-9]+]], [x29, #40] | |
| ; 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: sub sp, x29, #16 | |
| ; CHECK: ldp x29, x30, [sp, #16] | |
| ; CHECK: ldp x28, x19, [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"} |