https://github.com/FlyGoat created https://github.com/llvm/llvm-project/pull/217013
NetBSD dedicates GPR $24 to mips_curlwp and passes -ffixed-24 when building the MIPS kernel. Add Clang driver options for numeric MIPS GPRs and lower them to reserve-gprN target features. Teach the backend to reserve the corresponding 32-bit register and its 64-bit super-register, and require named-register accesses to refer to reserved registers. Also replace the regex-based numeric register parsing with StringRef::getAsInteger and add driver, allocation, and global-register regression coverage. >From 113b5bc1016a99867b8a59e166d969531b3bc795 Mon Sep 17 00:00:00 2001 From: Jiaxun Yang <[email protected]> Date: Tue, 18 Aug 2026 09:49:15 +0100 Subject: [PATCH] [Mips] Support reserving GPRs with -ffixed-N NetBSD dedicates GPR $24 to mips_curlwp and passes -ffixed-24 when building the MIPS kernel. Add Clang driver options for numeric MIPS GPRs and lower them to reserve-gprN target features. Teach the backend to reserve the corresponding 32-bit register and its 64-bit super-register, and require named-register accesses to refer to reserved registers. Also replace the regex-based numeric register parsing with StringRef::getAsInteger and add driver, allocation, and global-register regression coverage. --- clang/include/clang/Options/Options.td | 3 ++ clang/lib/Driver/ToolChains/Arch/Mips.cpp | 38 ++++++++++++++++ .../test/CodeGen/Mips/fixed-register-global.c | 20 +++++++++ clang/test/Driver/mips-fixed-register.c | 44 +++++++++++++++++++ llvm/lib/Target/Mips/Mips.td | 5 +++ llvm/lib/Target/Mips/MipsISelLowering.cpp | 37 ++++++++-------- llvm/lib/Target/Mips/MipsRegisterInfo.cpp | 5 +++ llvm/lib/Target/Mips/MipsSubtarget.h | 9 ++++ .../test/CodeGen/Mips/get-register-reserve.ll | 23 ++++++++++ llvm/test/CodeGen/Mips/named-register-n32.ll | 3 +- llvm/test/CodeGen/Mips/named-register-n64.ll | 3 +- llvm/test/CodeGen/Mips/named-register-o32.ll | 3 +- llvm/test/CodeGen/Mips/reserved-gpr.ll | 22 ++++++++++ 13 files changed, 194 insertions(+), 21 deletions(-) create mode 100644 clang/test/CodeGen/Mips/fixed-register-global.c create mode 100644 clang/test/Driver/mips-fixed-register.c create mode 100644 llvm/test/CodeGen/Mips/get-register-reserve.ll create mode 100644 llvm/test/CodeGen/Mips/reserved-gpr.ll diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td index adc4224dd561c..5904977979415 100644 --- a/clang/include/clang/Options/Options.td +++ b/clang/include/clang/Options/Options.td @@ -6403,6 +6403,9 @@ def mno_fix_r5900 : Flag<["-"], "mno-fix-r5900">, HelpText<"Disable R5900 short loop erratum fix">; def mcompact_branches_EQ : Joined<["-"], "mcompact-branches=">, Group<m_mips_Features_Group>; +foreach i = {1-31} in + def ffixed_#i : Flag<["-"], "ffixed-"#i>, Group<m_Group>, + HelpText<"Reserve the MIPS GPR "#i#" register (MIPS only)">; } // let Flags = [TargetSpecific] def mbranch_likely : Flag<["-"], "mbranch-likely">, Group<m_Group>, IgnoredGCCCompat; diff --git a/clang/lib/Driver/ToolChains/Arch/Mips.cpp b/clang/lib/Driver/ToolChains/Arch/Mips.cpp index b72d654291658..e3187351a0b55 100644 --- a/clang/lib/Driver/ToolChains/Arch/Mips.cpp +++ b/clang/lib/Driver/ToolChains/Arch/Mips.cpp @@ -190,6 +190,44 @@ void mips::getMIPSTargetFeatures(const Driver &D, const llvm::Triple &Triple, getMipsCPUAndABI(Args, Triple, CPUName, ABIName); ABIName = getGnuCompatibleMipsABIName(ABIName); + // Handle features corresponding to GCC's -ffixed-REG options. MIPS spells + // its GPRs numerically, so preserve that spelling in the driver interface. +#define RESERVE_GPR(REG) \ + if (Args.hasArg(options::OPT_ffixed_##REG)) \ + Features.push_back("+reserve-gpr" #REG); + RESERVE_GPR(1) + RESERVE_GPR(2) + RESERVE_GPR(3) + RESERVE_GPR(4) + RESERVE_GPR(5) + RESERVE_GPR(6) + RESERVE_GPR(7) + RESERVE_GPR(8) + RESERVE_GPR(9) + RESERVE_GPR(10) + RESERVE_GPR(11) + RESERVE_GPR(12) + RESERVE_GPR(13) + RESERVE_GPR(14) + RESERVE_GPR(15) + RESERVE_GPR(16) + RESERVE_GPR(17) + RESERVE_GPR(18) + RESERVE_GPR(19) + RESERVE_GPR(20) + RESERVE_GPR(21) + RESERVE_GPR(22) + RESERVE_GPR(23) + RESERVE_GPR(24) + RESERVE_GPR(25) + RESERVE_GPR(26) + RESERVE_GPR(27) + RESERVE_GPR(28) + RESERVE_GPR(29) + RESERVE_GPR(30) + RESERVE_GPR(31) +#undef RESERVE_GPR + // Historically, PIC code for MIPS was associated with -mabicalls, a.k.a // SVR4 abicalls. Static code does not use SVR4 calling sequences. An ABI // extension was developed by Richard Sandiford & Code Sourcery to support diff --git a/clang/test/CodeGen/Mips/fixed-register-global.c b/clang/test/CodeGen/Mips/fixed-register-global.c new file mode 100644 index 0000000000000..6fbba1798e6be --- /dev/null +++ b/clang/test/CodeGen/Mips/fixed-register-global.c @@ -0,0 +1,20 @@ +// REQUIRES: mips-registered-target +// RUN: %clang --target=mipsel-unknown-netbsd -ffixed-24 -O2 -S %s -o - \ +// RUN: | FileCheck %s +// RUN: %clang --target=mips64el-unknown-netbsd -ffixed-24 -O2 -S %s -o - \ +// RUN: | FileCheck %s + +// Match GCC's global register variable syntax used by the NetBSD MIPS kernel. +register void *mips_curlwp asm("$24"); + +// CHECK-LABEL: get_curlwp: +// CHECK: move $2, $24 +void *get_curlwp(void) { + return mips_curlwp; +} + +// CHECK-LABEL: set_curlwp: +// CHECK: move $24, $4 +void set_curlwp(void *lwp) { + mips_curlwp = lwp; +} diff --git a/clang/test/Driver/mips-fixed-register.c b/clang/test/Driver/mips-fixed-register.c new file mode 100644 index 0000000000000..4a7d59697764e --- /dev/null +++ b/clang/test/Driver/mips-fixed-register.c @@ -0,0 +1,44 @@ +// RUN: %clang --target=mipsel-unknown-linux-gnu \ +// RUN: -ffixed-1 -ffixed-2 -ffixed-3 -ffixed-4 -ffixed-5 \ +// RUN: -ffixed-6 -ffixed-7 -ffixed-8 -ffixed-9 -ffixed-10 \ +// RUN: -ffixed-11 -ffixed-12 -ffixed-13 -ffixed-14 -ffixed-15 \ +// RUN: -ffixed-16 -ffixed-17 -ffixed-18 -ffixed-19 -ffixed-20 \ +// RUN: -ffixed-21 -ffixed-22 -ffixed-23 -ffixed-24 -ffixed-25 \ +// RUN: -ffixed-26 -ffixed-27 -ffixed-28 -ffixed-29 -ffixed-30 \ +// RUN: -ffixed-31 -### %s 2>&1 | FileCheck %s + +// CHECK-DAG: "-target-feature" "+reserve-gpr1" +// CHECK-DAG: "-target-feature" "+reserve-gpr2" +// CHECK-DAG: "-target-feature" "+reserve-gpr3" +// CHECK-DAG: "-target-feature" "+reserve-gpr4" +// CHECK-DAG: "-target-feature" "+reserve-gpr5" +// CHECK-DAG: "-target-feature" "+reserve-gpr6" +// CHECK-DAG: "-target-feature" "+reserve-gpr7" +// CHECK-DAG: "-target-feature" "+reserve-gpr8" +// CHECK-DAG: "-target-feature" "+reserve-gpr9" +// CHECK-DAG: "-target-feature" "+reserve-gpr10" +// CHECK-DAG: "-target-feature" "+reserve-gpr11" +// CHECK-DAG: "-target-feature" "+reserve-gpr12" +// CHECK-DAG: "-target-feature" "+reserve-gpr13" +// CHECK-DAG: "-target-feature" "+reserve-gpr14" +// CHECK-DAG: "-target-feature" "+reserve-gpr15" +// CHECK-DAG: "-target-feature" "+reserve-gpr16" +// CHECK-DAG: "-target-feature" "+reserve-gpr17" +// CHECK-DAG: "-target-feature" "+reserve-gpr18" +// CHECK-DAG: "-target-feature" "+reserve-gpr19" +// CHECK-DAG: "-target-feature" "+reserve-gpr20" +// CHECK-DAG: "-target-feature" "+reserve-gpr21" +// CHECK-DAG: "-target-feature" "+reserve-gpr22" +// CHECK-DAG: "-target-feature" "+reserve-gpr23" +// CHECK-DAG: "-target-feature" "+reserve-gpr24" +// CHECK-DAG: "-target-feature" "+reserve-gpr25" +// CHECK-DAG: "-target-feature" "+reserve-gpr26" +// CHECK-DAG: "-target-feature" "+reserve-gpr27" +// CHECK-DAG: "-target-feature" "+reserve-gpr28" +// CHECK-DAG: "-target-feature" "+reserve-gpr29" +// CHECK-DAG: "-target-feature" "+reserve-gpr30" +// CHECK-DAG: "-target-feature" "+reserve-gpr31" + +// RUN: not %clang --target=x86_64-unknown-linux-gnu -ffixed-24 -### %s 2>&1 \ +// RUN: | FileCheck --check-prefix=NOT-MIPS %s +// NOT-MIPS: error: unsupported option '-ffixed-24' for target 'x86_64-unknown-linux-gnu' diff --git a/llvm/lib/Target/Mips/Mips.td b/llvm/lib/Target/Mips/Mips.td index 41d38f10da816..3b78de8ec43ad 100644 --- a/llvm/lib/Target/Mips/Mips.td +++ b/llvm/lib/Target/Mips/Mips.td @@ -252,6 +252,11 @@ include "MipsCallingConv.td" include "MipsRegisterBanks.td" include "MipsCombine.td" +foreach i = {1-31} in + def FeatureReserveGPR#i : + SubtargetFeature<"reserve-gpr"#i, "UserReservedGPR["#i#"]", "true", + "Reserve MIPS GPR "#i>; + // Avoid forward declaration issues. include "MipsScheduleI6400.td" include "MipsScheduleP5600.td" diff --git a/llvm/lib/Target/Mips/MipsISelLowering.cpp b/llvm/lib/Target/Mips/MipsISelLowering.cpp index 076ca31649c43..a374cce447353 100644 --- a/llvm/lib/Target/Mips/MipsISelLowering.cpp +++ b/llvm/lib/Target/Mips/MipsISelLowering.cpp @@ -72,7 +72,6 @@ #include <cstdint> #include <deque> #include <iterator> -#include <regex> #include <string> #include <utility> #include <vector> @@ -4983,29 +4982,31 @@ int MipsTargetLowering::getCPURegisterIndex(StringRef Name) const { Register MipsTargetLowering::getRegisterByName(const char *RegName, LLT VT, const MachineFunction &MF) const { - // 1. Delete symbol '$'. - std::string newRegName = RegName; - if (StringRef(RegName).starts_with("$")) - newRegName = StringRef(RegName).substr(1); - - // 2. Get register index value. - std::smatch matchResult; - int regIdx; - static const std::regex matchStr("^[0-9]*$"); - if (std::regex_match(newRegName, matchResult, matchStr)) - regIdx = std::stoi(newRegName); - else { - newRegName = StringRef(newRegName).lower(); - regIdx = getCPURegisterIndex(StringRef(newRegName)); + StringRef Name(RegName); + Name.consume_front("$"); + + unsigned RegIdx; + if (Name.getAsInteger(10, RegIdx)) { + std::string LowerName = Name.lower(); + int NamedRegIdx = getCPURegisterIndex(LowerName); + if (NamedRegIdx < 0) + report_fatal_error( + Twine("Invalid register name \"" + StringRef(RegName) + "\".")); + RegIdx = NamedRegIdx; } - // 3. Get register. - if (regIdx >= 0 && regIdx < 32) { + if (RegIdx < 32) { const MCRegisterInfo *MRI = MF.getContext().getRegisterInfo(); const MCRegisterClass &RC = Subtarget.isGP64bit() ? MRI->getRegClass(Mips::GPR64RegClassID) : MRI->getRegClass(Mips::GPR32RegClassID); - return RC.getRegister(regIdx); + Register Reg = RC.getRegister(RegIdx); + BitVector ReservedRegs = + Subtarget.getRegisterInfo()->getReservedRegs(MF); + if (!ReservedRegs.test(Reg)) + reportFatalUsageError(Twine("Trying to obtain non-reserved register \"" + + StringRef(RegName) + "\".")); + return Reg; } report_fatal_error( diff --git a/llvm/lib/Target/Mips/MipsRegisterInfo.cpp b/llvm/lib/Target/Mips/MipsRegisterInfo.cpp index 494c07214d1b6..ed5f2d48902f2 100644 --- a/llvm/lib/Target/Mips/MipsRegisterInfo.cpp +++ b/llvm/lib/Target/Mips/MipsRegisterInfo.cpp @@ -185,6 +185,11 @@ getReservedRegs(const MachineFunction &MF) const { for (MCPhysReg R : ReservedGPR64) Reserved.set(R); + // Mark user-reserved GPRs and their 64-bit super-registers. + for (unsigned I = 1; I < 32; ++I) + if (Subtarget.isGPRReservedByUser(I)) + markSuperRegs(Reserved, Mips::GPR32RegClass.getRegister(I)); + // For mno-abicalls, GP is a program invariant! bool GPIsGlobal = isGPUsedAsGlobalRegister(MF); if (!Subtarget.isABICalls() || GPIsGlobal) { diff --git a/llvm/lib/Target/Mips/MipsSubtarget.h b/llvm/lib/Target/Mips/MipsSubtarget.h index 3acfaa82965ab..58011de3dbd8a 100644 --- a/llvm/lib/Target/Mips/MipsSubtarget.h +++ b/llvm/lib/Target/Mips/MipsSubtarget.h @@ -24,6 +24,7 @@ #include "llvm/CodeGen/TargetSubtargetInfo.h" #include "llvm/IR/DataLayout.h" #include "llvm/Support/ErrorHandling.h" +#include <bitset> #define GET_SUBTARGETINFO_HEADER #include "MipsGenSubtargetInfo.inc" @@ -111,6 +112,9 @@ class MipsSubtarget : public MipsGenSubtargetInfo { // IsGP64bit - General-purpose registers are 64 bits wide bool IsGP64bit; + // MIPS GPRs explicitly reserved through -ffixed-REG. + std::bitset<32> UserReservedGPR; + // IsPTR64bit - Pointers are 64 bit wide bool IsPTR64bit; @@ -252,6 +256,11 @@ class MipsSubtarget : public MipsGenSubtargetInfo { const MipsABIInfo &getABI() const; bool isABI_FPXX() const { return isABI_O32() && IsFPXX; } + bool isGPRReservedByUser(unsigned GPR) const { + assert(GPR < UserReservedGPR.size() && "GPR number out of range"); + return UserReservedGPR[GPR]; + } + /// This constructor initializes the data members to match that /// of the specified triple. MipsSubtarget(const Triple &TT, StringRef CPU, StringRef FS, bool little, diff --git a/llvm/test/CodeGen/Mips/get-register-reserve.ll b/llvm/test/CodeGen/Mips/get-register-reserve.ll new file mode 100644 index 0000000000000..7792719808238 --- /dev/null +++ b/llvm/test/CodeGen/Mips/get-register-reserve.ll @@ -0,0 +1,23 @@ +; RUN: not llc < %s -mtriple=mipsel 2>&1 \ +; RUN: | FileCheck --check-prefix=NO-RESERVE %s +; RUN: llc < %s -mtriple=mipsel -mattr=+reserve-gpr24,+noabicalls \ +; RUN: | FileCheck --check-prefix=RESERVE %s + +define i32 @get_reg_t8() nounwind { +; NO-RESERVE: Trying to obtain non-reserved register "$24". +; RESERVE-LABEL: get_reg_t8: +; RESERVE: move $2, $24 + %t8 = call i32 @llvm.read_register.i32(metadata !0) + ret i32 %t8 +} + +; Static MIPS code uses -mno-abicalls, which inherently reserves $gp. +define i32 @get_reg_gp() nounwind { +; RESERVE-LABEL: get_reg_gp: +; RESERVE: move $2, $gp + %gp = call i32 @llvm.read_register.i32(metadata !1) + ret i32 %gp +} + +!0 = !{!"$24\00"} +!1 = !{!"$gp\00"} diff --git a/llvm/test/CodeGen/Mips/named-register-n32.ll b/llvm/test/CodeGen/Mips/named-register-n32.ll index ab7a91e9e7cb9..953c58456bfc2 100644 --- a/llvm/test/CodeGen/Mips/named-register-n32.ll +++ b/llvm/test/CodeGen/Mips/named-register-n32.ll @@ -1,5 +1,6 @@ ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py -; RUN: llc -mtriple=mips64 -relocation-model=static -mattr=+noabicalls \ +; RUN: llc -mtriple=mips64 -relocation-model=static \ +; RUN: -mattr=+noabicalls,+reserve-gpr1,+reserve-gpr2,+reserve-gpr3,+reserve-gpr4,+reserve-gpr5,+reserve-gpr6,+reserve-gpr7,+reserve-gpr8,+reserve-gpr9,+reserve-gpr10,+reserve-gpr11,+reserve-gpr12,+reserve-gpr13,+reserve-gpr14,+reserve-gpr15,+reserve-gpr16,+reserve-gpr17,+reserve-gpr18,+reserve-gpr19,+reserve-gpr20,+reserve-gpr21,+reserve-gpr22,+reserve-gpr23,+reserve-gpr24,+reserve-gpr25,+reserve-gpr26,+reserve-gpr27,+reserve-gpr28,+reserve-gpr29,+reserve-gpr30,+reserve-gpr31 \ ; RUN: -target-abi n32 -verify-machineinstrs < %s | FileCheck %s declare i64 @llvm.read_register.i64(metadata) diff --git a/llvm/test/CodeGen/Mips/named-register-n64.ll b/llvm/test/CodeGen/Mips/named-register-n64.ll index d886e98d76df9..49d0eb61fd058 100644 --- a/llvm/test/CodeGen/Mips/named-register-n64.ll +++ b/llvm/test/CodeGen/Mips/named-register-n64.ll @@ -1,5 +1,6 @@ ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py -; RUN: llc -mtriple=mips64 -relocation-model=static -mattr=+noabicalls \ +; RUN: llc -mtriple=mips64 -relocation-model=static \ +; RUN: -mattr=+noabicalls,+reserve-gpr1,+reserve-gpr2,+reserve-gpr3,+reserve-gpr4,+reserve-gpr5,+reserve-gpr6,+reserve-gpr7,+reserve-gpr8,+reserve-gpr9,+reserve-gpr10,+reserve-gpr11,+reserve-gpr12,+reserve-gpr13,+reserve-gpr14,+reserve-gpr15,+reserve-gpr16,+reserve-gpr17,+reserve-gpr18,+reserve-gpr19,+reserve-gpr20,+reserve-gpr21,+reserve-gpr22,+reserve-gpr23,+reserve-gpr24,+reserve-gpr25,+reserve-gpr26,+reserve-gpr27,+reserve-gpr28,+reserve-gpr29,+reserve-gpr30,+reserve-gpr31 \ ; RUN: -verify-machineinstrs < %s | FileCheck %s declare i64 @llvm.read_register.i64(metadata) diff --git a/llvm/test/CodeGen/Mips/named-register-o32.ll b/llvm/test/CodeGen/Mips/named-register-o32.ll index 8ec4842ef2753..c61eee4f5a240 100644 --- a/llvm/test/CodeGen/Mips/named-register-o32.ll +++ b/llvm/test/CodeGen/Mips/named-register-o32.ll @@ -1,5 +1,6 @@ ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py -; RUN: llc -mtriple=mips -relocation-model=static -mattr=+noabicalls \ +; RUN: llc -mtriple=mips -relocation-model=static \ +; RUN: -mattr=+noabicalls,+reserve-gpr1,+reserve-gpr2,+reserve-gpr3,+reserve-gpr4,+reserve-gpr5,+reserve-gpr6,+reserve-gpr7,+reserve-gpr8,+reserve-gpr9,+reserve-gpr10,+reserve-gpr11,+reserve-gpr12,+reserve-gpr13,+reserve-gpr14,+reserve-gpr15,+reserve-gpr16,+reserve-gpr17,+reserve-gpr18,+reserve-gpr19,+reserve-gpr20,+reserve-gpr21,+reserve-gpr22,+reserve-gpr23,+reserve-gpr24,+reserve-gpr25,+reserve-gpr26,+reserve-gpr27,+reserve-gpr28,+reserve-gpr29,+reserve-gpr30,+reserve-gpr31 \ ; RUN: -verify-machineinstrs < %s | FileCheck %s declare i32 @llvm.read_register.i64(metadata) diff --git a/llvm/test/CodeGen/Mips/reserved-gpr.ll b/llvm/test/CodeGen/Mips/reserved-gpr.ll new file mode 100644 index 0000000000000..3b5103524031c --- /dev/null +++ b/llvm/test/CodeGen/Mips/reserved-gpr.ll @@ -0,0 +1,22 @@ +; RUN: llc -mtriple=mipsel -verify-machineinstrs < %s \ +; RUN: | FileCheck %s --check-prefix=UNRESERVED +; RUN: llc -mtriple=mips64el -verify-machineinstrs < %s \ +; RUN: | FileCheck %s --check-prefix=UNRESERVED +; RUN: llc -mtriple=mipsel -mattr=+reserve-gpr24 -verify-machineinstrs < %s \ +; RUN: | FileCheck %s --check-prefix=RESERVED +; RUN: llc -mtriple=mips64el -mattr=+reserve-gpr24 -verify-machineinstrs < %s \ +; RUN: | FileCheck %s --check-prefix=RESERVED + +; Exhaust the allocatable GPRs so this uses $24 without the reservation. +@var = global [32 x i64] zeroinitializer + +define void @foo() { +; UNRESERVED-LABEL: foo: +; UNRESERVED: $24 +; RESERVED-LABEL: foo: +; RESERVED-NOT: $24 +; RESERVED: .end foo + %v = load volatile [32 x i64], ptr @var + store volatile [32 x i64] %v, ptr @var + ret void +} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
