[llvm] [Mips] Fix $gp was restored when used as global register variable (PR #201778)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Jun 11 01:43:15 PDT 2026
https://github.com/yingopq updated https://github.com/llvm/llvm-project/pull/201778
>From a36e92a4b8ec1bb075de910e7763ae04095df59e Mon Sep 17 00:00:00 2001
From: Ying Huang <ying.huang at oss.cipunited.com>
Date: Fri, 5 Jun 2026 16:19:00 +0800
Subject: [PATCH 1/2] [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`.
Check the module metadata `llvm.named.register.$28` to detect if
$28 is used as global register. 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/MipsRegisterInfo.cpp | 22 +++++++++++++++-----
llvm/test/CodeGen/Mips/write_register_gp.ll | 23 +++++++++++++++++++++
3 files changed, 53 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/MipsRegisterInfo.cpp b/llvm/lib/Target/Mips/MipsRegisterInfo.cpp
index 948d4db8585db..494c07214d1b6 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,13 @@ 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();
+
+ return Module->getNamedMetadata("llvm.named.register.$28");
+}
+
/// Mips Callee Saved Registers
const MCPhysReg *
MipsRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const {
@@ -89,20 +97,23 @@ MipsRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const {
: CSR_Interrupt_32_SaveList;
}
+ bool GPIsGlobal = isGPUsedAsGlobalRegister(*MF);
// 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
@@ -175,7 +186,8 @@ getReservedRegs(const MachineFunction &MF) const {
Reserved.set(R);
// For mno-abicalls, GP is a program invariant!
- if (!Subtarget.isABICalls()) {
+ 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
new file mode 100644
index 0000000000000..62f88206a1d64
--- /dev/null
+++ b/llvm/test/CodeGen/Mips/write_register_gp.ll
@@ -0,0 +1,23 @@
+; RUN: llc -mtriple=mips64el -mcpu=mips64r2 < %s | FileCheck %s -check-prefix=MIPS64
+
+; 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_$28(i64 %x) nounwind {
+; MIPS64-LABEL: setglobal_$28:
+; 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) nounwind
+
+!llvm.named.register.$28 = !{!0}
+!0 = !{!"$28"}
+
>From 930513e2ed86b911357508c85ff3fd05515d9d1a Mon Sep 17 00:00:00 2001
From: Ying Huang <ying.huang at oss.cipunited.com>
Date: Thu, 11 Jun 2026 16:42:31 +0800
Subject: [PATCH 2/2] Append test for N32 and N64.
---
llvm/test/CodeGen/Mips/write_register_gp.ll | 22 ++++++++++++++-------
1 file changed, 15 insertions(+), 7 deletions(-)
diff --git a/llvm/test/CodeGen/Mips/write_register_gp.ll b/llvm/test/CodeGen/Mips/write_register_gp.ll
index 62f88206a1d64..3c118b1389c6e 100644
--- a/llvm/test/CodeGen/Mips/write_register_gp.ll
+++ b/llvm/test/CodeGen/Mips/write_register_gp.ll
@@ -1,15 +1,23 @@
-; RUN: llc -mtriple=mips64el -mcpu=mips64r2 < %s | FileCheck %s -check-prefix=MIPS64
+; RUN: llc -mtriple=mips64el-unknown-linux-gnu -mcpu=mips64r2 -target-abi=n32 < %s -filetype=asm -o - \
+; RUN: | FileCheck -check-prefixes=N32 %s
+; RUN: llc -mtriple=mips64el-unknown-linux-gnu -mcpu=mips64r2 -target-abi=n64 < %s -filetype=asm -o - \
+; RUN: | FileCheck -check-prefixes=N64 %s
; Test that when a user declares $28 as a global register, assignments to it are
-; not optimizes away.
+; not optimized away.
; Clang previously generated no instruction, which GCC generated `move $gp, $4`.
; This test ensures Clang matches GCC behavior.
-define void @setglobal_$28(i64 %x) nounwind {
-; MIPS64-LABEL: setglobal_$28:
-; MIPS64: # %bb.0: # %entry
-; MIPS64-NEXT: jr $ra
-; MIPS64-NEXT: move $gp, $4
+define void @setglobal(i64 %x) nounwind {
+; N32-LABEL: setglobal:
+; N32: # %bb.0: # %entry
+; N32-NEXT: jr $ra
+; N32-NEXT: move $gp, $4
+
+; N64-LABEL: setglobal:
+; N64: # %bb.0: # %entry
+; N64-NEXT: jr $ra
+; N64-NEXT: move $gp, $4
entry:
tail call void @llvm.write_register.i64(metadata !0, i64 %x)
More information about the llvm-commits
mailing list