From ac9497ed3fffb45a8044c043f703487baeedb4e5 Mon Sep 17 00:00:00 2001 From: Djordje Todorovic 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()); if (GlobalAddressSDNode *G = dyn_cast(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 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()); - 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 && 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 &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 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 &Ops,