[clang] [llvm] [MIPS][ISel] Fix musttail (PR #161860)

Djordje Todorovic via llvm-commits llvm-commits at lists.llvm.org
Wed Oct 29 12:08:03 PDT 2025


https://github.com/djtodoro updated https://github.com/llvm/llvm-project/pull/161860

>From ac9497ed3fffb45a8044c043f703487baeedb4e5 Mon Sep 17 00:00:00 2001
From: Djordje Todorovic <djordje.todorovic at htecgroup.com>
Date: Fri, 3 Oct 2025 17:03:52 +0200
Subject: [PATCH 1/9] [MIPS][ISel] Fix musttail

Properly handle clang::musttail attribute on MIPS backend.
---
 llvm/lib/Target/Mips/MipsISelLowering.cpp |  7 +++--
 llvm/test/CodeGen/Mips/musttail.ll        | 38 +++++++++++++++++++++++
 2 files changed, 42 insertions(+), 3 deletions(-)
 create mode 100644 llvm/test/CodeGen/Mips/musttail.ll

diff --git a/llvm/lib/Target/Mips/MipsISelLowering.cpp b/llvm/lib/Target/Mips/MipsISelLowering.cpp
index 881ba8e2f9eff..d79db127f01a2 100644
--- a/llvm/lib/Target/Mips/MipsISelLowering.cpp
+++ b/llvm/lib/Target/Mips/MipsISelLowering.cpp
@@ -3407,7 +3407,8 @@ 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;
-  if (IsTailCall) {
+  bool IsMustTail = CLI.CB && CLI.CB->isMustTailCall();
+  if (IsTailCall && !IsMustTail) {
     IsTailCall = isEligibleForTailCallOptimization(
         CCInfo, StackSize, *MF.getInfo<MipsFunctionInfo>());
     if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee)) {
@@ -3416,9 +3417,9 @@ MipsTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
                      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/test/CodeGen/Mips/musttail.ll b/llvm/test/CodeGen/Mips/musttail.ll
new file mode 100644
index 0000000000000..d5f457f6eb665
--- /dev/null
+++ b/llvm/test/CodeGen/Mips/musttail.ll
@@ -0,0 +1,38 @@
+; 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
+
+declare void @external_func()
+
+; Test basic musttail with external function
+define void @test_musttail_external() {
+; MIPS32-LABEL: test_musttail_external:
+; MIPS32:       # %bb.0:
+; MIPS32-NEXT:    j external_func
+; MIPS32-NEXT:    nop
+;
+; MIPS64-LABEL: test_musttail_external:
+; MIPS64:       # %bb.0:
+; MIPS64-NEXT:    j external_func
+; MIPS64-NEXT:    nop
+  musttail call void @external_func()
+  ret void
+}
+
+declare i32 @callee_args(i32 %a, i32 %b, i32 %c)
+
+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
+}

>From 9a77adf5a2d1217ac419413c06480f92998dafe8 Mon Sep 17 00:00:00 2001
From: Djordje Todorovic <djordje.todorovic at htecgroup.com>
Date: Tue, 7 Oct 2025 10:04:21 +0200
Subject: [PATCH 2/9] Address comments

---
 llvm/lib/Target/Mips/Mips16ISelLowering.cpp |  2 +-
 llvm/lib/Target/Mips/Mips16ISelLowering.h   |  3 ++-
 llvm/lib/Target/Mips/MipsISelLowering.cpp   | 19 +++++++++++--------
 llvm/lib/Target/Mips/MipsISelLowering.h     |  3 ++-
 llvm/lib/Target/Mips/MipsSEISelLowering.cpp |  4 ++--
 llvm/lib/Target/Mips/MipsSEISelLowering.h   |  3 ++-
 llvm/test/CodeGen/Mips/musttail.ll          | 19 ++-----------------
 7 files changed, 22 insertions(+), 31 deletions(-)

diff --git a/llvm/lib/Target/Mips/Mips16ISelLowering.cpp b/llvm/lib/Target/Mips/Mips16ISelLowering.cpp
index 330cb4e0e206f..e7144d1fecfb9 100644
--- a/llvm/lib/Target/Mips/Mips16ISelLowering.cpp
+++ b/llvm/lib/Target/Mips/Mips16ISelLowering.cpp
@@ -248,7 +248,7 @@ Mips16TargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI,
 
 bool Mips16TargetLowering::isEligibleForTailCallOptimization(
     const CCState &CCInfo, unsigned NextStackOffset,
-    const MipsFunctionInfo &FI) const {
+    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..8ac40644dce0a 100644
--- a/llvm/lib/Target/Mips/Mips16ISelLowering.h
+++ b/llvm/lib/Target/Mips/Mips16ISelLowering.h
@@ -33,7 +33,8 @@ 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 d79db127f01a2..52a6e65abfd29 100644
--- a/llvm/lib/Target/Mips/MipsISelLowering.cpp
+++ b/llvm/lib/Target/Mips/MipsISelLowering.cpp
@@ -3408,15 +3408,18 @@ MipsTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
   // that are part of this compilation unit.
   bool InternalLinkage = false;
   bool IsMustTail = CLI.CB && CLI.CB->isMustTailCall();
-  if (IsTailCall && !IsMustTail) {
+  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);
+    if (IsTailCall) {
+      if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee)) {
+        InternalLinkage = G->getGlobal()->hasInternalLinkage();
+        IsTailCall &= (InternalLinkage || G->getGlobal()->hasLocalLinkage() ||
+                       G->getGlobal()->isDSOLocal() ||
+                       G->getGlobal()->hasPrivateLinkage() ||
+                       G->getGlobal()->hasHiddenVisibility() ||
+                       G->getGlobal()->hasProtectedVisibility());
+      }
     }
   }
   if (!IsTailCall && IsMustTail)
