Skip to content
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions llvm/lib/Target/Mips/Mips16ISelLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -247,8 +247,8 @@ Mips16TargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI,
}

bool Mips16TargetLowering::isEligibleForTailCallOptimization(
const CCState &CCInfo, unsigned NextStackOffset,
const MipsFunctionInfo &FI) const {
const CCState &CCInfo, unsigned NextStackOffset, const MipsFunctionInfo &FI,
bool IsMustTail) const {
// No tail call optimization for mips16.
return false;
}
Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/Target/Mips/Mips16ISelLowering.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ namespace llvm {
private:
bool isEligibleForTailCallOptimization(
const CCState &CCInfo, unsigned NextStackOffset,
const MipsFunctionInfo &FI) const override;
const MipsFunctionInfo &FI, bool IsMustTail) const override;

void setMips16HardFloatLibCalls();

Expand Down
27 changes: 16 additions & 11 deletions llvm/lib/Target/Mips/MipsISelLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3404,21 +3404,26 @@ MipsTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
if (MF.getTarget().Options.EmitCallGraphSection && CB && CB->isIndirectCall())
CSInfo = MachineFunction::CallSiteInfo(*CB);

// Check if it's really possible to do a tail call. Restrict it to functions
// that are part of this compilation unit.
// Check if it's really possible to do a tail call.
// For non-musttail calls, restrict to functions that won't require $gp
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If there's a ABI problem, we need to reject musttail calls which would trigger that problem. A miscompile is a lot worse than a backend error.

If there's not an ABI problem, I'm not sure why we'd need these checks.

// restoration. In PIC mode, calling external functions via tail call can
// cause issues with $gp register handling (see D24763).
bool InternalLinkage = false;
bool IsMustTail = CLI.CB && CLI.CB->isMustTailCall();
if (IsTailCall) {
IsTailCall = isEligibleForTailCallOptimization(
CCInfo, StackSize, *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());
}
CCInfo, StackSize, *MF.getInfo<MipsFunctionInfo>(), IsMustTail);
// For non-musttail calls, restrict to local or non-interposable functions
if (IsTailCall && !IsMustTail) {
if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee)) {
InternalLinkage = G->getGlobal()->hasInternalLinkage();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you clean up this InternalLinkage variable? The remaining usage doesn't seem like it's connected to this code.

Is musttail of a function pointer okay?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you clean up this InternalLinkage variable? The remaining usage doesn't seem like it's connected to this code.

yep, it makes sense

Is musttail of a function pointer okay?

yes, I will add a test case for it

IsTailCall &= (G->getGlobal()->hasLocalLinkage() ||
G->getGlobal()->hasHiddenVisibility() ||
G->getGlobal()->hasProtectedVisibility());
}
}
}
if (!IsTailCall && CLI.CB && CLI.CB->isMustTailCall())
if (!IsTailCall && IsMustTail)
report_fatal_error("failed to perform tail call elimination on a call "
"site marked musttail");

Expand Down
7 changes: 3 additions & 4 deletions llvm/lib/Target/Mips/MipsISelLowering.h
Original file line number Diff line number Diff line change
Expand Up @@ -595,10 +595,9 @@ class TargetRegisterClass;

/// isEligibleForTailCallOptimization - Check whether the call is eligible
/// for tail call optimization.
virtual bool
isEligibleForTailCallOptimization(const CCState &CCInfo,
unsigned NextStackOffset,
const MipsFunctionInfo &FI) const = 0;
virtual bool isEligibleForTailCallOptimization(
const CCState &CCInfo, unsigned NextStackOffset,
const MipsFunctionInfo &FI, bool IsMustTail) const = 0;

/// copyByValArg - Copy argument registers which were used to pass a byval
/// argument to the stack. Create a stack frame object for the byval
Expand Down
6 changes: 3 additions & 3 deletions llvm/lib/Target/Mips/MipsSEISelLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1179,9 +1179,9 @@ MipsSETargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI,
}

bool MipsSETargetLowering::isEligibleForTailCallOptimization(
const CCState &CCInfo, unsigned NextStackOffset,
const MipsFunctionInfo &FI) const {
if (!UseMipsTailCalls)
const CCState &CCInfo, unsigned NextStackOffset, const MipsFunctionInfo &FI,
bool IsMustTail) const {
if (!UseMipsTailCalls && !IsMustTail)
return false;

// Exception has to be cleared with eret.
Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/Target/Mips/MipsSEISelLowering.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ class TargetRegisterClass;
private:
bool isEligibleForTailCallOptimization(
const CCState &CCInfo, unsigned NextStackOffset,
const MipsFunctionInfo &FI) const override;
const MipsFunctionInfo &FI, bool IsMustTail) const override;

