| ; 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 | |
| } | |
| declare ghccc void @tail() | |
| ; We should not save/restore fp/bp around terminator. | |
| define ghccc void @test5() { | |
| ; CHECK-LABEL: test5: | |
| ; 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: andq $-8, %rsp | |
| ; CHECK-NEXT: testb %al, %al | |
| ; CHECK-NEXT: jne .LBB3_2 | |
| ; CHECK-NEXT: # %bb.1: # %then | |
| ; CHECK-NEXT: movq $0, (%rax) | |
| ; CHECK-NEXT: movq %rbp, %rsp | |
| ; CHECK-NEXT: popq %rbp | |
| ; CHECK-NEXT: .cfi_def_cfa %rsp, 8 | |
| ; CHECK-NEXT: retq | |
| ; CHECK-NEXT: .LBB3_2: # %else | |
| ; CHECK-NEXT: .cfi_def_cfa %rbp, 16 | |
| ; CHECK-NEXT: movq %rbp, %rsp | |
| ; CHECK-NEXT: popq %rbp | |
| ; CHECK-NEXT: .cfi_def_cfa %rsp, 8 | |
| ; CHECK-NEXT: jmp tail@PLT # TAILCALL | |
| entry: | |
| br i1 poison, label %then, label %else | |
| then: | |
| store i64 0, ptr undef | |
| br label %exit | |
| else: | |
| musttail call ghccc void @tail() | |
| ret void | |
| exit: | |
| ret void | |
| } |