diff --git a/llvm/lib/Target/Mips/MipsISelLowering.h b/llvm/lib/Target/Mips/MipsISelLowering.h
index c65c76ccffc75..3189f94046b35 100644
--- a/llvm/lib/Target/Mips/MipsISelLowering.h
+++ b/llvm/lib/Target/Mips/MipsISelLowering.h
@@ -598,7 +598,8 @@ class TargetRegisterClass;
     virtual bool
     isEligibleForTailCallOptimization(const CCState &CCInfo,
                                       unsigned NextStackOffset,
-                                      const MipsFunctionInfo &FI) const = 0;
+                                      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..33e31bb06e50f 100644
--- a/llvm/lib/Target/Mips/MipsSEISelLowering.cpp
+++ b/llvm/lib/Target/Mips/MipsSEISelLowering.cpp
@@ -1180,8 +1180,8 @@ MipsSETargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI,
 
 bool MipsSETargetLowering::isEligibleForTailCallOptimization(
     const CCState &CCInfo, unsigned NextStackOffset,
-    const MipsFunctionInfo &FI) const {
-  if (!UseMipsTailCalls)
+    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..7230e9cff6efa 100644
--- a/llvm/lib/Target/Mips/MipsSEISelLowering.h
+++ b/llvm/lib/Target/Mips/MipsSEISelLowering.h
@@ -65,7 +65,8 @@ 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<SDValue> &Ops,
diff --git a/llvm/test/CodeGen/Mips/musttail.ll b/llvm/test/CodeGen/Mips/musttail.ll
index d5f457f6eb665..48d3d7178b203 100644
--- a/llvm/test/CodeGen/Mips/musttail.ll
+++ b/llvm/test/CodeGen/Mips/musttail.ll
@@ -4,25 +4,10 @@
 
 ; Test musttail support for MIPS
 
-declare void @external_func()
-
-; Test basic musttail with external function
-define void @test_musttail_external() {
-; MIPS32-LABEL: test_musttail_external:
-; MIPS32:       # %bb.0:
-; MIPS32-NEXT:    j external_func
-; MIPS32-NEXT:    nop
-;
-; MIPS64-LABEL: test_musttail_external:
-; MIPS64:       # %bb.0:
-; MIPS64-NEXT:    j external_func
-; MIPS64-NEXT:    nop
-  musttail call void @external_func()
-  ret void
+define dso_local i32 @callee_args(i32 %a, i32 %b, i32 %c) {
+  ret i32 %a;
 }
 
-declare i32 @callee_args(i32 %a, i32 %b, i32 %c)
-
 define i32 @test_musttail_args(i32 %x, i32 %y, i32 %z) {
 ; MIPS32-LABEL: test_musttail_args:
 ; MIPS32:       # %bb.0:

>From 1e26120441a1278257561a7f10cd18056368ffca Mon Sep 17 00:00:00 2001
From: Djordje Todorovic <djordje.todorovic at htecgroup.com>
Date: Tue, 7 Oct 2025 10:13:39 +0200
Subject: [PATCH 3/9] Apply clang-format

---
 llvm/lib/Target/Mips/Mips16ISelLowering.cpp | 4 ++--
 llvm/lib/Target/Mips/Mips16ISelLowering.h   | 3 +--
 llvm/lib/Target/Mips/MipsISelLowering.h     | 8 +++-----
 llvm/lib/Target/Mips/MipsSEISelLowering.cpp | 4 ++--
 llvm/lib/Target/Mips/MipsSEISelLowering.h   | 3 +--
 5 files changed, 9 insertions(+), 13 deletions(-)

diff --git a/llvm/lib/Target/Mips/Mips16ISelLowering.cpp b/llvm/lib/Target/Mips/Mips16ISelLowering.cpp
index e7144d1fecfb9..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, bool IsMustTail) 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 8ac40644dce0a..6d0b909b748de 100644
--- a/llvm/lib/Target/Mips/Mips16ISelLowering.h
+++ b/llvm/lib/Target/Mips/Mips16ISelLowering.h
@@ -33,8 +33,7 @@ namespace llvm {
   private:
     bool isEligibleForTailCallOptimization(
         const CCState &CCInfo, unsigned NextStackOffset,
-        const MipsFunctionInfo &FI,
-        bool IsMustTail = false) const override;
+        const MipsFunctionInfo &FI, bool IsMustTail = false) const override;
 
     void setMips16HardFloatLibCalls();
 
diff --git a/llvm/lib/Target/Mips/MipsISelLowering.h b/llvm/lib/Target/Mips/MipsISelLowering.h
index 3189f94046b35..c8e0de89639a8 100644
--- a/llvm/lib/Target/Mips/MipsISelLowering.h
+++ b/llvm/lib/Target/Mips/MipsISelLowering.h
@@ -595,11 +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,
-                                      bool IsMustTail = false) 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 33e31bb06e50f..cb6bd9c385519 100644
--- a/llvm/lib/Target/Mips/MipsSEISelLowering.cpp
+++ b/llvm/lib/Target/Mips/MipsSEISelLowering.cpp
@@ -1179,8 +1179,8 @@ MipsSETargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI,
 }
 
 bool MipsSETargetLowering::isEligibleForTailCallOptimization(
-    const CCState &CCInfo, unsigned NextStackOffset,
-    const MipsFunctionInfo &FI, bool IsMustTail) const {
+    const CCState &CCInfo, unsigned NextStackOffset, const MipsFunctionInfo &FI,
+    bool IsMustTail) const {
   if (!UseMipsTailCalls && !IsMustTail)
     return false;
 
diff --git a/llvm/lib/Target/Mips/MipsSEISelLowering.h b/llvm/lib/Target/Mips/MipsSEISelLowering.h
index 7230e9cff6efa..9a44957027dee 100644
--- a/llvm/lib/Target/Mips/MipsSEISelLowering.h
+++ b/llvm/lib/Target/Mips/MipsSEISelLowering.h
@@ -65,8 +65,7 @@ class TargetRegisterClass;
   private:
     bool isEligibleForTailCallOptimization(
         const CCState &CCInfo, unsigned NextStackOffset,
-        const MipsFunctionInfo &FI,
-        bool IsMustTail = false) const override;
+        const MipsFunctionInfo &FI, bool IsMustTail = false) const override;
 
     void
     getOpndList(SmallVectorImpl<SDValue> &Ops,

>From 20d634f42afeb918f1a12422e9fb4d55550ecd70 Mon Sep 17 00:00:00 2001
From: Djordje Todorovic <djordje.todorovic at htecgroup.com>
Date: Fri, 17 Oct 2025 18:31:27 +0200
Subject: [PATCH 4/9] address comments

---
 llvm/lib/Target/Mips/Mips16ISelLowering.h |  2 +-
 llvm/lib/Target/Mips/MipsISelLowering.cpp | 13 ++--
 llvm/lib/Target/Mips/MipsISelLowering.h   |  2 +-
 llvm/lib/Target/Mips/MipsSEISelLowering.h |  2 +-
 llvm/test/CodeGen/Mips/musttail.ll        | 74 +++++++++++++++++++++++
 5 files changed, 84 insertions(+), 9 deletions(-)

diff --git a/llvm/lib/Target/Mips/Mips16ISelLowering.h b/llvm/lib/Target/Mips/Mips16ISelLowering.h
index 6d0b909b748de..ea6f049393327 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, bool IsMustTail = false) const override;
+        const MipsFunctionInfo &FI, bool IsMustTail) const override;
 
     void setMips16HardFloatLibCalls();
 
