[mips] Add support for Virtualization ASE
authorPetar Jovanovic <petar.jovanovic@mips.com>
Fri, 27 Apr 2018 09:12:08 +0000 (09:12 +0000)
committerPetar Jovanovic <petar.jovanovic@mips.com>
Fri, 27 Apr 2018 09:12:08 +0000 (09:12 +0000)
This includes

  Instructions: tlbginv, tlbginvf, tlbgp, tlbgr, tlbgwi, tlbgwr, hypcall
                mfgc0, mtgc0, mfhgc0, mthgc0, dmfgc0, dmtgc0,

  Assembler directives: .set virt, .set novirt, .module virt, .module novirt

  Attribute: virt

  .MIPS.abiflags: VZ (0x100)

Patch by Vladimir Stefanovic.

Differential Revision: https://reviews.llvm.org/D44905

llvm-svn: 331024

28 files changed:
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/MicroMipsInstrFormats.td
llvm/lib/Target/Mips/MicroMipsInstrInfo.td
llvm/lib/Target/Mips/Mips.td
llvm/lib/Target/Mips/Mips64InstrInfo.td
llvm/lib/Target/Mips/MipsInstrFormats.td
llvm/lib/Target/Mips/MipsInstrInfo.td
llvm/lib/Target/Mips/MipsSchedule.td
llvm/lib/Target/Mips/MipsSubtarget.cpp
llvm/lib/Target/Mips/MipsSubtarget.h
llvm/lib/Target/Mips/MipsTargetStreamer.h
llvm/test/MC/Disassembler/Mips/virt/valid-32-el.txt [new file with mode: 0644]
llvm/test/MC/Disassembler/Mips/virt/valid-32.txt [new file with mode: 0644]
llvm/test/MC/Disassembler/Mips/virt/valid-64-el.txt [new file with mode: 0644]
llvm/test/MC/Disassembler/Mips/virt/valid-64.txt [new file with mode: 0644]
llvm/test/MC/Disassembler/Mips/virt/valid-micromips-el.txt [new file with mode: 0644]
llvm/test/MC/Disassembler/Mips/virt/valid-micromips.txt [new file with mode: 0644]
llvm/test/MC/Mips/virt/invalid.s [new file with mode: 0644]
llvm/test/MC/Mips/virt/invalid64.s [new file with mode: 0644]
llvm/test/MC/Mips/virt/module-novirt.s [new file with mode: 0644]
llvm/test/MC/Mips/virt/module-virt.s [new file with mode: 0644]
llvm/test/MC/Mips/virt/set-novirt-directive.s [new file with mode: 0644]
llvm/test/MC/Mips/virt/set-virt-directive.s [new file with mode: 0644]
llvm/test/MC/Mips/virt/valid-micromips.s [new file with mode: 0644]
llvm/test/MC/Mips/virt/valid.s [new file with mode: 0644]
llvm/test/MC/Mips/virt/valid64.s [new file with mode: 0644]

index 59eeefe..b3cfc86 100644 (file)
@@ -349,6 +349,7 @@ class MipsAsmParser : public MCTargetAsmParser {
   bool parseSetMtDirective();
   bool parseSetNoMtDirective();
   bool parseSetNoCRCDirective();
+  bool parseSetNoVirtDirective();
 
   bool parseSetAssignment();
 
@@ -649,6 +650,10 @@ public:
     return getSTI().getFeatureBits()[Mips::FeatureCRC];
   }
 
+  bool hasVirt() const {
+    return getSTI().getFeatureBits()[Mips::FeatureVirt];
+  }
+
   /// Warn if RegIndex is the same as the current AT.
   void warnIfRegIndexIsAT(unsigned RegIndex, SMLoc Loc);
 
@@ -6718,6 +6723,23 @@ bool MipsAsmParser::parseSetNoCRCDirective() {
   return false;
 }
 
+bool MipsAsmParser::parseSetNoVirtDirective() {
+  MCAsmParser &Parser = getParser();
+  Parser.Lex(); // Eat "novirt".
+
+  // 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::FeatureVirt, "virt");
+
+  getTargetStreamer().emitDirectiveSetNoVirt();
+  Parser.Lex(); // Consume the EndOfStatement.
+  return false;
+}
+
 bool MipsAsmParser::parseSetPopDirective() {
   MCAsmParser &Parser = getParser();
   SMLoc Loc = getLexer().getLoc();
@@ -6943,6 +6965,10 @@ bool MipsAsmParser::parseSetFeature(uint64_t Feature) {
     setFeatureBits(Mips::FeatureCRC, "crc");
     getTargetStreamer().emitDirectiveSetCRC();
     break;
+  case Mips::FeatureVirt:
+    setFeatureBits(Mips::FeatureVirt, "virt");
+    getTargetStreamer().emitDirectiveSetVirt();
+    break;
   }
   return false;
 }
