Skip to content

Commit

Permalink
[mips] Restrict tail call optimization
Browse files Browse the repository at this point in the history
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
  • Loading branch information
Simon Dardis committed Nov 20, 2016
1 parent 0878d46 commit 1dcb911
Show file tree
Hide file tree
Showing 8 changed files with 151 additions and 166 deletions.
17 changes: 13 additions & 4 deletions llvm/lib/Target/Mips/MipsISelLowering.cpp
Expand Up @@ -2650,11 +2650,20 @@ MipsTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
// Get a count of how many bytes are to be pushed on the stack.
unsigned NextStackOffset = CCInfo.getNextStackOffset();

// Check if it's really possible to do a tail call.
if (IsTailCall)
// Check if it's really possible to do a tail call. Restrict it to functions
// that are part of this compilation unit.
bool InternalLinkage = false;
if (IsTailCall) {
IsTailCall = isEligibleForTailCallOptimization(
CCInfo, NextStackOffset, *MF.getInfo<MipsFunctionInfo>());

if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee)) {
InternalLinkage = G->getGlobal()->hasInternalLinkage();
IsTailCall &= (InternalLinkage || G->getGlobal()->hasLocalLinkage() ||
G->getGlobal()->hasPrivateLinkage() ||
G->getGlobal()->hasHiddenVisibility() ||
G->getGlobal()->hasProtectedVisibility());
}
}
if (!IsTailCall && CLI.CS && CLI.CS->isMustTailCall())
report_fatal_error("failed to perform tail call elimination on a call "
"site marked musttail");
Expand Down Expand Up @@ -2789,9 +2798,9 @@ MipsTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
// node so that legalize doesn't hack it.
bool IsPICCall = (ABI.IsN64() || IsPIC); // true if calls are translated to
// jalr $25
bool GlobalOrExternal = false, InternalLinkage = false, IsCallReloc = false;
SDValue CalleeLo;
EVT Ty = Callee.getValueType();
bool GlobalOrExternal = false, IsCallReloc = false;

