Simon Dardis 1dcb911061 [mips] Restrict tail call optimization
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
2016-11-20 21:23:08 +00:00

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
}