Index: include/llvm/Support/MipsABIFlags.h =================================================================== --- include/llvm/Support/MipsABIFlags.h +++ include/llvm/Support/MipsABIFlags.h @@ -42,7 +42,8 @@ AFL_ASE_MSA = 0x00000200, // MSA ASE AFL_ASE_MIPS16 = 0x00000400, // MIPS16 ASE AFL_ASE_MICROMIPS = 0x00000800, // MICROMIPS ASE - AFL_ASE_XPA = 0x00001000 // XPA ASE + AFL_ASE_XPA = 0x00001000, // XPA ASE + AFL_ASE_CRC = 0x00008000 // CRC ASE }; // Values for the isa_ext word of an ABI flags structure. Index: lib/Target/Mips/AsmParser/MipsAsmParser.cpp =================================================================== --- lib/Target/Mips/AsmParser/MipsAsmParser.cpp +++ lib/Target/Mips/AsmParser/MipsAsmParser.cpp @@ -348,6 +348,7 @@ bool parseSetHardFloatDirective(); bool parseSetMtDirective(); bool parseSetNoMtDirective(); + bool parseSetNoCRCDirective(); bool parseSetAssignment(); @@ -644,6 +645,10 @@ return getSTI().getFeatureBits()[Mips::FeatureMT]; } + bool hasCRC() const { + return getSTI().getFeatureBits()[Mips::FeatureCRC]; + } + /// Warn if RegIndex is the same as the current AT. void warnIfRegIndexIsAT(unsigned RegIndex, SMLoc Loc); @@ -5246,6 +5251,13 @@ return Match_RequiresPosSizeRange33_64; return Match_Success; } + case Mips::CRC32B: case Mips::CRC32CB: + case Mips::CRC32H: case Mips::CRC32CH: + case Mips::CRC32W: case Mips::CRC32CW: + case Mips::CRC32D: case Mips::CRC32CD: + if (Inst.getOperand(0).getReg() != Inst.getOperand(2).getReg()) + return Match_RequiresSameSrcAndDst; + return Match_Success; } uint64_t TSFlags = getInstDesc(Inst.getOpcode()).TSFlags; @@ -6665,6 +6677,23 @@ return false; } +bool MipsAsmParser::parseSetNoCRCDirective() { + MCAsmParser &Parser = getParser(); + Parser.Lex(); // Eat "nocrc". + + // If this is not the end of the statement, report an error. + if (getLexer().isNot(AsmToken::EndOfStatement)) { + reportParseError("unexpected token, expected end of statement"); + return false; + } + + clearFeatureBits(Mips::FeatureCRC, "crc"); + + getTargetStreamer().emitDirectiveSetNoCRC(); + Parser.Lex(); // Consume the EndOfStatement. + return false; +} + bool MipsAsmParser::parseSetPopDirective() { MCAsmParser &Parser = getParser(); SMLoc Loc = getLexer().getLoc(); @@ -6886,6 +6915,10 @@ selectArch("mips64r6"); getTargetStreamer().emitDirectiveSetMips64R6(); break; + case Mips::FeatureCRC: + setFeatureBits(Mips::FeatureCRC, "crc"); + getTargetStreamer().emitDirectiveSetCRC(); + break; } return false; } @@ -7190,6 +7223,10 @@ return parseSetSoftFloatDirective(); } else if (Tok.getString() == "hardfloat") { return parseSetHardFloatDirective(); + } else if (Tok.getString() == "crc") { + return parseSetFeature(Mips::FeatureCRC); + } else if (Tok.getString() == "nocrc") { + return parseSetNoCRCDirective(); } else { // It is just an identifier, look for an assignment. parseSetAssignment(); @@ -7436,6 +7473,8 @@ /// ::= .module softfloat /// ::= .module hardfloat /// ::= .module mt +/// ::= .module crc +/// ::= .module nocrc bool MipsAsmParser::parseDirectiveModule() { MCAsmParser &Parser = getParser(); MCAsmLexer &Lexer = getLexer(); @@ -7554,6 +7593,44 @@ } return false; // parseDirectiveModule has finished successfully. + } else if (Option == "crc") { + setModuleFeatureBits(Mips::FeatureCRC, "crc"); + + // Synchronize the ABI Flags information with the FeatureBits information we + // updated above. + getTargetStreamer().updateABIInfo(*this); + + // If printing assembly, use the recently updated ABI Flags information. + // If generating ELF, don't do anything (the .MIPS.abiflags section gets + // emitted later). + getTargetStreamer().emitDirectiveModuleCRC(); + + // If this is not the end of the statement, report an error. + if (getLexer().isNot(AsmToken::EndOfStatement)) { + reportParseError("unexpected token, expected end of statement"); + return false; + } + + return false; // parseDirectiveModule has finished successfully. + } else if (Option == "nocrc") { + clearModuleFeatureBits(Mips::FeatureCRC, "crc"); + + // Synchronize the ABI Flags information with the FeatureBits information we + // updated above. + getTargetStreamer().updateABIInfo(*this); + + // If printing assembly, use the recently updated ABI Flags information. + // If generating ELF, don't do anything (the .MIPS.abiflags section gets + // emitted later). + getTargetStreamer().emitDirectiveModuleNoCRC(); + + // If this is not the end of the statement, report an error. + if (getLexer().isNot(AsmToken::EndOfStatement)) { + reportParseError("unexpected token, expected end of statement"); + return false; + } + + return false; // parseDirectiveModule has finished successfully. } else { return Error(L, "'" + Twine(Option) + "' is not a valid .module option."); } Index: lib/Target/Mips/Disassembler/MipsDisassembler.cpp =================================================================== --- lib/Target/Mips/Disassembler/MipsDisassembler.cpp +++ lib/Target/Mips/Disassembler/MipsDisassembler.cpp @@ -517,6 +517,10 @@ static DecodeStatus DecodeDEXT(MCInst &MI, InsnType Insn, uint64_t Address, const void *Decoder); +template +static DecodeStatus DecodeCRC(MCInst &MI, InsnType Insn, uint64_t Address, + const void *Decoder); + static DecodeStatus DecodeRegListOperand(MCInst &Inst, unsigned Insn, uint64_t Address, const void *Decoder); @@ -1129,6 +1133,22 @@ return MCDisassembler::Success; } + +// Auto-generated decoder wouldn't add the third operand for CRC32*. +template +static DecodeStatus DecodeCRC(MCInst &MI, InsnType Insn, uint64_t Address, + const void *Decoder) { + InsnType Rs = fieldFromInstruction(Insn, 21, 5); + InsnType Rt = fieldFromInstruction(Insn, 16, 5); + MI.addOperand(MCOperand::createReg(getReg(Decoder, Mips::GPR32RegClassID, + Rt))); + MI.addOperand(MCOperand::createReg(getReg(Decoder, Mips::GPR32RegClassID, + Rs))); + MI.addOperand(MCOperand::createReg(getReg(Decoder, Mips::GPR32RegClassID, + Rt))); + return MCDisassembler::Success; +} + /// Read two bytes from the ArrayRef and return 16 bit halfword sorted /// according to the given endianness. static DecodeStatus readInstruction16(ArrayRef Bytes, uint64_t Address, Index: lib/Target/Mips/MCTargetDesc/MipsABIFlagsSection.h =================================================================== --- lib/Target/Mips/MCTargetDesc/MipsABIFlagsSection.h +++ lib/Target/Mips/MCTargetDesc/MipsABIFlagsSection.h @@ -161,6 +161,8 @@ ASESet |= Mips::AFL_ASE_MIPS16; if (P.hasMT()) ASESet |= Mips::AFL_ASE_MT; + if (P.hasCRC()) + ASESet |= Mips::AFL_ASE_CRC; } template Index: lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp =================================================================== --- lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp +++ lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp @@ -52,6 +52,8 @@ void MipsTargetStreamer::emitDirectiveSetNoMsa() { forbidModuleDirective(); } void MipsTargetStreamer::emitDirectiveSetMt() {} void MipsTargetStreamer::emitDirectiveSetNoMt() { forbidModuleDirective(); } +void MipsTargetStreamer::emitDirectiveSetCRC() {} +void MipsTargetStreamer::emitDirectiveSetNoCRC() {} void MipsTargetStreamer::emitDirectiveSetAt() { forbidModuleDirective(); } void MipsTargetStreamer::emitDirectiveSetAtWithArg(unsigned RegNo) { forbidModuleDirective(); @@ -122,6 +124,8 @@ void MipsTargetStreamer::emitDirectiveModuleSoftFloat() {} void MipsTargetStreamer::emitDirectiveModuleHardFloat() {} void MipsTargetStreamer::emitDirectiveModuleMT() {} +void MipsTargetStreamer::emitDirectiveModuleCRC() {} +void MipsTargetStreamer::emitDirectiveModuleNoCRC() {} void MipsTargetStreamer::emitDirectiveSetFp( MipsABIFlagsSection::FpABIKind Value) { forbidModuleDirective(); @@ -421,6 +425,16 @@ MipsTargetStreamer::emitDirectiveSetNoMt(); } +void MipsTargetAsmStreamer::emitDirectiveSetCRC() { + OS << "\t.set\tcrc\n"; + MipsTargetStreamer::emitDirectiveSetCRC(); +} + +void MipsTargetAsmStreamer::emitDirectiveSetNoCRC() { + OS << "\t.set\tnocrc\n"; + MipsTargetStreamer::emitDirectiveSetNoCRC(); +} + void MipsTargetAsmStreamer::emitDirectiveSetAt() { OS << "\t.set\tat\n"; MipsTargetStreamer::emitDirectiveSetAt(); @@ -694,6 +708,14 @@ OS << "\t.module\tmt\n"; } +void MipsTargetAsmStreamer::emitDirectiveModuleCRC() { + OS << "\t.module\tcrc\n"; +} + +void MipsTargetAsmStreamer::emitDirectiveModuleNoCRC() { + OS << "\t.module\tnocrc\n"; +} + // This part is for ELF object output. MipsTargetELFStreamer::MipsTargetELFStreamer(MCStreamer &S, const MCSubtargetInfo &STI) Index: lib/Target/Mips/Mips.td =================================================================== --- lib/Target/Mips/Mips.td +++ lib/Target/Mips/Mips.td @@ -176,6 +176,8 @@ def FeatureEVA : SubtargetFeature<"eva", "HasEVA", "true", "Mips EVA ASE">; +def FeatureCRC : SubtargetFeature<"crc", "HasCRC", "true", "Mips R6 CRC ASE">; + def FeatureMicroMips : SubtargetFeature<"micromips", "InMicroMipsMode", "true", "microMips mode">; Index: lib/Target/Mips/Mips32r6InstrFormats.td =================================================================== --- lib/Target/Mips/Mips32r6InstrFormats.td +++ lib/Target/Mips/Mips32r6InstrFormats.td @@ -576,3 +576,18 @@ let Inst{15-11} = base; let Inst{10-0} = offset; } + +class SPECIAL3_2R_SZ_CRC sz, bits<3> direction> : MipsR6Inst { + bits<5> rs; + bits<5> rt; + + let Inst{31-26} = OPGROUP_SPECIAL3.Value; + let Inst{25-21} = rs; + let Inst{20-16} = rt; + let Inst{15-11} = 0b00000; + let Inst{10-8} = direction; + let Inst{7-6} = sz; + let Inst{5-0} = 0b001111; + + string DecoderMethod = "DecodeCRC"; +} Index: lib/Target/Mips/Mips32r6InstrInfo.td =================================================================== --- lib/Target/Mips/Mips32r6InstrInfo.td +++ lib/Target/Mips/Mips32r6InstrInfo.td @@ -190,6 +190,13 @@ class SDBBP_R6_ENC : SPECIAL_SDBBP_FM; +class CRC32B_ENC : SPECIAL3_2R_SZ_CRC<0,0>; +class CRC32H_ENC : SPECIAL3_2R_SZ_CRC<1,0>; +class CRC32W_ENC : SPECIAL3_2R_SZ_CRC<2,0>; +class CRC32CB_ENC : SPECIAL3_2R_SZ_CRC<0,1>; +class CRC32CH_ENC : SPECIAL3_2R_SZ_CRC<1,1>; +class CRC32CW_ENC : SPECIAL3_2R_SZ_CRC<2,1>; + //===----------------------------------------------------------------------===// // // Instruction Multiclasses @@ -804,6 +811,22 @@ InstrItinClass Itinerary = II_SDBBP; } +class CRC_DESC_BASE : MipsR6Arch { + dag OutOperandList = (outs GPROpnd:$rd); + dag InOperandList = (ins GPROpnd:$rs, GPROpnd:$rt); + string AsmString = !strconcat(instr_asm, "\t$rd, $rs, $rt"); + list Pattern = []; + InstrItinClass Itinerary = itin; +} + +class CRC32B_DESC : CRC_DESC_BASE<"crc32b", GPR32Opnd, II_CRC32B>; +class CRC32H_DESC : CRC_DESC_BASE<"crc32h", GPR32Opnd, II_CRC32H>; +class CRC32W_DESC : CRC_DESC_BASE<"crc32w", GPR32Opnd, II_CRC32W>; +class CRC32CB_DESC : CRC_DESC_BASE<"crc32cb", GPR32Opnd, II_CRC32CB>; +class CRC32CH_DESC : CRC_DESC_BASE<"crc32ch", GPR32Opnd, II_CRC32CH>; +class CRC32CW_DESC : CRC_DESC_BASE<"crc32cw", GPR32Opnd, II_CRC32CW>; + //===----------------------------------------------------------------------===// // // Instruction Definitions @@ -923,6 +946,15 @@ def SWC2_R6 : SWC2_R6_ENC, SWC2_R6_DESC, ISA_MIPS32R6; } +let AdditionalPredicates = [NotInMicroMips] in { + def CRC32B : R6MMR6Rel, CRC32B_ENC, CRC32B_DESC, ISA_MIPS32R6, ASE_CRC; + def CRC32H : R6MMR6Rel, CRC32H_ENC, CRC32H_DESC, ISA_MIPS32R6, ASE_CRC; + def CRC32W : R6MMR6Rel, CRC32W_ENC, CRC32W_DESC, ISA_MIPS32R6, ASE_CRC; + def CRC32CB : R6MMR6Rel, CRC32CB_ENC, CRC32CB_DESC, ISA_MIPS32R6, ASE_CRC; + def CRC32CH : R6MMR6Rel, CRC32CH_ENC, CRC32CH_DESC, ISA_MIPS32R6, ASE_CRC; + def CRC32CW : R6MMR6Rel, CRC32CW_ENC, CRC32CW_DESC, ISA_MIPS32R6, ASE_CRC; +} + //===----------------------------------------------------------------------===// // // Instruction Aliases Index: lib/Target/Mips/Mips64r6InstrInfo.td =================================================================== --- lib/Target/Mips/Mips64r6InstrInfo.td +++ lib/Target/Mips/Mips64r6InstrInfo.td @@ -39,6 +39,8 @@ class LDPC_ENC : PCREL18_FM; class LLD_R6_ENC : SPECIAL3_LL_SC_FM; class SCD_R6_ENC : SPECIAL3_LL_SC_FM; +class CRC32D_ENC : SPECIAL3_2R_SZ_CRC<3,0>; +class CRC32CD_ENC : SPECIAL3_2R_SZ_CRC<3,1>; //===----------------------------------------------------------------------===// // @@ -114,6 +116,10 @@ bit isCTI = 1; InstrItinClass Itinerary = II_JR_HB; } + +class CRC32D_DESC : CRC_DESC_BASE<"crc32d", GPR32Opnd, II_CRC32D>; +class CRC32CD_DESC : CRC_DESC_BASE<"crc32cd", GPR32Opnd, II_CRC32CD>; + //===----------------------------------------------------------------------===// // // Instruction Definitions @@ -174,6 +180,10 @@ def BLTZC64 : BLTZC_ENC, BLTZC64_DESC, ISA_MIPS64R6, GPR_64; def BGEZC64 : BGEZC_ENC, BGEZC64_DESC, ISA_MIPS64R6, GPR_64; } +let AdditionalPredicates = [NotInMicroMips] in { + def CRC32D : R6MMR6Rel, CRC32D_ENC, CRC32D_DESC, ISA_MIPS64R6, ASE_CRC; + def CRC32CD : R6MMR6Rel, CRC32CD_ENC, CRC32CD_DESC, ISA_MIPS64R6, ASE_CRC; +} //===----------------------------------------------------------------------===// // Index: lib/Target/Mips/MipsInstrInfo.td =================================================================== --- lib/Target/Mips/MipsInstrInfo.td +++ lib/Target/Mips/MipsInstrInfo.td @@ -246,6 +246,8 @@ AssemblerPredicate<"FeatureUseIndirectJumpsHazard">; def NoIndirectJumpGuards : Predicate<"!Subtarget->useIndirectJumpsHazard()">, AssemblerPredicate<"!FeatureUseIndirectJumpsHazard">; +def HasCRC : Predicate<"Subtarget->hasCRC()">, + AssemblerPredicate<"FeatureCRC">; //===----------------------------------------------------------------------===// // Mips GPR size adjectives. // They are mutually exclusive. @@ -443,6 +445,10 @@ list ASEPredicate = [HasMT]; } +class ASE_CRC { + list ASEPredicate = [HasCRC]; +} + // Class used for separating microMIPSr6 and microMIPS (r3) instruction. // It can be used only on instructions that doesn't inherit PredicateControl. class ISA_MICROMIPS_NOT_32R6 : PredicateControl { Index: lib/Target/Mips/MipsSchedule.td =================================================================== --- lib/Target/Mips/MipsSchedule.td +++ lib/Target/Mips/MipsSchedule.td @@ -57,6 +57,14 @@ def II_CFC2 : InstrItinClass; def II_CLO : InstrItinClass; def II_CLZ : InstrItinClass; +def II_CRC32B : InstrItinClass; +def II_CRC32CB : InstrItinClass; +def II_CRC32CD : InstrItinClass; +def II_CRC32CH : InstrItinClass; +def II_CRC32CW : InstrItinClass; +def II_CRC32D : InstrItinClass; +def II_CRC32H : InstrItinClass; +def II_CRC32W : InstrItinClass; def II_CTC1 : InstrItinClass; def II_CTC2 : InstrItinClass; def II_CVT : InstrItinClass; @@ -686,5 +694,13 @@ InstrItinData]>, InstrItinData]>, InstrItinData]>, - InstrItinData]> + InstrItinData]>, + InstrItinData]>, + InstrItinData]>, + InstrItinData]>, + InstrItinData]>, + InstrItinData]>, + InstrItinData]>, + InstrItinData]>, + InstrItinData]> ]>; Index: lib/Target/Mips/MipsSubtarget.h =================================================================== --- lib/Target/Mips/MipsSubtarget.h +++ lib/Target/Mips/MipsSubtarget.h @@ -162,6 +162,9 @@ // HasMT -- support MT ASE. bool HasMT; + // HasCRC -- supports R6 CRC ASE + bool HasCRC; + // Use hazard variants of the jump register instructions for indirect // function calls and jump tables. bool UseIndirectJumpsHazard; @@ -286,6 +289,7 @@ bool disableMadd4() const { return DisableMadd4; } bool hasEVA() const { return HasEVA; } bool hasMT() const { return HasMT; } + bool hasCRC() const { return HasCRC; } bool useIndirectJumpsHazard() const { return UseIndirectJumpsHazard && hasMips32r2(); } Index: lib/Target/Mips/MipsSubtarget.cpp =================================================================== --- lib/Target/Mips/MipsSubtarget.cpp +++ lib/Target/Mips/MipsSubtarget.cpp @@ -78,7 +78,7 @@ 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), + HasEVA(false), DisableMadd4(false), HasMT(false), HasCRC(false), UseIndirectJumpsHazard(false), StackAlignOverride(StackAlignOverride), TM(TM), TargetTriple(TT), TSInfo(), InstrInfo( Index: lib/Target/Mips/MipsTargetStreamer.h =================================================================== --- lib/Target/Mips/MipsTargetStreamer.h +++ lib/Target/Mips/MipsTargetStreamer.h @@ -42,6 +42,8 @@ virtual void emitDirectiveSetNoMsa(); virtual void emitDirectiveSetMt(); virtual void emitDirectiveSetNoMt(); + virtual void emitDirectiveSetCRC(); + virtual void emitDirectiveSetNoCRC(); virtual void emitDirectiveSetAt(); virtual void emitDirectiveSetAtWithArg(unsigned RegNo); virtual void emitDirectiveSetNoAt(); @@ -103,6 +105,8 @@ virtual void emitDirectiveSetFp(MipsABIFlagsSection::FpABIKind Value); virtual void emitDirectiveSetOddSPReg(); virtual void emitDirectiveSetNoOddSPReg(); + virtual void emitDirectiveModuleCRC(); + virtual void emitDirectiveModuleNoCRC(); void emitR(unsigned Opcode, unsigned Reg0, SMLoc IDLoc, const MCSubtargetInfo *STI); @@ -213,6 +217,8 @@ void emitDirectiveSetNoMsa() override; void emitDirectiveSetMt() override; void emitDirectiveSetNoMt() override; + void emitDirectiveSetCRC() override; + void emitDirectiveSetNoCRC() override; void emitDirectiveSetAt() override; void emitDirectiveSetAtWithArg(unsigned RegNo) override; void emitDirectiveSetNoAt() override; @@ -278,6 +284,8 @@ void emitDirectiveModuleSoftFloat() override; void emitDirectiveModuleHardFloat() override; void emitDirectiveModuleMT() override; + void emitDirectiveModuleCRC() override; + void emitDirectiveModuleNoCRC() override; void emitDirectiveSetFp(MipsABIFlagsSection::FpABIKind Value) override; void emitDirectiveSetOddSPReg() override; void emitDirectiveSetNoOddSPReg() override; Index: test/MC/Disassembler/Mips/crc/valid-32r6-el.txt =================================================================== --- /dev/null +++ test/MC/Disassembler/Mips/crc/valid-32r6-el.txt @@ -0,0 +1,9 @@ +# RUN: llvm-mc --disassemble %s -triple=mipsel-unknown-linux-gnu \ +# RUN: -mcpu=mips32r6 -mattr=+crc | FileCheck %s + +0x0f 0x00 0x41 0x7c # CHECK: crc32b $1, $2, $1 +0x4f 0x00 0xa4 0x7c # CHECK: crc32h $4, $5, $4 +0x8f 0x00 0x07 0x7d # CHECK: crc32w $7, $8, $7 +0x0f 0x01 0x41 0x7c # CHECK: crc32cb $1, $2, $1 +0x4f 0x01 0xa4 0x7c # CHECK: crc32ch $4, $5, $4 +0x8f 0x01 0x07 0x7d # CHECK: crc32cw $7, $8, $7 Index: test/MC/Disassembler/Mips/crc/valid-32r6.txt =================================================================== --- /dev/null +++ test/MC/Disassembler/Mips/crc/valid-32r6.txt @@ -0,0 +1,9 @@ +# RUN: llvm-mc --disassemble %s -triple=mips-unknown-linux-gnu \ +# RUN: -mcpu=mips32r6 -mattr=+crc | FileCheck %s + +0x7c 0x41 0x00 0x0f # CHECK: crc32b $1, $2, $1 +0x7c 0xa4 0x00 0x4f # CHECK: crc32h $4, $5, $4 +0x7d 0x07 0x00 0x8f # CHECK: crc32w $7, $8, $7 +0x7c 0x41 0x01 0x0f # CHECK: crc32cb $1, $2, $1 +0x7c 0xa4 0x01 0x4f # CHECK: crc32ch $4, $5, $4 +0x7d 0x07 0x01 0x8f # CHECK: crc32cw $7, $8, $7 Index: test/MC/Disassembler/Mips/crc/valid-64r6-el.txt =================================================================== --- /dev/null +++ test/MC/Disassembler/Mips/crc/valid-64r6-el.txt @@ -0,0 +1,11 @@ +# RUN: llvm-mc --disassemble %s -triple=mips64el-unknown-linux-gnu \ +# RUN: -mcpu=mips64r6 -mattr=+crc | FileCheck %s + +0x0f 0x00 0x41 0x7c # CHECK: crc32b $1, $2, $1 +0x4f 0x00 0xa4 0x7c # CHECK: crc32h $4, $5, $4 +0x8f 0x00 0x07 0x7d # CHECK: crc32w $7, $8, $7 +0xcf 0x00 0x6a 0x7d # CHECK: crc32d $10, $11, $10 +0x0f 0x01 0x41 0x7c # CHECK: crc32cb $1, $2, $1 +0x4f 0x01 0xa4 0x7c # CHECK: crc32ch $4, $5, $4 +0x8f 0x01 0x07 0x7d # CHECK: crc32cw $7, $8, $7 +0xcf 0x01 0x6a 0x7d # CHECK: crc32cd $10, $11, $10 Index: test/MC/Disassembler/Mips/crc/valid-64r6.txt =================================================================== --- /dev/null +++ test/MC/Disassembler/Mips/crc/valid-64r6.txt @@ -0,0 +1,11 @@ +# RUN: llvm-mc --disassemble %s -triple=mips64-unknown-linux-gnu \ +# RUN: -mcpu=mips64r6 -mattr=+crc | FileCheck %s + +0x7c 0x41 0x00 0x0f # CHECK: crc32b $1, $2, $1 +0x7c 0xa4 0x00 0x4f # CHECK: crc32h $4, $5, $4 +0x7d 0x07 0x00 0x8f # CHECK: crc32w $7, $8, $7 +0x7d 0x6a 0x00 0xcf # CHECK: crc32d $10, $11, $10 +0x7c 0x41 0x01 0x0f # CHECK: crc32cb $1, $2, $1 +0x7c 0xa4 0x01 0x4f # CHECK: crc32ch $4, $5, $4 +0x7d 0x07 0x01 0x8f # CHECK: crc32cw $7, $8, $7 +0x7d 0x6a 0x01 0xcf # CHECK: crc32cd $10, $11, $10 Index: test/MC/Mips/crc/invalid.s =================================================================== --- /dev/null +++ test/MC/Mips/crc/invalid.s @@ -0,0 +1,65 @@ +# Instructions that are invalid. +# +# RUN: not llvm-mc %s -arch=mips -mcpu=mips32r6 -mattr=+crc 2>%t1 +# RUN: FileCheck %s < %t1 +# RUN: not llvm-mc %s -arch=mips64 -mcpu=mips64r6 -mattr=+crc 2>%t1 +# RUN: FileCheck %s < %t1 + + .set noat + crc32b $1, $2, $2 # CHECK: :[[@LINE]]:3: error: source and destination must match + crc32b $1, $2, $3 # CHECK: :[[@LINE]]:3: error: source and destination must match + crc32b $1, $2, 2 # CHECK: :[[@LINE]]:19: error: invalid operand for instruction + crc32b $1, 2, $2 # CHECK: :[[@LINE]]:15: error: invalid operand for instruction + crc32b 1, $2, $2 # CHECK: :[[@LINE]]:11: error: invalid operand for instruction + crc32b $1, $2 # CHECK: :[[@LINE]]:3: error: too few operands for instruction + crc32b $1 # CHECK: :[[@LINE]]:3: error: too few operands for instruction + crc32b $1, $2, 0($2) # CHECK: :[[@LINE]]:19: error: invalid operand for instruction + + crc32h $1, $2, $2 # CHECK: :[[@LINE]]:3: error: source and destination must match + crc32h $1, $2, $3 # CHECK: :[[@LINE]]:3: error: source and destination must match + crc32h $1, $2, 2 # CHECK: :[[@LINE]]:19: error: invalid operand for instruction + crc32h $1, 2, $2 # CHECK: :[[@LINE]]:15: error: invalid operand for instruction + crc32h 1, $2, $2 # CHECK: :[[@LINE]]:11: error: invalid operand for instruction + crc32h $1, $2 # CHECK: :[[@LINE]]:3: error: too few operands for instruction + crc32h $1 # CHECK: :[[@LINE]]:3: error: too few operands for instruction + crc32h $1, $2, 0($2) # CHECK: :[[@LINE]]:19: error: invalid operand for instruction + + crc32w $1, $2, $2 # CHECK: :[[@LINE]]:3: error: source and destination must match + crc32w $1, $2, $3 # CHECK: :[[@LINE]]:3: error: source and destination must match + crc32w $1, $2, 2 # CHECK: :[[@LINE]]:19: error: invalid operand for instruction + crc32w $1, 2, $2 # CHECK: :[[@LINE]]:15: error: invalid operand for instruction + crc32w 1, $2, $2 # CHECK: :[[@LINE]]:11: error: invalid operand for instruction + crc32w $1, $2 # CHECK: :[[@LINE]]:3: error: too few operands for instruction + crc32w $1 # CHECK: :[[@LINE]]:3: error: too few operands for instruction + crc32w $1, $2, 0($2) # CHECK: :[[@LINE]]:19: error: invalid operand for instruction + + crc32cb $1, $2, $2 # CHECK: :[[@LINE]]:3: error: source and destination must match + crc32cb $1, $2, $3 # CHECK: :[[@LINE]]:3: error: source and destination must match + crc32cb $1, $2, 2 # CHECK: :[[@LINE]]:20: error: invalid operand for instruction + crc32cb $1, 2, $2 # CHECK: :[[@LINE]]:16: error: invalid operand for instruction + crc32cb 1, $2, $2 # CHECK: :[[@LINE]]:12: error: invalid operand for instruction + crc32cb $1, $2 # CHECK: :[[@LINE]]:3: error: too few operands for instruction + crc32cb $1 # CHECK: :[[@LINE]]:3: error: too few operands for instruction + crc32cb $1, $2, 0($2) # CHECK: :[[@LINE]]:20: error: invalid operand for instruction + + crc32ch $1, $2, $2 # CHECK: :[[@LINE]]:3: error: source and destination must match + crc32ch $1, $2, $3 # CHECK: :[[@LINE]]:3: error: source and destination must match + crc32ch $1, $2, 2 # CHECK: :[[@LINE]]:20: error: invalid operand for instruction + crc32ch $1, 2, $2 # CHECK: :[[@LINE]]:16: error: invalid operand for instruction + crc32ch 1, $2, $2 # CHECK: :[[@LINE]]:12: error: invalid operand for instruction + crc32ch $1, $2 # CHECK: :[[@LINE]]:3: error: too few operands for instruction + crc32ch $1 # CHECK: :[[@LINE]]:3: error: too few operands for instruction + crc32ch $1, $2, 0($2) # CHECK: :[[@LINE]]:20: error: invalid operand for instruction + + crc32cw $1, $2, $2 # CHECK: :[[@LINE]]:3: error: source and destination must match + crc32cw $1, $2, $3 # CHECK: :[[@LINE]]:3: error: source and destination must match + crc32cw $1, $2, 2 # CHECK: :[[@LINE]]:20: error: invalid operand for instruction + crc32cw $1, 2, $2 # CHECK: :[[@LINE]]:16: error: invalid operand for instruction + crc32cw 1, $2, $2 # CHECK: :[[@LINE]]:12: error: invalid operand for instruction + crc32cw $1, $2 # CHECK: :[[@LINE]]:3: error: too few operands for instruction + crc32cw $1 # CHECK: :[[@LINE]]:3: error: too few operands for instruction + crc32cw $1, $2, 0($2) # CHECK: :[[@LINE]]:20: error: invalid operand for instruction + + crc32 $1, $2, $2 # CHECK: :[[@LINE]]:3: error: unknown instruction + crcb $1, $2, $2 # CHECK: :[[@LINE]]:3: error: unknown instruction + crc $1, $2, $2 # CHECK: :[[@LINE]]:3: error: unknown instruction Index: test/MC/Mips/crc/invalid64.s =================================================================== --- /dev/null +++ test/MC/Mips/crc/invalid64.s @@ -0,0 +1,24 @@ +# Instructions that are invalid. +# +# RUN: not llvm-mc %s -triple=mips64-unknown-linux-gnu -mcpu=mips64r6 \ +# RUN: -mattr=+crc 2>%t1 +# RUN: FileCheck %s < %t1 + + .set noat + crc32d $1, $2, $2 # CHECK: :[[@LINE]]:3: error: source and destination must match + crc32d $1, $2, $3 # CHECK: :[[@LINE]]:3: error: source and destination must match + crc32d $1, $2, 2 # CHECK: :[[@LINE]]:18: error: invalid operand for instruction + crc32d $1, 2, $2 # CHECK: :[[@LINE]]:14: error: invalid operand for instruction + crc32d 1, $2, $2 # CHECK: :[[@LINE]]:10: error: invalid operand for instruction + crc32d $1, $2 # CHECK: :[[@LINE]]:3: error: too few operands for instruction + crc32d $1 # CHECK: :[[@LINE]]:3: error: too few operands for instruction + crc32d $1, $2, 0($2) # CHECK: :[[@LINE]]:18: error: invalid operand for instruction + + crc32cd $1, $2, $2 # CHECK: :[[@LINE]]:3: error: source and destination must match + crc32cd $1, $2, $3 # CHECK: :[[@LINE]]:3: error: source and destination must match + crc32cd $1, $2, 2 # CHECK: :[[@LINE]]:19: error: invalid operand for instruction + crc32cd $1, 2, $2 # CHECK: :[[@LINE]]:15: error: invalid operand for instruction + crc32cd 1, $2, $2 # CHECK: :[[@LINE]]:11: error: invalid operand for instruction + crc32cd $1, $2 # CHECK: :[[@LINE]]:3: error: too few operands for instruction + crc32cd $1 # CHECK: :[[@LINE]]:3: error: too few operands for instruction + crc32cd $1, $2, 0($2) # CHECK: :[[@LINE]]:19: error: invalid operand for instruction Index: test/MC/Mips/crc/module-crc.s =================================================================== --- /dev/null +++ test/MC/Mips/crc/module-crc.s @@ -0,0 +1,22 @@ +# RUN: llvm-mc %s -triple=mips-unknown-linux-gnu -mcpu=mips32r6 | \ +# RUN: FileCheck %s -check-prefix=CHECK-ASM +# +# RUN: llvm-mc %s -triple=mips-unknown-linux-gnu -mcpu=mips32r6 \ +# RUN: -filetype=obj -o - | \ +# RUN: llvm-readobj -mips-abi-flags - | \ +# RUN: FileCheck %s -check-prefix=CHECK-OBJ + +# CHECK-ASM: .module crc + +# Check if the MIPS.abiflags section was correctly emitted: +# CHECK-OBJ: MIPS ABI Flags { +# CHECK-OBJ: ASEs [ (0x8000) +# CHECK-OBJ: CRC (0x8000) +# CHECK-OBJ: } + + .module crc + crc32b $2,$3,$2 + +# FIXME: Test should include gnu_attributes directive when implemented. +# An explicit .gnu_attribute must be checked against the effective +# command line options and any inconsistencies reported via a warning. Index: test/MC/Mips/crc/module-nocrc.s =================================================================== --- /dev/null +++ test/MC/Mips/crc/module-nocrc.s @@ -0,0 +1,21 @@ +# RUN: llvm-mc %s -arch=mips -mcpu=mips32r6 -mattr=+crc | \ +# RUN: FileCheck %s -check-prefix=CHECK-ASM +# +# RUN: llvm-mc %s -arch=mips -mcpu=mips32r6 -filetype=obj -o - -mattr=+crc | \ +# RUN: llvm-readobj -mips-abi-flags - | \ +# RUN: FileCheck %s -check-prefix=CHECK-OBJ + +# CHECK-ASM: .module nocrc + +# Check that MIPS.abiflags has no CRC flag. +# CHECK-OBJ: MIPS ABI Flags { +# CHECK-OBJ: ASEs [ (0x0) +# CHECK-OBJ-NOT: ASEs [ (0x8000) +# CHECK-OBJ-NOT: CRC (0x8000) +# CHECK-OBJ: } + + .module nocrc + +# FIXME: Test should include gnu_attributes directive when implemented. +# An explicit .gnu_attribute must be checked against the effective +# command line options and any inconsistencies reported via a warning. Index: test/MC/Mips/crc/set-crc-directive.s =================================================================== --- /dev/null +++ test/MC/Mips/crc/set-crc-directive.s @@ -0,0 +1,7 @@ +# RUN: llvm-mc %s -show-encoding -triple=mips-unknown-linux-gnu \ +# RUN: -mcpu=mips32r6 | FileCheck %s +# RUN: llvm-mc %s -show-encoding -triple=mips64-unknown-linux-gnu \ +# RUN: -mcpu=mips64r6 | FileCheck %s + + .set crc + crc32b $1, $2, $1 # CHECK: crc32b $1, $2, $1 # encoding: [0x7c,0x41,0x00,0x0f] Index: test/MC/Mips/crc/set-nocrc-directive.s =================================================================== --- /dev/null +++ test/MC/Mips/crc/set-nocrc-directive.s @@ -0,0 +1,9 @@ +# RUN: not llvm-mc %s -triple=mips-unknown-linux-gnu -show-encoding \ +# RUN: -mcpu=mips32r6 -mattr=+crc 2>%t1 +# RUN: FileCheck %s < %t1 +# RUN: not llvm-mc %s -triple=mips64-unknown-linux-gnu -show-encoding \ +# RUN: -mcpu=mips64r6 -mattr=+crc 2>%t1 +# RUN: FileCheck %s < %t1 + + .set nocrc + crc32b $1, $2, $1 # CHECK: instruction requires a CPU feature not currently enabled Index: test/MC/Mips/crc/valid.s =================================================================== --- /dev/null +++ test/MC/Mips/crc/valid.s @@ -0,0 +1,12 @@ +# RUN: llvm-mc %s -triple=mips-unknown-linux-gnu -show-encoding \ +# RUN: -mcpu=mips32r6 -mattr=+crc | FileCheck %s +# RUN: llvm-mc %s -triple=mips64-unknown-linux-gnu -show-encoding \ +# RUN: -mcpu=mips64r6 -mattr=+crc | FileCheck %s + + .set noat + crc32b $1, $2, $1 # CHECK: crc32b $1, $2, $1 # encoding: [0x7c,0x41,0x00,0x0f] + crc32h $4, $5, $4 # CHECK: crc32h $4, $5, $4 # encoding: [0x7c,0xa4,0x00,0x4f] + crc32w $7, $8, $7 # CHECK: crc32w $7, $8, $7 # encoding: [0x7d,0x07,0x00,0x8f] + crc32cb $1, $2, $1 # CHECK: crc32cb $1, $2, $1 # encoding: [0x7c,0x41,0x01,0x0f] + crc32ch $4, $5, $4 # CHECK: crc32ch $4, $5, $4 # encoding: [0x7c,0xa4,0x01,0x4f] + crc32cw $7, $8, $7 # CHECK: crc32cw $7, $8, $7 # encoding: [0x7d,0x07,0x01,0x8f] Index: test/MC/Mips/crc/valid64.s =================================================================== --- /dev/null +++ test/MC/Mips/crc/valid64.s @@ -0,0 +1,6 @@ +# RUN: llvm-mc %s -triple=mips64-unknown-linux-gnu -show-encoding \ +# RUN: -mcpu=mips64r6 -mattr=+crc | FileCheck %s + + .set noat + crc32d $10, $11, $10 # CHECK: crc32d $10, $11, $10 # encoding: [0x7d,0x6a,0x00,0xcf] + crc32cd $10, $11, $10 # CHECK: crc32cd $10, $11, $10 # encoding: [0x7d,0x6a,0x01,0xcf] Index: tools/llvm-readobj/ELFDumper.cpp =================================================================== --- tools/llvm-readobj/ELFDumper.cpp +++ tools/llvm-readobj/ELFDumper.cpp @@ -2261,7 +2261,8 @@ {"MSA", Mips::AFL_ASE_MSA}, {"MIPS16", Mips::AFL_ASE_MIPS16}, {"microMIPS", Mips::AFL_ASE_MICROMIPS}, - {"XPA", Mips::AFL_ASE_XPA} + {"XPA", Mips::AFL_ASE_XPA}, + {"CRC", Mips::AFL_ASE_CRC}, }; static const EnumEntry ElfMipsFpABIType[] = {