diff --git a/llvm/lib/Target/Mips/Mips16ISelLowering.cpp b/llvm/lib/Target/Mips/Mips16ISelLowering.cpp index 330cb4e0e206f..72019008bbd1c 100644 --- a/llvm/lib/Target/Mips/Mips16ISelLowering.cpp +++ b/llvm/lib/Target/Mips/Mips16ISelLowering.cpp @@ -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; } diff --git a/llvm/lib/Target/Mips/Mips16ISelLowering.h b/llvm/lib/Target/Mips/Mips16ISelLowering.h index f120cbbd24f91..6d0b909b748de 100644 --- a/llvm/lib/Target/Mips/Mips16ISelLowering.h +++ b/llvm/lib/Target/Mips/Mips16ISelLowering.h @@ -33,7 +33,7 @@ namespace llvm { private: bool isEligibleForTailCallOptimization( const CCState &CCInfo, unsigned NextStackOffset, - const MipsFunctionInfo &FI) const override; + const MipsFunctionInfo &FI, bool IsMustTail = false) const override; void setMips16HardFloatLibCalls(); diff --git a/llvm/lib/Target/Mips/MipsISelLowering.cpp b/llvm/lib/Target/Mips/MipsISelLowering.cpp index 881ba8e2f9eff..52a6e65abfd29 100644 --- a/llvm/lib/Target/Mips/MipsISelLowering.cpp +++ b/llvm/lib/Target/Mips/MipsISelLowering.cpp @@ -3407,18 +3407,22 @@ MipsTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, // 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; + bool IsMustTail = CLI.CB && CLI.CB->isMustTailCall(); if (IsTailCall) { IsTailCall = isEligibleForTailCallOptimization( - CCInfo, StackSize, *MF.getInfo()); - if (GlobalAddressSDNode *G = dyn_cast(Callee)) { - InternalLinkage = G->getGlobal()->hasInternalLinkage(); - IsTailCall &= (InternalLinkage || G->getGlobal()->hasLocalLinkage() || - G->getGlobal()->hasPrivateLinkage() || - G->getGlobal()->hasHiddenVisibility() || - G->getGlobal()->hasProtectedVisibility()); - } + CCInfo, StackSize, *MF.getInfo(), IsMustTail); + if (IsTailCall) { + if (GlobalAddressSDNode *G = dyn_cast(Callee)) { + InternalLinkage = G->getGlobal()->hasInternalLinkage(); + IsTailCall &= (InternalLinkage || G->getGlobal()->hasLocalLinkage() || + G->getGlobal()->isDSOLocal() || + G->getGlobal()->hasPrivateLinkage() || + 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"); diff --git a/llvm/lib/Target/Mips/MipsISelLowering.h b/llvm/lib/Target/Mips/MipsISelLowering.h index c65c76ccffc75..c8e0de89639a8 100644 --- a/llvm/lib/Target/Mips/MipsISelLowering.h +++ b/llvm/lib/Target/Mips/MipsISelLowering.h @@ -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 = false) 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 diff --git a/llvm/lib/Target/Mips/MipsSEISelLowering.cpp b/llvm/lib/Target/Mips/MipsSEISelLowering.cpp index 71a70d9c2dd46..cb6bd9c385519 100644 --- a/llvm/lib/Target/Mips/MipsSEISelLowering.cpp +++ b/llvm/lib/Target/Mips/MipsSEISelLowering.cpp @@ -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. diff --git a/llvm/lib/Target/Mips/MipsSEISelLowering.h b/llvm/lib/Target/Mips/MipsSEISelLowering.h index 675131aefb6dd..9a44957027dee 100644 --- a/llvm/lib/Target/Mips/MipsSEISelLowering.h +++ b/llvm/lib/Target/Mips/MipsSEISelLowering.h @@ -65,7 +65,7 @@ class TargetRegisterClass; private: bool isEligibleForTailCallOptimization( const CCState &CCInfo, unsigned NextStackOffset, - const MipsFunctionInfo &FI) const override; + const MipsFunctionInfo &FI, bool IsMustTail = false) const override; void getOpndList(SmallVectorImpl &Ops, diff --git a/llvm/test/CodeGen/Mips/musttail.ll b/llvm/test/CodeGen/Mips/musttail.ll new file mode 100644 index 0000000000000..48d3d7178b203 --- /dev/null +++ b/llvm/test/CodeGen/Mips/musttail.ll @@ -0,0 +1,23 @@ +; 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 +}