[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