void
getOpndList(SmallVectorImpl<SDValue> &Ops,
Expand Down
97 changes: 97 additions & 0 deletions llvm/test/CodeGen/Mips/musttail.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc -mtriple=mips-unknown-linux-gnu < %s | FileCheck %s --check-prefix=MIPS32
; RUN: llc -mtriple=mips64-unknown-linux-gnu < %s | FileCheck %s --check-prefix=MIPS64

; Test musttail support for MIPS

define dso_local i32 @callee_args(i32 %a, i32 %b, i32 %c) {
ret i32 %a;
}

define i32 @test_musttail_args(i32 %x, i32 %y, i32 %z) {
; MIPS32-LABEL: test_musttail_args:
; MIPS32: # %bb.0:
; MIPS32-NEXT: j callee_args
; MIPS32-NEXT: nop
;
; MIPS64-LABEL: test_musttail_args:
; MIPS64: # %bb.0:
; MIPS64-NEXT: j callee_args
; MIPS64-NEXT: nop
%ret = musttail call i32 @callee_args(i32 %x, i32 %y, i32 %z)
ret i32 %ret
}

; Test musttail with many arguments that spill to stack (involves memory)
; MIPS O32 ABI: first 4 args in $a0-$a3, rest on stack
declare i32 @many_args_callee(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f, i32 %g, i32 %h)

define i32 @test_musttail_many_args(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f, i32 %g, i32 %h) {
; MIPS32-LABEL: test_musttail_many_args:
; MIPS32: # %bb.0:
; MIPS32-NEXT: lw $1, 24($sp)
; MIPS32-NEXT: lw $2, 20($sp)
; MIPS32-NEXT: lw $3, 16($sp)
; MIPS32-NEXT: sw $3, 16($sp)
; MIPS32-NEXT: sw $2, 20($sp)
; MIPS32-NEXT: sw $1, 24($sp)
; MIPS32-NEXT: lw $1, 28($sp)
; MIPS32-NEXT: j many_args_callee
; MIPS32-NEXT: sw $1, 28($sp)
;
; MIPS64-LABEL: test_musttail_many_args:
; MIPS64: # %bb.0:
; MIPS64-NEXT: j many_args_callee
; MIPS64-NEXT: nop
%ret = musttail call i32 @many_args_callee(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f, i32 %g, i32 %h)
ret i32 %ret
}

; Test musttail with large struct passed by value (involves memory)
%struct.large = type { i32, i32, i32, i32, i32, i32, i32, i32 }

declare i32 @callee_with_struct(%struct.large %s, i32 %x)

define i32 @test_musttail_struct(%struct.large %s, i32 %x) {
; MIPS32-LABEL: test_musttail_struct:
; MIPS32: # %bb.0:
; MIPS32-NEXT: lw $1, 28($sp)
; MIPS32-NEXT: lw $2, 24($sp)
; MIPS32-NEXT: lw $3, 20($sp)
; MIPS32-NEXT: lw $8, 16($sp)
; MIPS32-NEXT: sw $8, 16($sp)
; MIPS32-NEXT: sw $3, 20($sp)
; MIPS32-NEXT: sw $2, 24($sp)
; MIPS32-NEXT: sw $1, 28($sp)
; MIPS32-NEXT: lw $1, 32($sp)
; MIPS32-NEXT: j callee_with_struct
; MIPS32-NEXT: sw $1, 32($sp)
;
; MIPS64-LABEL: test_musttail_struct:
; MIPS64: # %bb.0:
; MIPS64-NEXT: ld $1, 0($sp)
; MIPS64-NEXT: j callee_with_struct
; MIPS64-NEXT: sd $1, 0($sp)
%ret = musttail call i32 @callee_with_struct(%struct.large %s, i32 %x)
ret i32 %ret
}

; Test musttail with mixed int and float arguments that use stack
declare float @mixed_args_callee(i32 %a, float %b, i32 %c, float %d, i32 %e, float %f)

define float @test_musttail_mixed_args(i32 %a, float %b, i32 %c, float %d, i32 %e, float %f) {
; MIPS32-LABEL: test_musttail_mixed_args:
; MIPS32: # %bb.0:
; MIPS32-NEXT: lw $1, 16($sp)
; MIPS32-NEXT: sw $1, 16($sp)
; MIPS32-NEXT: lwc1 $f0, 20($sp)
; MIPS32-NEXT: j mixed_args_callee
; MIPS32-NEXT: swc1 $f0, 20($sp)
;
; MIPS64-LABEL: test_musttail_mixed_args:
; MIPS64: # %bb.0:
; MIPS64-NEXT: j mixed_args_callee
; MIPS64-NEXT: nop
%ret = musttail call float @mixed_args_callee(i32 %a, float %b, i32 %c, float %d, i32 %e, float %f)
ret float %ret
}
Loading