Summary: Before this change, callee-save registers would be rounded up to even pairs of GPRs and FPRs. This change eliminates these extra padding load/stores, though it does keep the stack allocation the same size unless both the GPR and FPR sets have an odd size, in which case one full pair stack slot (16 bytes) is saved. This optimization cannot currently be done for MachO targets since they rely on a fast-path .debug_frame equivalent that can only encode callee-save registers as pairs. Reviewers: t.p.northover, rengolin, mcrosier, jmolloy Subscribers: aemerson, rengolin, mcrosier, llvm-commits Differential Revision: http://reviews.llvm.org/D17000 llvm-svn: 260689
710 lines
28 KiB
LLVM
710 lines
28 KiB
LLVM
; RUN: llc -verify-machineinstrs -mtriple=aarch64-none-linux-gnu -disable-post-ra < %s | FileCheck %s
|
|
; RUN: llc -verify-machineinstrs -mtriple=arm64-apple-ios -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: str x19, [sp, #-32]!
|
|
; Check that the frame pointer is created:
|
|
; CHECK: stp x29, x30, [sp, #16]
|
|
; CHECK: add x29, 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, -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 stack pointer
|
|
; CHECK: ldr w[[ILOC:[0-9]+]], [sp, #12]
|
|
; Check epilogue:
|
|
; CHECK: ldp x29, x30, [sp, #16]
|
|
; CHECK: ldr x19, [sp], #32
|
|
; 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: 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 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, #16]
|
|
; CHECK-MACHO: ldp x20, x19, [sp], #32
|
|
; 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 4
|
|
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-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" }
|
|
attributes #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" }
|
|
|
|
!1 = !{!2, !2, i64 0}
|
|
!2 = !{!"int", !3, i64 0}
|
|
!3 = !{!"omnipotent char", !4, i64 0}
|
|
!4 = !{!"Simple C/C++ TBAA"}
|