| ; 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: xorl %eax, %eax |
| ; 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 |
| } |