diff --git a/llvm/lib/Target/Mips/MipsISelLowering.cpp b/llvm/lib/Target/Mips/MipsISelLowering.cpp
index 52a6e65abfd29..92404effe3896 100644
--- a/llvm/lib/Target/Mips/MipsISelLowering.cpp
+++ b/llvm/lib/Target/Mips/MipsISelLowering.cpp
@@ -3404,19 +3404,20 @@ 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
+  // 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>(), IsMustTail);
-    if (IsTailCall) {
+    // 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();
-        IsTailCall &= (InternalLinkage || G->getGlobal()->hasLocalLinkage() ||
-                       G->getGlobal()->isDSOLocal() ||
-                       G->getGlobal()->hasPrivateLinkage() ||
+        IsTailCall &= (G->getGlobal()->hasLocalLinkage() ||
                        G->getGlobal()->hasHiddenVisibility() ||
                        G->getGlobal()->hasProtectedVisibility());
       }
diff --git a/llvm/lib/Target/Mips/MipsISelLowering.h b/llvm/lib/Target/Mips/MipsISelLowering.h
index c8e0de89639a8..866b2d36fb893 100644
--- a/llvm/lib/Target/Mips/MipsISelLowering.h
+++ b/llvm/lib/Target/Mips/MipsISelLowering.h
@@ -597,7 +597,7 @@ class TargetRegisterClass;
     /// for tail call optimization.
     virtual bool isEligibleForTailCallOptimization(
         const CCState &CCInfo, unsigned NextStackOffset,
-        const MipsFunctionInfo &FI, bool IsMustTail = false) const = 0;
+        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
diff --git a/llvm/lib/Target/Mips/MipsSEISelLowering.h b/llvm/lib/Target/Mips/MipsSEISelLowering.h
index 9a44957027dee..978abd4490c39 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, bool IsMustTail = false) const override;
+        const MipsFunctionInfo &FI, bool IsMustTail) const override;
 
     void
     getOpndList(SmallVectorImpl<SDValue> &Ops,
diff --git a/llvm/test/CodeGen/Mips/musttail.ll b/llvm/test/CodeGen/Mips/musttail.ll
index 48d3d7178b203..0bcce8882d6b0 100644
--- a/llvm/test/CodeGen/Mips/musttail.ll
+++ b/llvm/test/CodeGen/Mips/musttail.ll
@@ -21,3 +21,77 @@ define i32 @test_musttail_args(i32 %x, i32 %y, i32 %z) {
   %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
+}

>From eaa5678dfed669abb8d733b2243dc1ced89d73f0 Mon Sep 17 00:00:00 2001
From: Djordje Todorovic <djordje.todorovic at htecgroup.com>
Date: Sat, 18 Oct 2025 20:40:58 +0200
Subject: [PATCH 5/9] Clean up and improve tests

---
 llvm/lib/Target/Mips/MipsISelLowering.cpp |  3 +--
 llvm/lib/Target/Mips/MipsSEISelLowering.h |  7 ++++---
 llvm/test/CodeGen/Mips/musttail.ll        | 17 +++++++++++++++++
 3 files changed, 22 insertions(+), 5 deletions(-)

diff --git a/llvm/lib/Target/Mips/MipsISelLowering.cpp b/llvm/lib/Target/Mips/MipsISelLowering.cpp
index 92404effe3896..262c2212b1a4f 100644
--- a/llvm/lib/Target/Mips/MipsISelLowering.cpp
+++ b/llvm/lib/Target/Mips/MipsISelLowering.cpp
@@ -3408,7 +3408,6 @@ MipsTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
   // For non-musttail calls, restrict to functions that won't require $gp
   // 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(
@@ -3416,7 +3415,6 @@ MipsTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
     // 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();
         IsTailCall &= (G->getGlobal()->hasLocalLinkage() ||
                        G->getGlobal()->hasHiddenVisibility() ||
                        G->getGlobal()->hasProtectedVisibility());
@@ -3600,6 +3598,7 @@ MipsTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
     }
   }
 
