https://github.com/rickgaiser created https://github.com/llvm/llvm-project/pull/176666
This PR adds basic support for the MIPS R5900 CPU, the Emotion Engine processor used in the PlayStation 2. **LLVM changes:** - Add r5900 CPU definition (with soft float support for now) - Disable instructions not supported by r5900 (64-bit multiply/divide, LL/SC atomics, COP3) - Add r5900 specific short loop delay slot fix (hardware errata workaround) - Set ISA extension `AFL_EXT_5900` in ELF flags for proper ABI identification **Clang changes:** - Add r5900 as a valid CPU target for `-mcpu=r5900` - Add r5900 to CPU test coverage ## Usage Basic compilation: ```bash clang --target=mips64el-none-elf -mcpu=r5900 -c file.c ``` Assembly: ```bash llvm-mc -triple=mips64el-none-elf -mcpu=r5900 file.s -filetype=obj -o file.o ``` ## Future work - Instruction scheduling for r5900 pipeline - MIPS IV instruction subset (MOVN, MOVZ, PREF already supported; MADD/MSUB use different encoding) - MMI instructions: 128-bit integer SIMD (v16i8, v8i16, v4i32) - COP1 FPU with r5900-specific behavior - COP2/VU0 macro mode instructions: 128-bit float SIMD (v4f32) ## Test plan - [x] `ninja check-llvm-mc-mips` - passed - [x] `ninja check-llvm-codegen-mips` - passed - [x] `clang/test/Misc/target-invalid-cpu-note/mips.c` - passed ## Note I have some experience with gcc (from implementing and maintaining r5900 in a separate fork), but this is my first experience with LLVM. Initial tests have showed that LLVM compiled code for the r5900 (RetroArch/emulator) performs 60% faster than a gcc compiled one, so I'm very excited about LLVM and what it can bring. That will need proper instruction scheduling though, but that's the topic for another PR. I would kindly request @MaskRay to review this PR, as you seem to be the most active on MIPS recently. This is my first PR to LLVM, so please let me know if there's anything I need to change or should do differently. >From 7041a2c74f4482df135393b9e84e88576864352b 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 ac31d4e40f2658995c403d381dada03e82a91e03 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 cd9ea0b39895ce2bb04431cbf4a0f09cc0894b68 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 90b7ffbf01111af9fad22995d5f6bcba1e8210b1 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. --- .../Mips/MCTargetDesc/MipsABIFlagsSection.h | 2 + llvm/test/CodeGen/Mips/cpus.ll | 1 + llvm/tools/llvm-readobj/ELFDumper.cpp | 41 +++++++++---------- 3 files changed, 23 insertions(+), 21 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..a18ec743c7131 100644 --- a/llvm/tools/llvm-readobj/ELFDumper.cpp +++ b/llvm/tools/llvm-readobj/ELFDumper.cpp @@ -3327,27 +3327,26 @@ MipsGOTParser<ELFT>::getPltSym(const Entry *E) const { } const EnumEntry<unsigned> ElfMipsISAExtType[] = { - {"None", Mips::AFL_EXT_NONE}, - {"Broadcom SB-1", Mips::AFL_EXT_SB1}, - {"Cavium Networks Octeon", Mips::AFL_EXT_OCTEON}, - {"Cavium Networks Octeon2", Mips::AFL_EXT_OCTEON2}, - {"Cavium Networks OcteonP", Mips::AFL_EXT_OCTEONP}, - {"Cavium Networks Octeon3", Mips::AFL_EXT_OCTEON3}, - {"LSI R4010", Mips::AFL_EXT_4010}, - {"Loongson 2E", Mips::AFL_EXT_LOONGSON_2E}, - {"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}, - {"NEC VR4120", Mips::AFL_EXT_4120}, - {"NEC VR5400", Mips::AFL_EXT_5400}, - {"NEC VR5500", Mips::AFL_EXT_5500}, - {"RMI Xlr", Mips::AFL_EXT_XLR}, - {"Toshiba R3900", Mips::AFL_EXT_3900} -}; + {"None", Mips::AFL_EXT_NONE}, + {"Broadcom SB-1", Mips::AFL_EXT_SB1}, + {"Cavium Networks Octeon", Mips::AFL_EXT_OCTEON}, + {"Cavium Networks Octeon2", Mips::AFL_EXT_OCTEON2}, + {"Cavium Networks OcteonP", Mips::AFL_EXT_OCTEONP}, + {"Cavium Networks Octeon3", Mips::AFL_EXT_OCTEON3}, + {"LSI R4010", Mips::AFL_EXT_4010}, + {"Loongson 2E", Mips::AFL_EXT_LOONGSON_2E}, + {"Loongson 2F", Mips::AFL_EXT_LOONGSON_2F}, + {"Loongson 3A", Mips::AFL_EXT_LOONGSON_3A}, + {"MIPS R4650", Mips::AFL_EXT_4650}, + {"MIPS R10000", Mips::AFL_EXT_10000}, + {"NEC VR4100", Mips::AFL_EXT_4100}, + {"NEC VR4111/VR4181", Mips::AFL_EXT_4111}, + {"NEC VR4120", Mips::AFL_EXT_4120}, + {"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 R5900", Mips::AFL_EXT_5900}}; const EnumEntry<unsigned> ElfMipsASEFlags[] = { {"DSP", Mips::AFL_ASE_DSP}, >From b6897046349cb33ac304e6b4bb0f29be6a84274a 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 c1f875671b304ee788b347599972a54b5154b24e 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
