llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-llvm-binary-utilities @llvm/pr-subscribers-backend-mips Author: Rick Gaiser (rickgaiser) <details> <summary>Changes</summary> 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. --- Patch is 38.28 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/176666.diff 17 Files Affected: - (modified) clang/lib/Basic/Targets/Mips.cpp (+3-1) - (modified) clang/test/Misc/target-invalid-cpu-note/mips.c (+3) - (modified) llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp (+2) - (modified) llvm/lib/Target/Mips/MCTargetDesc/MipsABIFlagsSection.h (+2) - (modified) llvm/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp (+2) - (modified) llvm/lib/Target/Mips/Mips.td (+5) - (modified) llvm/lib/Target/Mips/Mips64InstrInfo.td (+95-80) - (modified) llvm/lib/Target/Mips/MipsDelaySlotFiller.cpp (+75-4) - (modified) llvm/lib/Target/Mips/MipsISelLowering.cpp (+4-1) - (modified) llvm/lib/Target/Mips/MipsInstrInfo.td (+55-13) - (modified) llvm/lib/Target/Mips/MipsSEISelLowering.cpp (+11-2) - (modified) llvm/lib/Target/Mips/MipsSubtarget.cpp (+4-4) - (modified) llvm/lib/Target/Mips/MipsSubtarget.h (+4) - (modified) llvm/test/CodeGen/Mips/cpus.ll (+5) - (added) llvm/test/CodeGen/Mips/r5900-short-loop.ll (+59) - (added) llvm/test/MC/Mips/r5900-invalid.s (+59) - (modified) llvm/tools/llvm-readobj/ELFDumper.cpp (+20-21) ``````````diff 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 17b6ff9c57084..738362edf3c80 100644 --- a/clang/test/Misc/target-invalid-cpu-note/mips.c +++ b/clang/test/Misc/target-invalid-cpu-note/mips.c @@ -23,4 +23,7 @@ // CHECK-SAME: {{^}}, octeon // CHECK-SAME: {{^}}, octeon+ // CHECK-SAME: {{^}}, p5600 +// CHECK-SAME: {{^}}, r5900 +// CHECK-SAME: {{^}}, i6400 +// CHECK-SAME: {{^}}, i6500 // CHECK-SAME: {{$}} 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/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/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/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/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 ma... [truncated] `````````` </details> https://github.com/llvm/llvm-project/pull/176666 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
