; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 4
; RUN: llc -mtriple=x86_64-pc-linux -stackrealign -verify-machineinstrs < %s | FileCheck %s
; Calling convention ghccc uses ebp to pass parameter, so calling a function
; using ghccc clobbers ebp. We should save and restore ebp around such a call
; if ebp is used as frame pointer.
declare ghccc i32 @external(i32)
; Basic test with ghccc calling convention.
define i32 @test1(i32 %0, i32 %1) {
; CHECK-LABEL: test1:
; CHECK: # %bb.0:
; CHECK-NEXT: pushq %rbp
; CHECK-NEXT: .cfi_def_cfa_offset 16
; CHECK-NEXT: .cfi_offset %rbp, -16
; CHECK-NEXT: movq %rsp, %rbp
; CHECK-NEXT: .cfi_def_cfa_register %rbp
; CHECK-NEXT: pushq %r15
; CHECK-NEXT: pushq %r14
; CHECK-NEXT: pushq %r13
; CHECK-NEXT: pushq %r12
; CHECK-NEXT: pushq %rbx
; CHECK-NEXT: andq $-16, %rsp
; CHECK-NEXT: subq $16, %rsp
; CHECK-NEXT: .cfi_offset %rbx, -56
; CHECK-NEXT: .cfi_offset %r12, -48
; CHECK-NEXT: .cfi_offset %r13, -40
; CHECK-NEXT: .cfi_offset %r14, -32
; CHECK-NEXT: .cfi_offset %r15, -24
; CHECK-NEXT: # kill: def $edi killed $edi def $rdi
; CHECK-NEXT: pushq %rbp
; CHECK-NEXT: pushq %rax
; CHECK-NEXT: .cfi_remember_state
; CHECK-NEXT: .cfi_escape 0x0f, 0x06, 0x77, 0x08, 0x06, 0x11, 0x10, 0x22 #
; CHECK-NEXT: movl %esi, %ebp
; CHECK-NEXT: movq %rdi, %r13
; CHECK-NEXT: callq external@PLT
; CHECK-NEXT: addq $8, %rsp
; CHECK-NEXT: popq %rbp
; CHECK-NEXT: .cfi_restore_state
; CHECK-NEXT: leaq -40(%rbp), %rsp
; CHECK-NEXT: popq %rbx
; CHECK-NEXT: popq %r12
; CHECK-NEXT: popq %r13
; CHECK-NEXT: popq %r14
; CHECK-NEXT: popq %r15
; CHECK-NEXT: popq %rbp
; CHECK-NEXT: .cfi_def_cfa %rsp, 8
; CHECK-NEXT: retq
%x = call ghccc i32 @external(i32 %0, i32 %1)
ret i32 %x
}
; Calling convention hipe has similar behavior. It clobbers rbp but not rbx.
declare cc 11 i64 @hipe1(i64)
declare cc 11 i64 @hipe2(i64, i64, i64, i64, i64, i64, i64)
; Basic test with hipe calling convention.
define i64 @test2(i64 %a0, i64 %a1) {
; CHECK-LABEL: test2:
; CHECK: # %bb.0:
; CHECK-NEXT: pushq %rbp
; CHECK-NEXT: .cfi_def_cfa_offset 16
; CHECK-NEXT: .cfi_offset %rbp, -16
; CHECK-NEXT: movq %rsp, %rbp
; CHECK-NEXT: .cfi_def_cfa_register %rbp
; CHECK-NEXT: pushq %r15
; CHECK-NEXT: pushq %r14
; CHECK-NEXT: pushq %r13
; CHECK-NEXT: pushq %r12
; CHECK-NEXT: pushq %rbx
; CHECK-NEXT: andq $-16, %rsp
; CHECK-NEXT: subq $16, %rsp
; CHECK-NEXT: .cfi_offset %rbx, -56
; CHECK-NEXT: .cfi_offset %r12, -48
; CHECK-NEXT: .cfi_offset %r13, -40
; CHECK-NEXT: .cfi_offset %r14, -32
; CHECK-NEXT: .cfi_offset %r15, -24
; CHECK-NEXT: pushq %rbp
; CHECK-NEXT: pushq %rax
; CHECK-NEXT: .cfi_remember_state
; CHECK-NEXT: .cfi_escape 0x0f, 0x06, 0x77, 0x08, 0x06, 0x11, 0x10, 0x22 #
; CHECK-NEXT: movq %rsi, %rbp
; CHECK-NEXT: movq %rdi, %r15
; CHECK-NEXT: callq hipe1@PLT
; CHECK-NEXT: addq $8, %rsp
; CHECK-NEXT: popq %rbp
; CHECK-NEXT: .cfi_restore_state
; CHECK-NEXT: movq %r15, %rax
; CHECK-NEXT: leaq -40(%rbp), %rsp
; CHECK-NEXT: popq %rbx
; CHECK-NEXT: popq %r12
; CHECK-NEXT: popq %r13
; CHECK-NEXT: popq %r14
; CHECK-NEXT: popq %r15
; CHECK-NEXT: popq %rbp
; CHECK-NEXT: .cfi_def_cfa %rsp, 8
; CHECK-NEXT: retq
%x = call cc 11 i64 @hipe1(i64 %a0, i64 %a1)
ret i64 %x
}
@buf = dso_local global [20 x ptr] zeroinitializer, align 16
; longjmp modifies fp, it is expected behavior, wo should not save/restore fp
; around it.
define void @test4() {
; CHECK-LABEL: test4:
; CHECK: # %bb.0: # %entry
; CHECK-NEXT: pushq %rbp
; CHECK-NEXT: .cfi_def_cfa_offset 16
; CHECK-NEXT: .cfi_offset %rbp, -16
; CHECK-NEXT: movq %rsp, %rbp
; CHECK-NEXT: .cfi_def_cfa_register %rbp
; CHECK-NEXT: pushq %r15
; CHECK-NEXT: pushq %r14
; CHECK-NEXT: pushq %r13
; CHECK-NEXT: pushq %r12
; CHECK-NEXT: pushq %rbx
; CHECK-NEXT: andq $-16, %rsp
; CHECK-NEXT: subq $16, %rsp
; CHECK-NEXT: .cfi_offset %rbx, -56
; CHECK-NEXT: .cfi_offset %r12, -48
; CHECK-NEXT: .cfi_offset %r13, -40
; CHECK-NEXT: .cfi_offset %r14, -32
; CHECK-NEXT: .cfi_offset %r15, -24
; CHECK-NEXT: xorl %r13d, %r13d
; CHECK-NEXT: pushq %rbp
; CHECK-NEXT: pushq %rax
; CHECK-NEXT: .cfi_remember_state
; CHECK-NEXT: .cfi_escape 0x0f, 0x06, 0x77, 0x08, 0x06, 0x11, 0x10, 0x22 #
; CHECK-NEXT: callq external@PLT
; CHECK-NEXT: addq $8, %rsp
; CHECK-NEXT: popq %rbp
; CHECK-NEXT: .cfi_restore_state
; CHECK-NEXT: movq buf(%rip), %rbp
; CHECK-NEXT: movq buf+8(%rip), %rax
; CHECK-NEXT: movq buf+16(%rip), %rsp
; CHECK-NEXT: jmpq *%rax
entry:
%x = call ghccc i32 @external(i32 0)
call void @llvm.eh.sjlj.longjmp(ptr @buf)
unreachable
}