+  bool InternalLinkage = false;
   if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee)) {
     if (Subtarget.isTargetCOFF() &&
         G->getGlobal()->hasDLLImportStorageClass()) {
diff --git a/llvm/lib/Target/Mips/MipsSEISelLowering.h b/llvm/lib/Target/Mips/MipsSEISelLowering.h
index 978abd4490c39..392e8dc3dbb11 100644
--- a/llvm/lib/Target/Mips/MipsSEISelLowering.h
+++ b/llvm/lib/Target/Mips/MipsSEISelLowering.h
@@ -63,9 +63,10 @@ class TargetRegisterClass;
     const TargetRegisterClass *getRepRegClassFor(MVT VT) const override;
 
   private:
-    bool isEligibleForTailCallOptimization(
-        const CCState &CCInfo, unsigned NextStackOffset,
-        const MipsFunctionInfo &FI, bool IsMustTail) const override;
+    bool isEligibleForTailCallOptimization(const CCState &CCInfo,
+                                           unsigned NextStackOffset,
+                                           const MipsFunctionInfo &FI,
+                                           bool IsMustTail) const override;
 
     void
     getOpndList(SmallVectorImpl<SDValue> &Ops,
diff --git a/llvm/test/CodeGen/Mips/musttail.ll b/llvm/test/CodeGen/Mips/musttail.ll
index 0bcce8882d6b0..c486ea5c59eea 100644
--- a/llvm/test/CodeGen/Mips/musttail.ll
+++ b/llvm/test/CodeGen/Mips/musttail.ll
@@ -95,3 +95,20 @@ define float @test_musttail_mixed_args(i32 %a, float %b, i32 %c, float %d, i32 %
   %ret = musttail call float @mixed_args_callee(i32 %a, float %b, i32 %c, float %d, i32 %e, float %f)
   ret float %ret
 }
+
+; Test musttail with indirect call
+define i32 @test_musttail_fptr(ptr %fptr, i32 %x) {
+; MIPS32-LABEL: test_musttail_fptr:
+; MIPS32:       # %bb.0:
+; MIPS32-NEXT:    move $25, $4
+; MIPS32-NEXT:    jr $25
+; MIPS32-NEXT:    nop
+;
+; MIPS64-LABEL: test_musttail_fptr:
+; MIPS64:       # %bb.0:
+; MIPS64-NEXT:    move $25, $4
+; MIPS64-NEXT:    jr $25
+; MIPS64-NEXT:    nop
+  %ret = musttail call i32 %fptr(ptr %fptr, i32 %x)
+  ret i32 %ret
+}

>From 54412fe1481c39b8537ae847a9b056ed726b2c88 Mon Sep 17 00:00:00 2001
From: Djordje Todorovic <djordje.todorovic at htecgroup.com>
Date: Sun, 19 Oct 2025 08:50:16 +0200
Subject: [PATCH 6/9] apply clang-format

---
 llvm/lib/Target/Mips/MipsISelLowering.h | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/llvm/lib/Target/Mips/MipsISelLowering.h b/llvm/lib/Target/Mips/MipsISelLowering.h
index 866b2d36fb893..3aa0a0d3ad7c4 100644
--- a/llvm/lib/Target/Mips/MipsISelLowering.h
+++ b/llvm/lib/Target/Mips/MipsISelLowering.h
@@ -595,9 +595,10 @@ class TargetRegisterClass;
 
     /// isEligibleForTailCallOptimization - Check whether the call is eligible
     /// for tail call optimization.
-    virtual bool isEligibleForTailCallOptimization(
-        const CCState &CCInfo, unsigned NextStackOffset,
-        const MipsFunctionInfo &FI, bool IsMustTail) 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

>From b9e145d26aedadbfcc38a9ce8f97a5c7df425107 Mon Sep 17 00:00:00 2001
From: Djordje Todorovic <djordje.todorovic at htecgroup.com>
Date: Sun, 19 Oct 2025 08:59:28 +0200
Subject: [PATCH 7/9] apply clang-format on Mips16ISelLowering.h

---
 llvm/lib/Target/Mips/Mips16ISelLowering.h | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/llvm/lib/Target/Mips/Mips16ISelLowering.h b/llvm/lib/Target/Mips/Mips16ISelLowering.h
index ea6f049393327..5281a62791590 100644
--- a/llvm/lib/Target/Mips/Mips16ISelLowering.h
+++ b/llvm/lib/Target/Mips/Mips16ISelLowering.h
@@ -31,9 +31,10 @@ namespace llvm {
                                 MachineBasicBlock *MBB) const override;
 
   private:
-    bool isEligibleForTailCallOptimization(
-        const CCState &CCInfo, unsigned NextStackOffset,
-        const MipsFunctionInfo &FI, bool IsMustTail) const override;
+    bool isEligibleForTailCallOptimization(const CCState &CCInfo,
+                                           unsigned NextStackOffset,
+                                           const MipsFunctionInfo &FI,
+                                           bool IsMustTail) const override;
 
     void setMips16HardFloatLibCalls();
 

>From e4a399181f57004006b7db75df7da0e5e5c01a92 Mon Sep 17 00:00:00 2001
From: Djordje Todorovic <djordje.todorovic at htecgroup.com>
Date: Tue, 28 Oct 2025 15:38:13 +0100
Subject: [PATCH 8/9] Align with PPC solution

---
 .../clang/Basic/DiagnosticCommonKinds.td      |  5 +++
 clang/lib/CodeGen/CGCall.cpp                  | 28 ++++++++++++++-
 clang/lib/CodeGen/CodeGenModule.cpp           | 34 ++++++++++++++-----
 clang/test/CodeGen/Mips/musttail.c            | 19 +++++++++++
 llvm/lib/Target/Mips/MipsISelLowering.cpp     | 25 ++++++++++----
 llvm/test/CodeGen/Mips/musttail.ll            | 12 +++++--
 6 files changed, 104 insertions(+), 19 deletions(-)
 create mode 100644 clang/test/CodeGen/Mips/musttail.c

diff --git a/clang/include/clang/Basic/DiagnosticCommonKinds.td b/clang/include/clang/Basic/DiagnosticCommonKinds.td
index 0bd8a423c393e..c744378ae8ec0 100644
--- a/clang/include/clang/Basic/DiagnosticCommonKinds.td
+++ b/clang/include/clang/Basic/DiagnosticCommonKinds.td
@@ -372,6 +372,11 @@ def err_ppc_impossible_musttail: Error<
   "indirect calls cannot be tail called on PPC|"
   "external calls cannot be tail called on PPC}0"
   >;
+def err_mips_impossible_musttail: Error<
+  "'musttail' attribute for this call is impossible because %select{"
+  "the MIPS16 ABI does not support tail calls|"
+  "calls outside the current linkage unit cannot be tail called on MIPS}0"
+  >;
 def err_aix_musttail_unsupported: Error<
   "'musttail' attribute is not supported on AIX">;
 
diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp
index d9bd443455e0f..5a94db834342d 100644
--- a/clang/lib/CodeGen/CGCall.cpp
+++ b/clang/lib/CodeGen/CGCall.cpp
@@ -31,6 +31,7 @@
 #include "clang/Basic/TargetInfo.h"
 #include "clang/CodeGen/CGFunctionInfo.h"
 #include "clang/CodeGen/SwiftCallingConv.h"
+#include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/Analysis/ValueTracking.h"
 #include "llvm/IR/Assumptions.h"
@@ -5954,11 +5955,20 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
     AddObjCARCExceptionMetadata(CI);
 
   // Set tail call kind if necessary.
+  bool IsPPC = getTarget().getTriple().isPPC();
+  bool IsMIPS = getTarget().getTriple().isMIPS();
+  bool HasMips16 = false;
+  if (IsMIPS) {
+    const TargetOptions &TargetOpts = getTarget().getTargetOpts();
+    HasMips16 = TargetOpts.FeatureMap.lookup("mips16");
+    if (!HasMips16)
+      HasMips16 = llvm::is_contained(TargetOpts.Features, "+mips16");
+  }
   if (llvm::CallInst *Call = dyn_cast<llvm::CallInst>(CI)) {
     if (TargetDecl && TargetDecl->hasAttr<NotTailCalledAttr>())
       Call->setTailCallKind(llvm::CallInst::TCK_NoTail);
     else if (IsMustTail) {
-      if (getTarget().getTriple().isPPC()) {
+      if (IsPPC) {
         if (getTarget().getTriple().isOSAIX())
           CGM.getDiags().Report(Loc, diag::err_aix_musttail_unsupported);
         else if (!getTarget().hasFeature("pcrelative-memops")) {
@@ -5984,6 +5994,22 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
           }
         }
       }
+      if (IsMIPS) {
+        if (HasMips16)
+          CGM.getDiags().Report(Loc, diag::err_mips_impossible_musttail) << 0;
+        else if (const auto *FD = dyn_cast_or_null<FunctionDecl>(TargetDecl)) {
+          if (!FD->isDefined()) {
+            CGM.addUndefinedGlobalForTailCall({FD, Loc});
+          } else {
+            llvm::GlobalValue::LinkageTypes Linkage =
+                CGM.getFunctionLinkage(GlobalDecl(FD));
+            if (!llvm::GlobalValue::isLocalLinkage(Linkage) &&
+                FD->isExternallyVisible())
+              CGM.getDiags().Report(Loc, diag::err_mips_impossible_musttail)
+                  << 1;
+          }
+        }
+      }
       Call->setTailCallKind(llvm::CallInst::TCK_MustTail);
     }
   }
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index 834b1c067d84c..11a71bf7f769b 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -1561,16 +1561,32 @@ void CodeGenModule::Release() {
   setVisibilityFromDLLStorageClass(LangOpts, getModule());
 
   // Check the tail call symbols are truly undefined.
-  if (getTriple().isPPC() && !MustTailCallUndefinedGlobals.empty()) {
-    for (auto &I : MustTailCallUndefinedGlobals) {
-      if (!I.first->isDefined())
-        getDiags().Report(I.second, diag::err_ppc_impossible_musttail) << 2;
-      else {
-        StringRef MangledName = getMangledName(GlobalDecl(I.first));
-        llvm::GlobalValue *Entry = GetGlobalValue(MangledName);
-        if (!Entry || Entry->isWeakForLinker() ||
-            Entry->isDeclarationForLinker())
+  if (!MustTailCallUndefinedGlobals.empty()) {
+    if (getTriple().isPPC()) {
+      for (auto &I : MustTailCallUndefinedGlobals) {
+        if (!I.first->isDefined())
           getDiags().Report(I.second, diag::err_ppc_impossible_musttail) << 2;
+        else {
+          StringRef MangledName = getMangledName(GlobalDecl(I.first));
+          llvm::GlobalValue *Entry = GetGlobalValue(MangledName);
+          if (!Entry || Entry->isWeakForLinker() ||
+              Entry->isDeclarationForLinker())
+            getDiags().Report(I.second, diag::err_ppc_impossible_musttail) << 2;
+        }
+      }
+    } else if (getTriple().isMIPS()) {
+      for (auto &I : MustTailCallUndefinedGlobals) {
+        const FunctionDecl *FD = I.first;
+        const FunctionDecl *Definition = FD->getDefinition();
+        if (!Definition) {
+          getDiags().Report(I.second, diag::err_mips_impossible_musttail) << 1;
+          continue;
+        }
+        llvm::GlobalValue::LinkageTypes Linkage =
+            getFunctionLinkage(GlobalDecl(Definition));
+        if (!llvm::GlobalValue::isLocalLinkage(Linkage) &&
+            Definition->isExternallyVisible())
+          getDiags().Report(I.second, diag::err_mips_impossible_musttail) << 1;
       }
     }
   }
diff --git a/clang/test/CodeGen/Mips/musttail.c b/clang/test/CodeGen/Mips/musttail.c
new file mode 100644
index 0000000000000..c0c0132e7f82f
--- /dev/null
+++ b/clang/test/CodeGen/Mips/musttail.c
@@ -0,0 +1,19 @@
+// RUN: not %clang_cc1 %s -triple mipsel-unknown-linux-gnu -emit-llvm 2>&1 \
+// RUN:   | FileCheck %s
+// RUN: not %clang_cc1 %s -triple mipsel-unknown-linux-gnu -target-feature +mips16 \
+// RUN:   -emit-llvm 2>&1 | FileCheck %s --check-prefix=CHECK-MIPS16
+
+// CHECK: error: 'musttail' attribute for this call is impossible because calls outside the current linkage unit cannot be tail called on MIPS
+// CHECK-MIPS16: error: 'musttail' attribute for this call is impossible because the MIPS16 ABI does not support tail calls
+
+static int local(int x) { return x; }
+
+int call_local(int x) {
+  [[clang::musttail]] return local(x);
+}
+
+extern int external(int x);
+
+int call_external(int x) {
+  [[clang::musttail]] return external(x);
+}
diff --git a/llvm/lib/Target/Mips/MipsISelLowering.cpp b/llvm/lib/Target/Mips/MipsISelLowering.cpp
index 262c2212b1a4f..7dbbaf1b9371f 100644
--- a/llvm/lib/Target/Mips/MipsISelLowering.cpp
+++ b/llvm/lib/Target/Mips/MipsISelLowering.cpp
@@ -3409,15 +3409,28 @@ MipsTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
   // restoration. In PIC mode, calling external functions via tail call can
   // cause issues with $gp register handling (see D24763).
   bool IsMustTail = CLI.CB && CLI.CB->isMustTailCall();
+  bool CalleeIsLocal = true;
+  if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee)) {
+    const GlobalValue *GV = G->getGlobal();
+    bool HasLocalLinkage = GV->hasLocalLinkage() || GV->hasPrivateLinkage();
+    bool HasHiddenVisibility = GV->hasHiddenVisibility() ||
+                               GV->hasProtectedVisibility();
+    if (GV->isDeclarationForLinker())
+      CalleeIsLocal = HasLocalLinkage || HasHiddenVisibility;
+    else
+      CalleeIsLocal = GV->isDSOLocal();
+  }
+
   if (IsTailCall) {
     IsTailCall = isEligibleForTailCallOptimization(
         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)) {
-        IsTailCall &= (G->getGlobal()->hasLocalLinkage() ||
-                       G->getGlobal()->hasHiddenVisibility() ||
-                       G->getGlobal()->hasProtectedVisibility());
+    if (IsTailCall) {
+      if (IsMustTail) {
+        if (!CalleeIsLocal)
+          report_fatal_error("failed to perform tail call elimination on a call "
+                             "site marked musttail");
+      } else {
+        IsTailCall &= CalleeIsLocal;
       }
     }
   }
diff --git a/llvm/test/CodeGen/Mips/musttail.ll b/llvm/test/CodeGen/Mips/musttail.ll
index c486ea5c59eea..17a55c11bf669 100644
--- a/llvm/test/CodeGen/Mips/musttail.ll
+++ b/llvm/test/CodeGen/Mips/musttail.ll
@@ -24,7 +24,9 @@ define i32 @test_musttail_args(i32 %x, i32 %y, i32 %z) {
 
 ; 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 hidden i32 @many_args_callee(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f, i32 %g, i32 %h) {
+  ret i32 %a
+}
 
 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:
@@ -50,7 +52,9 @@ define i32 @test_musttail_many_args(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32
 ; 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 hidden i32 @callee_with_struct(%struct.large %s, i32 %x) {
+  ret i32 %x
+}
 
 define i32 @test_musttail_struct(%struct.large %s, i32 %x) {
 ; MIPS32-LABEL: test_musttail_struct:
@@ -77,7 +81,9 @@ define i32 @test_musttail_struct(%struct.large %s, i32 %x) {
 }
 
 ; 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 hidden float @mixed_args_callee(i32 %a, float %b, i32 %c, float %d, i32 %e, float %f) {
+  ret float %b
+}
 
 define float @test_musttail_mixed_args(i32 %a, float %b, i32 %c, float %d, i32 %e, float %f) {
 ; MIPS32-LABEL: test_musttail_mixed_args:

>From a4b960c33bb814f46086b6ee5b43546c570ee20b Mon Sep 17 00:00:00 2001
From: Djordje Todorovic <djordje.todorovic at htecgroup.com>
Date: Wed, 29 Oct 2025 20:07:10 +0100
Subject: [PATCH 9/9] Apply clang-format and simplify code for err reporting

---
 llvm/lib/Target/Mips/MipsISelLowering.cpp | 22 ++++++++--------------
 1 file changed, 8 insertions(+), 14 deletions(-)

diff --git a/llvm/lib/Target/Mips/MipsISelLowering.cpp b/llvm/lib/Target/Mips/MipsISelLowering.cpp
index 7dbbaf1b9371f..2b2073099e04a 100644
--- a/llvm/lib/Target/Mips/MipsISelLowering.cpp
+++ b/llvm/lib/Target/Mips/MipsISelLowering.cpp
@@ -3413,8 +3413,8 @@ MipsTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
   if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee)) {
     const GlobalValue *GV = G->getGlobal();
     bool HasLocalLinkage = GV->hasLocalLinkage() || GV->hasPrivateLinkage();
-    bool HasHiddenVisibility = GV->hasHiddenVisibility() ||
-                               GV->hasProtectedVisibility();
+    bool HasHiddenVisibility =
+        GV->hasHiddenVisibility() || GV->hasProtectedVisibility();
     if (GV->isDeclarationForLinker())
       CalleeIsLocal = HasLocalLinkage || HasHiddenVisibility;
     else
@@ -3422,21 +3422,15 @@ MipsTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
   }
 
   if (IsTailCall) {
-    IsTailCall = isEligibleForTailCallOptimization(
+    bool Eligible = isEligibleForTailCallOptimization(
         CCInfo, StackSize, *MF.getInfo<MipsFunctionInfo>(), IsMustTail);
-    if (IsTailCall) {
-      if (IsMustTail) {
-        if (!CalleeIsLocal)
-          report_fatal_error("failed to perform tail call elimination on a call "
-                             "site marked musttail");
-      } else {
-        IsTailCall &= CalleeIsLocal;
-      }
+    if (!Eligible || !CalleeIsLocal) {
+      IsTailCall = false;
+      if (IsMustTail)
+        report_fatal_error("failed to perform tail call elimination on a call "
+                           "site marked musttail");
     }
   }
-  if (!IsTailCall && IsMustTail)
-    report_fatal_error("failed to perform tail call elimination on a call "
-                       "site marked musttail");
 
   if (IsTailCall)
     ++NumTailCalls;



More information about the llvm-commits mailing list