
The tail call optimization was being used without proper consideration of ABI requirements for saving and restoring the GP. This patch restricts tail call optimization to functions within the same translation unit. Reviewers: vkalintiris Differential Revision: https://reviews.llvm.org/D24763 llvm-svn: 287505
189 lines
7.2 KiB
LLVM
189 lines
7.2 KiB
LLVM
; Test the 'call' instruction and the tailcall variant.
|
|
|
|
; RUN: llc -march=mips -mcpu=mips32 -relocation-model=pic -mips-tail-calls=1 < %s | FileCheck %s -check-prefixes=ALL,O32,NOT-R6C
|
|
; RUN: llc -march=mips -mcpu=mips32r2 -relocation-model=pic -mips-tail-calls=1 < %s | FileCheck %s -check-prefixes=ALL,O32,NOT-R6C
|
|
; RUN: llc -march=mips -mcpu=mips32r3 -relocation-model=pic -mips-tail-calls=1 < %s | FileCheck %s -check-prefixes=ALL,O32,NOT-R6C
|
|
; RUN: llc -march=mips -mcpu=mips32r5 -relocation-model=pic -mips-tail-calls=1 < %s | FileCheck %s -check-prefixes=ALL,O32,NOT-R6C
|
|
; RUN: llc -march=mips -mcpu=mips32r6 -relocation-model=pic -disable-mips-delay-filler -mips-tail-calls=1 < %s | FileCheck %s -check-prefixes=ALL,O32,R6C
|
|
; RUN: llc -march=mips -mcpu=mips32r6 -relocation-model=pic -mattr=+fp64,+nooddspreg -disable-mips-delay-filler -mips-tail-calls=1 < %s | FileCheck %s -check-prefixes=ALL,O32,R6C
|
|
; RUN: llc -march=mips64 -mcpu=mips4 -mips-tail-calls=1 < %s | FileCheck %s -check-prefixes=ALL,N64,NOT-R6C
|
|
; RUN: llc -march=mips64 -mcpu=mips64 -mips-tail-calls=1 < %s | FileCheck %s -check-prefixes=ALL,N64,NOT-R6C
|
|
; RUN: llc -march=mips64 -mcpu=mips64r2 -mips-tail-calls=1 < %s | FileCheck %s -check-prefixes=ALL,N64,NOT-R6C
|
|
; RUN: llc -march=mips64 -mcpu=mips64r3 -mips-tail-calls=1 < %s | FileCheck %s -check-prefixes=ALL,N64,NOT-R6C
|
|
; RUN: llc -march=mips64 -mcpu=mips64r5 -mips-tail-calls=1 < %s | FileCheck %s -check-prefixes=ALL,N64,NOT-R6C
|
|
; RUN: llc -march=mips64 -mcpu=mips64r6 -disable-mips-delay-filler -mips-tail-calls=1 < %s | FileCheck %s -check-prefixes=ALL,N64,R6C
|
|
; RUN: llc -march=mips -mcpu=mips32 -relocation-model=pic -mips-tail-calls=1 < %s | FileCheck %s -check-prefix=ALL -check-prefix=O32 -check-prefix=NOT-R6C
|
|
; RUN: llc -march=mips -mcpu=mips32r2 -relocation-model=pic -mips-tail-calls=1 < %s | FileCheck %s -check-prefix=ALL -check-prefix=O32 -check-prefix=NOT-R6C
|
|
; RUN: llc -march=mips -mcpu=mips32r3 -relocation-model=pic -mips-tail-calls=1 < %s | FileCheck %s -check-prefix=ALL -check-prefix=O32 -check-prefix=NOT-R6C
|
|
; RUN: llc -march=mips -mcpu=mips32r5 -relocation-model=pic -mips-tail-calls=1 < %s | FileCheck %s -check-prefix=ALL -check-prefix=O32 -check-prefix=NOT-R6C
|
|
; RUN: llc -march=mips -mcpu=mips32r6 -relocation-model=pic -disable-mips-delay-filler -mips-tail-calls=1 < %s | FileCheck %s -check-prefix=ALL -check-prefix=O32 -check-prefix=R6C
|
|
; RUN: llc -march=mips -mcpu=mips32r6 -relocation-model=pic -mattr=+fp64,+nooddspreg -disable-mips-delay-filler -mips-tail-calls=1 < %s | FileCheck %s -check-prefix=ALL -check-prefix=O32 -check-prefix=R6C
|
|
; RUN: llc -march=mips64 -mcpu=mips4 -mips-tail-calls=1 < %s | FileCheck %s -check-prefix=ALL -check-prefix=N64 -check-prefix=NOT-R6C
|
|
; RUN: llc -march=mips64 -mcpu=mips64 -mips-tail-calls=1 < %s | FileCheck %s -check-prefix=ALL -check-prefix=N64 -check-prefix=NOT-R6C
|
|
; RUN: llc -march=mips64 -mcpu=mips64r2 -mips-tail-calls=1 < %s | FileCheck %s -check-prefix=ALL -check-prefix=N64 -check-prefix=NOT-R6C
|
|
; RUN: llc -march=mips64 -mcpu=mips64r3 -mips-tail-calls=1 < %s | FileCheck %s -check-prefix=ALL -check-prefix=N64 -check-prefix=NOT-R6C
|
|
; RUN: llc -march=mips64 -mcpu=mips64r5 -mips-tail-calls=1 < %s | FileCheck %s -check-prefix=ALL -check-prefix=N64 -check-prefix=NOT-R6C
|
|
; RUN: llc -march=mips64 -mcpu=mips64r6 -disable-mips-delay-filler -mips-tail-calls=1 < %s | FileCheck %s -check-prefix=ALL -check-prefix=N64 -check-prefix=R6C
|
|
|
|
declare void @extern_void_void()
|
|
declare i32 @extern_i32_void()
|
|
declare float @extern_float_void()
|
|
|
|
define i32 @call_void_void() {
|
|
; ALL-LABEL: call_void_void:
|
|
|
|
; O32: lw $[[TGT:[0-9]+]], %call16(extern_void_void)($gp)
|
|
|
|
; N64: ld $[[TGT:[0-9]+]], %call16(extern_void_void)($gp)
|
|
|
|
; NOT-R6C: jalr $[[TGT]]
|
|
; R6C: jalrc $[[TGT]]
|
|
|
|
call void @extern_void_void()
|
|
; R6C: jrc $ra
|
|
ret i32 0
|
|
}
|
|
|
|
define i32 @call_i32_void() {
|
|
; ALL-LABEL: call_i32_void:
|
|
|
|
; O32: lw $[[TGT:[0-9]+]], %call16(extern_i32_void)($gp)
|
|
|
|
; N64: ld $[[TGT:[0-9]+]], %call16(extern_i32_void)($gp)
|
|
|
|
; NOT-R6C: jalr $[[TGT]]
|
|
; R6C: jalrc $[[TGT]]
|
|
|
|
%1 = call i32 @extern_i32_void()
|
|
%2 = add i32 %1, 1
|
|
; R6C: jrc $ra
|
|
ret i32 %2
|
|
}
|
|
|
|
define float @call_float_void() {
|
|
; ALL-LABEL: call_float_void:
|
|
|
|
; FIXME: Not sure why we don't use $gp directly on such a simple test. We should
|
|
; look into it at some point.
|
|
; O32: addu $[[GP:[0-9]+]], ${{[0-9]+}}, $25
|
|
; O32: lw $[[TGT:[0-9]+]], %call16(extern_float_void)($[[GP]])
|
|
|
|
; N64: ld $[[TGT:[0-9]+]], %call16(extern_float_void)($gp)
|
|
|
|
; NOT-R6C: jalr $[[TGT]]
|
|
; R6C: jalrc $[[TGT]]
|
|
|
|
|
|
%1 = call float @extern_float_void()
|
|
%2 = fadd float %1, 1.0
|
|
; R6C: jrc $ra
|
|
ret float %2
|
|
}
|
|
|
|
define i32 @indirect_call_void_void(void ()* %addr) {
|
|
; ALL-LABEL: indirect_call_void_void:
|
|
|
|
; ALL: move $25, $4
|
|
; NOT-R6C: jalr $25
|
|
; R6C: jalrc $25
|
|
|
|
call void %addr()
|
|
; R6C: jrc $ra
|
|
ret i32 0
|
|
}
|
|
|
|
define i32 @indirect_call_i32_void(i32 ()* %addr) {
|
|
; ALL-LABEL: indirect_call_i32_void:
|
|
|
|
; ALL: move $25, $4
|
|
; NOT-R6C: jalr $25
|
|
; R6C: jalrc $25
|
|
|
|
|
|
%1 = call i32 %addr()
|
|
%2 = add i32 %1, 1
|
|
; R6C: jrc $ra
|
|
ret i32 %2
|
|
}
|
|
|
|
define float @indirect_call_float_void(float ()* %addr) {
|
|
; ALL-LABEL: indirect_call_float_void:
|
|
|
|
; ALL: move $25, $4
|
|
; NOT-R6C: jalr $25
|
|
; R6C: jalrc $25
|
|
|
|
|
|
%1 = call float %addr()
|
|
%2 = fadd float %1, 1.0
|
|
; R6C: jrc $ra
|
|
ret float %2
|
|
}
|
|
|
|
; We can't use 'musttail' here because the verifier is too conservative and
|
|
; prohibits any prototype difference.
|
|
define void @tail_indirect_call_void_void(void ()* %addr) {
|
|
; ALL-LABEL: tail_indirect_call_void_void:
|
|
|
|
; ALL: move $25, $4
|
|
; NOT-R6C: jr $[[TGT]]
|
|
; R6C: jrc $[[TGT]]
|
|
|
|
tail call void %addr()
|
|
ret void
|
|
}
|
|
|
|
define i32 @tail_indirect_call_i32_void(i32 ()* %addr) {
|
|
; ALL-LABEL: tail_indirect_call_i32_void:
|
|
|
|
; ALL: move $25, $4
|
|
; NOT-R6C: jr $[[TGT]]
|
|
; R6C: jrc $[[TGT]]
|
|
|
|
%1 = tail call i32 %addr()
|
|
ret i32 %1
|
|
}
|
|
|
|
define float @tail_indirect_call_float_void(float ()* %addr) {
|
|
; ALL-LABEL: tail_indirect_call_float_void:
|
|
|
|
; ALL: move $25, $4
|
|
; NOT-R6C: jr $[[TGT]]
|
|
; R6C: jrc $[[TGT]]
|
|
|
|
%1 = tail call float %addr()
|
|
ret float %1
|
|
}
|
|
|
|
; Check that passing undef as a double value doesn't cause machine code errors
|
|
; for FP64.
|
|
declare hidden void @undef_double(i32 %this, double %volume) unnamed_addr align 2
|
|
|
|
define hidden void @thunk_undef_double(i32 %this, double %volume) unnamed_addr align 2 {
|
|
; ALL-LABEL: thunk_undef_double:
|
|
; O32: # implicit-def: %A2
|
|
; O32: # implicit-def: %A3
|
|
; NOT-R6C: jr $[[TGT]]
|
|
; R6C: jrc $[[TGT]]
|
|
|
|
tail call void @undef_double(i32 undef, double undef) #8
|
|
ret void
|
|
}
|
|
|
|
; Check that immediate addresses do not use jal.
|
|
define i32 @jal_only_allows_symbols() {
|
|
; ALL-LABEL: jal_only_allows_symbols:
|
|
|
|
; ALL-NOT: {{jal }}
|
|
; ALL: addiu $[[TGT:[0-9]+]], $zero, 1234
|
|
; ALL-NOT: {{jal }}
|
|
; NOT-R6C: jalr $[[TGT]]
|
|
; R6C: jalrc $[[TGT]]
|
|
; ALL-NOT: {{jal }}
|
|
|
|
call void () inttoptr (i32 1234 to void ()*)()
|
|
; R6C: jrc $ra
|
|
ret i32 0
|
|
}
|
|
|