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

Djordje Todorovic via llvm-commits llvm-commits at lists.llvm.org
Tue Oct 7 01:13:58 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/3] [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/3] 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/3] 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,



More information about the llvm-commits mailing list