@@ -7251,6 +7277,10 @@ bool MipsAsmParser::parseDirectiveSet() {
     return parseSetFeature(Mips::FeatureCRC);
   } else if (Tok.getString() == "nocrc") {
     return parseSetNoCRCDirective();
+  } else if (Tok.getString() == "virt") {
+    return parseSetFeature(Mips::FeatureVirt);
+  } else if (Tok.getString() == "novirt") {
+    return parseSetNoVirtDirective();
   } else {
     // It is just an identifier, look for an assignment.
     parseSetAssignment();
@@ -7499,6 +7529,8 @@ bool MipsAsmParser::parseSSectionDirective(StringRef Section, unsigned Type) {
 ///  ::= .module mt
 ///  ::= .module crc
 ///  ::= .module nocrc
+///  ::= .module virt
+///  ::= .module novirt
 bool MipsAsmParser::parseDirectiveModule() {
   MCAsmParser &Parser = getParser();
   MCAsmLexer &Lexer = getLexer();
@@ -7655,6 +7687,44 @@ bool MipsAsmParser::parseDirectiveModule() {
     }
 
     return false; // parseDirectiveModule has finished successfully.
+  } else if (Option == "virt") {
+    setModuleFeatureBits(Mips::FeatureVirt, "virt");
+
+    // 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().emitDirectiveModuleVirt();
+
+    // 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 == "novirt") {
+    clearModuleFeatureBits(Mips::FeatureVirt, "virt");
+
+    // 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().emitDirectiveModuleNoVirt();
+
+    // 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 ea75d98..bced1e9 100644 (file)
@@ -163,6 +163,8 @@ public:
       ASESet |= Mips::AFL_ASE_MT;
     if (P.hasCRC())
       ASESet |= Mips::AFL_ASE_CRC;
+    if (P.hasVirt())
+      ASESet |= Mips::AFL_ASE_VIRT;
   }
 
   template <class PredicateLibrary>
index 7f0cc9e..96c6f08 100644 (file)
@@ -54,6 +54,8 @@ void MipsTargetStreamer::emitDirectiveSetMt() {}
 void MipsTargetStreamer::emitDirectiveSetNoMt() { forbidModuleDirective(); }
 void MipsTargetStreamer::emitDirectiveSetCRC() {}
 void MipsTargetStreamer::emitDirectiveSetNoCRC() {}
+void MipsTargetStreamer::emitDirectiveSetVirt() {}
+void MipsTargetStreamer::emitDirectiveSetNoVirt() {}
 void MipsTargetStreamer::emitDirectiveSetAt() { forbidModuleDirective(); }
 void MipsTargetStreamer::emitDirectiveSetAtWithArg(unsigned RegNo) {
   forbidModuleDirective();
@@ -126,6 +128,8 @@ void MipsTargetStreamer::emitDirectiveModuleHardFloat() {}
 void MipsTargetStreamer::emitDirectiveModuleMT() {}
 void MipsTargetStreamer::emitDirectiveModuleCRC() {}
 void MipsTargetStreamer::emitDirectiveModuleNoCRC() {}
+void MipsTargetStreamer::emitDirectiveModuleVirt() {}
+void MipsTargetStreamer::emitDirectiveModuleNoVirt() {}
 void MipsTargetStreamer::emitDirectiveSetFp(
     MipsABIFlagsSection::FpABIKind Value) {
   forbidModuleDirective();
@@ -435,6 +439,16 @@ void MipsTargetAsmStreamer::emitDirectiveSetNoCRC() {
   MipsTargetStreamer::emitDirectiveSetNoCRC();
 }
 
+void MipsTargetAsmStreamer::emitDirectiveSetVirt() {
+  OS << "\t.set\tvirt\n";
+  MipsTargetStreamer::emitDirectiveSetVirt();
+}
+
+void MipsTargetAsmStreamer::emitDirectiveSetNoVirt() {
+  OS << "\t.set\tnovirt\n";
+  MipsTargetStreamer::emitDirectiveSetNoVirt();
+}
+
 void MipsTargetAsmStreamer::emitDirectiveSetAt() {
   OS << "\t.set\tat\n";
   MipsTargetStreamer::emitDirectiveSetAt();
@@ -716,6 +730,14 @@ void MipsTargetAsmStreamer::emitDirectiveModuleNoCRC() {
   OS << "\t.module\tnocrc\n";
 }
 
+void MipsTargetAsmStreamer::emitDirectiveModuleVirt() {
+  OS << "\t.module\tvirt\n";
+}
+
+void MipsTargetAsmStreamer::emitDirectiveModuleNoVirt() {
+  OS << "\t.module\tnovirt\n";
+}
+
 // This part is for ELF object output.
 MipsTargetELFStreamer::MipsTargetELFStreamer(MCStreamer &S,
                                              const MCSubtargetInfo &STI)
index 050f8ba..a72078c 100644 (file)
@@ -1053,3 +1053,39 @@ class POOL32A_CFTC2_FM_MM<bits<10> funct> : MMArch {
   let Inst{15-6}  = funct;
   let Inst{5-0}   = 0b111100;
 }
+
+class POOL32A_TLBINV_FM_MM<bits<10> funct> : MMArch {
+  bits<32> Inst;
+
+  let Inst{31-26} = 0x0;
+  let Inst{25-16} = 0x0;
+  let Inst{15-6}  = funct;
+  let Inst{5-0}   = 0b111100;
+}
+
+class POOL32A_MFTC0_FM_MM<bits<5> funct, bits<6> opcode> : MMArch {
+  bits<5> rt;
+  bits<5> rs;
+  bits<3> sel;
+
+  bits<32> Inst;
+
+  let Inst{31-26} = 0b000000;
+  let Inst{25-21} = rt;
+  let Inst{20-16} = rs;
+  let Inst{15-14} = 0;
+  let Inst{13-11} = sel;
+  let Inst{10-6}  = funct;
+  let Inst{5-0}   = opcode;
+}
+
+class POOL32A_HYPCALL_FM_MM : MMArch {
+  bits<32> Inst;
+
+  bits<10> code_;
+
+  let Inst{31-26} = 0x0;
+  let Inst{25-16} = code_;
+  let Inst{15-6}  = 0b1100001101;
+  let Inst{5-0}   = 0b111100;
+}
index 3e560f5..f83d9e6 100644 (file)
@@ -595,6 +595,31 @@ class UncondBranchMM16<string opstr> :
   let Defs = [AT];
 }
 
+class HypcallMM<string opstr> :
+  InstSE<(outs), (ins uimm10:$code_),
+          !strconcat(opstr, "\t$code_"), [], II_HYPCALL, FrmOther> {
+  let BaseOpcode = opstr;
+}
+
+class TLBINVMM<string opstr, InstrItinClass Itin> :
+  InstSE<(outs), (ins), opstr, [], Itin, FrmOther> {
+  let BaseOpcode = opstr;
+}
+
+class MfCop0MM<string opstr, RegisterOperand DstRC,
+               RegisterOperand SrcRC, InstrItinClass Itin> :
+  InstSE<(outs DstRC:$rt), (ins SrcRC:$rs, uimm3:$sel),
+          !strconcat(opstr, "\t$rt, $rs, $sel"), [], Itin, FrmR> {
+  let BaseOpcode = opstr;
+}
+
+class MtCop0MM<string opstr, RegisterOperand DstRC,
+               RegisterOperand SrcRC, InstrItinClass Itin> :
+  InstSE<(outs DstRC:$rs), (ins SrcRC:$rt, uimm3:$sel),
+          !strconcat(opstr, "\t$rt, $rs, $sel"), [], Itin, FrmR> {
+  let BaseOpcode = opstr;
+}
+
 def ADDU16_MM : ArithRMM16<"addu16", GPRMM16Opnd, 1, II_ADDU, add>,
     ARITH_FM_MM16<0>, ISA_MICROMIPS_NOT_32R6;
 def AND16_MM : LogicRMM16<"and16", GPRMM16Opnd, II_AND, and>,
@@ -1072,6 +1097,35 @@ let DecoderNamespace = "MicroMips" in {
                ISA_MICROMIPS32_NOT_MIPS32R6;
 }
 
+let DecoderNamespace = "MicroMips" in {
+  def MFGC0_MM    : MMRel, MfCop0MM<"mfgc0", GPR32Opnd, COP0Opnd, II_MFGC0>,
+                    POOL32A_MFTC0_FM_MM<0b10011, 0b111100>,
+                    ISA_MICROMIPS32R5, ASE_VIRT;
+  def MFHGC0_MM   : MMRel, MfCop0MM<"mfhgc0", GPR32Opnd, COP0Opnd, II_MFHGC0>,
+                    POOL32A_MFTC0_FM_MM<0b10011, 0b110100>,
+                    ISA_MICROMIPS32R5, ASE_VIRT;
+  def MTGC0_MM    : MMRel, MtCop0MM<"mtgc0", COP0Opnd, GPR32Opnd, II_MTGC0>,
+                    POOL32A_MFTC0_FM_MM<0b11011, 0b111100>,
+                    ISA_MICROMIPS32R5, ASE_VIRT;
+  def MTHGC0_MM   : MMRel, MtCop0MM<"mthgc0", COP0Opnd, GPR32Opnd, II_MTHGC0>,
+                    POOL32A_MFTC0_FM_MM<0b11011, 0b110100>,
+                    ISA_MICROMIPS32R5, ASE_VIRT;
+  def HYPCALL_MM  : MMRel, HypcallMM<"hypcall">, POOL32A_HYPCALL_FM_MM,
+                    ISA_MICROMIPS32R5, ASE_VIRT;
+  def TLBGINV_MM  : MMRel, TLBINVMM<"tlbginv", II_TLBGINV>,
+                    POOL32A_TLBINV_FM_MM<0x105>, ISA_MICROMIPS32R5, ASE_VIRT;
+  def TLBGINVF_MM : MMRel, TLBINVMM<"tlbginvf", II_TLBGINVF>,
+                    POOL32A_TLBINV_FM_MM<0x145>, ISA_MICROMIPS32R5, ASE_VIRT;
+  def TLBGP_MM    : MMRel, TLBINVMM<"tlbgp", II_TLBGP>,
+                    POOL32A_TLBINV_FM_MM<0x5>, ISA_MICROMIPS32R5, ASE_VIRT;
+  def TLBGR_MM    : MMRel, TLBINVMM<"tlbgr", II_TLBGR>,
+                    POOL32A_TLBINV_FM_MM<0x45>, ISA_MICROMIPS32R5, ASE_VIRT;
+  def TLBGWI_MM   : MMRel, TLBINVMM<"tlbgwi", II_TLBGWI>,
+                    POOL32A_TLBINV_FM_MM<0x85>, ISA_MICROMIPS32R5, ASE_VIRT;
+  def TLBGWR_MM   : MMRel, TLBINVMM<"tlbgwr", II_TLBGWR>,
+                    POOL32A_TLBINV_FM_MM<0xc5>, ISA_MICROMIPS32R5, ASE_VIRT;
+}
+
 //===----------------------------------------------------------------------===//
 // MicroMips arbitrary patterns that map to one or more instructions
 //===----------------------------------------------------------------------===//
@@ -1262,3 +1316,17 @@ let Predicates = [InMicroMips] in {
   def : MipsInstAlias<"break $imm", (BREAK_MM uimm10:$imm, 0), 1>,
         ISA_MICROMIPS;
 }
+def : MipsInstAlias<"hypcall", (HYPCALL_MM 0), 1>,
+                    ISA_MICROMIPS32R5, ASE_VIRT;
+def : MipsInstAlias<"mfgc0 $rt, $rs",
+                    (MFGC0_MM GPR32Opnd:$rt, COP0Opnd:$rs, 0), 0>,
+                    ISA_MICROMIPS32R5, ASE_VIRT;
+def : MipsInstAlias<"mfhgc0 $rt, $rs",
+                    (MFHGC0_MM GPR32Opnd:$rt, COP0Opnd:$rs, 0), 0>,
+                    ISA_MICROMIPS32R5, ASE_VIRT;
+def : MipsInstAlias<"mtgc0 $rt, $rs",
+                    (MTGC0_MM COP0Opnd:$rs, GPR32Opnd:$rt, 0), 0>,
+                    ISA_MICROMIPS32R5, ASE_VIRT;
+def : MipsInstAlias<"mthgc0 $rt, $rs",
+                    (MTHGC0_MM COP0Opnd:$rs, GPR32Opnd:$rt, 0), 0>,
+                    ISA_MICROMIPS32R5, ASE_VIRT;
index 75bf915..38559a9 100644 (file)
@@ -179,6 +179,9 @@ def FeatureEVA : SubtargetFeature<"eva", "HasEVA", "true", "Mips EVA ASE">;
 
 def FeatureCRC : SubtargetFeature<"crc", "HasCRC", "true", "Mips R6 CRC ASE">;
 
+def FeatureVirt : SubtargetFeature<"virt", "HasVirt", "true",
+                                   "Mips Virtualization ASE">;
+
 def FeatureMicroMips  : SubtargetFeature<"micromips", "InMicroMipsMode", "true",
                                          "microMips mode">;
 
index 93f8e09..8da35bb 100644 (file)
@@ -545,16 +545,23 @@ def DMTC2_OCTEON : MFC2OP<"dmtc2", GPR64Opnd, II_DMTC2>, MFC2OP_FM<0x12, 5>,
 
 /// Move between CPU and coprocessor registers
 let DecoderNamespace = "Mips64", Predicates = [HasMips64] in {
-def DMFC0 : MFC3OP<"dmfc0", GPR64Opnd, COP0Opnd, II_DMFC0>, MFC3OP_FM<0x10, 1>,
-            ISA_MIPS3;
-def DMTC0 : MTC3OP<"dmtc0", COP0Opnd, GPR64Opnd, II_DMTC0>, MFC3OP_FM<0x10, 5>,
-            ISA_MIPS3;
-def DMFC2 : MFC3OP<"dmfc2", GPR64Opnd, COP2Opnd, II_DMFC2>, MFC3OP_FM<0x12, 1>,
-            ISA_MIPS3;
-def DMTC2 : MTC3OP<"dmtc2", COP2Opnd, GPR64Opnd, II_DMTC2>, MFC3OP_FM<0x12, 5>,
-            ISA_MIPS3;
+def DMFC0 : MFC3OP<"dmfc0", GPR64Opnd, COP0Opnd, II_DMFC0>,
+            MFC3OP_FM<0x10, 1, 0>, ISA_MIPS3;
+def DMTC0 : MTC3OP<"dmtc0", COP0Opnd, GPR64Opnd, II_DMTC0>,
+            MFC3OP_FM<0x10, 5, 0>, ISA_MIPS3;
+def DMFC2 : MFC3OP<"dmfc2", GPR64Opnd, COP2Opnd, II_DMFC2>,
+            MFC3OP_FM<0x12, 1, 0>, ISA_MIPS3;
+def DMTC2 : MTC3OP<"dmtc2", COP2Opnd, GPR64Opnd, II_DMTC2>,
+            MFC3OP_FM<0x12, 5, 0>, ISA_MIPS3;
 }
 
+/// Move between CPU and guest coprocessor registers (Virtualization ASE)
+let DecoderNamespace = "Mips64" in {
+  def DMFGC0 : MFC3OP<"dmfgc0", GPR64Opnd, COP0Opnd, II_DMFGC0>,
+               MFC3OP_FM<0x10, 3, 1>, ISA_MIPS64R5, ASE_VIRT;
+  def DMTGC0 : MTC3OP<"dmtgc0", COP0Opnd, GPR64Opnd, II_DMTGC0>,
+               MFC3OP_FM<0x10, 3, 3>, ISA_MIPS64R5, ASE_VIRT;
+}
 
 let AdditionalPredicates = [UseIndirectJumpsHazard] in
   def JALRHB64Pseudo : JumpLinkRegPseudo<GPR64Opnd, JALR_HB64, RA_64>;
@@ -873,6 +880,12 @@ let AdditionalPredicates = [NotInMicroMips] in {
                       (DMTC0 COP0Opnd:$rd, GPR64Opnd:$rt, 0), 0>;
   def : MipsInstAlias<"dmfc0 $rt, $rd",
                       (DMFC0 GPR64Opnd:$rt, COP0Opnd:$rd, 0), 0>;
+  def : MipsInstAlias<"dmfgc0 $rt, $rd",
+                      (DMFGC0 GPR64Opnd:$rt, COP0Opnd:$rd, 0), 0>,
+                      ISA_MIPS64R5, ASE_VIRT;
+  def : MipsInstAlias<"dmtgc0 $rt, $rd",
+                      (DMTGC0 COP0Opnd:$rd, GPR64Opnd:$rt, 0), 0>,
+                      ISA_MIPS64R5, ASE_VIRT;
 }
 def : MipsInstAlias<"dmfc2 $rt, $rd", (DMFC2 GPR64Opnd:$rt, COP2Opnd:$rd, 0), 0>;
 def : MipsInstAlias<"dmtc2 $rt, $rd", (DMTC2 COP2Opnd:$rd, GPR64Opnd:$rt, 0), 0>;
index 516edef..1c3ecda 100644 (file)
@@ -220,10 +220,9 @@ class FJ<bits<6> op> : StdArch
 }
 
 //===----------------------------------------------------------------------===//
-// MFC instruction class in Mips : <|op|mf|rt|rd|0000000|sel|>
+// MFC instruction class in Mips : <|op|mf|rt|rd|gst|0000|sel|>
 //===----------------------------------------------------------------------===//
-class MFC3OP_FM<bits<6> op, bits<5> mfmt>
-{
+class MFC3OP_FM<bits<6> op, bits<5> mfmt, bits<3> guest> : StdArch {
   bits<5> rt;
   bits<5> rd;
   bits<3> sel;
@@ -234,7 +233,8 @@ class MFC3OP_FM<bits<6> op, bits<5> mfmt>
   let Inst{25-21} = mfmt;
   let Inst{20-16} = rt;
   let Inst{15-11} = rd;
-  let Inst{10-3}  = 0;
+  let Inst{10-8}  = guest;
+  let Inst{7-3}   = 0;
   let Inst{2-0}   = sel;
 }
 
@@ -970,3 +970,14 @@ class CACHEOP_FM<bits<6> op> : StdArch {
   let Inst{20-16} = hint;
   let Inst{15-0}  = offset;
 }
+
+class HYPCALL_FM<bits<6> op> : StdArch {
+  bits<10> code_;
+
+  bits<32> Inst;
+
+  let Inst{31-26} = 0b010000;
+  let Inst{25}    = 1;
+  let Inst{20-11} = code_;
+  let Inst{5-0}   = op;
+}
index 31e568d..b71068d 100644 (file)
@@ -202,6 +202,8 @@ def NotMips64    :    Predicate<"!Subtarget->hasMips64()">,
                       AssemblerPredicate<"!FeatureMips64">;
 def HasMips64r2  :    Predicate<"Subtarget->hasMips64r2()">,
                       AssemblerPredicate<"FeatureMips64r2">;
+def HasMips64r5  :    Predicate<"Subtarget->hasMips64r5()">,
+                      AssemblerPredicate<"FeatureMips64r5">;
 def HasMips64r6  :    Predicate<"Subtarget->hasMips64r6()">,
                       AssemblerPredicate<"FeatureMips64r6">;
 def NotMips64r6  :    Predicate<"!Subtarget->hasMips64r6()">,
@@ -248,6 +250,8 @@ def NoIndirectJumpGuards : Predicate<"!Subtarget->useIndirectJumpsHazard()">,
                            AssemblerPredicate<"!FeatureUseIndirectJumpsHazard">;
 def HasCRC   : Predicate<"Subtarget->hasCRC()">,
                AssemblerPredicate<"FeatureCRC">;
+def HasVirt  : Predicate<"Subtarget->hasVirt()">,
+               AssemblerPredicate<"FeatureVirt">;
 //===----------------------------------------------------------------------===//
 // Mips GPR size adjectives.
 // They are mutually exclusive.
@@ -340,6 +344,10 @@ class ISA_MIPS64R2 {
   list<Predicate> InsnPredicates = [HasMips64r2];
   list<Predicate> EncodingPredicates = [HasStdEnc];
 }
+class ISA_MIPS64R5 {
+  list<Predicate> InsnPredicates = [HasMips64r5];
+  list<Predicate> EncodingPredicates = [HasStdEnc];
+}
 class ISA_MIPS32R6 {
   list<Predicate> InsnPredicates = [HasMips32r6];
   list<Predicate> EncodingPredicates = [HasStdEnc];
@@ -351,6 +359,10 @@ class ISA_MIPS64R6 {
 class ISA_MICROMIPS {
   list<Predicate> EncodingPredicates = [InMicroMips];
 }
+class ISA_MICROMIPS32R5 {
+  list<Predicate> InsnPredicates = [HasMips32r5];
+  list<Predicate> EncodingPredicates = [InMicroMips];
+}
 class ISA_MICROMIPS32R6 {
   list<Predicate> InsnPredicates = [HasMips32r6];
   list<Predicate> EncodingPredicates = [InMicroMips];
@@ -449,6 +461,10 @@ class ASE_CRC {
   list <Predicate> ASEPredicate = [HasCRC];
 }
 
+class ASE_VIRT {
+  list <Predicate> ASEPredicate = [HasVirt];
+}
+
 // 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 {
@@ -1844,12 +1860,16 @@ class SCBase<string opstr, RegisterOperand RO> :
 class MFC3OP<string asmstr, RegisterOperand RO, RegisterOperand RD,
              InstrItinClass itin> :
   InstSE<(outs RO:$rt), (ins RD:$rd, uimm3:$sel),
-         !strconcat(asmstr, "\t$rt, $rd, $sel"), [], itin, FrmFR>;
+         !strconcat(asmstr, "\t$rt, $rd, $sel"), [], itin, FrmFR> {
+  let BaseOpcode = asmstr;
+}
 
 class MTC3OP<string asmstr, RegisterOperand RO, RegisterOperand RD,
              InstrItinClass itin> :
   InstSE<(outs RO:$rd), (ins RD:$rt, uimm3:$sel),
-         !strconcat(asmstr, "\t$rt, $rd, $sel"), [], itin, FrmFR>;
+         !strconcat(asmstr, "\t$rt, $rd, $sel"), [], itin, FrmFR> {
+  let BaseOpcode = asmstr;
+}
 
 class TrapBase<Instruction RealInst>
   : PseudoSE<(outs), (ins), [(trap)], II_TRAP>,
@@ -2329,14 +2349,14 @@ let AdditionalPredicates = [NotInMicroMips] in {
 }
 /// Move Control Registers From/To CPU Registers
 let AdditionalPredicates = [NotInMicroMips] in {
-  def MTC0 : MTC3OP<"mtc0", COP0Opnd, GPR32Opnd, II_MTC0>, MFC3OP_FM<0x10, 4>,
-             ISA_MIPS1;
-  def MFC0 : MFC3OP<"mfc0", GPR32Opnd, COP0Opnd, II_MFC0>, MFC3OP_FM<0x10, 0>,
-             ISA_MIPS1;
-  def MFC2 : MFC3OP<"mfc2", GPR32Opnd, COP2Opnd, II_MFC2>, MFC3OP_FM<0x12, 0>,
-             ISA_MIPS1;
-  def MTC2 : MTC3OP<"mtc2", COP2Opnd, GPR32Opnd, II_MTC2>, MFC3OP_FM<0x12, 4>,
-             ISA_MIPS1;
+  def MTC0 : MTC3OP<"mtc0", COP0Opnd, GPR32Opnd, II_MTC0>,
+             MFC3OP_FM<0x10, 4, 0>, ISA_MIPS1;
+  def MFC0 : MFC3OP<"mfc0", GPR32Opnd, COP0Opnd, II_MFC0>,
+             MFC3OP_FM<0x10, 0, 0>, ISA_MIPS1;
+  def MFC2 : MFC3OP<"mfc2", GPR32Opnd, COP2Opnd, II_MFC2>,
+             MFC3OP_FM<0x12, 0, 0>, ISA_MIPS1;
+  def MTC2 : MTC3OP<"mtc2", COP2Opnd, GPR32Opnd, II_MTC2>,
+             MFC3OP_FM<0x12, 4, 0>, ISA_MIPS1;
 }
 
 class Barrier<string asmstr, InstrItinClass itin = NoItinerary> :
@@ -2502,6 +2522,38 @@ def MULOUMacro : MipsAsmPseudoInst<(outs), (ins GPR32Opnd:$rd, GPR32Opnd:$rs,
                                    "mulou\t$rd, $rs, $rt">,
                  ISA_MIPS1_NOT_32R6_64R6;
 
+// Virtualization ASE
+class HYPCALL_FT<string opstr> :
+  InstSE<(outs), (ins uimm10:$code_),
+         !strconcat(opstr, "\t$code_"), [], II_HYPCALL, FrmOther, opstr> {
+  let BaseOpcode = opstr;
+}
+
+let AdditionalPredicates = [NotInMicroMips] in {
+  def MFGC0    : MMRel, MFC3OP<"mfgc0", GPR32Opnd, COP0Opnd, II_MFGC0>,
+                 MFC3OP_FM<0x10, 3, 0>, ISA_MIPS32R5, ASE_VIRT;
+  def MTGC0    : MMRel, MTC3OP<"mtgc0", COP0Opnd, GPR32Opnd, II_MTGC0>,
+                 MFC3OP_FM<0x10, 3, 2>, ISA_MIPS32R5, ASE_VIRT;
+  def MFHGC0   : MMRel, MFC3OP<"mfhgc0", GPR32Opnd, COP0Opnd, II_MFHGC0>,
+                 MFC3OP_FM<0x10, 3, 4>, ISA_MIPS32R5, ASE_VIRT;
+  def MTHGC0   : MMRel, MTC3OP<"mthgc0", COP0Opnd, GPR32Opnd, II_MTHGC0>,
+                 MFC3OP_FM<0x10, 3, 6>, ISA_MIPS32R5, ASE_VIRT;
+  def TLBGINV  : MMRel, TLB<"tlbginv", II_TLBGINV>, COP0_TLB_FM<0b001011>,
+                 ISA_MIPS32R5, ASE_VIRT;
+  def TLBGINVF : MMRel, TLB<"tlbginvf", II_TLBGINVF>, COP0_TLB_FM<0b001100>,
+                 ISA_MIPS32R5, ASE_VIRT;
+  def TLBGP    : MMRel, TLB<"tlbgp", II_TLBGP>, COP0_TLB_FM<0b010000>,
+                 ISA_MIPS32R5, ASE_VIRT;
+  def TLBGR    : MMRel, TLB<"tlbgr", II_TLBGR>, COP0_TLB_FM<0b001001>,
+                 ISA_MIPS32R5, ASE_VIRT;
+  def TLBGWI   : MMRel, TLB<"tlbgwi", II_TLBGWI>, COP0_TLB_FM<0b001010>,
+                 ISA_MIPS32R5, ASE_VIRT;
+  def TLBGWR   : MMRel, TLB<"tlbgwr", II_TLBGWR>, COP0_TLB_FM<0b001110>,
+                 ISA_MIPS32R5, ASE_VIRT;
+  def HYPCALL  : MMRel, HYPCALL_FT<"hypcall">,
+                 HYPCALL_FM<0b101000>, ISA_MIPS32R5, ASE_VIRT;
+}
+
 //===----------------------------------------------------------------------===//
 // Instruction aliases
 //===----------------------------------------------------------------------===//
@@ -2584,6 +2636,20 @@ let AdditionalPredicates = [NotInMicroMips] in {
 }
 def : MipsInstAlias<"mfc0 $rt, $rd", (MFC0 GPR32Opnd:$rt, COP0Opnd:$rd, 0), 0>;
 def : MipsInstAlias<"mtc0 $rt, $rd", (MTC0 COP0Opnd:$rd, GPR32Opnd:$rt, 0), 0>;
+let AdditionalPredicates = [NotInMicroMips] in {
+  def : MipsInstAlias<"mfgc0 $rt, $rd",
+                      (MFGC0 GPR32Opnd:$rt, COP0Opnd:$rd, 0), 0>,
+                      ISA_MIPS32R5, ASE_VIRT;
+  def : MipsInstAlias<"mtgc0 $rt, $rd",
+                      (MTGC0 COP0Opnd:$rd, GPR32Opnd:$rt, 0), 0>,
+                      ISA_MIPS32R5, ASE_VIRT;
+  def : MipsInstAlias<"mfhgc0 $rt, $rd",
+                      (MFHGC0 GPR32Opnd:$rt, COP0Opnd:$rd, 0), 0>,
+                      ISA_MIPS32R5, ASE_VIRT;
+  def : MipsInstAlias<"mthgc0 $rt, $rd",
+                      (MTHGC0 COP0Opnd:$rd, GPR32Opnd:$rt, 0), 0>,
+                      ISA_MIPS32R5, ASE_VIRT;
+}
 def : MipsInstAlias<"mfc2 $rt, $rd", (MFC2 GPR32Opnd:$rt, COP2Opnd:$rd, 0), 0>;
 def : MipsInstAlias<"mtc2 $rt, $rd", (MTC2 COP2Opnd:$rd, GPR32Opnd:$rt, 0), 0>;
 let AdditionalPredicates = [NotInMicroMips] in {
@@ -2658,6 +2724,9 @@ def : MipsInstAlias<"mulou $rs, $rt",
                     (MULOUMacro GPR32Opnd:$rs, GPR32Opnd:$rs, GPR32Opnd:$rt), 0>,
                     ISA_MIPS1_NOT_32R6_64R6;
 
+let AdditionalPredicates = [NotInMicroMips] in
+  def : MipsInstAlias<"hypcall", (HYPCALL 0), 1>, ISA_MIPS32R5, ASE_VIRT;
+
 //===----------------------------------------------------------------------===//
 // Assembler Pseudo Instructions
 //===----------------------------------------------------------------------===//
index aedbed3..e9f1cb7 100644 (file)
@@ -92,8 +92,10 @@ def II_DIVU             : InstrItinClass;
 def II_DIV_D            : InstrItinClass;
 def II_DIV_S            : InstrItinClass;
 def II_DMFC0            : InstrItinClass;
+def II_DMFGC0           : InstrItinClass;
 def II_DMT              : InstrItinClass;
 def II_DMTC0            : InstrItinClass;
+def II_DMTGC0           : InstrItinClass;
 def II_DMFC1            : InstrItinClass;
 def II_DMTC1            : InstrItinClass;
 def II_DMOD             : InstrItinClass;
@@ -128,6 +130,7 @@ def II_EVPE             : InstrItinClass;
 def II_EXT              : InstrItinClass; // Any EXT instruction
 def II_FLOOR            : InstrItinClass;
 def II_FORK             : InstrItinClass;
+def II_HYPCALL          : InstrItinClass;
 def II_INS              : InstrItinClass; // Any INS instruction
 def II_IndirectBranchPseudo : InstrItinClass; // Indirect branch pseudo.
 def II_J                : InstrItinClass;
@@ -233,6 +236,8 @@ def II_MFHC0            : InstrItinClass;
 def II_MFC1             : InstrItinClass;
 def II_MFHC1            : InstrItinClass;
 def II_MFC2             : InstrItinClass;
+def II_MFGC0            : InstrItinClass;
+def II_MFHGC0           : InstrItinClass;
 def II_MFHI_MFLO        : InstrItinClass; // mfhi and mflo
 def II_MFTR             : InstrItinClass;
 def II_MOD              : InstrItinClass;
@@ -263,6 +268,8 @@ def II_MTHC0            : InstrItinClass;
 def II_MTC1             : InstrItinClass;
 def II_MTHC1            : InstrItinClass;
 def II_MTC2             : InstrItinClass;
+def II_MTGC0            : InstrItinClass;
+def II_MTHGC0           : InstrItinClass;
 def II_MTHI_MTLO        : InstrItinClass; // mthi and mtlo
 def II_MTTR             : InstrItinClass;
 def II_MUL              : InstrItinClass;
@@ -354,6 +361,12 @@ def II_CACHEE           : InstrItinClass;
 def II_PREFE            : InstrItinClass;
 def II_LLE              : InstrItinClass;
 def II_SCE              : InstrItinClass;
+def II_TLBGINV          : InstrItinClass;
+def II_TLBGINVF         : InstrItinClass;
+def II_TLBGP            : InstrItinClass;
+def II_TLBGR            : InstrItinClass;
+def II_TLBGWI           : InstrItinClass;
+def II_TLBGWR           : InstrItinClass;
 def II_TLBINV           : InstrItinClass;
 def II_TLBINVF          : InstrItinClass;
 def II_WRPGPR           : InstrItinClass;
@@ -702,5 +715,18 @@ def MipsGenericItineraries : ProcessorItineraries<[ALU, IMULDIV], [], [
   InstrItinData<II_CRC32CB         , [InstrStage<1,  [ALU]>]>,
   InstrItinData<II_CRC32CH         , [InstrStage<1,  [ALU]>]>,
   InstrItinData<II_CRC32CW         , [InstrStage<1,  [ALU]>]>,
-  InstrItinData<II_CRC32CD         , [InstrStage<1,  [ALU]>]>
+  InstrItinData<II_CRC32CD         , [InstrStage<1,  [ALU]>]>,
+  InstrItinData<II_MFGC0           , [InstrStage<2,  [ALU]>]>,
+  InstrItinData<II_MTGC0           , [InstrStage<2,  [ALU]>]>,
+  InstrItinData<II_MFHGC0          , [InstrStage<2,  [ALU]>]>,
+  InstrItinData<II_MTHGC0          , [InstrStage<2,  [ALU]>]>,
+  InstrItinData<II_HYPCALL         , [InstrStage<2,  [ALU]>]>,
+  InstrItinData<II_TLBGINV         , [InstrStage<2,  [ALU]>]>,
+  InstrItinData<II_TLBGINVF        , [InstrStage<2,  [ALU]>]>,
+  InstrItinData<II_TLBGP           , [InstrStage<2,  [ALU]>]>,
+  InstrItinData<II_TLBGR           , [InstrStage<2,  [ALU]>]>,
+  InstrItinData<II_TLBWI           , [InstrStage<2,  [ALU]>]>,
+  InstrItinData<II_TLBWR           , [InstrStage<2,  [ALU]>]>,
+  InstrItinData<II_DMFGC0          , [InstrStage<2,  [ALU]>]>,
+  InstrItinData<II_DMTGC0          , [InstrStage<2,  [ALU]>]>
 ]>;
index fd22b02..1cbffbf 100644 (file)
@@ -79,7 +79,8 @@ MipsSubtarget::MipsSubtarget(const Triple &TT, StringRef CPU, StringRef FS,
       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),
-      UseIndirectJumpsHazard(false), StackAlignOverride(StackAlignOverride),
+      HasVirt(false), UseIndirectJumpsHazard(false),
+      StackAlignOverride(StackAlignOverride),
       TM(TM), TargetTriple(TT), TSInfo(),
       InstrInfo(
           MipsInstrInfo::create(initializeSubtargetDependencies(CPU, FS, TM))),
index 5a8efcc..7aebfe1 100644 (file)
@@ -165,6 +165,9 @@ class MipsSubtarget : public MipsGenSubtargetInfo {
   // HasCRC -- supports R6 CRC ASE
   bool HasCRC;
 
+  // HasVirt -- supports Virtualization ASE
+  bool HasVirt;
+
   // Use hazard variants of the jump register instructions for indirect
   // function calls and jump tables.
   bool UseIndirectJumpsHazard;
@@ -290,6 +293,7 @@ public:
   bool hasEVA() const { return HasEVA; }
   bool hasMT() const { return HasMT; }
   bool hasCRC() const { return HasCRC; }
+  bool hasVirt() const { return HasVirt; }
   bool useIndirectJumpsHazard() const {
     return UseIndirectJumpsHazard && hasMips32r2();
   }
index 0447436..f9714d2 100644 (file)
@@ -44,6 +44,8 @@ public:
   virtual void emitDirectiveSetNoMt();
   virtual void emitDirectiveSetCRC();
   virtual void emitDirectiveSetNoCRC();
+  virtual void emitDirectiveSetVirt();
+  virtual void emitDirectiveSetNoVirt();
   virtual void emitDirectiveSetAt();
   virtual void emitDirectiveSetAtWithArg(unsigned RegNo);
   virtual void emitDirectiveSetNoAt();
@@ -107,6 +109,8 @@ public:
   virtual void emitDirectiveSetNoOddSPReg();
   virtual void emitDirectiveModuleCRC();
   virtual void emitDirectiveModuleNoCRC();
+  virtual void emitDirectiveModuleVirt();
+  virtual void emitDirectiveModuleNoVirt();
 
   void emitR(unsigned Opcode, unsigned Reg0, SMLoc IDLoc,
              const MCSubtargetInfo *STI);
@@ -219,6 +223,8 @@ public:
   void emitDirectiveSetNoMt() override;
   void emitDirectiveSetCRC() override;
   void emitDirectiveSetNoCRC() override;
+  void emitDirectiveSetVirt() override;
+  void emitDirectiveSetNoVirt() override;
   void emitDirectiveSetAt() override;
   void emitDirectiveSetAtWithArg(unsigned RegNo) override;
   void emitDirectiveSetNoAt() override;
@@ -286,6 +292,8 @@ public:
   void emitDirectiveModuleMT() override;
   void emitDirectiveModuleCRC() override;
   void emitDirectiveModuleNoCRC() override;
+  void emitDirectiveModuleVirt() override;
+  void emitDirectiveModuleNoVirt() override;
   void emitDirectiveSetFp(MipsABIFlagsSection::FpABIKind Value) override;
   void emitDirectiveSetOddSPReg() override;
   void emitDirectiveSetNoOddSPReg() override;
diff --git a/llvm/test/MC/Disassembler/Mips/virt/valid-32-el.txt b/llvm/test/MC/Disassembler/Mips/virt/valid-32-el.txt
new file mode 100644 (file)
index 0000000..f4eddda
--- /dev/null
@@ -0,0 +1,19 @@
+# RUN: llvm-mc --disassemble %s -triple=mipsel-unknown-linux-gnu \
+# RUN:   -mcpu=mips32r5 -mattr=+virt | FileCheck %s
+
+0x00 0x28 0x64 0x40  # CHECK: mfgc0 $4, $5, 0
+0x02 0x28 0x64 0x40  # CHECK: mfgc0 $4, $5, 2
+0x00 0x2a 0x64 0x40  # CHECK: mtgc0 $4, $5, 0
+0x02 0x22 0x65 0x40  # CHECK: mtgc0 $5, $4, 2
+0x00 0x2c 0x64 0x40  # CHECK: mfhgc0 $4, $5, 0
+0x04 0x2c 0x64 0x40  # CHECK: mfhgc0 $4, $5, 4
+0x00 0x2e 0x64 0x40  # CHECK: mthgc0 $4, $5, 0
+0x04 0x2e 0x64 0x40  # CHECK: mthgc0 $4, $5, 4
+0x28 0x00 0x00 0x42  # CHECK: hypcall
+0x28 0x50 0x00 0x42  # CHECK: hypcall 10
+0x0b 0x00 0x00 0x42  # CHECK: tlbginv
+0x0c 0x00 0x00 0x42  # CHECK: tlbginvf
+0x10 0x00 0x00 0x42  # CHECK: tlbgp
+0x09 0x00 0x00 0x42  # CHECK: tlbgr
+0x0a 0x00 0x00 0x42  # CHECK: tlbgwi
+0x0e 0x00 0x00 0x42  # CHECK: tlbgwr
diff --git a/llvm/test/MC/Disassembler/Mips/virt/valid-32.txt b/llvm/test/MC/Disassembler/Mips/virt/valid-32.txt
new file mode 100644 (file)
index 0000000..ffad888
--- /dev/null
@@ -0,0 +1,19 @@
+# RUN: llvm-mc --disassemble %s -triple=mips-unknown-linux-gnu \
+# RUN:   -mcpu=mips32r5 -mattr=+virt | FileCheck %s
+
+0x40 0x64 0x28 0x00  # CHECK: mfgc0 $4, $5, 0
+0x40 0x64 0x28 0x02  # CHECK: mfgc0 $4, $5, 2
+0x40 0x64 0x2a 0x00  # CHECK: mtgc0 $4, $5, 0
+0x40 0x65 0x22 0x02  # CHECK: mtgc0 $5, $4, 2
+0x40 0x64 0x2c 0x00  # CHECK: mfhgc0 $4, $5, 0
+0x40 0x64 0x2c 0x04  # CHECK: mfhgc0 $4, $5, 4
+0x40 0x64 0x2e 0x00  # CHECK: mthgc0 $4, $5, 0
+0x40 0x64 0x2e 0x04  # CHECK: mthgc0 $4, $5, 4
+0x42 0x00 0x00 0x28  # CHECK: hypcall
+0x42 0x00 0x50 0x28  # CHECK: hypcall 10
+0x42 0x00 0x00 0x0b  # CHECK: tlbginv
+0x42 0x00 0x00 0x0c  # CHECK: tlbginvf
+0x42 0x00 0x00 0x10  # CHECK: tlbgp
+0x42 0x00 0x00 0x09  # CHECK: tlbgr
+0x42 0x00 0x00 0x0a  # CHECK: tlbgwi
+0x42 0x00 0x00 0x0e  # CHECK: tlbgwr
diff --git a/llvm/test/MC/Disassembler/Mips/virt/valid-64-el.txt b/llvm/test/MC/Disassembler/Mips/virt/valid-64-el.txt
new file mode 100644 (file)
index 0000000..169b86c
--- /dev/null
@@ -0,0 +1,7 @@
+# RUN: llvm-mc --disassemble %s -triple=mips64el-unknown-linux-gnu \
+# RUN:   -mcpu=mips64r5 -mattr=+virt | FileCheck %s
+
+0x00 0x29 0x64 0x40  # CHECK: dmfgc0 $4, $5, 0
+0x04 0x29 0x64 0x40  # CHECK: dmfgc0 $4, $5, 4
+0x00 0x23 0x65 0x40  # CHECK: dmtgc0 $5, $4, 0
+0x04 0x2b 0x64 0x40  # CHECK: dmtgc0 $4, $5, 4
diff --git a/llvm/test/MC/Disassembler/Mips/virt/valid-64.txt b/llvm/test/MC/Disassembler/Mips/virt/valid-64.txt
new file mode 100644 (file)
index 0000000..05672bd
--- /dev/null
@@ -0,0 +1,7 @@
+# RUN: llvm-mc --disassemble %s -triple=mips64-unknown-linux-gnu \
+# RUN:   -mcpu=mips64r5 -mattr=+virt | FileCheck %s
+
+0x40 0x64 0x29 0x00  # CHECK: dmfgc0 $4, $5, 0
+0x40 0x64 0x29 0x04  # CHECK: dmfgc0 $4, $5, 4
+0x40 0x65 0x23 0x00  # CHECK: dmtgc0 $5, $4, 0
+0x40 0x64 0x2b 0x04  # CHECK: dmtgc0 $4, $5, 4
diff --git a/llvm/test/MC/Disassembler/Mips/virt/valid-micromips-el.txt b/llvm/test/MC/Disassembler/Mips/virt/valid-micromips-el.txt
new file mode 100644 (file)
index 0000000..1f6535e
--- /dev/null
@@ -0,0 +1,19 @@
+# RUN: llvm-mc --disassemble %s -triple=mipsel-unknown-linux-gnu \
+# RUN:   -mcpu=mips32r5 -mattr=+micromips,+virt | FileCheck %s
+
+0x85 0x00 0xfc 0x04  # CHECK: mfgc0 $4, $5, 0
+0x85 0x00 0xfc 0x14  # CHECK: mfgc0 $4, $5, 2
+0xa4 0x00 0xfc 0x06  # CHECK: mtgc0 $5, $4, 0
+0xa4 0x00 0xfc 0x16  # CHECK: mtgc0 $5, $4, 2
+0x85 0x00 0xf4 0x04  # CHECK: mfhgc0 $4, $5, 0
+0x85 0x00 0xf4 0x14  # CHECK: mfhgc0 $4, $5, 2
+0xa4 0x00 0xf4 0x06  # CHECK: mthgc0 $5, $4, 0
+0xa4 0x00 0xf4 0x16  # CHECK: mthgc0 $5, $4, 2
+0x00 0x00 0x7c 0xc3  # CHECK: hypcall
+0x0a 0x00 0x7c 0xc3  # CHECK: hypcall 10
+0x00 0x00 0x7c 0x41  # CHECK: tlbginv
+0x00 0x00 0x7c 0x51  # CHECK: tlbginvf
+0x00 0x00 0x7c 0x01  # CHECK: tlbgp
+0x00 0x00 0x7c 0x11  # CHECK: tlbgr
+0x00 0x00 0x7c 0x21  # CHECK: tlbgwi
+0x00 0x00 0x7c 0x31  # CHECK: tlbgwr
diff --git a/llvm/test/MC/Disassembler/Mips/virt/valid-micromips.txt b/llvm/test/MC/Disassembler/Mips/virt/valid-micromips.txt
new file mode 100644 (file)
index 0000000..bfc78ea
--- /dev/null
@@ -0,0 +1,19 @@
+# RUN: llvm-mc --disassemble %s -triple=mips-unknown-linux-gnu \
+# RUN:   -mcpu=mips32r5 -mattr=+micromips,+virt | FileCheck %s
+
+0x00 0x85 0x04 0xfc  # CHECK: mfgc0 $4, $5, 0
+0x00 0x85 0x14 0xfc  # CHECK: mfgc0 $4, $5, 2
+0x00 0xa4 0x06 0xfc  # CHECK: mtgc0 $5, $4, 0
+0x00 0xa4 0x16 0xfc  # CHECK: mtgc0 $5, $4, 2
+0x00 0x85 0x04 0xf4  # CHECK: mfhgc0 $4, $5, 0
+0x00 0x85 0x14 0xf4  # CHECK: mfhgc0 $4, $5, 2
+0x00 0xa4 0x06 0xf4  # CHECK: mthgc0 $5, $4, 0
+0x00 0xa4 0x16 0xf4  # CHECK: mthgc0 $5, $4, 2
+0x00 0x00 0xc3 0x7c  # CHECK: hypcall
+0x00 0x0a 0xc3 0x7c  # CHECK: hypcall 10
+0x00 0x00 0x41 0x7c  # CHECK: tlbginv
+0x00 0x00 0x51 0x7c  # CHECK: tlbginvf
+0x00 0x00 0x01 0x7c  # CHECK: tlbgp
+0x00 0x00 0x11 0x7c  # CHECK: tlbgr
+0x00 0x00 0x21 0x7c  # CHECK: tlbgwi
+0x00 0x00 0x31 0x7c  # CHECK: tlbgwr
diff --git a/llvm/test/MC/Mips/virt/invalid.s b/llvm/test/MC/Mips/virt/invalid.s
new file mode 100644 (file)
index 0000000..9cf664e
--- /dev/null
@@ -0,0 +1,103 @@
+# Instructions that are invalid.
+#
+# RUN: not llvm-mc %s -arch=mips -mcpu=mips32r5 -mattr=+virt 2>%t1
+# RUN: FileCheck %s < %t1
+# RUN: not llvm-mc %s -arch=mips64 -mcpu=mips64r5 -mattr=+virt 2>%t1
+# RUN: FileCheck %s < %t1
+# RUN: not llvm-mc %s -arch=mips -mcpu=mips32r5 -mattr=+micromips,+virt 2>%t1
+# RUN: FileCheck %s < %t1
+
+  mfgc0                   # CHECK: :[[@LINE]]:3: error: too few operands for instruction
+  mfgc0 0                 # CHECK: :[[@LINE]]:9: error: invalid operand for instruction
+  mfgc0 $4                # CHECK: :[[@LINE]]:3: error: too few operands for instruction
+  mfgc0 0, $4             # CHECK: :[[@LINE]]:9: error: invalid operand for instruction
+  mfgc0 0, $4, $5         # CHECK: :[[@LINE]]:9: error: invalid operand for instruction
+  mfgc0 $4, 0, $5         # CHECK: :[[@LINE]]:13: error: invalid operand for instruction
+  mfgc0 $4, $5, 8         # CHECK: :[[@LINE]]:17: error: expected 3-bit unsigned immediate
+  mfgc0 $4, $5, -1        # CHECK: :[[@LINE]]:17: error: expected 3-bit unsigned immediate
+  mfgc0 $4, $5, 0($4)     # CHECK: :[[@LINE]]:18: error: invalid operand for instruction
+  mtgc0                   # CHECK: :[[@LINE]]:3: error: too few operands for instruction
+  mtgc0 0                 # CHECK: :[[@LINE]]:9: error: invalid operand for instruction
+  mtgc0 $4                # CHECK: :[[@LINE]]:3: error: too few operands for instruction
+  mtgc0 0, $4             # CHECK: :[[@LINE]]:9: error: invalid operand for instruction
+  mtgc0 0, $4, $5         # CHECK: :[[@LINE]]:9: error: invalid operand for instruction
+  mtgc0 $4, 0, $5         # CHECK: :[[@LINE]]:13: error: invalid operand for instruction
+  mtgc0 $4, $5, 8         # CHECK: :[[@LINE]]:17: error: expected 3-bit unsigned immediate
+  mtgc0 $4, $5, -1        # CHECK: :[[@LINE]]:17: error: expected 3-bit unsigned immediate
+  mtgc0 $4, $5, 0($4)     # CHECK: :[[@LINE]]:18: error: invalid operand for instruction
+  mfhgc0                  # CHECK: :[[@LINE]]:3: error: too few operands for instruction
+  mfhgc0 0                # CHECK: :[[@LINE]]:10: error: invalid operand for instruction
+  mfhgc0 $4               # CHECK: :[[@LINE]]:3: error: too few operands for instruction
+  mfhgc0 0, $4            # CHECK: :[[@LINE]]:10: error: invalid operand for instruction
+  mfhgc0 0, $4, $5        # CHECK: :[[@LINE]]:10: error: invalid operand for instruction
+  mfhgc0 $4, 0, $5        # CHECK: :[[@LINE]]:14: error: invalid operand for instruction
+  mfhgc0 $4, $5, 8        # CHECK: :[[@LINE]]:18: error: expected 3-bit unsigned immediate
+  mfhgc0 $4, $5, -1       # CHECK: :[[@LINE]]:18: error: expected 3-bit unsigned immediate
+  mfhgc0 $4, $5, 0($4)    # CHECK: :[[@LINE]]:19: error: invalid operand for instruction
+  mthgc0                  # CHECK: :[[@LINE]]:3: error: too few operands for instruction
+  mthgc0 0                # CHECK: :[[@LINE]]:10: error: invalid operand for instruction
+  mthgc0 $4               # CHECK: :[[@LINE]]:3: error: too few operands for instruction
+  mthgc0 0, $4            # CHECK: :[[@LINE]]:10: error: invalid operand for instruction
+  mthgc0 0, $4, $5        # CHECK: :[[@LINE]]:10: error: invalid operand for instruction
+  mthgc0 $4, 0, $5        # CHECK: :[[@LINE]]:14: error: invalid operand for instruction
+  mthgc0 $4, $5, 8        # CHECK: :[[@LINE]]:18: error: expected 3-bit unsigned immediate
+  mthgc0 $4, $5, -1       # CHECK: :[[@LINE]]:18: error: expected 3-bit unsigned immediate
+  mthgc0 $4, $5, 0($4)    # CHECK: :[[@LINE]]:19: error: invalid operand for instruction
+  hypcall $4              # CHECK: :[[@LINE]]:11: error: expected 10-bit unsigned immediate
+  hypcall 0, $4           # CHECK: :[[@LINE]]:14: error: invalid operand for instruction
+  hypcall 0, $4, $5       # CHECK: :[[@LINE]]:14: error: invalid operand for instruction
+  hypcall $4, 0, $5       # CHECK: :[[@LINE]]:11: error: expected 10-bit unsigned immediate
+  hypcall $4, $5, 8       # CHECK: :[[@LINE]]:11: error: expected 10-bit unsigned immediate
+  hypcall $4, $5, -1      # CHECK: :[[@LINE]]:11: error: expected 10-bit unsigned immediate
+  hypcall $4, $5, 0($4)   # CHECK: :[[@LINE]]:11: error: expected 10-bit unsigned immediate
+  hypcall 2048            # CHECK: :[[@LINE]]:11: error: expected 10-bit unsigned immediate
+  hypcall -1              # CHECK: :[[@LINE]]:11: error: expected 10-bit unsigned immediate
+  hypcall 0($4)           # CHECK: :[[@LINE]]:12: error: unexpected token in argument list
+  tlbginv 0               # CHECK: :[[@LINE]]:11: error: invalid operand for instruction
+  tlbginv $4              # CHECK: :[[@LINE]]:11: error: invalid operand for instruction
+  tlbginv 0, $4           # CHECK: :[[@LINE]]:11: error: invalid operand for instruction
+  tlbginv 0, $4, $5       # CHECK: :[[@LINE]]:11: error: invalid operand for instruction
+  tlbginv $4, 0, $5       # CHECK: :[[@LINE]]:11: error: invalid operand for instruction
+  tlbginv $4, $5, 8       # CHECK: :[[@LINE]]:11: error: invalid operand for instruction
+  tlbginv $4, $5, -1      # CHECK: :[[@LINE]]:11: error: invalid operand for instruction
+  tlbginv $4, $5, 0($4)   # CHECK: :[[@LINE]]:11: error: invalid operand for instruction
+  tlbginvf 0              # CHECK: :[[@LINE]]:12: error: invalid operand for instruction
+  tlbginvf $4             # CHECK: :[[@LINE]]:12: error: invalid operand for instruction
+  tlbginvf 0, $4          # CHECK: :[[@LINE]]:12: error: invalid operand for instruction
+  tlbginvf 0, $4, $5      # CHECK: :[[@LINE]]:12: error: invalid operand for instruction
+  tlbginvf $4, 0, $5      # CHECK: :[[@LINE]]:12: error: invalid operand for instruction
+  tlbginvf $4, $5, 8      # CHECK: :[[@LINE]]:12: error: invalid operand for instruction
+  tlbginvf $4, $5, -1     # CHECK: :[[@LINE]]:12: error: invalid operand for instruction
+  tlbginvf $4, $5, 0($4)  # CHECK: :[[@LINE]]:12: error: invalid operand for instruction
+  tlbgp 0                 # CHECK: :[[@LINE]]:9: error: invalid operand for instruction
+  tlbgp $4                # CHECK: :[[@LINE]]:9: error: invalid operand for instruction
+  tlbgp 0, $4             # CHECK: :[[@LINE]]:9: error: invalid operand for instruction
+  tlbgp 0, $4, $5         # CHECK: :[[@LINE]]:9: error: invalid operand for instruction
+  tlbgp $4, 0, $5         # CHECK: :[[@LINE]]:9: error: invalid operand for instruction
+  tlbgp $4, $5, 8         # CHECK: :[[@LINE]]:9: error: invalid operand for instruction
+  tlbgp $4, $5, -1        # CHECK: :[[@LINE]]:9: error: invalid operand for instruction
+  tlbgp $4, $5, 0($4)     # CHECK: :[[@LINE]]:9: error: invalid operand for instruction
+  tlbgr 0                 # CHECK: :[[@LINE]]:9: error: invalid operand for instruction
+  tlbgr $4                # CHECK: :[[@LINE]]:9: error: invalid operand for instruction
+  tlbgr 0, $4             # CHECK: :[[@LINE]]:9: error: invalid operand for instruction
+  tlbgr 0, $4, $5         # CHECK: :[[@LINE]]:9: error: invalid operand for instruction
+  tlbgr $4, 0, $5         # CHECK: :[[@LINE]]:9: error: invalid operand for instruction
+  tlbgr $4, $5, 8         # CHECK: :[[@LINE]]:9: error: invalid operand for instruction
+  tlbgr $4, $5, -1        # CHECK: :[[@LINE]]:9: error: invalid operand for instruction
+  tlbgr $4, $5, 0($4)     # CHECK: :[[@LINE]]:9: error: invalid operand for instruction
+  tlbgwi 0                # CHECK: :[[@LINE]]:10: error: invalid operand for instruction
+  tlbgwi $4               # CHECK: :[[@LINE]]:10: error: invalid operand for instruction
+  tlbgwi 0, $4            # CHECK: :[[@LINE]]:10: error: invalid operand for instruction
+  tlbgwi 0, $4, $5        # CHECK: :[[@LINE]]:10: error: invalid operand for instruction
+  tlbgwi $4, 0, $5        # CHECK: :[[@LINE]]:10: error: invalid operand for instruction
+  tlbgwi $4, $5, 8        # CHECK: :[[@LINE]]:10: error: invalid operand for instruction
+  tlbgwi $4, $5, -1       # CHECK: :[[@LINE]]:10: error: invalid operand for instruction
+  tlbgwi $4, $5, 0($4)    # CHECK: :[[@LINE]]:10: error: invalid operand for instruction
+  tlbgwr 0                # CHECK: :[[@LINE]]:10: error: invalid operand for instruction
+  tlbgwr $4               # CHECK: :[[@LINE]]:10: error: invalid operand for instruction
+  tlbgwr 0, $4            # CHECK: :[[@LINE]]:10: error: invalid operand for instruction
+  tlbgwr 0, $4, $5        # CHECK: :[[@LINE]]:10: error: invalid operand for instruction
+  tlbgwr $4, 0, $5        # CHECK: :[[@LINE]]:10: error: invalid operand for instruction
+  tlbgwr $4, $5, 8        # CHECK: :[[@LINE]]:10: error: invalid operand for instruction
+  tlbgwr $4, $5, -1       # CHECK: :[[@LINE]]:10: error: invalid operand for instruction
+  tlbgwr $4, $5, 0($4)    # CHECK: :[[@LINE]]:10: error: invalid operand for instruction
diff --git a/llvm/test/MC/Mips/virt/invalid64.s b/llvm/test/MC/Mips/virt/invalid64.s
new file mode 100644 (file)
index 0000000..8a9aede
--- /dev/null
@@ -0,0 +1,23 @@
+# Instructions that are invalid.
+#
+# RUN: not llvm-mc %s -arch=mips -mcpu=mips64r5 -mattr=+virt 2>%t1
+# RUN: FileCheck %s < %t1
+
+  dmfgc0                # CHECK: :[[@LINE]]:3: error: too few operands for instruction
+  dmfgc0 0              # CHECK: :[[@LINE]]:10: error: invalid operand for instruction
+  dmfgc0 $4             # CHECK: :[[@LINE]]:3: error: too few operands for instruction
+  dmfgc0 0, $4          # CHECK: :[[@LINE]]:10: error: invalid operand for instruction
+  dmfgc0 0, $4, $5      # CHECK: :[[@LINE]]:10: error: invalid operand for instruction
+  dmfgc0 $4, 0, $5      # CHECK: :[[@LINE]]:14: error: invalid operand for instruction
+  dmfgc0 $4, $5, 8      # CHECK: :[[@LINE]]:18: error: expected 3-bit unsigned immediate
+  dmfgc0 $4, $5, -1     # CHECK: :[[@LINE]]:18: error: expected 3-bit unsigned immediate
+  dmfgc0 $4, $5, 0($4)  # CHECK: :[[@LINE]]:19: error: invalid operand for instruction
+  dmtgc0                # CHECK: :[[@LINE]]:3: error: too few operands for instruction
+  dmtgc0 0              # CHECK: :[[@LINE]]:10: error: invalid operand for instruction
+  dmtgc0 $4             # CHECK: :[[@LINE]]:3: error: too few operands for instruction
+  dmtgc0 0, $4          # CHECK: :[[@LINE]]:10: error: invalid operand for instruction
+  dmtgc0 0, $4, $5      # CHECK: :[[@LINE]]:10: error: invalid operand for instruction
+  dmtgc0 $4, 0, $5      # CHECK: :[[@LINE]]:14: error: invalid operand for instruction
+  dmtgc0 $4, $5, 8      # CHECK: :[[@LINE]]:18: error: expected 3-bit unsigned immediate
+  dmtgc0 $4, $5, -1     # CHECK: :[[@LINE]]:18: error: expected 3-bit unsigned immediate
+  dmtgc0 $4, $5, 0($4)  # CHECK: :[[@LINE]]:19: error: invalid operand for instruction
diff --git a/llvm/test/MC/Mips/virt/module-novirt.s b/llvm/test/MC/Mips/virt/module-novirt.s
new file mode 100644 (file)
index 0000000..53c0459
--- /dev/null
@@ -0,0 +1,21 @@
+# RUN: llvm-mc %s -arch=mips -mcpu=mips32r5 -mattr=+virt | \
+# RUN:   FileCheck %s -check-prefix=CHECK-ASM
+#
+# RUN: llvm-mc %s -arch=mips -mcpu=mips32r5 -filetype=obj -o - -mattr=+virt | \
+# RUN:   llvm-readobj -mips-abi-flags - | \
+# RUN:   FileCheck %s -check-prefix=CHECK-OBJ
+
+# CHECK-ASM: .module novirt
+
+# Check that MIPS.abiflags has no VZ flag.
+# CHECK-OBJ: MIPS ABI Flags {
+# CHECK-OBJ:   ASEs [ (0x0)
+# CHECK-OBJ-NOT:   ASEs [ (0x100)
+# CHECK-OBJ-NOT:     VZ (0x100)
+# CHECK-OBJ: }
+
+  .module novirt
+
+# 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.
diff --git a/llvm/test/MC/Mips/virt/module-virt.s b/llvm/test/MC/Mips/virt/module-virt.s
new file mode 100644 (file)
index 0000000..9a025ed
--- /dev/null
@@ -0,0 +1,22 @@
+# RUN: llvm-mc %s -triple=mips-unknown-linux-gnu -mcpu=mips32r5 | \
+# RUN:   FileCheck %s -check-prefix=CHECK-ASM
+#
+# RUN: llvm-mc %s -triple=mips-unknown-linux-gnu -mcpu=mips32r5 \
+# RUN:   -filetype=obj -o - | \
+# RUN:   llvm-readobj -mips-abi-flags - | \
+# RUN:   FileCheck %s -check-prefix=CHECK-OBJ
+
+# CHECK-ASM: .module virt
+
+# Check if the MIPS.abiflags section was correctly emitted:
+# CHECK-OBJ: MIPS ABI Flags {
+# CHECK-OBJ:   ASEs [ (0x100)
+# CHECK-OBJ:     VZ (0x100)
+# CHECK-OBJ: }
+
+  .module virt
+  hypcall
+
+# 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.
diff --git a/llvm/test/MC/Mips/virt/set-novirt-directive.s b/llvm/test/MC/Mips/virt/set-novirt-directive.s
new file mode 100644 (file)
index 0000000..f7bd5f1
--- /dev/null
@@ -0,0 +1,9 @@
+# RUN: not llvm-mc %s -triple=mips-unknown-linux-gnu -show-encoding \
+# RUN:     -mcpu=mips32r5 -mattr=+virt 2>%t1
+# RUN: FileCheck %s < %t1
+# RUN: not llvm-mc %s -triple=mips64-unknown-linux-gnu -show-encoding \
+# RUN:     -mcpu=mips64r5 -mattr=+virt 2>%t1
+# RUN: FileCheck %s < %t1
+
+  .set novirt
+  hypcall  # CHECK: instruction requires a CPU feature not currently enabled
diff --git a/llvm/test/MC/Mips/virt/set-virt-directive.s b/llvm/test/MC/Mips/virt/set-virt-directive.s
new file mode 100644 (file)
index 0000000..a3a7a88
--- /dev/null
@@ -0,0 +1,7 @@
+# RUN: llvm-mc %s -show-encoding -triple=mips-unknown-linux-gnu \
+# RUN:   -mcpu=mips32r5 | FileCheck %s
+# RUN: llvm-mc %s -show-encoding -triple=mips64-unknown-linux-gnu \
+# RUN:   -mcpu=mips64r5 | FileCheck %s
+
+  .set virt
+  hypcall  # CHECK: hypcall # encoding: [0x42,0x00,0x00,0x28]
diff --git a/llvm/test/MC/Mips/virt/valid-micromips.s b/llvm/test/MC/Mips/virt/valid-micromips.s
new file mode 100644 (file)
index 0000000..de6c349
--- /dev/null
@@ -0,0 +1,19 @@
+# RUN: llvm-mc %s -triple=mips-unknown-linux-gnu -show-encoding \
+# RUN:   -mcpu=mips32r5 -mattr=+micromips,+virt | FileCheck %s
+
+  mfgc0 $4, $5        # CHECK: mfgc0 $4, $5, 0   # encoding: [0x00,0x85,0x04,0xfc]
+  mfgc0 $4, $5, 2     # CHECK: mfgc0 $4, $5, 2   # encoding: [0x00,0x85,0x14,0xfc]
+  mtgc0 $5, $4        # CHECK: mtgc0 $5, $4, 0   # encoding: [0x00,0xa4,0x06,0xfc]
+  mtgc0 $5, $4, 2     # CHECK: mtgc0 $5, $4, 2   # encoding: [0x00,0xa4,0x16,0xfc]
+  mthgc0 $5, $4       # CHECK: mthgc0 $5, $4, 0  # encoding: [0x00,0xa4,0x06,0xf4]
+  mthgc0 $5, $4, 1    # CHECK: mthgc0 $5, $4, 1  # encoding: [0x00,0xa4,0x0e,0xf4]
+  mfhgc0 $5, $4       # CHECK: mfhgc0 $5, $4, 0  # encoding: [0x00,0xa4,0x04,0xf4]
+  mfhgc0 $5, $4, 7    # CHECK: mfhgc0 $5, $4, 7  # encoding: [0x00,0xa4,0x3c,0xf4]
+  hypcall             # CHECK: hypcall           # encoding: [0x00,0x00,0xc3,0x7c]
+  hypcall 10          # CHECK: hypcall 10        # encoding: [0x00,0x0a,0xc3,0x7c]
+  tlbginv             # CHECK: tlbginv           # encoding: [0x00,0x00,0x41,0x7c]
+  tlbginvf            # CHECK: tlbginvf          # encoding: [0x00,0x00,0x51,0x7c]
+  tlbgp               # CHECK: tlbgp             # encoding: [0x00,0x00,0x01,0x7c]
+  tlbgr               # CHECK: tlbgr             # encoding: [0x00,0x00,0x11,0x7c]
+  tlbgwi              # CHECK: tlbgwi            # encoding: [0x00,0x00,0x21,0x7c]
+  tlbgwr              # CHECK: tlbgwr            # encoding: [0x00,0x00,0x31,0x7c]
diff --git a/llvm/test/MC/Mips/virt/valid.s b/llvm/test/MC/Mips/virt/valid.s
new file mode 100644 (file)
index 0000000..175df7b
--- /dev/null
@@ -0,0 +1,21 @@
+# RUN: llvm-mc %s -triple=mips-unknown-linux-gnu -show-encoding \
+# RUN:   -mcpu=mips32r5 -mattr=+virt | FileCheck %s
+# RUN: llvm-mc %s -triple=mips64-unknown-linux-gnu -show-encoding \
+# RUN:   -mcpu=mips64r5 -mattr=+virt | FileCheck %s
+
+  mfgc0 $4, $5           # CHECK: mfgc0 $4, $5, 0   # encoding: [0x40,0x64,0x28,0x00]
+  mfgc0 $4, $5, 2        # CHECK: mfgc0 $4, $5, 2   # encoding: [0x40,0x64,0x28,0x02]
+  mtgc0 $4, $5           # CHECK: mtgc0 $4, $5, 0   # encoding: [0x40,0x64,0x2a,0x00]
+  mtgc0 $5, $4, 2        # CHECK: mtgc0 $5, $4, 2   # encoding: [0x40,0x65,0x22,0x02]
+  mthgc0 $5, $4          # CHECK: mthgc0 $5, $4, 0  # encoding: [0x40,0x65,0x26,0x00]
+  mthgc0 $5, $4, 1       # CHECK: mthgc0 $5, $4, 1  # encoding: [0x40,0x65,0x26,0x01]
+  mfhgc0 $5, $4          # CHECK: mfhgc0 $5, $4, 0  # encoding: [0x40,0x65,0x24,0x00]
+  mfhgc0 $5, $4, 7       # CHECK: mfhgc0 $5, $4, 7  # encoding: [0x40,0x65,0x24,0x07]
+  hypcall                # CHECK: hypcall           # encoding: [0x42,0x00,0x00,0x28]
+  hypcall 10             # CHECK: hypcall 10        # encoding: [0x42,0x00,0x50,0x28]
+  tlbginv                # CHECK: tlbginv           # encoding: [0x42,0x00,0x00,0x0b]
+  tlbginvf               # CHECK: tlbginvf          # encoding: [0x42,0x00,0x00,0x0c]
+  tlbgp                  # CHECK: tlbgp             # encoding: [0x42,0x00,0x00,0x10]
+  tlbgr                  # CHECK: tlbgr             # encoding: [0x42,0x00,0x00,0x09]
+  tlbgwi                 # CHECK: tlbgwi            # encoding: [0x42,0x00,0x00,0x0a]
+  tlbgwr                 # CHECK: tlbgwr            # encoding: [0x42,0x00,0x00,0x0e]
diff --git a/llvm/test/MC/Mips/virt/valid64.s b/llvm/test/MC/Mips/virt/valid64.s
new file mode 100644 (file)
index 0000000..f456f09
--- /dev/null
@@ -0,0 +1,7 @@
+# RUN: llvm-mc %s -triple=mips64-unknown-linux-gnu -show-encoding \
+# RUN:   -mcpu=mips64r5 -mattr=+virt | FileCheck %s
+
+  dmfgc0 $4,$5      # CHECK: dmfgc0 $4, $5, 0  # encoding: [0x40,0x64,0x29,0x00]
+  dmfgc0 $4,$5,4    # CHECK: dmfgc0 $4, $5, 4  # encoding: [0x40,0x64,0x29,0x04]
+  dmtgc0 $4,$5      # CHECK: dmtgc0 $4, $5, 0  # encoding: [0x40,0x64,0x2b,0x00]
+  dmtgc0 $4,$5,4    # CHECK: dmtgc0 $4, $5, 4  # encoding: [0x40,0x64,0x2b,0x04]