342 lines
12 KiB
LLVM
342 lines
12 KiB
LLVM
|
;; Check that this produces the expected assembly output
|
||
|
; RUN: llc -mtriple=thumbv7-windows -o - %s -verify-machineinstrs | FileCheck %s
|
||
|
;; Also try to write an object file, which verifies that the SEH opcodes
|
||
|
;; match the actual prologue/epilogue length.
|
||
|
; RUN: llc -mtriple=thumbv7-windows -filetype=obj -o %t.obj %s -verify-machineinstrs
|
||
|
|
||
|
; CHECK-LABEL: clobberR4Frame:
|
||
|
; CHECK-NEXT: .seh_proc clobberR4Frame
|
||
|
; CHECK-NEXT: @ %bb.0: @ %entry
|
||
|
; CHECK-NEXT: push.w {r4, r7, r11, lr}
|
||
|
; CHECK-NEXT: .seh_save_regs_w {r4, r7, r11, lr}
|
||
|
; CHECK-NEXT: add.w r11, sp, #8
|
||
|
; CHECK-NEXT: .seh_nop_w
|
||
|
; CHECK-NEXT: .seh_endprologue
|
||
|
; CHECK-NEXT: bl other
|
||
|
|
||
|
; CHECK: .seh_startepilogue
|
||
|
; CHECK-NEXT: pop.w {r4, r7, r11, pc}
|
||
|
; CHECK-NEXT: .seh_save_regs_w {r4, r7, r11, lr}
|
||
|
; CHECK-NEXT: .seh_endepilogue
|
||
|
; CHECK-NEXT: .seh_endproc
|
||
|
|
||
|
define arm_aapcs_vfpcc void @clobberR4Frame() uwtable "frame-pointer"="all" {
|
||
|
entry:
|
||
|
call arm_aapcs_vfpcc void @other()
|
||
|
call void asm sideeffect "", "~{r4}"()
|
||
|
ret void
|
||
|
}
|
||
|
|
||
|
; CHECK-LABEL: clobberR4NoFrame:
|
||
|
; CHECK-NEXT: .seh_proc clobberR4NoFrame
|
||
|
; CHECK-NEXT: @ %bb.0: @ %entry
|
||
|
; CHECK-NEXT: push {r4, lr}
|
||
|
; CHECK-NEXT: .seh_save_regs {r4, lr}
|
||
|
; CHECK-NEXT: .seh_endprologue
|
||
|
; CHECK-NEXT: bl other
|
||
|
|
||
|
; CHECK: .seh_startepilogue
|
||
|
; CHECK-NEXT: pop {r4, pc}
|
||
|
; CHECK-NEXT: .seh_save_regs {r4, lr}
|
||
|
; CHECK-NEXT: .seh_endepilogue
|
||
|
; CHECK-NEXT: .seh_endproc
|
||
|
|
||
|
define arm_aapcs_vfpcc void @clobberR4NoFrame() uwtable "frame-pointer"="none" {
|
||
|
entry:
|
||
|
call arm_aapcs_vfpcc void @other()
|
||
|
call void asm sideeffect "", "~{r4}"()
|
||
|
ret void
|
||
|
}
|
||
|
|
||
|
; CHECK-LABEL: clobberR4Tail:
|
||
|
; CHECK-NEXT: .seh_proc clobberR4Tail
|
||
|
; CHECK-NEXT: @ %bb.0: @ %entry
|
||
|
; CHECK-NEXT: push {r4, lr}
|
||
|
; CHECK-NEXT: .seh_save_regs {r4, lr}
|
||
|
; CHECK-NEXT: .seh_endprologue
|
||
|
|
||
|
; CHECK: .seh_startepilogue
|
||
|
; CHECK-NEXT: pop.w {r4, lr}
|
||
|
; CHECK-NEXT: .seh_save_regs_w {r4, lr}
|
||
|
; CHECK-NEXT: b.w other
|
||
|
; CHECK-NEXT: .seh_nop_w
|
||
|
; CHECK-NEXT: .seh_endepilogue
|
||
|
; CHECK-NEXT: .seh_endproc
|
||
|
|
||
|
define arm_aapcs_vfpcc void @clobberR4Tail() uwtable "frame-pointer"="none" {
|
||
|
entry:
|
||
|
call void asm sideeffect "", "~{r4}"()
|
||
|
tail call arm_aapcs_vfpcc void @other()
|
||
|
ret void
|
||
|
}
|
||
|
|
||
|
; CHECK-LABEL: clobberD8D10:
|
||
|
; CHECK-NEXT: .seh_proc clobberD8D10
|
||
|
; CHECK-NEXT: @ %bb.0: @ %entry
|
||
|
; CHECK-NEXT: vpush {d8, d9, d10}
|
||
|
; CHECK-NEXT: .seh_save_fregs {d8-d10}
|
||
|
; CHECK-NEXT: .seh_endprologue
|
||
|
|
||
|
; CHECK: .seh_startepilogue
|
||
|
; CHECK-NEXT: vpop {d8, d9, d10}
|
||
|
; CHECK-NEXT: .seh_save_fregs {d8-d10}
|
||
|
; CHECK-NEXT: b.w other
|
||
|
; CHECK-NEXT: .seh_nop_w
|
||
|
; CHECK-NEXT: .seh_endepilogue
|
||
|
; CHECK-NEXT: .seh_endproc
|
||
|
|
||
|
define arm_aapcs_vfpcc void @clobberD8D10() uwtable "frame-pointer"="none" {
|
||
|
entry:
|
||
|
call void asm sideeffect "", "~{d8},~{d9},~{d10}"()
|
||
|
tail call arm_aapcs_vfpcc void @other()
|
||
|
ret void
|
||
|
}
|
||
|
|
||
|
declare arm_aapcs_vfpcc void @other()
|
||
|
|
||
|
; CHECK-LABEL: vararg:
|
||
|
; CHECK-NEXT: .seh_proc vararg
|
||
|
; CHECK-NEXT: @ %bb.0: @ %entry
|
||
|
; CHECK-NEXT: sub sp, #12
|
||
|
; CHECK-NEXT: .seh_stackalloc 12
|
||
|
; CHECK-NEXT: push.w {r11, lr}
|
||
|
; CHECK-NEXT: .seh_save_regs_w {r11, lr}
|
||
|
; CHECK-NEXT: sub sp, #4
|
||
|
; CHECK-NEXT: .seh_stackalloc 4
|
||
|
; CHECK-NEXT: .seh_endprologue
|
||
|
|
||
|
; CHECK: .seh_startepilogue
|
||
|
; CHECK-NEXT: add sp, #4
|
||
|
; CHECK-NEXT: .seh_stackalloc 4
|
||
|
; CHECK-NEXT: pop.w {r11, lr}
|
||
|
; CHECK-NEXT: .seh_save_regs_w {r11, lr}
|
||
|
; CHECK-NEXT: add sp, #12
|
||
|
; CHECK-NEXT: .seh_stackalloc 12
|
||
|
; CHECK-NEXT: bx lr
|
||
|
; CHECK-NEXT: .seh_nop
|
||
|
; CHECK-NEXT: .seh_endepilogue
|
||
|
; CHECK-NEXT: .seh_endproc
|
||
|
|
||
|
define arm_aapcs_vfpcc void @vararg(i32 noundef %a, ...) uwtable "frame-pointer"="none" {
|
||
|
entry:
|
||
|
%ap = alloca ptr, align 4
|
||
|
call void @llvm.lifetime.start.p0(i64 4, ptr nonnull %ap)
|
||
|
call void @llvm.va_start(ptr nonnull %ap)
|
||
|
%0 = load ptr, ptr %ap
|
||
|
call arm_aapcs_vfpcc void @useva(ptr noundef %0)
|
||
|
call void @llvm.va_end(ptr nonnull %ap)
|
||
|
call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %ap)
|
||
|
ret void
|
||
|
}
|
||
|
|
||
|
declare void @llvm.lifetime.start.p0(i64 immarg, ptr nocapture)
|
||
|
declare void @llvm.lifetime.end.p0(i64 immarg, ptr nocapture)
|
||
|
declare void @llvm.va_start(ptr)
|
||
|
declare void @llvm.va_end(ptr)
|
||
|
|
||
|
declare arm_aapcs_vfpcc void @useva(ptr noundef)
|
||
|
|
||
|
; CHECK-LABEL: onlystack:
|
||
|
; CHECK-NEXT: .seh_proc onlystack
|
||
|
; CHECK-NEXT: @ %bb.0: @ %entry
|
||
|
; CHECK-NEXT: sub sp, #4
|
||
|
; CHECK-NEXT: .seh_stackalloc 4
|
||
|
; CHECK-NEXT: .seh_endprologue
|
||
|
|
||
|
; CHECK: .seh_startepilogue
|
||
|
; CHECK-NEXT: add sp, #4
|
||
|
; CHECK-NEXT: .seh_stackalloc 4
|
||
|
; CHECK-NEXT: bx lr
|
||
|
; CHECK-NEXT: .seh_nop
|
||
|
; CHECK-NEXT: .seh_endepilogue
|
||
|
; CHECK-NEXT: .seh_endproc
|
||
|
|
||
|
define dso_local arm_aapcs_vfpcc void @onlystack() uwtable "frame-pointer"="none" {
|
||
|
entry:
|
||
|
%buf = alloca [4 x i8], align 1
|
||
|
call void @llvm.lifetime.start.p0(i64 4, ptr nonnull %buf)
|
||
|
call void asm sideeffect "", "r"(ptr nonnull %buf)
|
||
|
call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %buf)
|
||
|
ret void
|
||
|
}
|
||
|
|
||
|
; CHECK-LABEL: func50:
|
||
|
; CHECK-NEXT: .seh_proc func50
|
||
|
; CHECK-NEXT: @ %bb.0: @ %entry
|
||
|
; CHECK-NEXT: push.w {r11, lr}
|
||
|
; CHECK-NEXT: .seh_save_regs_w {r11, lr}
|
||
|
; CHECK-NEXT: sub sp, #56
|
||
|
; CHECK-NEXT: .seh_stackalloc 56
|
||
|
; CHECK-NEXT: .seh_endprologue
|
||
|
|
||
|
; CHECK: .seh_startepilogue
|
||
|
; CHECK-NEXT: add sp, #56
|
||
|
; CHECK-NEXT: .seh_stackalloc 56
|
||
|
; CHECK-NEXT: pop.w {r11, pc}
|
||
|
; CHECK-NEXT: .seh_save_regs_w {r11, lr}
|
||
|
; CHECK-NEXT: .seh_endepilogue
|
||
|
; CHECK-NEXT: .seh_endproc
|
||
|
|
||
|
define arm_aapcs_vfpcc void @func50() {
|
||
|
entry:
|
||
|
%buf = alloca [50 x i8], align 1
|
||
|
call void @llvm.lifetime.start.p0(i64 50, ptr nonnull %buf)
|
||
|
call arm_aapcs_vfpcc void @useptr(ptr noundef nonnull %buf)
|
||
|
call void @llvm.lifetime.end.p0(i64 50, ptr nonnull %buf)
|
||
|
ret void
|
||
|
}
|
||
|
|
||
|
; CHECK-LABEL: func4000:
|
||
|
; CHECK-NEXT: .seh_proc func4000
|
||
|
; CHECK-NEXT: @ %bb.0: @ %entry
|
||
|
; CHECK-NEXT: push.w {r11, lr}
|
||
|
; CHECK-NEXT: .seh_save_regs_w {r11, lr}
|
||
|
; CHECK-NEXT: sub.w sp, sp, #4000
|
||
|
; CHECK-NEXT: .seh_stackalloc_w 4000
|
||
|
; CHECK-NEXT: .seh_endprologue
|
||
|
|
||
|
; CHECK: .seh_startepilogue
|
||
|
; CHECK-NEXT: add.w sp, sp, #4000
|
||
|
; CHECK-NEXT: .seh_stackalloc_w 4000
|
||
|
; CHECK-NEXT: pop.w {r11, pc}
|
||
|
; CHECK-NEXT: .seh_save_regs_w {r11, lr}
|
||
|
; CHECK-NEXT: .seh_endepilogue
|
||
|
; CHECK-NEXT: .seh_endproc
|
||
|
|
||
|
define arm_aapcs_vfpcc void @func4000() {
|
||
|
entry:
|
||
|
%buf = alloca [4000 x i8], align 1
|
||
|
call void @llvm.lifetime.start.p0(i64 4000, ptr nonnull %buf)
|
||
|
call arm_aapcs_vfpcc void @useptr(ptr noundef nonnull %buf)
|
||
|
call void @llvm.lifetime.end.p0(i64 4000, ptr nonnull %buf)
|
||
|
ret void
|
||
|
}
|
||
|
|
||
|
; CHECK-LABEL: func5000:
|
||
|
; CHECK-NEXT: .seh_proc func5000
|
||
|
; CHECK-NEXT: @ %bb.0: @ %entry
|
||
|
; CHECK-NEXT: push {r4, r5, r6, lr}
|
||
|
; CHECK-NEXT: .seh_save_regs {r4-r6, lr}
|
||
|
; CHECK-NEXT: movw r4, #1250
|
||
|
; CHECK-NEXT: .seh_nop_w
|
||
|
; CHECK-NEXT: bl __chkstk
|
||
|
; CHECK-NEXT: .seh_nop_w
|
||
|
; CHECK-NEXT: sub.w sp, sp, r4
|
||
|
; CHECK-NEXT: .seh_stackalloc_w 5000
|
||
|
; CHECK-NEXT: .seh_endprologue
|
||
|
|
||
|
; CHECK: .seh_startepilogue
|
||
|
; CHECK-NEXT: add.w sp, sp, #4992
|
||
|
; CHECK-NEXT: .seh_stackalloc_w 4992
|
||
|
; CHECK-NEXT: add sp, #8
|
||
|
; CHECK-NEXT: .seh_stackalloc 8
|
||
|
; CHECK-NEXT: pop {r4, r5, r6, pc}
|
||
|
; CHECK-NEXT: .seh_save_regs {r4-r6, lr}
|
||
|
; CHECK-NEXT: .seh_endepilogue
|
||
|
; CHECK-NEXT: .seh_endproc
|
||
|
|
||
|
define arm_aapcs_vfpcc void @func5000() {
|
||
|
entry:
|
||
|
%buf = alloca [5000 x i8], align 1
|
||
|
call void @llvm.lifetime.start.p0(i64 5000, ptr nonnull %buf)
|
||
|
call arm_aapcs_vfpcc void @useptr(ptr noundef nonnull %buf)
|
||
|
call void @llvm.lifetime.end.p0(i64 5000, ptr nonnull %buf)
|
||
|
ret void
|
||
|
}
|
||
|
|
||
|
; CHECK-LABEL: func262144:
|
||
|
; CHECK-NEXT: .seh_proc func262144
|
||
|
; CHECK-NEXT: @ %bb.0: @ %entry
|
||
|
; CHECK-NEXT: push {r4, r5, r6, lr}
|
||
|
; CHECK-NEXT: .seh_save_regs {r4-r6, lr}
|
||
|
; CHECK-NEXT: movs r4, #0
|
||
|
; CHECK-NEXT: .seh_nop
|
||
|
; CHECK-NEXT: movt r4, #1
|
||
|
; CHECK-NEXT: .seh_nop_w
|
||
|
; CHECK-NEXT: bl __chkstk
|
||
|
; CHECK-NEXT: .seh_nop_w
|
||
|
; CHECK-NEXT: sub.w sp, sp, r4
|
||
|
; CHECK-NEXT: .seh_stackalloc_w 262144
|
||
|
; CHECK-NEXT: .seh_endprologue
|
||
|
|
||
|
; CHECK: .seh_startepilogue
|
||
|
; CHECK-NEXT: add.w sp, sp, #262144
|
||
|
; CHECK-NEXT: .seh_stackalloc_w 262144
|
||
|
; CHECK-NEXT: pop {r4, r5, r6, pc}
|
||
|
; CHECK-NEXT: .seh_save_regs {r4-r6, lr}
|
||
|
; CHECK-NEXT: .seh_endepilogue
|
||
|
; CHECK-NEXT: .seh_endproc
|
||
|
|
||
|
define arm_aapcs_vfpcc void @func262144() {
|
||
|
entry:
|
||
|
%buf = alloca [262144 x i8], align 1
|
||
|
call void @llvm.lifetime.start.p0(i64 262144, ptr nonnull %buf)
|
||
|
call arm_aapcs_vfpcc void @useptr(ptr noundef nonnull %buf)
|
||
|
call void @llvm.lifetime.end.p0(i64 262144, ptr nonnull %buf)
|
||
|
ret void
|
||
|
}
|
||
|
|
||
|
; CHECK-LABEL: func270000:
|
||
|
; CHECK-NEXT: .seh_proc func270000
|
||
|
; CHECK-NEXT: @ %bb.0: @ %entry
|
||
|
; CHECK-NEXT: push {r4, r5, r6, lr}
|
||
|
; CHECK-NEXT: .seh_save_regs {r4-r6, lr}
|
||
|
; CHECK-NEXT: movw r4, #1964
|
||
|
; CHECK-NEXT: .seh_nop_w
|
||
|
; CHECK-NEXT: movt r4, #1
|
||
|
; CHECK-NEXT: .seh_nop_w
|
||
|
; CHECK-NEXT: bl __chkstk
|
||
|
; CHECK-NEXT: .seh_nop_w
|
||
|
; CHECK-NEXT: sub.w sp, sp, r4
|
||
|
; CHECK-NEXT: .seh_stackalloc_w 270000
|
||
|
; CHECK-NEXT: .seh_endprologue
|
||
|
|
||
|
; CHECK: .seh_startepilogue
|
||
|
; CHECK-NEXT: add.w sp, sp, #268288
|
||
|
; CHECK-NEXT: .seh_stackalloc_w 268288
|
||
|
; CHECK-NEXT: add.w sp, sp, #1712
|
||
|
; CHECK-NEXT: .seh_stackalloc_w 1712
|
||
|
; CHECK-NEXT: pop {r4, r5, r6, pc}
|
||
|
; CHECK-NEXT: .seh_save_regs {r4-r6, lr}
|
||
|
; CHECK-NEXT: .seh_endepilogue
|
||
|
; CHECK-NEXT: .seh_endproc
|
||
|
|
||
|
define arm_aapcs_vfpcc void @func270000() {
|
||
|
entry:
|
||
|
%buf = alloca [270000 x i8], align 1
|
||
|
call void @llvm.lifetime.start.p0(i64 270000, ptr nonnull %buf)
|
||
|
call arm_aapcs_vfpcc void @useptr(ptr noundef nonnull %buf)
|
||
|
call void @llvm.lifetime.end.p0(i64 270000, ptr nonnull %buf)
|
||
|
ret void
|
||
|
}
|
||
|
|
||
|
declare arm_aapcs_vfpcc void @useptr(ptr noundef)
|
||
|
|
||
|
; CHECK-LABEL: func_fp:
|
||
|
; CHECK-NEXT: .seh_proc func_fp
|
||
|
; CHECK-NEXT: @ %bb.0: @ %entry
|
||
|
; CHECK-NEXT: str r11, [sp, #-4]!
|
||
|
; CHECK-NEXT: .seh_save_regs_w {r11}
|
||
|
; CHECK-NEXT: mov r11, sp
|
||
|
; CHECK-NEXT: .seh_save_sp r11
|
||
|
; CHECK-NEXT: .seh_endprologue
|
||
|
|
||
|
; CHECK-NEXT: mov r0, r11
|
||
|
|
||
|
; CHECK-NEXT: .seh_startepilogue
|
||
|
; CHECK-NEXT: ldr r11, [sp], #4
|
||
|
; CHECK-NEXT: .seh_save_regs_w {r11}
|
||
|
; CHECK-NEXT: bx lr
|
||
|
; CHECK-NEXT: .seh_nop
|
||
|
; CHECK-NEXT: .seh_endepilogue
|
||
|
; CHECK-NEXT: .seh_endproc
|
||
|
|
||
|
define arm_aapcs_vfpcc i32 @func_fp() {
|
||
|
entry:
|
||
|
%0 = tail call ptr @llvm.frameaddress.p0(i32 0)
|
||
|
%1 = ptrtoint ptr %0 to i32
|
||
|
ret i32 %1
|
||
|
}
|
||
|
|
||
|
declare ptr @llvm.frameaddress.p0(i32 immarg)
|