[llvm] [Mips] Fix $gp was restored when used as global register variable (PR #184975)

via llvm-commits llvm-commits at lists.llvm.org
Sun May 31 19:39:29 PDT 2026


https://github.com/yingopq updated https://github.com/llvm/llvm-project/pull/184975

>From c3da0cc598fe6dfcb9a2274c1f450998581580f3 Mon Sep 17 00:00:00 2001
From: Ying Huang <ying.huang at oss.cipunited.com>
Date: Fri, 6 Mar 2026 17:31:13 +0800
Subject: [PATCH 1/4] [Mips] Fix $gp was restored when used as global register
 variable

The function `eliminateDeadMI` would check `if (MRI.isReserved(Reg))`,
now we only set GP to reserved when `!Subtarget.isABICalls()`. So
`eliminateDeadMI` delete the `move $gp, $4`. And we would restore
$gp after instr selection through `$gp_64 = LD $sp_64, 8`.

Add a bool val when process instr `write_register` selection to
represent whether $gp used as global register val.
Then append new conditon when set $gp to reserverd status and return
CalleeSavedRegs without $gp.

Fix #176546.
---
 llvm/lib/Target/Mips/MipsCallingConv.td     | 13 +++++++++++++
 llvm/lib/Target/Mips/MipsISelDAGToDAG.cpp   | 10 ++++++++++
 llvm/lib/Target/Mips/MipsMachineFunction.h  |  5 +++++
 llvm/lib/Target/Mips/MipsRegisterInfo.cpp   | 15 ++++++++++-----
 llvm/test/CodeGen/Mips/write_register_gp.ll | 18 ++++++++++++++++++
 5 files changed, 56 insertions(+), 5 deletions(-)
 create mode 100644 llvm/test/CodeGen/Mips/write_register_gp.ll

diff --git a/llvm/lib/Target/Mips/MipsCallingConv.td b/llvm/lib/Target/Mips/MipsCallingConv.td
index 748162525b091..d3e552bc71ca9 100644
--- a/llvm/lib/Target/Mips/MipsCallingConv.td
+++ b/llvm/lib/Target/Mips/MipsCallingConv.td
@@ -362,16 +362,29 @@ def CSR_O32_FP64 :
 def CSR_N32 : CalleeSavedRegs<(add(decimate(sequence "D%u_64", 30, 20), 2),
                   RA_64, FP_64, GP_64, (sequence "S%u_64", 7, 0))>;
 
+def CSR_N32_NoGP : CalleeSavedRegs<(add(decimate(sequence "D%u_64", 30, 20), 2),
+                  RA_64, FP_64, (sequence "S%u_64", 7, 0))>;
+
 def CSR_N32_SingleFloat
     : CalleeSavedRegs<(add(decimate(sequence "F%u", 30, 20), 2), RA_64, FP_64,
           GP_64, (sequence "S%u_64", 7, 0))>;
 
+def CSR_N32_SingleFloat_NoGP
+    : CalleeSavedRegs<(add(decimate(sequence "F%u", 30, 20), 2), RA_64, FP_64,
+          (sequence "S%u_64", 7, 0))>;
+
 def CSR_N64 : CalleeSavedRegs<(add (sequence "D%u_64", 31, 24), RA_64, FP_64,
                                    GP_64, (sequence "S%u_64", 7, 0))>;
 
+def CSR_N64_NoGP : CalleeSavedRegs<(add (sequence "D%u_64", 31, 24), RA_64, FP_64,
+                                   (sequence "S%u_64", 7, 0))>;
+
 def CSR_N64_SingleFloat : CalleeSavedRegs<(add(sequence "F%u", 31, 24), RA_64,
                               FP_64, GP_64, (sequence "S%u_64", 7, 0))>;
 
+def CSR_N64_SingleFloat_NoGP : CalleeSavedRegs<(add(sequence "F%u", 31, 24), RA_64,
+                              FP_64, (sequence "S%u_64", 7, 0))>;
+
 def CSR_Mips16RetHelper :
   CalleeSavedRegs<(add V0, V1, FP,
                    (sequence "A%u", 3, 0), (sequence "S%u", 7, 0),
diff --git a/llvm/lib/Target/Mips/MipsISelDAGToDAG.cpp b/llvm/lib/Target/Mips/MipsISelDAGToDAG.cpp
index 36706243232c0..41345de1f0cd9 100644
--- a/llvm/lib/Target/Mips/MipsISelDAGToDAG.cpp
+++ b/llvm/lib/Target/Mips/MipsISelDAGToDAG.cpp
@@ -254,6 +254,16 @@ void MipsDAGToDAGISel::Select(SDNode *Node) {
     ReplaceNode(Node, getGlobalBaseReg());
     return;
 
+  case ISD::WRITE_REGISTER: {
+    MDNodeSDNode *MD = cast<MDNodeSDNode>(Node->getOperand(1));
+    const MDString *RegStr = cast<MDString>(MD->getMD()->getOperand(0));
+    StringRef Reg = RegStr->getString();
+    if (Reg == "$gp" || Reg == "$28" || Reg == "$28_64" || Reg == "$gp_64") {
+      MachineFunction &MF = CurDAG->getMachineFunction();
+      MF.getInfo<MipsFunctionInfo>()->setGPGlobalRegister(true);
+    }
+    break;
+  }
 #ifndef NDEBUG
   case ISD::LOAD:
   case ISD::STORE:
diff --git a/llvm/lib/Target/Mips/MipsMachineFunction.h b/llvm/lib/Target/Mips/MipsMachineFunction.h
index b7b748838569f..cff249e8d9ba8 100644
--- a/llvm/lib/Target/Mips/MipsMachineFunction.h
+++ b/llvm/lib/Target/Mips/MipsMachineFunction.h
@@ -62,6 +62,9 @@ class MipsFunctionInfo : public MachineFunctionInfo {
   int getEhDataRegFI(unsigned Reg) const { return EhDataRegFI[Reg]; }
   bool isEhDataRegFI(int FI) const;
 
+  void setGPGlobalRegister(bool Val) { GPIsGlobalRegister = Val; }
+  bool isGPGlobalRegister() const { return GPIsGlobalRegister; }
+
   /// Create a MachinePointerInfo that has an ExternalSymbolPseudoSourceValue
   /// object representing a GOT entry for an external function.
   MachinePointerInfo callPtrInfo(MachineFunction &MF, const char *ES);
@@ -126,6 +129,8 @@ class MipsFunctionInfo : public MachineFunctionInfo {
   /// FrameIndex for expanding BuildPairF64 nodes to spill and reload when the
   /// O32 FPXX ABI is enabled. -1 is used to denote invalid index.
   int MoveF64ViaSpillFI = -1;
+
+  bool GPIsGlobalRegister = false;
 };
 
 } // end namespace llvm
diff --git a/llvm/lib/Target/Mips/MipsRegisterInfo.cpp b/llvm/lib/Target/Mips/MipsRegisterInfo.cpp
index 948d4db8585db..16fafcffdaa68 100644
--- a/llvm/lib/Target/Mips/MipsRegisterInfo.cpp
+++ b/llvm/lib/Target/Mips/MipsRegisterInfo.cpp
@@ -89,20 +89,23 @@ MipsRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const {
                                      : CSR_Interrupt_32_SaveList;
   }
 
+  bool GPIsGlobal = MF->getInfo<MipsFunctionInfo>()->isGPGlobalRegister();
   // N64 ABI
   if (Subtarget.isABI_N64()) {
     if (Subtarget.isSingleFloat())
-      return CSR_N64_SingleFloat_SaveList;
+      return GPIsGlobal ? CSR_N64_SingleFloat_NoGP_SaveList
+                        : CSR_N64_SingleFloat_SaveList;
 
-    return CSR_N64_SaveList;
+    return GPIsGlobal ? CSR_N64_NoGP_SaveList : CSR_N64_SaveList;
   }
 
   // N32 ABI
   if (Subtarget.isABI_N32()) {
     if (Subtarget.isSingleFloat())
-      return CSR_N32_SingleFloat_SaveList;
+      return GPIsGlobal ? CSR_N32_SingleFloat_NoGP_SaveList
+                        : CSR_N32_SingleFloat_SaveList;
 
-    return CSR_N32_SaveList;
+    return GPIsGlobal ? CSR_N32_NoGP_SaveList : CSR_N32_SaveList;
   }
 
   // O32 ABI
@@ -122,6 +125,7 @@ const uint32_t *
 MipsRegisterInfo::getCallPreservedMask(const MachineFunction &MF,
                                        CallingConv::ID) const {
   const MipsSubtarget &Subtarget = MF.getSubtarget<MipsSubtarget>();
+
   // N64 ABI
   if (Subtarget.isABI_N64()) {
     if (Subtarget.isSingleFloat())
@@ -175,7 +179,8 @@ getReservedRegs(const MachineFunction &MF) const {
     Reserved.set(R);
 
   // For mno-abicalls, GP is a program invariant!
-  if (!Subtarget.isABICalls()) {
+  bool GPIsGlobal = MF.getInfo<MipsFunctionInfo>()->isGPGlobalRegister();
+  if (!Subtarget.isABICalls() || GPIsGlobal) {
     Reserved.set(Mips::GP);
     Reserved.set(Mips::GP_64);
   }
diff --git a/llvm/test/CodeGen/Mips/write_register_gp.ll b/llvm/test/CodeGen/Mips/write_register_gp.ll
new file mode 100644
index 0000000000000..02b434126af81
--- /dev/null
+++ b/llvm/test/CodeGen/Mips/write_register_gp.ll
@@ -0,0 +1,18 @@
+; RUN: llc -mtriple=mips64el -mcpu=mips64r2 < %s | FileCheck %s -check-prefix=MIPS64
+
+define void @setglobal(i64 %x) {
+; MIPS64-LABEL: setglobal:
+; MIPS64:       # %bb.0: # %entry
+; MIPS64-NEXT:    jr $ra
+; MIPS64-NEXT:    move $gp, $4
+
+entry:
+  tail call void @llvm.write_register.i64(metadata !0, i64 %x)
+  ret void
+}
+
+declare void @llvm.write_register.i64(metadata, i64) #1
+
+!llvm.named.register.$28 = !{!0}
+!0 = !{!"$28"}
+

>From d8ab241fae3ad8387e0c5fa0cc7c1aee40af7149 Mon Sep 17 00:00:00 2001
From: Ying Huang <ying.huang at oss.cipunited.com>
Date: Tue, 19 May 2026 17:49:32 +0800
Subject: [PATCH 2/4] Check the module metadata `llvm.named.register` to detect
 if $28 is used as global register instead checking WRITE_REGISTER; Add test
 comments.

---
 llvm/lib/Target/Mips/MipsISelDAGToDAG.cpp   | 10 ---------
 llvm/lib/Target/Mips/MipsMachineFunction.h  |  5 -----
 llvm/lib/Target/Mips/MipsRegisterInfo.cpp   | 23 +++++++++++++++++++--
 llvm/test/CodeGen/Mips/write_register_gp.ll |  9 ++++++--
 4 files changed, 28 insertions(+), 19 deletions(-)

diff --git a/llvm/lib/Target/Mips/MipsISelDAGToDAG.cpp b/llvm/lib/Target/Mips/MipsISelDAGToDAG.cpp
index 41345de1f0cd9..36706243232c0 100644
--- a/llvm/lib/Target/Mips/MipsISelDAGToDAG.cpp
+++ b/llvm/lib/Target/Mips/MipsISelDAGToDAG.cpp
@@ -254,16 +254,6 @@ void MipsDAGToDAGISel::Select(SDNode *Node) {
     ReplaceNode(Node, getGlobalBaseReg());
     return;
 
-  case ISD::WRITE_REGISTER: {
-    MDNodeSDNode *MD = cast<MDNodeSDNode>(Node->getOperand(1));
-    const MDString *RegStr = cast<MDString>(MD->getMD()->getOperand(0));
-    StringRef Reg = RegStr->getString();
-    if (Reg == "$gp" || Reg == "$28" || Reg == "$28_64" || Reg == "$gp_64") {
-      MachineFunction &MF = CurDAG->getMachineFunction();
-      MF.getInfo<MipsFunctionInfo>()->setGPGlobalRegister(true);
-    }
-    break;
-  }
 #ifndef NDEBUG
   case ISD::LOAD:
   case ISD::STORE:
diff --git a/llvm/lib/Target/Mips/MipsMachineFunction.h b/llvm/lib/Target/Mips/MipsMachineFunction.h
index cff249e8d9ba8..b7b748838569f 100644
--- a/llvm/lib/Target/Mips/MipsMachineFunction.h
+++ b/llvm/lib/Target/Mips/MipsMachineFunction.h
@@ -62,9 +62,6 @@ class MipsFunctionInfo : public MachineFunctionInfo {
   int getEhDataRegFI(unsigned Reg) const { return EhDataRegFI[Reg]; }
   bool isEhDataRegFI(int FI) const;
 
-  void setGPGlobalRegister(bool Val) { GPIsGlobalRegister = Val; }
-  bool isGPGlobalRegister() const { return GPIsGlobalRegister; }
-
   /// Create a MachinePointerInfo that has an ExternalSymbolPseudoSourceValue
   /// object representing a GOT entry for an external function.
   MachinePointerInfo callPtrInfo(MachineFunction &MF, const char *ES);
@@ -129,8 +126,6 @@ class MipsFunctionInfo : public MachineFunctionInfo {
   /// FrameIndex for expanding BuildPairF64 nodes to spill and reload when the
   /// O32 FPXX ABI is enabled. -1 is used to denote invalid index.
   int MoveF64ViaSpillFI = -1;
-
-  bool GPIsGlobalRegister = false;
 };
 
 } // end namespace llvm
diff --git a/llvm/lib/Target/Mips/MipsRegisterInfo.cpp b/llvm/lib/Target/Mips/MipsRegisterInfo.cpp
index 16fafcffdaa68..c64270b712531 100644
--- a/llvm/lib/Target/Mips/MipsRegisterInfo.cpp
+++ b/llvm/lib/Target/Mips/MipsRegisterInfo.cpp
@@ -25,6 +25,7 @@
 #include "llvm/CodeGen/TargetRegisterInfo.h"
 #include "llvm/CodeGen/TargetSubtargetInfo.h"
 #include "llvm/IR/Function.h"
+#include "llvm/IR/Module.h"
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/raw_ostream.h"
@@ -75,6 +76,24 @@ MipsRegisterInfo::getRegPressureLimit(const TargetRegisterClass *RC,
 // Callee Saved Registers methods
 //===----------------------------------------------------------------------===//
 
+/// Check if the user has declared $gp/$28 as a global regiater.
+bool isGPUsedAsGlobalRegister(const MachineFunction &MF) {
+  const Module *Module = MF.getFunction().getParent();
+
+  if (const NamedMDNode *NamedRegs =
+          Module->getNamedMetadata("llvm.named.register")) {
+    for (const auto *Op : NamedRegs->operands()) {
+      const MDString *RegStr = cast<MDString>(Op->getOperand(0));
+      StringRef RegName = RegStr->getString();
+      return RegName == "$28" || RegName == "$28_64" || RegName == "$gp" ||
+             RegName == "$gp_64";
+    }
+  } else if (Module->getNamedMetadata("llvm.named.register.$28"))
+    return true;
+
+  return false;
+}
+
 /// Mips Callee Saved Registers
 const MCPhysReg *
 MipsRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const {
@@ -89,7 +108,7 @@ MipsRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const {
                                      : CSR_Interrupt_32_SaveList;
   }
 
-  bool GPIsGlobal = MF->getInfo<MipsFunctionInfo>()->isGPGlobalRegister();
+  bool GPIsGlobal = isGPUsedAsGlobalRegister(*MF);
   // N64 ABI
   if (Subtarget.isABI_N64()) {
     if (Subtarget.isSingleFloat())
@@ -179,7 +198,7 @@ getReservedRegs(const MachineFunction &MF) const {
     Reserved.set(R);
 
   // For mno-abicalls, GP is a program invariant!
-  bool GPIsGlobal = MF.getInfo<MipsFunctionInfo>()->isGPGlobalRegister();
+  bool GPIsGlobal = isGPUsedAsGlobalRegister(MF);
   if (!Subtarget.isABICalls() || GPIsGlobal) {
     Reserved.set(Mips::GP);
     Reserved.set(Mips::GP_64);
diff --git a/llvm/test/CodeGen/Mips/write_register_gp.ll b/llvm/test/CodeGen/Mips/write_register_gp.ll
index 02b434126af81..bc31bf6b6ce80 100644
--- a/llvm/test/CodeGen/Mips/write_register_gp.ll
+++ b/llvm/test/CodeGen/Mips/write_register_gp.ll
@@ -1,6 +1,11 @@
 ; RUN: llc -mtriple=mips64el -mcpu=mips64r2 < %s | FileCheck %s -check-prefix=MIPS64
 
-define void @setglobal(i64 %x) {
+; Test that when a user declares $28 as a global register, assignments to it are
+; not optimizes away.
+; Clang previously generated no instruction, which GCC generated `move $gp, $4`.
+; This test ensures Clang matches GCC behavior.
+
+define void @setglobal(i64 %x) nounwind {
 ; MIPS64-LABEL: setglobal:
 ; MIPS64:       # %bb.0: # %entry
 ; MIPS64-NEXT:    jr $ra
@@ -11,7 +16,7 @@ entry:
   ret void
 }
 
-declare void @llvm.write_register.i64(metadata, i64) #1
+declare void @llvm.write_register.i64(metadata, i64) nounwind
 
 !llvm.named.register.$28 = !{!0}
 !0 = !{!"$28"}

>From 4bf03a84edf14e974a0c15d29962e81bcdee9b3b Mon Sep 17 00:00:00 2001
From: Ying Huang <ying.huang at oss.cipunited.com>
Date: Tue, 19 May 2026 17:59:01 +0800
Subject: [PATCH 3/4] Delete stray whitespace change.

---
 llvm/lib/Target/Mips/MipsRegisterInfo.cpp | 1 -
 1 file changed, 1 deletion(-)

diff --git a/llvm/lib/Target/Mips/MipsRegisterInfo.cpp b/llvm/lib/Target/Mips/MipsRegisterInfo.cpp
index c64270b712531..79b155fbbaa09 100644
--- a/llvm/lib/Target/Mips/MipsRegisterInfo.cpp
+++ b/llvm/lib/Target/Mips/MipsRegisterInfo.cpp
@@ -144,7 +144,6 @@ const uint32_t *
 MipsRegisterInfo::getCallPreservedMask(const MachineFunction &MF,
                                        CallingConv::ID) const {
   const MipsSubtarget &Subtarget = MF.getSubtarget<MipsSubtarget>();
-
   // N64 ABI
   if (Subtarget.isABI_N64()) {
     if (Subtarget.isSingleFloat())

>From 0ff5a7036a11688f8e0f83fa2c3dbf4a32809397 Mon Sep 17 00:00:00 2001
From: Ying Huang <ying.huang at oss.cipunited.com>
Date: Fri, 29 May 2026 17:04:41 +0800
Subject: [PATCH 4/4] Append test case for another register $gp

---
 llvm/lib/Target/Mips/MipsRegisterInfo.cpp   |  3 +--
 llvm/test/CodeGen/Mips/write_register_gp.ll | 17 +++++++++++++++--
 2 files changed, 16 insertions(+), 4 deletions(-)

diff --git a/llvm/lib/Target/Mips/MipsRegisterInfo.cpp b/llvm/lib/Target/Mips/MipsRegisterInfo.cpp
index 79b155fbbaa09..16eeebf505f2a 100644
--- a/llvm/lib/Target/Mips/MipsRegisterInfo.cpp
+++ b/llvm/lib/Target/Mips/MipsRegisterInfo.cpp
@@ -85,8 +85,7 @@ bool isGPUsedAsGlobalRegister(const MachineFunction &MF) {
     for (const auto *Op : NamedRegs->operands()) {
       const MDString *RegStr = cast<MDString>(Op->getOperand(0));
       StringRef RegName = RegStr->getString();
-      return RegName == "$28" || RegName == "$28_64" || RegName == "$gp" ||
-             RegName == "$gp_64";
+      return RegName == "$28" || RegName == "$gp";
     }
   } else if (Module->getNamedMetadata("llvm.named.register.$28"))
     return true;
diff --git a/llvm/test/CodeGen/Mips/write_register_gp.ll b/llvm/test/CodeGen/Mips/write_register_gp.ll
index bc31bf6b6ce80..58c497880cb8e 100644
--- a/llvm/test/CodeGen/Mips/write_register_gp.ll
+++ b/llvm/test/CodeGen/Mips/write_register_gp.ll
@@ -5,8 +5,8 @@
 ; Clang previously generated no instruction, which GCC generated `move $gp, $4`.
 ; This test ensures Clang matches GCC behavior.
 
-define void @setglobal(i64 %x) nounwind {
-; MIPS64-LABEL: setglobal:
+define void @setglobal_$28(i64 %x) nounwind {
+; MIPS64-LABEL: setglobal_$28:
 ; MIPS64:       # %bb.0: # %entry
 ; MIPS64-NEXT:    jr $ra
 ; MIPS64-NEXT:    move $gp, $4
@@ -16,8 +16,21 @@ entry:
   ret void
 }
 
+define void @setglobal_$gp(i64 %x) nounwind {
+; MIPS64-LABEL: setglobal_$gp:
+; MIPS64:       # %bb.0: # %entry
+; MIPS64-NEXT:    jr $ra
+; MIPS64-NEXT:    move $gp, $4
+
+entry:
+  tail call void @llvm.write_register.i64(metadata !1, i64 %x)
+  ret void
+}
+
 declare void @llvm.write_register.i64(metadata, i64) nounwind
 
 !llvm.named.register.$28 = !{!0}
+!llvm.named.register.$gp = !{!1}
 !0 = !{!"$28"}
+!1 = !{!"$gp"}
 



More information about the llvm-commits mailing list