1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-10-23 21:13:02 +02:00
llvm-mirror/test/CodeGen/X86/win64_frame.ll
David Majnemer 93803262f4 [X86] Add intrinsics for reading and writing to the flags register
LLVM's targets need to know if stack pointer adjustments occur after the
prologue.  This is needed to correctly determine if the red-zone is
appropriate to use or if a frame pointer is required.

Normally, LLVM can figure this out very precisely by reasoning about the
contents of the MachineFunction.  There is an interesting corner case:
inline assembly.

The vast majority of inline assembly which will perform a push or pop is
done so to pair up with pushf or popf as appropriate.  Unfortunately,
this inline assembly doesn't mark the stack pointer as clobbered
because, well, it isn't.  The stack pointer is decremented and then
immediately incremented.  Because of this, LLVM was changed in r256456
to conservatively assume that inline assembly contain a sequence of
stack operations.  This is unfortunate because the vast majority of
inline assembly will not end up manipulating the stack pointer in any
way at all.

Instead, let's provide a more principled solution: an intrinsic.
FWIW, other compilers (MSVC and GCC among them) also provide this
functionality as an intrinsic.

llvm-svn: 256685
2016-01-01 06:50:01 +00:00

191 lines
5.3 KiB
LLVM

; RUN: llc < %s -mtriple=x86_64-pc-win32 | FileCheck %s --check-prefix=CHECK --check-prefix=PUSHF
; RUN: llc < %s -mtriple=x86_64-pc-win32 -mattr=+sahf | FileCheck %s --check-prefix=SAHF
define i32 @f1(i32 %p1, i32 %p2, i32 %p3, i32 %p4, i32 %p5) "no-frame-pointer-elim"="true" {
; CHECK-LABEL: f1:
; CHECK: movl 48(%rbp), %eax
ret i32 %p5
}
define void @f2(i32 %p, ...) "no-frame-pointer-elim"="true" {
; CHECK-LABEL: f2:
; CHECK: .seh_stackalloc 8
; CHECK: movq %rsp, %rbp
; CHECK: .seh_setframe 5, 0
; CHECK: movq %rdx, 32(%rbp)
; CHECK: leaq 32(%rbp), %rax
%ap = alloca i8, align 8
call void @llvm.va_start(i8* %ap)
ret void
}
define i8* @f3() "no-frame-pointer-elim"="true" {
; CHECK-LABEL: f3:
; CHECK: movq %rsp, %rbp
; CHECK: .seh_setframe 5, 0
; CHECK: movq 8(%rbp), %rax
%ra = call i8* @llvm.returnaddress(i32 0)
ret i8* %ra
}
define i8* @f4() "no-frame-pointer-elim"="true" {
; CHECK-LABEL: f4:
; CHECK: pushq %rbp
; CHECK: .seh_pushreg 5
; CHECK: subq $304, %rsp
; CHECK: .seh_stackalloc 304
; CHECK: leaq 128(%rsp), %rbp
; CHECK: .seh_setframe 5, 128
; CHECK: .seh_endprologue
; CHECK: movq 184(%rbp), %rax
alloca [300 x i8]
%ra = call i8* @llvm.returnaddress(i32 0)
ret i8* %ra
}
declare void @external(i8*)
define void @f5() "no-frame-pointer-elim"="true" {
; CHECK-LABEL: f5:
; CHECK: subq $336, %rsp
; CHECK: .seh_stackalloc 336
; CHECK: leaq 128(%rsp), %rbp
; CHECK: .seh_setframe 5, 128
; CHECK: leaq -92(%rbp), %rcx
; CHECK: callq external
%a = alloca [300 x i8]
%gep = getelementptr [300 x i8], [300 x i8]* %a, i32 0, i32 0
call void @external(i8* %gep)
ret void
}
define void @f6(i32 %p, ...) "no-frame-pointer-elim"="true" {
; CHECK-LABEL: f6:
; CHECK: subq $336, %rsp
; CHECK: .seh_stackalloc 336
; CHECK: leaq 128(%rsp), %rbp
; CHECK: .seh_setframe 5, 128
; CHECK: leaq -92(%rbp), %rcx
; CHECK: callq external
%a = alloca [300 x i8]
%gep = getelementptr [300 x i8], [300 x i8]* %a, i32 0, i32 0
call void @external(i8* %gep)
ret void
}
define i32 @f7(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e) "no-frame-pointer-elim"="true" {
; CHECK-LABEL: f7:
; CHECK: pushq %rbp
; CHECK: .seh_pushreg 5
; CHECK: subq $304, %rsp
; CHECK: .seh_stackalloc 304
; CHECK: leaq 128(%rsp), %rbp
; CHECK: .seh_setframe 5, 128
; CHECK: andq $-64, %rsp
; CHECK: movl 224(%rbp), %eax
; CHECK: leaq 176(%rbp), %rsp
alloca [300 x i8], align 64
ret i32 %e
}
define i32 @f8(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e) "no-frame-pointer-elim"="true" {
; CHECK-LABEL: f8:
; CHECK: subq $352, %rsp
; CHECK: .seh_stackalloc 352
; CHECK: leaq 128(%rsp), %rbp
; CHECK: .seh_setframe 5, 128
%alloca = alloca [300 x i8], align 64
; CHECK: andq $-64, %rsp
; CHECK: movq %rsp, %rbx
alloca i32, i32 %a
; CHECK: movl %ecx, %eax
; CHECK: leaq 15(,%rax,4), %rcx
; CHECK: movabsq $34359738352, %rax
; CHECK: andq %rcx, %rax
; CHECK: callq __chkstk
; CHECK: subq %rax, %rsp
%gep = getelementptr [300 x i8], [300 x i8]* %alloca, i32 0, i32 0
call void @external(i8* %gep)
; CHECK: subq $32, %rsp
; CHECK: leaq (%rbx), %rcx
; CHECK: callq external
; CHECK: addq $32, %rsp
ret i32 %e
; CHECK: movl %esi, %eax
; CHECK: leaq 224(%rbp), %rsp
}
define i64 @f9() {
entry:
; CHECK-LABEL: f9:
; CHECK: pushq %rbp
; CHECK: .seh_pushreg 5
; CHECK-NEXT: movq %rsp, %rbp
; CHECK: .seh_setframe 5, 0
; CHECK: .seh_endprologue
%call = call i64 @llvm.x86.flags.read.u64()
; CHECK-NEXT: pushfq
; CHECK-NEXT: popq %rax
ret i64 %call
; CHECK-NEXT: popq %rbp
; CHECK-NEXT: retq
}
declare i64 @dummy()
define i64 @f10(i64* %foo, i64 %bar, i64 %baz) {
; CHECK-LABEL: f10:
; CHECK: pushq %rbp
; CHECK: .seh_pushreg 5
; CHECK: pushq %rsi
; CHECK: .seh_pushreg 6
; CHECK: pushq %rdi
; CHECK: .seh_pushreg 7
; CHECK: subq $32, %rsp
; CHECK: .seh_stackalloc 32
; CHECK: leaq 32(%rsp), %rbp
; CHECK: .seh_setframe 5, 32
; CHECK: .seh_endprologue
%cx = cmpxchg i64* %foo, i64 %bar, i64 %baz seq_cst seq_cst
; PUSHF: lock cmpxchgq
; PUSHF-NEXT: pushfq
; PUSHF-NEXT: popq %[[REG:.*]]
; SAHF: lock cmpxchgq
; SAHF-NEXT: seto %al
; SAHF-NEXT: lahf
%v = extractvalue { i64, i1 } %cx, 0
%p = extractvalue { i64, i1 } %cx, 1
%call = call i64 @dummy()
; PUSHF: callq dummy
; PUSHF-NEXT: pushq %[[REG]]
; PUSHF-NEXT: popfq
; SAHF: callq dummy
; SAHF-NEXT: pushq
; SAHF: addb $127, %al
; SAHF-NEXT: sahf
; SAHF-NEXT: popq
%sel = select i1 %p, i64 %call, i64 %bar
; CHECK-NEXT: cmovneq
ret i64 %sel
; CHECK-NEXT: addq $32, %rsp
; CHECK-NEXT: popq %rdi
; CHECK-NEXT: popq %rsi
; CHECK-NEXT: popq %rbp
}
declare i8* @llvm.returnaddress(i32) nounwind readnone
declare i64 @llvm.x86.flags.read.u64()
declare void @llvm.va_start(i8*) nounwind