https://github.com/rickgaiser updated 
https://github.com/llvm/llvm-project/pull/176666

>From 71b10943ce67885375dfa9bdd4ed767cb59b3943 Mon Sep 17 00:00:00 2001
From: Rick Gaiser <[email protected]>
Date: Sun, 18 Jan 2026 15:53:30 +0100
Subject: [PATCH 1/6] [Mips] Add r5900 CPU definition and feature flag

---
 llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp         | 2 ++
 llvm/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp | 2 ++
 llvm/lib/Target/Mips/Mips.td                             | 5 +++++
 llvm/lib/Target/Mips/MipsSubtarget.cpp                   | 8 ++++----
 llvm/lib/Target/Mips/MipsSubtarget.h                     | 4 ++++
 llvm/test/CodeGen/Mips/cpus.ll                           | 4 ++++
 6 files changed, 21 insertions(+), 4 deletions(-)

diff --git a/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp 
b/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp
index 6675db755d1a1..f91c378ad0afa 100644
--- a/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp
+++ b/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp
@@ -693,6 +693,8 @@ class MipsAsmParser : public MCTargetAsmParser {
     return (getSTI().hasFeature(Mips::FeatureCnMipsP));
   }
 
+  bool isR5900() const { return (getSTI().hasFeature(Mips::FeatureR5900)); }
+
   bool inPicMode() {
     return IsPicEnabled;
   }
diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp 
b/llvm/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp
index 01f18acf050d7..12a5b20cfb9ff 100644
--- a/llvm/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp
+++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp
@@ -921,6 +921,8 @@ MipsTargetELFStreamer::MipsTargetELFStreamer(MCStreamer &S,
   // Machine
   if (Features[Mips::FeatureCnMips])
     EFlags |= ELF::EF_MIPS_MACH_OCTEON;
+  else if (Features[Mips::FeatureR5900])
+    EFlags |= ELF::EF_MIPS_MACH_5900;
 
   // Other options.
   if (Features[Mips::FeatureNaN2008])
diff --git a/llvm/lib/Target/Mips/Mips.td b/llvm/lib/Target/Mips/Mips.td
index 8b0d87b5c5376..7cfa0800454c6 100644
--- a/llvm/lib/Target/Mips/Mips.td
+++ b/llvm/lib/Target/Mips/Mips.td
@@ -186,6 +186,10 @@ def FeatureCnMipsP : SubtargetFeature<"cnmipsp", 
"HasCnMipsP",
                                       "true", "Octeon+ cnMIPS Support",
                                       [FeatureCnMips]>;
 
+def FeatureR5900 : SubtargetFeature<"r5900", "IsR5900", "true",
+                                    "R5900 (PS2 Emotion Engine) Support",
+                                    [FeatureMips3, FeatureSoftFloat]>;
+
 def FeatureUseTCCInDIV : SubtargetFeature<
                                "use-tcc-in-div",
                                "UseTCCInDIV", "false",
@@ -296,6 +300,7 @@ def : Proc<"mips64r6", [FeatureMips64r6]>;
 def : Proc<"octeon", [FeatureMips64r2, FeatureCnMips]>;
 def : Proc<"octeon+", [FeatureMips64r2, FeatureCnMips, FeatureCnMipsP]>;
 def : ProcessorModel<"p5600", MipsP5600Model, [ImplP5600]>;
+def : Proc<"r5900", [FeatureR5900]>;
 def : ProcessorModel<"i6400", MipsI6400Model, [ImplI6400]>;
 def : ProcessorModel<"i6500", MipsI6400Model, [ImplI6500]>;
 
diff --git a/llvm/lib/Target/Mips/MipsSubtarget.cpp 
b/llvm/lib/Target/Mips/MipsSubtarget.cpp
index aef9382d3c1dc..5134e16a8d78b 100644
--- a/llvm/lib/Target/Mips/MipsSubtarget.cpp
+++ b/llvm/lib/Target/Mips/MipsSubtarget.cpp
@@ -86,10 +86,10 @@ MipsSubtarget::MipsSubtarget(const Triple &TT, StringRef 
CPU, StringRef FS,
       IsSingleFloat(false), IsFPXX(false), NoABICalls(false), Abs2008(false),
       IsFP64bit(false), UseOddSPReg(true), IsNaN2008bit(false),
       IsGP64bit(false), HasVFPU(false), HasCnMips(false), HasCnMipsP(false),
-      HasMips3_32(false), HasMips3_32r2(false), HasMips4_32(false),
-      HasMips4_32r2(false), HasMips5_32r2(false), InMips16Mode(false),
-      InMips16HardFloat(Mips16HardFloat), InMicroMipsMode(false), 
HasDSP(false),
-      HasDSPR2(false), HasDSPR3(false),
+      IsR5900(false), HasMips3_32(false), HasMips3_32r2(false),
+      HasMips4_32(false), HasMips4_32r2(false), HasMips5_32r2(false),
+      InMips16Mode(false), InMips16HardFloat(Mips16HardFloat),
+      InMicroMipsMode(false), HasDSP(false), HasDSPR2(false), HasDSPR3(false),
       AllowMixed16_32(Mixed16_32 || Mips_Os16), Os16(Mips_Os16), HasMSA(false),
       UseTCCInDIV(false), HasSym32(false), HasEVA(false), DisableMadd4(false),
       HasMT(false), HasCRC(false), HasVirt(false), HasGINV(false),
diff --git a/llvm/lib/Target/Mips/MipsSubtarget.h 
b/llvm/lib/Target/Mips/MipsSubtarget.h
index b09cfb3ac4a09..3c8b088421208 100644
--- a/llvm/lib/Target/Mips/MipsSubtarget.h
+++ b/llvm/lib/Target/Mips/MipsSubtarget.h
@@ -124,6 +124,9 @@ class MipsSubtarget : public MipsGenSubtargetInfo {
   // CPU supports cnMIPSP (Cavium Networks Octeon+ CPU).
   bool HasCnMipsP;
 
+  // IsR5900 - CPU is R5900 (PlayStation 2 Emotion Engine).
+  bool IsR5900;
+
   // isLinux - Target system is Linux. Is false we consider ELFOS for now.
   bool IsLinux;
 
@@ -297,6 +300,7 @@ class MipsSubtarget : public MipsGenSubtargetInfo {
 
   bool hasCnMips() const { return HasCnMips; }
   bool hasCnMipsP() const { return HasCnMipsP; }
+  bool isR5900() const { return IsR5900; }
 
   bool isLittle() const { return IsLittle; }
   bool isABICalls() const { return !NoABICalls; }
diff --git a/llvm/test/CodeGen/Mips/cpus.ll b/llvm/test/CodeGen/Mips/cpus.ll
index 077f8fb48bae0..14e7476d8f9ef 100644
--- a/llvm/test/CodeGen/Mips/cpus.ll
+++ b/llvm/test/CodeGen/Mips/cpus.ll
@@ -58,6 +58,10 @@
 ; OCTEONP: ISA: MIPS64r2
 ; OCTEONP: ISA Extension: Cavium Networks OcteonP
 
+; RUN: llc -mtriple=mips64el -mcpu=r5900 -filetype=obj < %s \
+; RUN:   | llvm-readelf -A - | FileCheck %s --check-prefix=R5900
+; R5900: ISA: MIPS3
+
 ; Check that we reject CPUs that are not implemented.
 
 ; RUN: not llc < %s -o /dev/null -mtriple=mips64 -mcpu=mips5 2>&1 \

>From c6a8b4ebde607615880fbb1d912f96f5e11e6054 Mon Sep 17 00:00:00 2001
From: Rick Gaiser <[email protected]>
Date: Sun, 18 Jan 2026 13:24:24 +0100
Subject: [PATCH 2/6] [Mips] Disable unsupported instructions for r5900

The R5900 is based on MIPS-III but lacks several instructions that were
also removed or relocated in MIPS32R6/MIPS64R6:

- LL/SC atomic instructions
- COP3 instructions (LWC3, SWC3, LDC3, SDC3)
- 64-bit multiply/divide (DMULT, DMULTU, DDIV, DDIVU)

Implementation uses combined ISA classes (e.g., ISA_MIPS2_NOT_32R6_64R6_R5900)
with InsnPredicates to properly combine the NotR5900 predicate with
existing ISA and ASE predicates.

- Add NotR5900 predicate
- Add ISA_MIPS*_NOT_*_R5900 combined classes
- Set MaxAtomicSizeInBitsSupported to 0 for R5900
- Expand 64-bit multiply/divide operations to 32-bit equivalents
- Add assembly tests for invalid instructions
---
 llvm/lib/Target/Mips/Mips64InstrInfo.td     | 175 +++++++++++---------
 llvm/lib/Target/Mips/MipsISelLowering.cpp   |   5 +-
 llvm/lib/Target/Mips/MipsInstrInfo.td       |  68 ++++++--
 llvm/lib/Target/Mips/MipsSEISelLowering.cpp |  13 +-
 llvm/test/MC/Mips/r5900-invalid.s           |  59 +++++++
 5 files changed, 224 insertions(+), 96 deletions(-)
 create mode 100644 llvm/test/MC/Mips/r5900-invalid.s

diff --git a/llvm/lib/Target/Mips/Mips64InstrInfo.td 
b/llvm/lib/Target/Mips/Mips64InstrInfo.td
index ef4eea8c50dc6..b22b0acf49507 100644
--- a/llvm/lib/Target/Mips/Mips64InstrInfo.td
+++ b/llvm/lib/Target/Mips/Mips64InstrInfo.td
@@ -245,18 +245,23 @@ def SDR   : StoreLeftRight<"sdr", MipsSDR, GPR64Opnd, 
II_SDR>, LW_FM<0x2d>,
 
 /// Load-linked, Store-conditional
 let AdditionalPredicates = [NotInMicroMips] in {
-  def LLD : LLBase<"lld", GPR64Opnd, mem_simmptr>, LW_FM<0x34>,
-            ISA_MIPS3_NOT_32R6_64R6;
+  def LLD : LLBase<"lld", GPR64Opnd, mem_simmptr>,
+            LW_FM<0x34>,
+            ISA_MIPS3_NOT_32R6_64R6_R5900;
 }
-def SCD : SCBase<"scd", GPR64Opnd>, LW_FM<0x3c>, ISA_MIPS3_NOT_32R6_64R6;
+def SCD : SCBase<"scd", GPR64Opnd>, LW_FM<0x3c>, ISA_MIPS3_NOT_32R6_64R6_R5900;
 
 let AdditionalPredicates = [NotInMicroMips],
     DecoderNamespace = "Mips32_64_PTR64" in {
-def LL64 : LLBase<"ll", GPR32Opnd>, LW_FM<0x30>, PTR_64,
-           ISA_MIPS2_NOT_32R6_64R6;
-def SC64 : SCBase<"sc", GPR32Opnd>, LW_FM<0x38>, PTR_64,
-           ISA_MIPS2_NOT_32R6_64R6;
-def JR64   : IndirectBranch<"jr", GPR64Opnd>, MTLO_FM<8>, PTR_64;
+  def LL64 : LLBase<"ll", GPR32Opnd>,
+             LW_FM<0x30>,
+             PTR_64,
+             ISA_MIPS2_NOT_32R6_64R6_R5900;
+  def SC64 : SCBase<"sc", GPR32Opnd>,
+             LW_FM<0x38>,
+             PTR_64,
+             ISA_MIPS2_NOT_32R6_64R6_R5900;
+  def JR64 : IndirectBranch<"jr", GPR64Opnd>, MTLO_FM<8>, PTR_64;
 }
 
 def JALR64 : JumpLinkReg<"jalr", GPR64Opnd>, JALR_FM, PTR_64;
@@ -305,25 +310,32 @@ let AdditionalPredicates = [NotInMips16Mode, 
NotInMicroMips,
 
 /// Multiply and Divide Instructions.
 let AdditionalPredicates = [NotInMicroMips] in {
-  def DMULT  : Mult<"dmult", II_DMULT, GPR64Opnd, [HI0_64, LO0_64]>,
-               MULT_FM<0, 0x1c>, ISA_MIPS3_NOT_32R6_64R6;
+  def DMULT : Mult<"dmult", II_DMULT, GPR64Opnd, [HI0_64, LO0_64]>,
+              MULT_FM<0, 0x1c>,
+              ISA_MIPS3_NOT_32R6_64R6_R5900;
   def DMULTu : Mult<"dmultu", II_DMULTU, GPR64Opnd, [HI0_64, LO0_64]>,
-               MULT_FM<0, 0x1d>, ISA_MIPS3_NOT_32R6_64R6;
+               MULT_FM<0, 0x1d>,
+               ISA_MIPS3_NOT_32R6_64R6_R5900;
 }
-def PseudoDMULT  : MultDivPseudo<DMULT, ACC128, GPR64Opnd, MipsMult,
-                                 II_DMULT>, ISA_MIPS3_NOT_32R6_64R6;
-def PseudoDMULTu : MultDivPseudo<DMULTu, ACC128, GPR64Opnd, MipsMultu,
-                                 II_DMULTU>, ISA_MIPS3_NOT_32R6_64R6;
+def PseudoDMULT : MultDivPseudo<DMULT, ACC128, GPR64Opnd, MipsMult, II_DMULT>,
+                  ISA_MIPS3_NOT_32R6_64R6_R5900;
+def PseudoDMULTu
+    : MultDivPseudo<DMULTu, ACC128, GPR64Opnd, MipsMultu, II_DMULTU>,
+      ISA_MIPS3_NOT_32R6_64R6_R5900;
 let AdditionalPredicates = [NotInMicroMips] in {
   def DSDIV : Div<"ddiv", II_DDIV, GPR64Opnd, [HI0_64, LO0_64]>,
-              MULT_FM<0, 0x1e>, ISA_MIPS3_NOT_32R6_64R6;
+              MULT_FM<0, 0x1e>,
+              ISA_MIPS3_NOT_32R6_64R6_R5900;
   def DUDIV : Div<"ddivu", II_DDIVU, GPR64Opnd, [HI0_64, LO0_64]>,
-              MULT_FM<0, 0x1f>, ISA_MIPS3_NOT_32R6_64R6;
+              MULT_FM<0, 0x1f>,
+              ISA_MIPS3_NOT_32R6_64R6_R5900;
 }
-def PseudoDSDIV : MultDivPseudo<DSDIV, ACC128, GPR64Opnd, MipsDivRem,
-                                II_DDIV, 0, 1, 1>, ISA_MIPS3_NOT_32R6_64R6;
-def PseudoDUDIV : MultDivPseudo<DUDIV, ACC128, GPR64Opnd, MipsDivRemU,
-                                II_DDIVU, 0, 1, 1>, ISA_MIPS3_NOT_32R6_64R6;
+def PseudoDSDIV
+    : MultDivPseudo<DSDIV, ACC128, GPR64Opnd, MipsDivRem, II_DDIV, 0, 1, 1>,
+      ISA_MIPS3_NOT_32R6_64R6_R5900;
+def PseudoDUDIV
+    : MultDivPseudo<DUDIV, ACC128, GPR64Opnd, MipsDivRemU, II_DDIVU, 0, 1, 1>,
+      ISA_MIPS3_NOT_32R6_64R6_R5900;
 
 let isCodeGenOnly = 1 in {
 def MTHI64 : MoveToLOHI<"mthi", GPR64Opnd, [HI0_64]>, MTLO_FM<0x11>,
@@ -1119,100 +1131,103 @@ def LoadAddrReg64 : MipsAsmPseudoInst<(outs 
GPR64Opnd:$rt), (ins mem:$addr),
 def LoadAddrImm64 : MipsAsmPseudoInst<(outs GPR64Opnd:$rt), (ins imm64:$imm64),
                                        "dla\t$rt, $imm64">;
 
-def DMULImmMacro : MipsAsmPseudoInst<(outs), (ins GPR64Opnd:$rs, GPR64Opnd:$rt,
-                                                  simm32_relaxed:$imm),
-                                     "dmul\t$rs, $rt, $imm">,
-                   ISA_MIPS3_NOT_32R6_64R6;
-def DMULOMacro : MipsAsmPseudoInst<(outs), (ins GPR64Opnd:$rs, GPR64Opnd:$rt,
-                                                GPR64Opnd:$rd),
-                                   "dmulo\t$rs, $rt, $rd">,
-                 ISA_MIPS3_NOT_32R6_64R6;
-def DMULOUMacro : MipsAsmPseudoInst<(outs), (ins GPR64Opnd:$rs, GPR64Opnd:$rt,
-                                                 GPR64Opnd:$rd),
-                                    "dmulou\t$rs, $rt, $rd">,
-                  ISA_MIPS3_NOT_32R6_64R6;
+def DMULImmMacro
+    : MipsAsmPseudoInst<(outs),
+                        (ins GPR64Opnd:$rs, GPR64Opnd:$rt, 
simm32_relaxed:$imm),
+                        "dmul\t$rs, $rt, $imm">,
+      ISA_MIPS3_NOT_32R6_64R6_R5900;
+def DMULOMacro
+    : MipsAsmPseudoInst<(outs),
+                        (ins GPR64Opnd:$rs, GPR64Opnd:$rt, GPR64Opnd:$rd),
+                        "dmulo\t$rs, $rt, $rd">,
+      ISA_MIPS3_NOT_32R6_64R6_R5900;
+def DMULOUMacro
+    : MipsAsmPseudoInst<(outs),
+                        (ins GPR64Opnd:$rs, GPR64Opnd:$rt, GPR64Opnd:$rd),
+                        "dmulou\t$rs, $rt, $rd">,
+      ISA_MIPS3_NOT_32R6_64R6_R5900;
 
 def DMULMacro : MipsAsmPseudoInst<(outs), (ins GPR64Opnd:$rs, GPR64Opnd:$rt,
                                                GPR64Opnd:$rd),
                                   "dmul\t$rs, $rt, $rd"> {
-  let InsnPredicates = [HasMips3, NotMips64r6, NotCnMips];
+  let InsnPredicates = [HasMips3, NotMips64r6, NotCnMips, NotR5900];
 }
 
 let AdditionalPredicates = [NotInMicroMips] in {
   def DSDivMacro : MipsAsmPseudoInst<(outs GPR64Opnd:$rd),
                                      (ins GPR64Opnd:$rs, GPR64Opnd:$rt),
                                      "ddiv\t$rd, $rs, $rt">,
-                   ISA_MIPS3_NOT_32R6_64R6;
-  def DSDivIMacro : MipsAsmPseudoInst<(outs GPR64Opnd:$rd),
-                                      (ins GPR64Opnd:$rs, imm64:$imm),
-                                      "ddiv\t$rd, $rs, $imm">,
-                    ISA_MIPS3_NOT_32R6_64R6;
+                   ISA_MIPS3_NOT_32R6_64R6_R5900;
+  def DSDivIMacro
+      : MipsAsmPseudoInst<(outs GPR64Opnd:$rd), (ins GPR64Opnd:$rs, 
imm64:$imm),
+                          "ddiv\t$rd, $rs, $imm">,
+        ISA_MIPS3_NOT_32R6_64R6_R5900;
   def DUDivMacro : MipsAsmPseudoInst<(outs GPR64Opnd:$rd),
                                      (ins GPR64Opnd:$rs, GPR64Opnd:$rt),
                                      "ddivu\t$rd, $rs, $rt">,
-                   ISA_MIPS3_NOT_32R6_64R6;
-  def DUDivIMacro : MipsAsmPseudoInst<(outs GPR64Opnd:$rd),
-                                      (ins GPR64Opnd:$rs, imm64:$imm),
-                                      "ddivu\t$rd, $rs, $imm">,
-                    ISA_MIPS3_NOT_32R6_64R6;
+                   ISA_MIPS3_NOT_32R6_64R6_R5900;
+  def DUDivIMacro
+      : MipsAsmPseudoInst<(outs GPR64Opnd:$rd), (ins GPR64Opnd:$rs, 
imm64:$imm),
+                          "ddivu\t$rd, $rs, $imm">,
+        ISA_MIPS3_NOT_32R6_64R6_R5900;
 
   // GAS expands 'div' and 'ddiv' differently when the destination
   // register is $zero and the instruction is in the two operand
   // form. 'ddiv' gets expanded, while 'div' is not expanded.
 
-  def : MipsInstAlias<"ddiv $rs, $rt", (DSDivMacro GPR64Opnd:$rs,
-                                               GPR64Opnd:$rs,
-                                               GPR64Opnd:$rt), 0>,
-        ISA_MIPS3_NOT_32R6_64R6;
-  def : MipsInstAlias<"ddiv $rd, $imm", (DSDivIMacro GPR64Opnd:$rd,
-                                                     GPR64Opnd:$rd,
-                                                     imm64:$imm), 0>,
-        ISA_MIPS3_NOT_32R6_64R6;
+  def : MipsInstAlias<"ddiv $rs, $rt",
+                      (DSDivMacro GPR64Opnd:$rs, GPR64Opnd:$rs, GPR64Opnd:$rt),
+                      0>,
+        ISA_MIPS3_NOT_32R6_64R6_R5900;
+  def : MipsInstAlias<"ddiv $rd, $imm",
+                      (DSDivIMacro GPR64Opnd:$rd, GPR64Opnd:$rd, imm64:$imm),
+                      0>,
+        ISA_MIPS3_NOT_32R6_64R6_R5900;
 
   // GAS expands 'divu' and 'ddivu' differently when the destination
   // register is $zero and the instruction is in the two operand
   // form. 'ddivu' gets expanded, while 'divu' is not expanded.
 
-  def : MipsInstAlias<"ddivu $rt, $rs", (DUDivMacro GPR64Opnd:$rt,
-                                                    GPR64Opnd:$rt,
-                                                    GPR64Opnd:$rs), 0>,
-        ISA_MIPS3_NOT_32R6_64R6;
-  def : MipsInstAlias<"ddivu $rd, $imm", (DUDivIMacro GPR64Opnd:$rd,
-                                                      GPR64Opnd:$rd,
-                                                      imm64:$imm), 0>,
-        ISA_MIPS3_NOT_32R6_64R6;
+  def : MipsInstAlias<"ddivu $rt, $rs",
+                      (DUDivMacro GPR64Opnd:$rt, GPR64Opnd:$rt, GPR64Opnd:$rs),
+                      0>,
+        ISA_MIPS3_NOT_32R6_64R6_R5900;
+  def : MipsInstAlias<"ddivu $rd, $imm",
+                      (DUDivIMacro GPR64Opnd:$rd, GPR64Opnd:$rd, imm64:$imm),
+                      0>,
+        ISA_MIPS3_NOT_32R6_64R6_R5900;
   def DSRemMacro : MipsAsmPseudoInst<(outs GPR64Opnd:$rd),
                                      (ins GPR64Opnd:$rs, GPR64Opnd:$rt),
                                      "drem\t$rd, $rs, $rt">,
-                   ISA_MIPS3_NOT_32R6_64R6;
+                   ISA_MIPS3_NOT_32R6_64R6_R5900;
   def DSRemIMacro : MipsAsmPseudoInst<(outs GPR64Opnd:$rd),
                                       (ins GPR64Opnd:$rs, simm32_relaxed:$imm),
                                       "drem\t$rd, $rs, $imm">,
-                    ISA_MIPS3_NOT_32R6_64R6;
+                    ISA_MIPS3_NOT_32R6_64R6_R5900;
   def DURemMacro : MipsAsmPseudoInst<(outs GPR64Opnd:$rd),
                                      (ins GPR64Opnd:$rs, GPR64Opnd:$rt),
                                      "dremu\t$rd, $rs, $rt">,
-                   ISA_MIPS3_NOT_32R6_64R6;
+                   ISA_MIPS3_NOT_32R6_64R6_R5900;
   def DURemIMacro : MipsAsmPseudoInst<(outs GPR64Opnd:$rd),
                                       (ins GPR64Opnd:$rs, simm32_relaxed:$imm),
                                       "dremu\t$rd, $rs, $imm">,
-                    ISA_MIPS3_NOT_32R6_64R6;
-  def : MipsInstAlias<"drem $rt, $rs", (DSRemMacro GPR64Opnd:$rt,
-                                                   GPR64Opnd:$rt,
-                                                   GPR64Opnd:$rs), 0>,
-        ISA_MIPS3_NOT_32R6_64R6;
-  def : MipsInstAlias<"drem $rd, $imm", (DSRemIMacro GPR64Opnd:$rd,
-                                                     GPR64Opnd:$rd,
-                                                     simm32_relaxed:$imm), 0>,
-        ISA_MIPS3_NOT_32R6_64R6;
-  def : MipsInstAlias<"dremu $rt, $rs", (DURemMacro GPR64Opnd:$rt,
-                                                    GPR64Opnd:$rt,
-                                                    GPR64Opnd:$rs), 0>,
-        ISA_MIPS3_NOT_32R6_64R6;
-  def : MipsInstAlias<"dremu $rd, $imm", (DURemIMacro GPR64Opnd:$rd,
-                                                      GPR64Opnd:$rd,
-                                                      simm32_relaxed:$imm), 0>,
-        ISA_MIPS3_NOT_32R6_64R6;
+                    ISA_MIPS3_NOT_32R6_64R6_R5900;
+  def : MipsInstAlias<"drem $rt, $rs",
+                      (DSRemMacro GPR64Opnd:$rt, GPR64Opnd:$rt, GPR64Opnd:$rs),
+                      0>,
+        ISA_MIPS3_NOT_32R6_64R6_R5900;
+  def : MipsInstAlias<
+            "drem $rd, $imm",
+            (DSRemIMacro GPR64Opnd:$rd, GPR64Opnd:$rd, simm32_relaxed:$imm), 
0>,
+        ISA_MIPS3_NOT_32R6_64R6_R5900;
+  def : MipsInstAlias<"dremu $rt, $rs",
+                      (DURemMacro GPR64Opnd:$rt, GPR64Opnd:$rt, GPR64Opnd:$rs),
+                      0>,
+        ISA_MIPS3_NOT_32R6_64R6_R5900;
+  def : MipsInstAlias<
+            "dremu $rd, $imm",
+            (DURemIMacro GPR64Opnd:$rd, GPR64Opnd:$rd, simm32_relaxed:$imm), 
0>,
+        ISA_MIPS3_NOT_32R6_64R6_R5900;
 }
 
 def NORImm64 : NORIMM_DESC_BASE<GPR64Opnd, imm64>, GPR_64;
diff --git a/llvm/lib/Target/Mips/MipsISelLowering.cpp 
b/llvm/lib/Target/Mips/MipsISelLowering.cpp
index dbbeb75e673c3..b62669d5d5fa6 100644
--- a/llvm/lib/Target/Mips/MipsISelLowering.cpp
+++ b/llvm/lib/Target/Mips/MipsISelLowering.cpp
@@ -412,7 +412,10 @@ MipsTargetLowering::MipsTargetLowering(const 
MipsTargetMachine &TM,
                        ISD::OR, ISD::ADD, ISD::SUB, ISD::AssertZext, ISD::SHL,
                        ISD::SIGN_EXTEND});
 
-  if (Subtarget.isGP64bit())
+  // R5900 has no LL/SC instructions for atomic operations
+  if (Subtarget.isR5900())
+    setMaxAtomicSizeInBitsSupported(0);
+  else if (Subtarget.isGP64bit())
     setMaxAtomicSizeInBitsSupported(64);
   else
     setMaxAtomicSizeInBitsSupported(32);
diff --git a/llvm/lib/Target/Mips/MipsInstrInfo.td 
b/llvm/lib/Target/Mips/MipsInstrInfo.td
index 5b464ff2957e4..2a476e789032c 100644
--- a/llvm/lib/Target/Mips/MipsInstrInfo.td
+++ b/llvm/lib/Target/Mips/MipsInstrInfo.td
@@ -259,6 +259,10 @@ def UseIndirectJumpsHazard : 
Predicate<"Subtarget->useIndirectJumpsHazard()">,
                             AssemblerPredicate<(all_of 
FeatureUseIndirectJumpsHazard)>;
 def NoIndirectJumpGuards : Predicate<"!Subtarget->useIndirectJumpsHazard()">,
                            AssemblerPredicate<(all_of (not 
FeatureUseIndirectJumpsHazard))>;
+def HasR5900 : Predicate<"Subtarget->isR5900()">,
+               AssemblerPredicate<(all_of FeatureR5900)>;
+def NotR5900 : Predicate<"!Subtarget->isR5900()">,
+               AssemblerPredicate<(all_of (not FeatureR5900))>;
 def HasCRC   : Predicate<"Subtarget->hasCRC()">,
                AssemblerPredicate<(all_of FeatureCRC)>;
 def HasVirt  : Predicate<"Subtarget->hasVirt()">,
@@ -312,14 +316,27 @@ class ISA_MIPS1_NOT_32R6_64R6 {
   list<Predicate> InsnPredicates = [NotMips32r6, NotMips64r6];
   list<Predicate> EncodingPredicates = [HasStdEnc];
 }
+class ISA_MIPS1_NOT_32R6_64R6_R5900 {
+  list<Predicate> InsnPredicates = [NotMips32r6, NotMips64r6, NotR5900];
+  list<Predicate> EncodingPredicates = [HasStdEnc];
+}
 class ISA_MIPS2 {
   list<Predicate> InsnPredicates = [HasMips2];
   list<Predicate> EncodingPredicates = [HasStdEnc];
 }
+class ISA_MIPS2_NOT_R5900 {
+  list<Predicate> InsnPredicates = [HasMips2, NotR5900];
+  list<Predicate> EncodingPredicates = [HasStdEnc];
+}
 class ISA_MIPS2_NOT_32R6_64R6 {
   list<Predicate> InsnPredicates = [HasMips2, NotMips32r6, NotMips64r6];
   list<Predicate> EncodingPredicates = [HasStdEnc];
 }
+class ISA_MIPS2_NOT_32R6_64R6_R5900 {
+  list<Predicate> InsnPredicates = [HasMips2, NotMips32r6, NotMips64r6,
+                                    NotR5900];
+  list<Predicate> EncodingPredicates = [HasStdEnc];
+}
 class ISA_MIPS3 {
   list<Predicate> InsnPredicates = [HasMips3];
   list<Predicate> EncodingPredicates = [HasStdEnc];
@@ -328,6 +345,11 @@ class ISA_MIPS3_NOT_32R6_64R6 {
   list<Predicate> InsnPredicates = [HasMips3, NotMips32r6, NotMips64r6];
   list<Predicate> EncodingPredicates = [HasStdEnc];
 }
+class ISA_MIPS3_NOT_32R6_64R6_R5900 {
+  list<Predicate> InsnPredicates = [HasMips3, NotMips32r6, NotMips64r6,
+                                    NotR5900];
+  list<Predicate> EncodingPredicates = [HasStdEnc];
+}
 class ISA_MIPS32 {
   list<Predicate> InsnPredicates = [HasMips32];
   list<Predicate> EncodingPredicates = [HasStdEnc];
@@ -1837,11 +1859,15 @@ class Atomic2OpsPostRA<RegisterClass RC> :
   PseudoSE<(outs RC:$dst), (ins PtrRC:$ptr, RC:$incr), []> {
   let mayLoad = 1;
   let mayStore = 1;
+  let Predicates = [NotR5900];
 }
 
-class Atomic2OpsSubwordPostRA<RegisterClass RC> :
-  PseudoSE<(outs RC:$dst), (ins PtrRC:$ptr, RC:$incr, RC:$mask, RC:$mask2,
-                                RC:$shiftamnt), []>;
+class Atomic2OpsSubwordPostRA<RegisterClass RC>
+    : PseudoSE<
+          (outs RC:$dst),
+          (ins PtrRC:$ptr, RC:$incr, RC:$mask, RC:$mask2, RC:$shiftamnt), []> {
+  let Predicates = [NotR5900];
+}
 
 // Atomic Compare & Swap.
 // Atomic compare and swap is lowered into two stages. The first stage happens
@@ -1856,6 +1882,7 @@ class AtomicCmpSwapPostRA<RegisterClass RC> :
   PseudoSE<(outs RC:$dst), (ins PtrRC:$ptr, RC:$cmp, RC:$swap), []> {
   let mayLoad = 1;
   let mayStore = 1;
+  let Predicates = [NotR5900];
 }
 
 class AtomicCmpSwapSubwordPostRA<RegisterClass RC> :
@@ -1863,6 +1890,7 @@ class AtomicCmpSwapSubwordPostRA<RegisterClass RC> :
                                 RC:$mask2, RC:$ShiftNewVal, RC:$ShiftAmt), []> 
{
   let mayLoad = 1;
   let mayStore = 1;
+  let Predicates = [NotR5900];
 }
 
 class LLBase<string opstr, RegisterOperand RO, DAGOperand MO = mem> :
@@ -2166,14 +2194,22 @@ def SDC2 : StdMMR6Rel, SW_FT2<"sdc2", COP2Opnd, 
II_SDC2, store>,
 
 // COP3 Memory Instructions
 let DecoderNamespace = "COP3_" in {
-  def LWC3 : LW_FT3<"lwc3", COP3Opnd, II_LWC3, load>, LW_FM<0x33>,
-             ISA_MIPS1_NOT_32R6_64R6, NOT_ASE_CNMIPS;
-  def SWC3 : SW_FT3<"swc3", COP3Opnd, II_SWC3, store>, LW_FM<0x3b>,
-             ISA_MIPS1_NOT_32R6_64R6, NOT_ASE_CNMIPS;
-  def LDC3 : LW_FT3<"ldc3", COP3Opnd, II_LDC3, load>, LW_FM<0x37>,
-             ISA_MIPS2, NOT_ASE_CNMIPS;
-  def SDC3 : SW_FT3<"sdc3", COP3Opnd, II_SDC3, store>, LW_FM<0x3f>,
-             ISA_MIPS2, NOT_ASE_CNMIPS;
+  def LWC3 : LW_FT3<"lwc3", COP3Opnd, II_LWC3, load>,
+             LW_FM<0x33>,
+             ISA_MIPS1_NOT_32R6_64R6_R5900,
+             NOT_ASE_CNMIPS;
+  def SWC3 : SW_FT3<"swc3", COP3Opnd, II_SWC3, store>,
+             LW_FM<0x3b>,
+             ISA_MIPS1_NOT_32R6_64R6_R5900,
+             NOT_ASE_CNMIPS;
+  def LDC3 : LW_FT3<"ldc3", COP3Opnd, II_LDC3, load>,
+             LW_FM<0x37>,
+             ISA_MIPS2_NOT_R5900,
+             NOT_ASE_CNMIPS;
+  def SDC3 : SW_FT3<"sdc3", COP3Opnd, II_SDC3, store>,
+             LW_FM<0x3f>,
+             ISA_MIPS2_NOT_R5900,
+             NOT_ASE_CNMIPS;
 }
 
   def SYNC : MMRel, StdMMR6Rel, SYNC_FT<"sync">, SYNC_FM, ISA_MIPS2;
@@ -2232,8 +2268,14 @@ let AdditionalPredicates = [NotInMicroMips] in {
 
 let AdditionalPredicates = [NotInMicroMips] in {
 /// Load-linked, Store-conditional
-def LL : LLBase<"ll", GPR32Opnd>, LW_FM<0x30>, PTR_32, ISA_MIPS2_NOT_32R6_64R6;
-def SC : SCBase<"sc", GPR32Opnd>, LW_FM<0x38>, PTR_32, ISA_MIPS2_NOT_32R6_64R6;
+def LL : LLBase<"ll", GPR32Opnd>,
+         LW_FM<0x30>,
+         PTR_32,
+         ISA_MIPS2_NOT_32R6_64R6_R5900;
+def SC : SCBase<"sc", GPR32Opnd>,
+         LW_FM<0x38>,
+         PTR_32,
+         ISA_MIPS2_NOT_32R6_64R6_R5900;
 }
 /// Jump and Branch Instructions
 let AdditionalPredicates = [NotInMicroMips, RelocNotPIC] in
diff --git a/llvm/lib/Target/Mips/MipsSEISelLowering.cpp 
b/llvm/lib/Target/Mips/MipsSEISelLowering.cpp
index 0906ab56e1671..10885d0b01376 100644
--- a/llvm/lib/Target/Mips/MipsSEISelLowering.cpp
+++ b/llvm/lib/Target/Mips/MipsSEISelLowering.cpp
@@ -235,10 +235,19 @@ MipsSETargetLowering::MipsSETargetLowering(const 
MipsTargetMachine &TM,
 
   if (Subtarget.hasCnMips())
     setOperationAction(ISD::MUL,              MVT::i64, Legal);
-  else if (Subtarget.isGP64bit())
+  else if (Subtarget.isR5900()) {
+    // R5900 doesn't have DMULT/DMULTU/DDIV/DDIVU - expand to 32-bit ops
+    setOperationAction(ISD::MUL, MVT::i64, Expand);
+    setOperationAction(ISD::SMUL_LOHI, MVT::i64, Expand);
+    setOperationAction(ISD::UMUL_LOHI, MVT::i64, Expand);
+    setOperationAction(ISD::MULHS, MVT::i64, Expand);
+    setOperationAction(ISD::MULHU, MVT::i64, Expand);
+    setOperationAction(ISD::SDIVREM, MVT::i64, Expand);
+    setOperationAction(ISD::UDIVREM, MVT::i64, Expand);
+  } else if (Subtarget.isGP64bit())
     setOperationAction(ISD::MUL,              MVT::i64, Custom);
 
-  if (Subtarget.isGP64bit()) {
+  if (Subtarget.isGP64bit() && !Subtarget.isR5900()) {
     setOperationAction(ISD::SMUL_LOHI,        MVT::i64, Custom);
     setOperationAction(ISD::UMUL_LOHI,        MVT::i64, Custom);
     setOperationAction(ISD::MULHS,            MVT::i64, Custom);
diff --git a/llvm/test/MC/Mips/r5900-invalid.s 
b/llvm/test/MC/Mips/r5900-invalid.s
new file mode 100644
index 0000000000000..4b1eed2f56bcc
--- /dev/null
+++ b/llvm/test/MC/Mips/r5900-invalid.s
@@ -0,0 +1,59 @@
+# Instructions that are invalid on R5900
+#
+# R5900 is a MIPS III-based processor with specific limitations:
+# - No 64-bit multiply/divide (DMULT/DMULTU/DDIV/DDIVU)
+# - No LL/SC atomic instructions
+# - No COP3 instructions (LWC3, SWC3, LDC3, SDC3)
+#
+# RUN: not llvm-mc %s -triple=mips64el-unknown-linux -mcpu=r5900 2>%t1
+# RUN: FileCheck %s < %t1
+
+        .set noat
+
+# =============================================================================
+# MIPS3 64-bit multiply/divide instructions that R5900 does NOT support
+# =============================================================================
+
+# CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: instruction requires a CPU feature 
not currently enabled
+        dmult   $4, $5
+
+# CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: instruction requires a CPU feature 
not currently enabled
+        dmultu  $6, $7
+
+# CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: instruction requires a CPU feature 
not currently enabled
+        ddiv    $zero, $8, $9
+
+# CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: instruction requires a CPU feature 
not currently enabled
+        ddivu   $zero, $10, $11
+
+# =============================================================================
+# LL/SC atomic instructions that R5900 does NOT support
+# =============================================================================
+
+# CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: instruction requires a CPU feature 
not currently enabled
+        ll      $4, 0($5)
+
+# CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: instruction requires a CPU feature 
not currently enabled
+        sc      $4, 0($5)
+
+# CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: instruction requires a CPU feature 
not currently enabled
+        lld     $4, 0($5)
+
+# CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: instruction requires a CPU feature 
not currently enabled
+        scd     $4, 0($5)
+
+# =============================================================================
+# COP3 instructions that R5900 does NOT support
+# =============================================================================
+
+# CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: instruction requires a CPU feature 
not currently enabled
+        lwc3    $4, 0($5)
+
+# CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: instruction requires a CPU feature 
not currently enabled
+        swc3    $4, 0($5)
+
+# CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: instruction requires a CPU feature 
not currently enabled
+        ldc3    $4, 0($5)
+
+# CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: instruction requires a CPU feature 
not currently enabled
+        sdc3    $4, 0($5)

>From 038de93597eb2d1b5b0ef40e5e41d9054c2675e1 Mon Sep 17 00:00:00 2001
From: Rick Gaiser <[email protected]>
Date: Sun, 18 Jan 2026 13:24:29 +0100
Subject: [PATCH 3/6] [Mips] Add r5900 short loop delay slot fix

---
 llvm/lib/Target/Mips/MipsDelaySlotFiller.cpp | 79 +++++++++++++++++++-
 llvm/test/CodeGen/Mips/r5900-short-loop.ll   | 59 +++++++++++++++
 2 files changed, 134 insertions(+), 4 deletions(-)
 create mode 100644 llvm/test/CodeGen/Mips/r5900-short-loop.ll

diff --git a/llvm/lib/Target/Mips/MipsDelaySlotFiller.cpp 
b/llvm/lib/Target/Mips/MipsDelaySlotFiller.cpp
index 850d3b59be5de..da15423853559 100644
--- a/llvm/lib/Target/Mips/MipsDelaySlotFiller.cpp
+++ b/llvm/lib/Target/Mips/MipsDelaySlotFiller.cpp
@@ -52,6 +52,8 @@ using namespace llvm;
 STATISTIC(FilledSlots, "Number of delay slots filled");
 STATISTIC(UsefulSlots, "Number of delay slots filled with instructions that"
                        " are not NOP.");
+STATISTIC(R5900ShortLoopNops, "Number of delay slots left as NOP for R5900 "
+                              "short loop fix");
 
 static cl::opt<bool> DisableDelaySlotFiller(
   "disable-mips-delay-filler",
@@ -278,6 +280,65 @@ static bool hasUnoccupiedSlot(const MachineInstr *MI) {
   return MI->hasDelaySlot() && !MI->isBundledWithSucc();
 }
 
+/// Check if a branch is a short backward loop that triggers the R5900 erratum.
+/// The erratum occurs when:
+/// - A loop has 6 or fewer instructions (including branch + delay slot)
+/// - The branch is a conditional backward branch
+/// - The delay slot is not NOP
+/// - No other branches exist in the loop body
+static bool isR5900ShortLoopBranch(const MachineInstr *MI,
+                                   const MachineBasicBlock &MBB) {
+  // Must be a conditional branch (not jump or indirect branch)
+  if (!MI->isBranch() || MI->isIndirectBranch())
+    return false;
+
+  // Check if this is a conditional branch by looking for an MBB operand
+  const MachineBasicBlock *TargetMBB = nullptr;
+  for (const MachineOperand &MO : MI->operands()) {
+    if (MO.isMBB()) {
+      TargetMBB = MO.getMBB();
+      break;
+    }
+  }
+
+  // Must have a target and must target the same basic block (backward branch)
+  if (!TargetMBB || TargetMBB != &MBB)
+    return false;
+
+  // Count instructions from the beginning of the block to the branch
+  // A short loop is 6 instructions or fewer (including branch + delay slot)
+  // The delay slot adds 1 more, so we check if instructions before branch <= 5
+  unsigned InstrCount = 0;
+  bool HasOtherBranch = false;
+
+  for (const MachineInstr &Instr : MBB) {
+    if (&Instr == MI)
+      break;
+
+    // Skip debug and pseudo instructions
+    if (Instr.isDebugInstr() || Instr.isTransient())
+      continue;
+
+    ++InstrCount;
+
+    // If there's another branch in the loop, the erratum doesn't apply
+    if (Instr.isBranch() || Instr.isCall()) {
+      HasOtherBranch = true;
+      break;
+    }
+  }
+
+  // If there's another branch/call in the loop, erratum doesn't apply
+  if (HasOtherBranch)
+    return false;
+
+  // Add 1 for the branch itself, +1 for delay slot = InstrCount + 2
+  // Erratum triggers when total <= 6, so InstrCount + 2 <= 6 => InstrCount <= 
4
+  // But we're conservative: if InstrCount <= 5 (total <= 7), skip filling
+  // to match the exact condition from r5900check: offset -5 to -1 (2-6 instrs)
+  return InstrCount <= 5;
+}
+
 INITIALIZE_PASS(MipsDelaySlotFiller, DEBUG_TYPE,
                 "Fill delay slot for MIPS", false, false)
 
@@ -587,10 +648,20 @@ bool 
MipsDelaySlotFiller::runOnMachineBasicBlock(MachineBasicBlock &MBB) {
     if (!hasUnoccupiedSlot(&*I))
       continue;
 
-    // Delay slot filling is disabled at -O0, or in microMIPS32R6.
-    if (!DisableDelaySlotFiller &&
-        (TM->getOptLevel() != CodeGenOptLevel::None) &&
-        !(InMicroMipsMode && STI.hasMips32r6())) {
+    // R5900 short loop erratum fix: skip delay slot filling for short backward
+    // loops to avoid triggering a hardware bug where short loops may exit
+    // early.
+    if (STI.isR5900() && isR5900ShortLoopBranch(&*I, MBB)) {
+      LLVM_DEBUG(dbgs() << DEBUG_TYPE ": skipping delay slot fill for R5900 "
+                                      "short loop branch.\n");
+      ++R5900ShortLoopNops;
+      // Fall through to insert NOP in delay slot
+    }
+    // Delay slot filling is disabled at -O0, in microMIPS32R6, or for R5900
+    // short loop branches.
+    else if (!DisableDelaySlotFiller &&
+             (TM->getOptLevel() != CodeGenOptLevel::None) &&
+             !(InMicroMipsMode && STI.hasMips32r6())) {
 
       bool Filled = false;
 
diff --git a/llvm/test/CodeGen/Mips/r5900-short-loop.ll 
b/llvm/test/CodeGen/Mips/r5900-short-loop.ll
new file mode 100644
index 0000000000000..a66f417f0c854
--- /dev/null
+++ b/llvm/test/CodeGen/Mips/r5900-short-loop.ll
@@ -0,0 +1,59 @@
+; RUN: llc -mtriple=mips64el -mcpu=r5900 < %s | FileCheck %s -check-prefix=FIX
+;
+; Test R5900 short loop erratum fix.
+; The R5900 has a hardware bug where short loops (6 instructions or fewer)
+; with a branch may exit after 1-2 iterations instead of the expected count.
+; The fix ensures the delay slot contains a NOP for such short backward 
branches.
+; The fix is always enabled for R5900 - there is no way to disable it.
+
+; Short loop test with store - delay slot NOT filled due to short loop fix
+; bnez followed by nop (short loop workaround)
+
+; FIX-LABEL: test_short_loop_store:
+; FIX:       .LBB0_1:
+; FIX:       bnez
+; FIX-NEXT:  nop
+define void @test_short_loop_store(ptr %arr, i32 %n) {
+entry:
+  br label %loop
+
+loop:
+  %i = phi i32 [ 0, %entry ], [ %inc, %loop ]
+  %ptr = getelementptr i32, ptr %arr, i32 %i
+  store i32 %i, ptr %ptr
+  %inc = add i32 %i, 1
+  %cmp = icmp slt i32 %inc, %n
+  br i1 %cmp, label %loop, label %exit
+
+exit:
+  ret void
+}
+
+; Long loop - should NOT be affected by the fix (too many instructions)
+; Delay slot can be filled since loop is longer than 6 instructions
+; The scheduler may choose different instructions for the delay slot
+; FIX-LABEL: test_long_loop:
+; FIX:       .LBB1_1:
+; FIX:       bnez ${{[0-9]+}}, .LBB1_1
+; Delay slot should be filled with actual instruction, not nop
+; FIX-NEXT:  {{sw|daddiu|addu}}
+define i32 @test_long_loop(ptr %arr, i32 %n) {
+entry:
+  br label %loop
+
+loop:
+  %i = phi i32 [ 0, %entry ], [ %inc, %loop ]
+  %sum = phi i32 [ 0, %entry ], [ %add, %loop ]
+  %ptr = getelementptr i32, ptr %arr, i32 %i
+  %val = load i32, ptr %ptr
+  %mul = mul i32 %val, %i
+  %add = add i32 %sum, %mul
+  %ptr2 = getelementptr i32, ptr %arr, i32 %add
+  store i32 %add, ptr %ptr2
+  %inc = add i32 %i, 1
+  %cmp = icmp slt i32 %inc, %n
+  br i1 %cmp, label %loop, label %exit
+
+exit:
+  ret i32 %add
+}

>From e80982d27cfc71d04a420371a5e2d1ce0fdfa4f4 Mon Sep 17 00:00:00 2001
From: Rick Gaiser <[email protected]>
Date: Sun, 18 Jan 2026 13:25:11 +0100
Subject: [PATCH 4/6] [Mips] Set ISA extension AFL_EXT_5900 for r5900

Set the ISA extension field in .MIPS.abiflags to AFL_EXT_5900 when
targeting the R5900, matching binutils behavior. This marks object
files as compiled for the R5900, enabling linker compatibility checking.

Also rename the display name in llvm-readobj from "MIPS R5900" to
"Toshiba R5900" to match binutils readelf output.
---
 llvm/lib/Target/Mips/MCTargetDesc/MipsABIFlagsSection.h | 2 ++
 llvm/test/CodeGen/Mips/cpus.ll                          | 1 +
 llvm/tools/llvm-readobj/ELFDumper.cpp                   | 6 ++++--
 3 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsABIFlagsSection.h 
b/llvm/lib/Target/Mips/MCTargetDesc/MipsABIFlagsSection.h
index 1a5bb64863ee8..f7b2fa5537d31 100644
--- a/llvm/lib/Target/Mips/MCTargetDesc/MipsABIFlagsSection.h
+++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsABIFlagsSection.h
@@ -143,6 +143,8 @@ struct MipsABIFlagsSection {
       ISAExtension = Mips::AFL_EXT_OCTEONP;
     else if (P.hasCnMips())
       ISAExtension = Mips::AFL_EXT_OCTEON;
+    else if (P.isR5900())
+      ISAExtension = Mips::AFL_EXT_5900;
     else
       ISAExtension = Mips::AFL_EXT_NONE;
   }
diff --git a/llvm/test/CodeGen/Mips/cpus.ll b/llvm/test/CodeGen/Mips/cpus.ll
index 14e7476d8f9ef..05d9a89660b7b 100644
--- a/llvm/test/CodeGen/Mips/cpus.ll
+++ b/llvm/test/CodeGen/Mips/cpus.ll
@@ -61,6 +61,7 @@
 ; RUN: llc -mtriple=mips64el -mcpu=r5900 -filetype=obj < %s \
 ; RUN:   | llvm-readelf -A - | FileCheck %s --check-prefix=R5900
 ; R5900: ISA: MIPS3
+; R5900: ISA Extension: Toshiba R5900
 
 ; Check that we reject CPUs that are not implemented.
 
diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp 
b/llvm/tools/llvm-readobj/ELFDumper.cpp
index 96c4668984965..0189c04bd1f03 100644
--- a/llvm/tools/llvm-readobj/ELFDumper.cpp
+++ b/llvm/tools/llvm-readobj/ELFDumper.cpp
@@ -3326,6 +3326,7 @@ MipsGOTParser<ELFT>::getPltSym(const Entry *E) const {
   }
 }
 
+// clang-format off
 const EnumEntry<unsigned> ElfMipsISAExtType[] = {
   {"None",                    Mips::AFL_EXT_NONE},
   {"Broadcom SB-1",           Mips::AFL_EXT_SB1},
@@ -3338,7 +3339,6 @@ const EnumEntry<unsigned> ElfMipsISAExtType[] = {
   {"Loongson 2F",             Mips::AFL_EXT_LOONGSON_2F},
   {"Loongson 3A",             Mips::AFL_EXT_LOONGSON_3A},
   {"MIPS R4650",              Mips::AFL_EXT_4650},
-  {"MIPS R5900",              Mips::AFL_EXT_5900},
   {"MIPS R10000",             Mips::AFL_EXT_10000},
   {"NEC VR4100",              Mips::AFL_EXT_4100},
   {"NEC VR4111/VR4181",       Mips::AFL_EXT_4111},
@@ -3346,8 +3346,10 @@ const EnumEntry<unsigned> ElfMipsISAExtType[] = {
   {"NEC VR5400",              Mips::AFL_EXT_5400},
   {"NEC VR5500",              Mips::AFL_EXT_5500},
   {"RMI Xlr",                 Mips::AFL_EXT_XLR},
-  {"Toshiba R3900",           Mips::AFL_EXT_3900}
+  {"Toshiba R3900",           Mips::AFL_EXT_3900},
+  {"Toshiba R5900",           Mips::AFL_EXT_5900},
 };
+// clang-format on
 
 const EnumEntry<unsigned> ElfMipsASEFlags[] = {
   {"DSP",                Mips::AFL_ASE_DSP},

>From 1bbe1086a9268df7e620add679d6f3910ac25525 Mon Sep 17 00:00:00 2001
From: Rick Gaiser <[email protected]>
Date: Sun, 18 Jan 2026 13:22:18 +0100
Subject: [PATCH 5/6] [clang][Mips] Add missing i6400 and i6500 to CPU test

The test for valid MIPS CPU names was missing entries for i6400 and
i6500, which are valid CPUs defined in LLVM.
---
 clang/test/Misc/target-invalid-cpu-note/mips.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/clang/test/Misc/target-invalid-cpu-note/mips.c 
b/clang/test/Misc/target-invalid-cpu-note/mips.c
index 17b6ff9c57084..e9d21b2253485 100644
--- a/clang/test/Misc/target-invalid-cpu-note/mips.c
+++ b/clang/test/Misc/target-invalid-cpu-note/mips.c
@@ -23,4 +23,6 @@
 // CHECK-SAME: {{^}}, octeon
 // CHECK-SAME: {{^}}, octeon+
 // CHECK-SAME: {{^}}, p5600
+// CHECK-SAME: {{^}}, i6400
+// CHECK-SAME: {{^}}, i6500
 // CHECK-SAME: {{$}}

>From 92358eb1733b6876cabc62314086a6920e583aae Mon Sep 17 00:00:00 2001
From: Rick Gaiser <[email protected]>
Date: Sun, 18 Jan 2026 15:53:34 +0100
Subject: [PATCH 6/6] [clang][Mips] Add r5900 CPU support

---
 clang/lib/Basic/Targets/Mips.cpp               | 4 +++-
 clang/test/Misc/target-invalid-cpu-note/mips.c | 1 +
 2 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/clang/lib/Basic/Targets/Mips.cpp b/clang/lib/Basic/Targets/Mips.cpp
index a999d1410d254..76c9081567053 100644
--- a/clang/lib/Basic/Targets/Mips.cpp
+++ b/clang/lib/Basic/Targets/Mips.cpp
@@ -46,6 +46,7 @@ bool MipsTargetInfo::processorSupportsGPR64() const {
       .Case("mips64r6", true)
       .Case("octeon", true)
       .Case("octeon+", true)
+      .Case("r5900", true)
       .Case("i6400", true)
       .Case("i6500", true)
       .Default(false);
@@ -55,7 +56,8 @@ static constexpr llvm::StringLiteral ValidCPUNames[] = {
     {"mips1"},  {"mips2"},    {"mips3"},    {"mips4"},    {"mips5"},
     {"mips32"}, {"mips32r2"}, {"mips32r3"}, {"mips32r5"}, {"mips32r6"},
     {"mips64"}, {"mips64r2"}, {"mips64r3"}, {"mips64r5"}, {"mips64r6"},
-    {"octeon"}, {"octeon+"},  {"p5600"},    {"i6400"},    {"i6500"}};
+    {"octeon"}, {"octeon+"},  {"p5600"},    {"r5900"},    {"i6400"},
+    {"i6500"}};
 
 bool MipsTargetInfo::isValidCPUName(StringRef Name) const {
   return llvm::is_contained(ValidCPUNames, Name);
diff --git a/clang/test/Misc/target-invalid-cpu-note/mips.c 
b/clang/test/Misc/target-invalid-cpu-note/mips.c
index e9d21b2253485..738362edf3c80 100644
--- a/clang/test/Misc/target-invalid-cpu-note/mips.c
+++ b/clang/test/Misc/target-invalid-cpu-note/mips.c
@@ -23,6 +23,7 @@
 // CHECK-SAME: {{^}}, octeon
 // CHECK-SAME: {{^}}, octeon+
 // CHECK-SAME: {{^}}, p5600
+// CHECK-SAME: {{^}}, r5900
 // CHECK-SAME: {{^}}, i6400
 // CHECK-SAME: {{^}}, i6500
 // CHECK-SAME: {{$}}

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to