[llvm] [Mips][RuntimeDyld] Reserve t9 for static JIT stubs (PR #228594)
Jiaxun Yang via llvm-commits
llvm-commits at lists.llvm.org
Sun Oct 4 16:06:19 PDT 2026
https://github.com/FlyGoat updated https://github.com/llvm/llvm-project/pull/228594
>From 5baf8c94ca48618b00beb1998bb7574f4e99c37a Mon Sep 17 00:00:00 2001
From: Jiaxun Yang <jiaxun.yang at flygoat.com>
Date: Fri, 2 Oct 2026 22:17:18 +0100
Subject: [PATCH] [MIPS][RuntimeDyld] Reserve t9 for static JIT stubs
MIPS PIC functions expect their entry address in t9 so their prologue can
compute gp. However, R_MIPS_26 is used for both function calls and jumps
within a function. A local jump is not a call boundary, so t9 may still
hold a live value there even though it is caller-saved.
Commit 458a983df422df85363ec40b1f1556f55b238aac switched these stubs from
t9 to at to preserve live t9 values across local jumps. That breaks calls
from JIT code with the static relocation model into PIC functions,
because the callee receives the wrong t9 and computes the wrong gp.
Revert that change so every MIPS stub materializes its destination in t9.
Reserve t9 in codegen to avoid stubs corrupting live values in registers.
Fixes #228414.
---
.../RuntimeDyld/RuntimeDyld.cpp | 56 +++++++++----------
llvm/lib/Target/Mips/MipsRegisterInfo.cpp | 7 +++
llvm/lib/Target/Mips/MipsTargetMachine.cpp | 4 +-
llvm/lib/Target/Mips/MipsTargetMachine.h | 2 +
4 files changed, 39 insertions(+), 30 deletions(-)
diff --git a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp
index 252506ef22853..7e173691f3f26 100644
--- a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp
+++ b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp
@@ -1006,45 +1006,45 @@ uint8_t *RuntimeDyldImpl::createStubFunction(uint8_t *Addr,
writeBytesUnaligned(0x4c000180, Addr + 16, 4);
return Addr;
} else if (IsMipsO32ABI || IsMipsN32ABI) {
- // 0: 3c010000 lui at,%hi(addr).
- // 4: 24210000 addiu at,at,%lo(addr).
- // 8: 00200008 jr at.
+ // 0: 3c190000 lui t9,%hi(addr).
+ // 4: 27390000 addiu t9,t9,%lo(addr).
+ // 8: 03200008 jr t9.
// c: 00000000 nop.
- const unsigned LuiATInstr = 0x3c010000, AdduiATInstr = 0x24210000;
+ const unsigned LuiT9Instr = 0x3c190000, AdduiT9Instr = 0x27390000;
const unsigned NopInstr = 0x0;
- unsigned JrATInstr = 0x00200008;
+ unsigned JrT9Instr = 0x03200008;
if ((AbiVariant & ELF::EF_MIPS_ARCH) == ELF::EF_MIPS_ARCH_32R6 ||
(AbiVariant & ELF::EF_MIPS_ARCH) == ELF::EF_MIPS_ARCH_64R6)
- JrATInstr = 0x00200009;
+ JrT9Instr = 0x03200009;
- writeBytesUnaligned(LuiATInstr, Addr, 4);
- writeBytesUnaligned(AdduiATInstr, Addr + 4, 4);
- writeBytesUnaligned(JrATInstr, Addr + 8, 4);
+ writeBytesUnaligned(LuiT9Instr, Addr, 4);
+ writeBytesUnaligned(AdduiT9Instr, Addr + 4, 4);
+ writeBytesUnaligned(JrT9Instr, Addr + 8, 4);
writeBytesUnaligned(NopInstr, Addr + 12, 4);
return Addr;
} else if (IsMipsN64ABI) {
- // 0: 3c010000 lui at,%highest(addr).
- // 4: 64210000 daddiu at,at,%higher(addr).
- // 8: 00010C38 dsll at,at,16.
- // c: 64210000 daddiu at,at,%hi(addr).
- // 10: 00010C38 dsll at,at,16.
- // 14: 64210000 daddiu at,at,%lo(addr).
- // 18: 00200008 jr at.
+ // 0: 3c190000 lui t9,%highest(addr).
+ // 4: 67390000 daddiu t9,t9,%higher(addr).
+ // 8: 0019CC38 dsll t9,t9,16.
+ // c: 67390000 daddiu t9,t9,%hi(addr).
+ // 10: 0019CC38 dsll t9,t9,16.
+ // 14: 67390000 daddiu t9,t9,%lo(addr).
+ // 18: 03200008 jr t9.
// 1c: 00000000 nop.
- const unsigned LuiATInstr = 0x3c010000, DaddiuATInstr = 0x64210000,
- DsllATInstr = 0x10c38;
+ const unsigned LuiT9Instr = 0x3c190000, DaddiuT9Instr = 0x67390000,
+ DsllT9Instr = 0x19CC38;
const unsigned NopInstr = 0x0;
- unsigned JrATInstr = 0x00200008;
+ unsigned JrT9Instr = 0x03200008;
if ((AbiVariant & ELF::EF_MIPS_ARCH) == ELF::EF_MIPS_ARCH_64R6)
- JrATInstr = 0x00200009;
-
- writeBytesUnaligned(LuiATInstr, Addr, 4);
- writeBytesUnaligned(DaddiuATInstr, Addr + 4, 4);
- writeBytesUnaligned(DsllATInstr, Addr + 8, 4);
- writeBytesUnaligned(DaddiuATInstr, Addr + 12, 4);
- writeBytesUnaligned(DsllATInstr, Addr + 16, 4);
- writeBytesUnaligned(DaddiuATInstr, Addr + 20, 4);
- writeBytesUnaligned(JrATInstr, Addr + 24, 4);
+ JrT9Instr = 0x03200009;
+
+ writeBytesUnaligned(LuiT9Instr, Addr, 4);
+ writeBytesUnaligned(DaddiuT9Instr, Addr + 4, 4);
+ writeBytesUnaligned(DsllT9Instr, Addr + 8, 4);
+ writeBytesUnaligned(DaddiuT9Instr, Addr + 12, 4);
+ writeBytesUnaligned(DsllT9Instr, Addr + 16, 4);
+ writeBytesUnaligned(DaddiuT9Instr, Addr + 20, 4);
+ writeBytesUnaligned(JrT9Instr, Addr + 24, 4);
writeBytesUnaligned(NopInstr, Addr + 28, 4);
return Addr;
} else if (Arch == Triple::ppc64 || Arch == Triple::ppc64le) {
diff --git a/llvm/lib/Target/Mips/MipsRegisterInfo.cpp b/llvm/lib/Target/Mips/MipsRegisterInfo.cpp
index d68ab86dd0efe..98e8e1f406cf8 100644
--- a/llvm/lib/Target/Mips/MipsRegisterInfo.cpp
+++ b/llvm/lib/Target/Mips/MipsRegisterInfo.cpp
@@ -15,6 +15,7 @@
#include "Mips.h"
#include "MipsMachineFunction.h"
#include "MipsSubtarget.h"
+#include "MipsTargetMachine.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineFunction.h"
@@ -178,6 +179,12 @@ getReservedRegs(const MachineFunction &MF) const {
for (MCPhysReg R : ReservedGPR64)
Reserved.set(R);
+ // Static JIT code uses t9 in RuntimeDyld stubs for R_MIPS_26 relocations,
+ // including jumps within a function. Keep it out of register allocation.
+ const auto &TM = static_cast<const MipsTargetMachine &>(MF.getTarget());
+ if (TM.isJIT() && TM.getRelocationModel() == Reloc::Static)
+ markSuperRegs(Reserved, Mips::T9);
+
// Mark user-reserved GPRs and their 64-bit super-registers.
for (unsigned I = 1; I < 32; ++I)
if (Subtarget.isGPRReservedByUser(I))
diff --git a/llvm/lib/Target/Mips/MipsTargetMachine.cpp b/llvm/lib/Target/Mips/MipsTargetMachine.cpp
index 25d7c22454ecf..b0d76b0aa633a 100644
--- a/llvm/lib/Target/Mips/MipsTargetMachine.cpp
+++ b/llvm/lib/Target/Mips/MipsTargetMachine.cpp
@@ -98,12 +98,12 @@ MipsTargetMachine::MipsTargetMachine(const Target &T, const Triple &TT,
const TargetOptions &Options,
std::optional<Reloc::Model> RM,
std::optional<CodeModel::Model> CM,
- CodeGenOptLevel OL, bool /*JIT*/,
+ CodeGenOptLevel OL, bool JIT,
bool isLittle)
: CodeGenTargetMachineImpl(T, TT, CPU, FS, Options,
getEffectiveRelocModel(RM),
getEffectiveCodeModel(CM, CodeModel::Small), OL),
- isLittle(isLittle),
+ isLittle(isLittle), IsJIT(JIT),
DefaultSubtarget(TT, CPU, FS, Options.MCOptions.getABIName(), isLittle,
*this, std::nullopt),
TLOF(createTLOF(TT, DefaultSubtarget.useSmallSection())) {
diff --git a/llvm/lib/Target/Mips/MipsTargetMachine.h b/llvm/lib/Target/Mips/MipsTargetMachine.h
index 5f4ca639408d9..3103ca252bf22 100644
--- a/llvm/lib/Target/Mips/MipsTargetMachine.h
+++ b/llvm/lib/Target/Mips/MipsTargetMachine.h
@@ -26,6 +26,7 @@ namespace llvm {
class MipsTargetMachine : public CodeGenTargetMachineImpl {
bool isLittle;
+ bool IsJIT;
// Used to initialize module-wide object-file policy.
MipsSubtarget DefaultSubtarget;
std::unique_ptr<TargetLoweringObjectFile> TLOF;
@@ -65,6 +66,7 @@ class MipsTargetMachine : public CodeGenTargetMachineImpl {
}
bool isLittleEndian() const { return isLittle; }
+ bool isJIT() const { return IsJIT; }
};
/// Mips32/64 big endian target machine.
More information about the llvm-commits
mailing list