llvm-6502/test/CodeGen/ARM/byval-align.ll
Tim Northover 52f83a9ab3 ARM: simplify and extend byval handling
The main issue being fixed here is that APCS targets handling a "byval align N"
parameter with N > 4 were miscounting what objects were where on the stack,
leading to FrameLowering setting the frame pointer incorrectly and clobbering
the stack.

But byval handling had grown over many years, and had multiple layers of cruft
trying to compensate for each other and calculate padding correctly. This only
really needs to be done once, in the HandleByVal function. Elsewhere should
just do what it's told by that call.

I also stripped out unnecessary APCS/AAPCS distinctions (now that Clang emits
byvals with the correct C ABI alignment), which simplified HandleByVal.

rdar://20095672

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@231959 91177308-0d34-0410-b5e6-96231b3b80d8
2015-03-11 18:54:22 +00:00

77 lines
2.2 KiB
LLVM

; RUN: llc -mtriple=thumbv7-apple-ios8.0 %s -o - | FileCheck %s
; This checks that alignments greater than 4 are respected by APCS
; targets. Mostly here to make sure *some* correct code is created after some
; simplifying refactoring; at the time of writing there were no actual APCS
; users of byval alignments > 4, so no real calls for ABI stability.
; "byval align 16" can't fit in any regs with an i8* taking up r0.
define i32 @test_align16(i8*, [4 x i32]* byval align 16 %b) {
; CHECK-LABEL: test_align16:
; CHECK-NOT: sub sp
; CHECK: push {r4, r7, lr}
; CHECK: add r7, sp, #4
; CHECK: ldr r0, [r7, #8]
call void @bar()
%valptr = getelementptr [4 x i32], [4 x i32]* %b, i32 0, i32 0
%val = load i32, i32* %valptr
ret i32 %val
}
; byval align 8 can, but we used to incorrectly set r7 here (miscalculating the
; space taken up by arg regs).
define i32 @test_align8(i8*, [4 x i32]* byval align 8 %b) {
; CHECK-LABEL: test_align8:
; CHECK: sub sp, #8
; CHECK: push {r4, r7, lr}
; CHECK: add r7, sp, #4
; CHECK-DAG: str r2, [r7, #8]
; CHECK-DAG: str r3, [r7, #12]
; CHECK: ldr r0, [r7, #8]
call void @bar()
%valptr = getelementptr [4 x i32], [4 x i32]* %b, i32 0, i32 0
%val = load i32, i32* %valptr
ret i32 %val
}
; "byval align 32" can't fit in regs no matter what: it would be misaligned
; unless the incoming stack was deliberately misaligned.
define i32 @test_align32(i8*, [4 x i32]* byval align 32 %b) {
; CHECK-LABEL: test_align32:
; CHECK-NOT: sub sp
; CHECK: push {r4, r7, lr}
; CHECK: add r7, sp, #4
; CHECK: ldr r0, [r7, #8]
call void @bar()
%valptr = getelementptr [4 x i32], [4 x i32]* %b, i32 0, i32 0
%val = load i32, i32* %valptr
ret i32 %val
}
; When passing an object "byval align N", the stack must be at least N-aligned.
define void @test_call_align16() {
; CHECK-LABEL: test_call_align16:
; CHECK: push {r4, r7, lr}
; CHECK: add r7, sp, #4
; CHECK: mov [[TMP:r[0-9]+]], sp
; CHECK: bfc [[TMP]], #0, #4
; CHECK: mov sp, [[TMP]]
; While we're here, make sure the caller also puts it at sp
; CHECK: mov r[[BASE:[0-9]+]], sp
; CHECK: vst1.32 {d{{[0-9]+}}, d{{[0-9]+}}}, [r[[BASE]]]
call i32 @test_align16(i8* null, [4 x i32]* byval align 16 @var)
ret void
}
@var = global [4 x i32] zeroinitializer
declare void @bar()