Author: Rick Gaiser Date: 2026-01-28T04:32:59-05:00 New Revision: f4b593a792a61a53068f43b83854b39e304c03f9
URL: https://github.com/llvm/llvm-project/commit/f4b593a792a61a53068f43b83854b39e304c03f9 DIFF: https://github.com/llvm/llvm-project/commit/f4b593a792a61a53068f43b83854b39e304c03f9.diff LOG: [Mips] Add r5900 (PlayStation 2 Emotion Engine) CPU support (#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 Added: llvm/test/CodeGen/Mips/r5900-short-loop.ll llvm/test/MC/Mips/r5900-invalid.s Modified: clang/include/clang/Options/Options.td clang/lib/Basic/Targets/Mips.cpp clang/lib/Driver/ToolChains/Arch/Mips.cpp clang/test/Misc/target-invalid-cpu-note/mips.c llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp llvm/lib/Target/Mips/MCTargetDesc/MipsABIFlagsSection.h llvm/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp llvm/lib/Target/Mips/Mips.td llvm/lib/Target/Mips/Mips64InstrInfo.td llvm/lib/Target/Mips/MipsDelaySlotFiller.cpp llvm/lib/Target/Mips/MipsISelLowering.cpp llvm/lib/Target/Mips/MipsInstrInfo.td llvm/lib/Target/Mips/MipsSEISelLowering.cpp llvm/lib/Target/Mips/MipsSubtarget.cpp llvm/lib/Target/Mips/MipsSubtarget.h llvm/test/CodeGen/Mips/cpus.ll llvm/tools/llvm-readobj/ELFDumper.cpp Removed: ################################################################################ diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td index a08100ef9d0cd..bcac5ff937d7b 100644 --- a/clang/include/clang/Options/Options.td +++ b/clang/include/clang/Options/Options.td @@ -5936,6 +5936,12 @@ def mcheck_zero_division : Flag<["-"], "mcheck-zero-division">, def mno_check_zero_division : Flag<["-"], "mno-check-zero-division">, Group<m_mips_Features_Group>; def mfix4300 : Flag<["-"], "mfix4300">, Group<m_mips_Features_Group>; +def mfix_r5900 : Flag<["-"], "mfix-r5900">, + Group<m_mips_Features_Group>, + HelpText<"Enable R5900 short loop erratum fix">; +def mno_fix_r5900 : Flag<["-"], "mno-fix-r5900">, + Group<m_mips_Features_Group>, + HelpText<"Disable R5900 short loop erratum fix">; def mcompact_branches_EQ : Joined<["-"], "mcompact-branches=">, Group<m_mips_Features_Group>; } // let Flags = [TargetSpecific] 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/lib/Driver/ToolChains/Arch/Mips.cpp b/clang/lib/Driver/ToolChains/Arch/Mips.cpp index 103aae7018fbf..b72d654291658 100644 --- a/clang/lib/Driver/ToolChains/Arch/Mips.cpp +++ b/clang/lib/Driver/ToolChains/Arch/Mips.cpp @@ -388,6 +388,8 @@ void mips::getMIPSTargetFeatures(const Driver &D, const llvm::Triple &Triple, "virt"); AddTargetFeature(Args, Features, options::OPT_mginv, options::OPT_mno_ginv, "ginv"); + AddTargetFeature(Args, Features, options::OPT_mfix_r5900, + options::OPT_mno_fix_r5900, "fix-r5900"); if (Arg *A = Args.getLastArg(options::OPT_mindirect_jump_EQ)) { StringRef Val = StringRef(A->getValue()); 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..2f3ec5d051a79 100644 --- a/llvm/lib/Target/Mips/Mips.td +++ b/llvm/lib/Target/Mips/Mips.td @@ -186,6 +186,14 @@ def FeatureCnMipsP : SubtargetFeature<"cnmipsp", "HasCnMipsP", "true", "Octeon+ cnMIPS Support", [FeatureCnMips]>; +def FeatureFixR5900 : SubtargetFeature<"fix-r5900", "FixR5900", "true", + "Enable R5900 short loop erratum fix">; + +def FeatureR5900 : SubtargetFeature<"r5900", "IsR5900", "true", + "R5900 (PS2 Emotion Engine) Support", + [FeatureMips3, FeatureSoftFloat, + FeatureFixR5900]>; + def FeatureUseTCCInDIV : SubtargetFeature< "use-tcc-in-div", "UseTCCInDIV", "false", @@ -296,6 +304,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' diff erently 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' diff erently 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..f04ce53340c5d 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,77 @@ 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. +/// Quote from binutils-gdb/gas/config/tc-mips.c: +/// +/// On the R5900 short loops need to be fixed by inserting a NOP in the +/// branch delay slot. +/// +/// The short loop bug under certain conditions causes loops to execute +/// only once or twice. We must ensure that the assembler never +/// generates loops that satisfy all of the following conditions: +/// +/// - a loop consists of less than or equal to six instructions +/// (including the branch delay slot); +/// - a loop contains only one conditional branch instruction at the end +/// of the loop; +/// - a loop does not contain any other branch or jump instructions; +/// - a branch delay slot of the loop is not NOP (EE 2.9 or later). +/// +/// We need to do this because of a hardware bug in the R5900 chip. +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 +660,22 @@ bool MipsDelaySlotFiller::runOnMachineBasicBlock(MachineBasicBlock &MBB) { if (!hasUnoccupiedSlot(&*I)) continue; - // Delay slot filling is disabled at -O0, or in microMIPS32R6. + // 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. The fix can be controlled with -mfix-r5900 / -mno-fix-r5900. + bool SkipForFixR5900 = false; + if (STI.fixR5900() && isR5900ShortLoopBranch(&*I, MBB)) { + LLVM_DEBUG(dbgs() << DEBUG_TYPE ": skipping delay slot fill for R5900 " + "short loop branch.\n"); + ++R5900ShortLoopNops; + SkipForFixR5900 = true; + } + + // Delay slot filling is disabled at -O0, in microMIPS32R6, or for R5900 + // short loop branches. if (!DisableDelaySlotFiller && (TM->getOptLevel() != CodeGenOptLevel::None) && - !(InMicroMipsMode && STI.hasMips32r6())) { + !(InMicroMipsMode && STI.hasMips32r6()) && !SkipForFixR5900) { bool Filled = false; diff --git a/llvm/lib/Target/Mips/MipsISelLowering.cpp b/llvm/lib/Target/Mips/MipsISelLowering.cpp index a19fb3d5440a2..f7e2825edcc5d 100644 --- a/llvm/lib/Target/Mips/MipsISelLowering.cpp +++ b/llvm/lib/Target/Mips/MipsISelLowering.cpp @@ -416,7 +416,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 e9191c1b9a2eb..442839975c3f5 100644 --- a/llvm/lib/Target/Mips/MipsSEISelLowering.cpp +++ b/llvm/lib/Target/Mips/MipsSEISelLowering.cpp @@ -231,10 +231,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/lib/Target/Mips/MipsSubtarget.cpp b/llvm/lib/Target/Mips/MipsSubtarget.cpp index aef9382d3c1dc..75f7a6c6a1118 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), FixR5900(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..9d2f4d3c2d458 100644 --- a/llvm/lib/Target/Mips/MipsSubtarget.h +++ b/llvm/lib/Target/Mips/MipsSubtarget.h @@ -124,6 +124,12 @@ class MipsSubtarget : public MipsGenSubtargetInfo { // CPU supports cnMIPSP (Cavium Networks Octeon+ CPU). bool HasCnMipsP; + // IsR5900 - CPU is R5900 (PlayStation 2 Emotion Engine). + bool IsR5900; + + // FixR5900 - Enable R5900 short loop erratum fix. + bool FixR5900; + // isLinux - Target system is Linux. Is false we consider ELFOS for now. bool IsLinux; @@ -297,6 +303,8 @@ class MipsSubtarget : public MipsGenSubtargetInfo { bool hasCnMips() const { return HasCnMips; } bool hasCnMipsP() const { return HasCnMipsP; } + bool isR5900() const { return IsR5900; } + bool fixR5900() const { return FixR5900; } 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..05d9a89660b7b 100644 --- a/llvm/test/CodeGen/Mips/cpus.ll +++ b/llvm/test/CodeGen/Mips/cpus.ll @@ -58,6 +58,11 @@ ; 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 +; R5900: ISA Extension: Toshiba R5900 + ; Check that we reject CPUs that are not implemented. ; RUN: not llc < %s -o /dev/null -mtriple=mips64 -mcpu=mips5 2>&1 \ 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..2904cfa21e075 --- /dev/null +++ b/llvm/test/CodeGen/Mips/r5900-short-loop.ll @@ -0,0 +1,70 @@ +; RUN: llc -mtriple=mips64el -mcpu=r5900 < %s | FileCheck %s -check-prefix=FIX +; RUN: llc -mtriple=mips64el -mcpu=r5900 -mattr=-fix-r5900 < %s | FileCheck %s -check-prefix=NOFIX +; +; 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. + +; Short loop test with store - delay slot can be filled when fix is disabled +; With fix enabled: bnez followed by nop +; With fix disabled: bnez followed by daddiu (delay slot filled) + +; FIX-LABEL: test_short_loop_store: +; FIX: .LBB0_1: +; FIX: bnez +; FIX-NEXT: nop + +; NOFIX-LABEL: test_short_loop_store: +; NOFIX: .LBB0_1: +; NOFIX: bnez +; NOFIX-NEXT: daddiu +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 diff erent 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}} + +; NOFIX-LABEL: test_long_loop: +; NOFIX: .LBB1_1: +; NOFIX: bnez ${{[0-9]+}}, .LBB1_1 +; NOFIX-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 +} 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) diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp index dd5a37b1c650d..a7e10718942dd 100644 --- a/llvm/tools/llvm-readobj/ELFDumper.cpp +++ b/llvm/tools/llvm-readobj/ELFDumper.cpp @@ -3327,6 +3327,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}, @@ -3339,7 +3340,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}, @@ -3347,8 +3347,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}, _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