if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee)) {
if (IsPICCall) {
Expand Down
2 changes: 1 addition & 1 deletion llvm/test/CodeGen/Mips/fastcc.ll
Expand Up @@ -290,7 +290,7 @@ entry:
; NOODDSPREG-DAG: lwc1 $f18, 36($[[R0]])

; NOODDSPREG-DAG: lwc1 $[[F0:f[0-9]*[02468]]], 40($[[R0]])
; NOODDSPREG-DAG: swc1 $[[F0]], 8($sp)
; NOODDSPREG-DAG: swc1 $[[F0]], 0($sp)

%0 = load float, float* getelementptr ([11 x float], [11 x float]* @fa, i32 0, i32 0), align 4
%1 = load float, float* getelementptr ([11 x float], [11 x float]* @fa, i32 0, i32 1), align 4
Expand Down
10 changes: 5 additions & 5 deletions llvm/test/CodeGen/Mips/i64arg.ll
Expand Up @@ -2,8 +2,8 @@

define void @f1(i64 %ll1, float %f, i64 %ll, i32 %i, float %f2) nounwind {
entry:
; CHECK-DAG: lw $[[R2:[0-9]+]], 64($sp)
; CHECK-DAG: lw $[[R3:[0-9]+]], 68($sp)
; CHECK-DAG: lw $[[R2:[0-9]+]], 80($sp)
; CHECK-DAG: lw $[[R3:[0-9]+]], 84($sp)
; CHECK-DAG: move $[[R1:[0-9]+]], $5
; CHECK-DAG: move $[[R0:[0-9]+]], $4
; CHECK-DAG: ori $6, ${{[0-9]+}}, 3855
Expand All @@ -18,11 +18,11 @@ entry:
tail call void @ff2(i64 %ll, double 3.000000e+00) nounwind
%sub = add nsw i32 %i, -1
; CHECK-DAG: lw $25, %call16(ff3)
; CHECK-DAG: sw $[[R1]], 76($sp)
; CHECK-DAG: sw $[[R0]], 72($sp)
; CHECK-DAG: sw $[[R1]], 28($sp)
; CHECK-DAG: sw $[[R0]], 24($sp)
; CHECK-DAG: move $6, $[[R2]]
; CHECK-DAG: move $7, $[[R3]]
; CHECK: jr $25
; CHECK: jalr $25
tail call void @ff3(i32 %i, i64 %ll, i32 %sub, i64 %ll1) nounwind
ret void
}
Expand Down
2 changes: 1 addition & 1 deletion llvm/test/CodeGen/Mips/lazy-binding.ll
Expand Up @@ -30,7 +30,7 @@ declare void @foo2()
; CHECK: lw $25, %call16(foo2)(${{[0-9]+}})
; CHECK: jalr $25
; CHECK: lw $25, %call16(foo2)(${{[0-9]+}})
; CHECK: jr $25
; CHECK: jalr $25

define void @foo1() {
entry:
Expand Down
42 changes: 0 additions & 42 deletions llvm/test/CodeGen/Mips/llvm-ir/call.ll
Expand Up @@ -80,48 +80,6 @@ define float @call_float_void() {
ret float %2
}

define void @musttail_call_void_void() {
; ALL-LABEL: musttail_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: jr $[[TGT]]
; R6C: jrc $[[TGT]]

musttail call void @extern_void_void()
ret void
}

define i32 @musttail_call_i32_void() {
; ALL-LABEL: musttail_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: jr $[[TGT]]
; R6C: jrc $[[TGT]]

%1 = musttail call i32 @extern_i32_void()
ret i32 %1
}

define float @musttail_call_float_void() {
; ALL-LABEL: musttail_call_float_void:

; O32: lw $[[TGT:[0-9]+]], %call16(extern_float_void)($gp)

; N64: ld $[[TGT:[0-9]+]], %call16(extern_float_void)($gp)

; NOT-R6C: jr $[[TGT]]
; R6C: jrc $[[TGT]]

%1 = musttail call float @extern_float_void()
ret float %1
}

define i32 @indirect_call_void_void(void ()* %addr) {
; ALL-LABEL: indirect_call_void_void:

Expand Down
28 changes: 22 additions & 6 deletions llvm/test/CodeGen/Mips/tailcall/tail-call-arguments-clobber.ll
Expand Up @@ -18,7 +18,14 @@
; O32 case: The last two arguments should appear at 16(sp), 20(sp). The order
; of the loads doesn't matter, but they have to become before the
; stores
declare i32 @func2(i32, i32, i32, i32, i32, i32)
define internal i32 @func2(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f) {
%1 = add i32 %a, %b
%2 = add i32 %1, %c
%3 = add i32 %2, %d
%4 = add i32 %3, %e
%5 = add i32 %4, %f
ret i32 %5
}

define i32 @func1(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f){
; MIPS32-LABEL: func1:
Expand All @@ -27,7 +34,7 @@ define i32 @func1(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f){
; MIPS32-NEXT: lw ${{[0-9]+}}, {{[0-9]+}}($sp)
; MIPS32-NEXT: sw ${{[0-9]+}}, {{[0-9]+}}($sp)
; MIPS32-NEXT: sw ${{[0-9]+}}, {{[0-9]+}}($sp)
%retval = tail call i32 @func1(i32 %a, i32 %f, i32 %c, i32 %d, i32 %e, i32 %b)
%retval = tail call i32 @func2(i32 %a, i32 %f, i32 %c, i32 %d, i32 %e, i32 %b)

ret i32 %retval
}
Expand All @@ -36,8 +43,19 @@ define i32 @func1(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f){
; of the loads doesn't matter, but they have to become before the
; stores

declare i64 @func4(i64, i64, i64, i64, i64, i64, i64, i64, i64, i64)

define internal i64 @func4(i64 %a, i64 %b, i64 %c, i64 %d, i64 %e,
i64 %f, i64 %g, i64 %h, i64 %i, i64 %j) {
%1 = add i64 %a, %b
%2 = add i64 %1, %c
%3 = add i64 %2, %d
%4 = add i64 %3, %e
%5 = add i64 %4, %f
%6 = add i64 %1, %g
%7 = add i64 %2, %h
%8 = add i64 %3, %i
%9 = add i64 %4, %j
ret i64 %5
}
define i64 @func3(i64 %a, i64 %b, i64 %c, i64 %d,
i64 %e, i64 %f, i64 %g, i64 %h,
i64 %i, i64 %j){
Expand All @@ -51,5 +69,3 @@ define i64 @func3(i64 %a, i64 %b, i64 %c, i64 %d,

ret i64 %retval
}


17 changes: 10 additions & 7 deletions llvm/test/CodeGen/Mips/tailcall/tailcall-wrong-isa.ll
Expand Up @@ -21,23 +21,26 @@
; RUN: llc -filetype=obj -march=mips64el -mcpu=mips64r6 -mips-tail-calls=1 < %s -o - \
; RUN: | llvm-objdump -d - | FileCheck %s -check-prefix=N64R6

declare i8 @f2(i8)
define internal i8 @f2(i8) {
ret i8 4
}

define i8 @f1(i8 signext %i) nounwind {
%a = tail call i8 @f2(i8 %i)
ret i8 %a
}

; PIC32: {{[0-9]}}: 08 00 20 03 jr $25
; STATIC32: {{[0-9]}}: 00 00 00 08 j 0
; ALL: f1:
; PIC32: {{[0-9a-z]}}: 08 00 20 03 jr $25
; STATIC32: {{[0-9a-z]}}: 00 00 00 08 j 0

; N64: {{[0-9a-z]+}}: 08 00 20 03 jr $25

; PIC32MM: {{[0-9a-z]+}}: b9 45 jrc $25
; STATIC32MM: {{[0-9]}}: 00 d4 00 00 j 0
; STATIC32MM: {{[0-9a-z]}}: 00 d4 00 00 j 0

; PIC32R6: {{[0-9]}}: 00 00 19 d8 jrc $25
; STATIC32R6: {{[0-9]}}: 00 00 00 08 j 0
; PIC32R6: {{[0-9a-z]}}: 00 00 19 d8 jrc $25
; STATIC32R6: {{[0-9a-z]}}: 00 00 00 08 j 0

; N64R6: {{[0-9a-z]+}}: 09 00 20 03 jr $25
; N64R6: {{[0-9a-z]+}}: 00 00 19 d8 jrc $25

0 comments on commit 1dcb911

Please sign in to comment.