Index: llvm/trunk/include/llvm/Support/MipsABIFlags.h
===================================================================
--- llvm/trunk/include/llvm/Support/MipsABIFlags.h
+++ llvm/trunk/include/llvm/Support/MipsABIFlags.h
@@ -43,7 +43,8 @@
   AFL_ASE_MIPS16 = 0x00000400,    // MIPS16 ASE
   AFL_ASE_MICROMIPS = 0x00000800, // MICROMIPS ASE
   AFL_ASE_XPA = 0x00001000,       // XPA ASE
-  AFL_ASE_CRC = 0x00008000        // CRC ASE
+  AFL_ASE_CRC = 0x00008000,       // CRC ASE
+  AFL_ASE_GINV = 0x00020000       // GINV ASE
 };
 
 // Values for the isa_ext word of an ABI flags structure.
Index: llvm/trunk/lib/Target/Mips/AsmParser/MipsAsmParser.cpp
===================================================================
--- llvm/trunk/lib/Target/Mips/AsmParser/MipsAsmParser.cpp
+++ llvm/trunk/lib/Target/Mips/AsmParser/MipsAsmParser.cpp
@@ -350,6 +350,7 @@
   bool parseSetNoMtDirective();
   bool parseSetNoCRCDirective();
   bool parseSetNoVirtDirective();
+  bool parseSetNoGINVDirective();
 
   bool parseSetAssignment();
 
@@ -654,6 +655,10 @@
     return getSTI().getFeatureBits()[Mips::FeatureVirt];
   }
 
+  bool hasGINV() const {
+    return getSTI().getFeatureBits()[Mips::FeatureGINV];
+  }
+
   /// Warn if RegIndex is the same as the current AT.
   void warnIfRegIndexIsAT(unsigned RegIndex, SMLoc Loc);
 
@@ -6740,6 +6745,23 @@
   return false;
 }
 
+bool MipsAsmParser::parseSetNoGINVDirective() {
+  MCAsmParser &Parser = getParser();
+  Parser.Lex(); // Eat "noginv".
+
+  // 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::FeatureGINV, "ginv");
+
+  getTargetStreamer().emitDirectiveSetNoGINV();
+  Parser.Lex(); // Consume the EndOfStatement.
+  return false;
+}
+
 bool MipsAsmParser::parseSetPopDirective() {
   MCAsmParser &Parser = getParser();
   SMLoc Loc = getLexer().getLoc();
@@ -6969,6 +6991,10 @@
     setFeatureBits(Mips::FeatureVirt, "virt");
     getTargetStreamer().emitDirectiveSetVirt();
     break;
+  case Mips::FeatureGINV:
+    setFeatureBits(Mips::FeatureGINV, "ginv");
+    getTargetStreamer().emitDirectiveSetGINV();
+    break;
   }
   return false;
 }
@@ -7281,6 +7307,10 @@
     return parseSetFeature(Mips::FeatureVirt);
   } else if (Tok.getString() == "novirt") {
     return parseSetNoVirtDirective();
+  } else if (Tok.getString() == "ginv") {
+    return parseSetFeature(Mips::FeatureGINV);
+  } else if (Tok.getString() == "noginv") {
+    return parseSetNoGINVDirective();
   } else {
     // It is just an identifier, look for an assignment.
     parseSetAssignment();
@@ -7531,6 +7561,8 @@
 ///  ::= .module nocrc
 ///  ::= .module virt
 ///  ::= .module novirt
+///  ::= .module ginv
+///  ::= .module noginv
 bool MipsAsmParser::parseDirectiveModule() {
   MCAsmParser &Parser = getParser();
   MCAsmLexer &Lexer = getLexer();
@@ -7725,6 +7757,44 @@
     }
 
     return false; // parseDirectiveModule has finished successfully.
+  } else if (Option == "ginv") {
+    setModuleFeatureBits(Mips::FeatureGINV, "ginv");
+
+    // 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().emitDirectiveModuleGINV();
+
+    // 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 == "noginv") {
+    clearModuleFeatureBits(Mips::FeatureGINV, "ginv");
+
+    // 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().emitDirectiveModuleNoGINV();
+
+    // 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: llvm/trunk/lib/Target/Mips/MCTargetDesc/MipsABIFlagsSection.h
===================================================================
--- llvm/trunk/lib/Target/Mips/MCTargetDesc/MipsABIFlagsSection.h
+++ llvm/trunk/lib/Target/Mips/MCTargetDesc/MipsABIFlagsSection.h
@@ -165,6 +165,8 @@
       ASESet |= Mips::AFL_ASE_CRC;
     if (P.hasVirt())
       ASESet |= Mips::AFL_ASE_VIRT;
+    if (P.hasGINV())
+      ASESet |= Mips::AFL_ASE_GINV;
   }
 
   template <class PredicateLibrary>
Index: llvm/trunk/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp
===================================================================
--- llvm/trunk/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp
+++ llvm/trunk/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp
@@ -56,6 +56,8 @@
 void MipsTargetStreamer::emitDirectiveSetNoCRC() {}
 void MipsTargetStreamer::emitDirectiveSetVirt() {}
 void MipsTargetStreamer::emitDirectiveSetNoVirt() {}
+void MipsTargetStreamer::emitDirectiveSetGINV() {}
+void MipsTargetStreamer::emitDirectiveSetNoGINV() {}
 void MipsTargetStreamer::emitDirectiveSetAt() { forbidModuleDirective(); }
 void MipsTargetStreamer::emitDirectiveSetAtWithArg(unsigned RegNo) {
   forbidModuleDirective();
@@ -130,6 +132,8 @@
 void MipsTargetStreamer::emitDirectiveModuleNoCRC() {}
 void MipsTargetStreamer::emitDirectiveModuleVirt() {}
 void MipsTargetStreamer::emitDirectiveModuleNoVirt() {}
+void MipsTargetStreamer::emitDirectiveModuleGINV() {}
+void MipsTargetStreamer::emitDirectiveModuleNoGINV() {}
 void MipsTargetStreamer::emitDirectiveSetFp(
     MipsABIFlagsSection::FpABIKind Value) {
   forbidModuleDirective();
@@ -449,6 +453,16 @@
   MipsTargetStreamer::emitDirectiveSetNoVirt();
 }
 
+void MipsTargetAsmStreamer::emitDirectiveSetGINV() {
+  OS << "\t.set\tginv\n";
+  MipsTargetStreamer::emitDirectiveSetGINV();
+}
+
+void MipsTargetAsmStreamer::emitDirectiveSetNoGINV() {
+  OS << "\t.set\tnoginv\n";
+  MipsTargetStreamer::emitDirectiveSetNoGINV();
+}
+
 void MipsTargetAsmStreamer::emitDirectiveSetAt() {
   OS << "\t.set\tat\n";
   MipsTargetStreamer::emitDirectiveSetAt();
@@ -738,6 +752,14 @@
   OS << "\t.module\tnovirt\n";
 }
 
+void MipsTargetAsmStreamer::emitDirectiveModuleGINV() {
+  OS << "\t.module\tginv\n";
+}
+
+void MipsTargetAsmStreamer::emitDirectiveModuleNoGINV() {
+  OS << "\t.module\tnoginv\n";
+}
+
 // This part is for ELF object output.
 MipsTargetELFStreamer::MipsTargetELFStreamer(MCStreamer &S,
                                              const MCSubtargetInfo &STI)
Index: llvm/trunk/lib/Target/Mips/MicroMips32r6InstrFormats.td
===================================================================
--- llvm/trunk/lib/Target/Mips/MicroMips32r6InstrFormats.td
+++ llvm/trunk/lib/Target/Mips/MicroMips32r6InstrFormats.td
@@ -889,6 +889,23 @@
   let Inst{5-0}   = opcode;
 }
 
+class POOL32A_GINV_FM_MMR6<string instr_asm, bits<2> ginv>
+    : MMR6Arch<instr_asm>, MipsR6Inst {
+  bits<5> rs;
+  bits<2> type;
+
+  bits<32> Inst;
+
+  let Inst{31-26} = 0x0;
+  let Inst{25-21} = 0x0;
+  let Inst{20-16} = rs;
+  let Inst{15-13} = 0b011;
+  let Inst{12-11} = ginv;
+  let Inst{10-9}  = type;
+  let Inst{8-6}   = 0b101;
+  let Inst{5-0}   = 0b111100;
+}
+
 class POOL32F_MFTC1_FM_MMR6<string instr_asm, bits<8> funct>
     : MMR6Arch<instr_asm> {
   bits<5> rt;
Index: llvm/trunk/lib/Target/Mips/MicroMips32r6InstrInfo.td
===================================================================
--- llvm/trunk/lib/Target/Mips/MicroMips32r6InstrInfo.td
+++ llvm/trunk/lib/Target/Mips/MicroMips32r6InstrInfo.td
@@ -106,6 +106,8 @@
 class ERET_MMR6_ENC : POOL32A_ERET_FM_MMR6<"eret", 0x3cd>;
 class DERET_MMR6_ENC : POOL32A_ERET_FM_MMR6<"eret", 0b1110001101>;
 class ERETNC_MMR6_ENC : ERETNC_FM_MMR6<"eretnc">;
+class GINVI_MMR6_ENC : POOL32A_GINV_FM_MMR6<"ginvi", 0b00>;
+class GINVT_MMR6_ENC : POOL32A_GINV_FM_MMR6<"ginvt", 0b10>;
 class JALRC16_MMR6_ENC : POOL16C_JALRC_FM_MM16R6<0xb>;
 class JIALC_MMR6_ENC : JMP_IDX_COMPACT_FM<0b100000>;
 class JIC_MMR6_ENC   : JMP_IDX_COMPACT_FM<0b101000>;
@@ -826,6 +828,25 @@
 class SDC2_MMR6_DESC : SDC2_SWC2_MMR6_DESC_BASE<"sdc2", II_SDC2>;
 class SWC2_MMR6_DESC : SDC2_SWC2_MMR6_DESC_BASE<"swc2", II_SWC2>;
 
+class GINV_MMR6_DESC_BASE<string opstr,
+                          RegisterOperand SrcRC, InstrItinClass Itin> {
+  dag InOperandList = (ins SrcRC:$rs, uimm2:$type);
+  dag OutOperandList = (outs);
+  string AsmString = !strconcat(opstr, "\t$rs, $type");
+  list<dag> Pattern = [];
+  Format f = FrmFR;
+  string BaseOpcode = opstr;
+  InstrItinClass Itinerary = Itin;
+}
+
+class GINVI_MMR6_DESC : GINV_MMR6_DESC_BASE<"ginvi", GPR32Opnd,
+                                            II_GINVI> {
+  dag InOperandList = (ins GPR32Opnd:$rs);
+  string AsmString = "ginvi\t$rs";
+}
+class GINVT_MMR6_DESC : GINV_MMR6_DESC_BASE<"ginvt", GPR32Opnd,
+                                            II_GINVT>;
+
 /// Floating Point Instructions
 class FARITH_MMR6_DESC_BASE<string instr_asm, RegisterOperand RC,
                             InstrItinClass Itin, bit isComm,
@@ -1346,6 +1367,10 @@
 def DERET_MMR6 : StdMMR6Rel, DERET_MMR6_DESC, DERET_MMR6_ENC, ISA_MICROMIPS32R6;
 def ERETNC_MMR6 : R6MMR6Rel, ERETNC_MMR6_DESC, ERETNC_MMR6_ENC,
                   ISA_MICROMIPS32R6;
+def GINVI_MMR6 : R6MMR6Rel, GINVI_MMR6_ENC, GINVI_MMR6_DESC,
+                 ISA_MICROMIPS32R6, ASE_GINV;
+def GINVT_MMR6 : R6MMR6Rel, GINVT_MMR6_ENC, GINVT_MMR6_DESC,
+                 ISA_MICROMIPS32R6, ASE_GINV;
 def JALRC16_MMR6 : R6MMR6Rel, JALRC16_MMR6_DESC, JALRC16_MMR6_ENC,
                    ISA_MICROMIPS32R6;
 def JIALC_MMR6 : R6MMR6Rel, JIALC_MMR6_ENC, JIALC_MMR6_DESC, ISA_MICROMIPS32R6;
Index: llvm/trunk/lib/Target/Mips/Mips.td
===================================================================
--- llvm/trunk/lib/Target/Mips/Mips.td
+++ llvm/trunk/lib/Target/Mips/Mips.td
@@ -182,6 +182,9 @@
 def FeatureVirt : SubtargetFeature<"virt", "HasVirt", "true",
                                    "Mips Virtualization ASE">;
 
+def FeatureGINV : SubtargetFeature<"ginv", "HasGINV", "true",
+                                   "Mips Global Invalidate ASE">;
+
 def FeatureMicroMips  : SubtargetFeature<"micromips", "InMicroMipsMode", "true",
                                          "microMips mode">;
 
Index: llvm/trunk/lib/Target/Mips/Mips32r6InstrFormats.td
===================================================================
--- llvm/trunk/lib/Target/Mips/Mips32r6InstrFormats.td
+++ llvm/trunk/lib/Target/Mips/Mips32r6InstrFormats.td
@@ -591,3 +591,15 @@
 
   string DecoderMethod = "DecodeCRC";
 }
+
+class SPECIAL3_GINV<bits<2> ginv> : MipsR6Inst {
+  bits<5> rs;
+  bits<2> type_;
+
+  let Inst{31-26} = OPGROUP_SPECIAL3.Value;
+  let Inst{25-21} = rs;
+  let Inst{20-10} = 0x0;
+  let Inst{9-8}   = type_;
+  let Inst{7-6}   = ginv;
+  let Inst{5-0}   = 0b111101;
+}
Index: llvm/trunk/lib/Target/Mips/Mips32r6InstrInfo.td
===================================================================
--- llvm/trunk/lib/Target/Mips/Mips32r6InstrInfo.td
+++ llvm/trunk/lib/Target/Mips/Mips32r6InstrInfo.td
@@ -197,6 +197,9 @@
 class CRC32CH_ENC : SPECIAL3_2R_SZ_CRC<1,1>;
 class CRC32CW_ENC : SPECIAL3_2R_SZ_CRC<2,1>;
 
+class GINVI_ENC : SPECIAL3_GINV<0>;
+class GINVT_ENC : SPECIAL3_GINV<2>;
+
 //===----------------------------------------------------------------------===//
 //
 // Instruction Multiclasses
@@ -827,6 +830,22 @@
 class CRC32CH_DESC : CRC_DESC_BASE<"crc32ch", GPR32Opnd, II_CRC32CH>;
 class CRC32CW_DESC : CRC_DESC_BASE<"crc32cw", GPR32Opnd, II_CRC32CW>;
 
+class GINV_DESC_BASE<string instr_asm, RegisterOperand GPROpnd,
+                     InstrItinClass itin> : MipsR6Arch<instr_asm> {
+  dag OutOperandList = (outs);
+  dag InOperandList = (ins GPROpnd:$rs, uimm2:$type_);
+  string AsmString = !strconcat(instr_asm, "\t$rs, $type_");
+  list<dag> Pattern = [];
+  InstrItinClass Itinerary = itin;
+  bit hasSideEffects = 1;
+}
+
+class GINVI_DESC : GINV_DESC_BASE<"ginvi", GPR32Opnd, II_GINVI> {
+  dag InOperandList = (ins GPR32Opnd:$rs);
+  string AsmString = "ginvi\t$rs";
+}
+class GINVT_DESC : GINV_DESC_BASE<"ginvt", GPR32Opnd, II_GINVT>;
+
 //===----------------------------------------------------------------------===//
 //
 // Instruction Definitions
@@ -955,6 +974,11 @@
   def CRC32CW : R6MMR6Rel, CRC32CW_ENC, CRC32CW_DESC, ISA_MIPS32R6, ASE_CRC;
 }
 
+let AdditionalPredicates = [NotInMicroMips] in {
+  def GINVI : R6MMR6Rel, GINVI_ENC, GINVI_DESC, ISA_MIPS32R6, ASE_GINV;
+  def GINVT : R6MMR6Rel, GINVT_ENC, GINVT_DESC, ISA_MIPS32R6, ASE_GINV;
+}
+
 //===----------------------------------------------------------------------===//
 //
 // Instruction Aliases
Index: llvm/trunk/lib/Target/Mips/MipsInstrInfo.td
===================================================================
--- llvm/trunk/lib/Target/Mips/MipsInstrInfo.td
+++ llvm/trunk/lib/Target/Mips/MipsInstrInfo.td
@@ -252,6 +252,8 @@
                AssemblerPredicate<"FeatureCRC">;
 def HasVirt  : Predicate<"Subtarget->hasVirt()">,
                AssemblerPredicate<"FeatureVirt">;
+def HasGINV  : Predicate<"Subtarget->hasGINV()">,
+               AssemblerPredicate<"FeatureGINV">;
 // TODO: Add support for FPOpFusion::Standard
 def AllowFPOpFusion : Predicate<"TM.Options.AllowFPOpFusion =="
                                 " FPOpFusion::Fast">;
@@ -468,6 +470,10 @@
   list <Predicate> ASEPredicate = [HasVirt];
 }
 
+class ASE_GINV {
+  list <Predicate> ASEPredicate = [HasGINV];
+}
+
 // 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: llvm/trunk/lib/Target/Mips/MipsSchedule.td
===================================================================
--- llvm/trunk/lib/Target/Mips/MipsSchedule.td
+++ llvm/trunk/lib/Target/Mips/MipsSchedule.td
@@ -130,6 +130,8 @@
 def II_EXT              : InstrItinClass; // Any EXT instruction
 def II_FLOOR            : InstrItinClass;
 def II_FORK             : InstrItinClass;
+def II_GINVI            : InstrItinClass;
+def II_GINVT            : InstrItinClass;
 def II_HYPCALL          : InstrItinClass;
 def II_INS              : InstrItinClass; // Any INS instruction
 def II_IndirectBranchPseudo : InstrItinClass; // Indirect branch pseudo.
@@ -728,5 +730,7 @@
   InstrItinData<II_TLBWI           , [InstrStage<2,  [ALU]>]>,
   InstrItinData<II_TLBWR           , [InstrStage<2,  [ALU]>]>,
   InstrItinData<II_DMFGC0          , [InstrStage<2,  [ALU]>]>,
-  InstrItinData<II_DMTGC0          , [InstrStage<2,  [ALU]>]>
+  InstrItinData<II_DMTGC0          , [InstrStage<2,  [ALU]>]>,
+  InstrItinData<II_GINVI           , [InstrStage<1,  [ALU]>]>,
+  InstrItinData<II_GINVT           , [InstrStage<1,  [ALU]>]>
 ]>;
Index: llvm/trunk/lib/Target/Mips/MipsSubtarget.h
===================================================================
--- llvm/trunk/lib/Target/Mips/MipsSubtarget.h
+++ llvm/trunk/lib/Target/Mips/MipsSubtarget.h
@@ -168,6 +168,9 @@
   // HasVirt -- supports Virtualization ASE
   bool HasVirt;
 
+  // HasGINV -- supports R6 Global INValidate ASE
+  bool HasGINV;
+
   // Use hazard variants of the jump register instructions for indirect
   // function calls and jump tables.
   bool UseIndirectJumpsHazard;
@@ -294,6 +297,7 @@
   bool hasMT() const { return HasMT; }
   bool hasCRC() const { return HasCRC; }
   bool hasVirt() const { return HasVirt; }
+  bool hasGINV() const { return HasGINV; }
   bool useIndirectJumpsHazard() const {
     return UseIndirectJumpsHazard && hasMips32r2();
   }
Index: llvm/trunk/lib/Target/Mips/MipsSubtarget.cpp
===================================================================
--- llvm/trunk/lib/Target/Mips/MipsSubtarget.cpp
+++ llvm/trunk/lib/Target/Mips/MipsSubtarget.cpp
@@ -79,7 +79,7 @@
       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), UseIndirectJumpsHazard(false),
+      HasVirt(false), HasGINV(false), UseIndirectJumpsHazard(false),
       StackAlignOverride(StackAlignOverride),
       TM(TM), TargetTriple(TT), TSInfo(),
       InstrInfo(
Index: llvm/trunk/lib/Target/Mips/MipsTargetStreamer.h
===================================================================
--- llvm/trunk/lib/Target/Mips/MipsTargetStreamer.h
+++ llvm/trunk/lib/Target/Mips/MipsTargetStreamer.h
@@ -46,6 +46,8 @@
   virtual void emitDirectiveSetNoCRC();
   virtual void emitDirectiveSetVirt();
   virtual void emitDirectiveSetNoVirt();
+  virtual void emitDirectiveSetGINV();
+  virtual void emitDirectiveSetNoGINV();
   virtual void emitDirectiveSetAt();
   virtual void emitDirectiveSetAtWithArg(unsigned RegNo);
   virtual void emitDirectiveSetNoAt();
@@ -111,6 +113,8 @@
   virtual void emitDirectiveModuleNoCRC();
   virtual void emitDirectiveModuleVirt();
   virtual void emitDirectiveModuleNoVirt();
+  virtual void emitDirectiveModuleGINV();
+  virtual void emitDirectiveModuleNoGINV();
 
   void emitR(unsigned Opcode, unsigned Reg0, SMLoc IDLoc,
              const MCSubtargetInfo *STI);
@@ -225,6 +229,8 @@
   void emitDirectiveSetNoCRC() override;
   void emitDirectiveSetVirt() override;
   void emitDirectiveSetNoVirt() override;
+  void emitDirectiveSetGINV() override;
+  void emitDirectiveSetNoGINV() override;
   void emitDirectiveSetAt() override;
   void emitDirectiveSetAtWithArg(unsigned RegNo) override;
   void emitDirectiveSetNoAt() override;
@@ -294,6 +300,8 @@
   void emitDirectiveModuleNoCRC() override;
   void emitDirectiveModuleVirt() override;
   void emitDirectiveModuleNoVirt() override;
+  void emitDirectiveModuleGINV() override;
+  void emitDirectiveModuleNoGINV() override;
   void emitDirectiveSetFp(MipsABIFlagsSection::FpABIKind Value) override;
   void emitDirectiveSetOddSPReg() override;
   void emitDirectiveSetNoOddSPReg() override;
Index: llvm/trunk/test/MC/Disassembler/Mips/ginv/valid-el.txt
===================================================================
--- llvm/trunk/test/MC/Disassembler/Mips/ginv/valid-el.txt
+++ llvm/trunk/test/MC/Disassembler/Mips/ginv/valid-el.txt
@@ -0,0 +1,5 @@
+# RUN: llvm-mc --disassemble %s -triple=mipsel-unknown-linux-gnu \
+# RUN:   -mcpu=mips32r6 -mattr=+ginv | FileCheck %s
+
+0x3d 0x02 0x40 0x7c  # CHECK: ginvi $2
+0xbd 0x02 0x40 0x7c  # CHECK: ginvt $2, 2
Index: llvm/trunk/test/MC/Disassembler/Mips/ginv/valid-micromips-el.txt
===================================================================
--- llvm/trunk/test/MC/Disassembler/Mips/ginv/valid-micromips-el.txt
+++ llvm/trunk/test/MC/Disassembler/Mips/ginv/valid-micromips-el.txt
@@ -0,0 +1,5 @@
+# RUN: llvm-mc --disassemble %s -triple=mipsel-unknown-linux-gnu \
+# RUN:   -mcpu=mips32r6 -mattr=+micromips,+ginv | FileCheck %s
+
+0x02 0x00 0x7c 0x65  # CHECK: ginvi $2
+0x02 0x00 0x7c 0x75  # CHECK: ginvt $2, 2
Index: llvm/trunk/test/MC/Disassembler/Mips/ginv/valid-micromips.txt
===================================================================
--- llvm/trunk/test/MC/Disassembler/Mips/ginv/valid-micromips.txt
+++ llvm/trunk/test/MC/Disassembler/Mips/ginv/valid-micromips.txt
@@ -0,0 +1,5 @@
+# RUN: llvm-mc --disassemble %s -triple=mips-unknown-linux-gnu \
+# RUN:   -mcpu=mips32r6 -mattr=+micromips,+ginv | FileCheck %s
+
+0x00 0x02 0x65 0x7c  # CHECK: ginvi $2
+0x00 0x02 0x75 0x7c  # CHECK: ginvt $2, 2
Index: llvm/trunk/test/MC/Disassembler/Mips/ginv/valid.txt
===================================================================
--- llvm/trunk/test/MC/Disassembler/Mips/ginv/valid.txt
+++ llvm/trunk/test/MC/Disassembler/Mips/ginv/valid.txt
@@ -0,0 +1,5 @@
+# RUN: llvm-mc --disassemble %s -triple=mips-unknown-linux-gnu \
+# RUN:   -mcpu=mips32r6 -mattr=+ginv | FileCheck %s
+
+0x7c 0x40 0x02 0x3d  # CHECK: ginvi $2
+0x7c 0x40 0x02 0xbd  # CHECK: ginvt $2, 2
Index: llvm/trunk/test/MC/Mips/ginv/invalid.s
===================================================================
--- llvm/trunk/test/MC/Mips/ginv/invalid.s
+++ llvm/trunk/test/MC/Mips/ginv/invalid.s
@@ -0,0 +1,23 @@
+# Instructions that are invalid.
+#
+# RUN: not llvm-mc %s -arch=mips -mcpu=mips32r6 -mattr=+ginv 2>%t1
+# RUN: FileCheck %s < %t1
+# RUN: not llvm-mc %s -arch=mips64 -mcpu=mips64r6 -mattr=+ginv 2>%t1
+# RUN: FileCheck %s < %t1
+# RUN: not llvm-mc %s -arch=mips -mcpu=mips32r6 \
+# RUN:     -mattr=+micromips,+ginv 2>%t1
+# RUN: FileCheck %s < %t1
+
+  ginvi            # CHECK: :[[@LINE]]:3: error: too few operands for instruction
+  ginvi 0          # CHECK: :[[@LINE]]:9: error: invalid operand for instruction
+  ginvi $4, 0      # CHECK: :[[@LINE]]:13: error: invalid operand for instruction
+  ginvi $4, $5     # CHECK: :[[@LINE]]:13: error: invalid operand for instruction
+  ginvi 0($4)      # CHECK: :[[@LINE]]:10: error: unexpected token in argument list
+  ginvt            # CHECK: :[[@LINE]]:3: error: too few operands for instruction
+  ginvt 0          # CHECK: :[[@LINE]]:9: error: invalid operand for instruction
+  ginvt $4         # CHECK: :[[@LINE]]:3: error: too few operands for instruction
+  ginvt $4, $5     # CHECK: :[[@LINE]]:13: error: expected 2-bit unsigned immediate
+  ginvt $4, 4      # CHECK: :[[@LINE]]:13: error: expected 2-bit unsigned immediate
+  ginvt $4, -1     # CHECK: :[[@LINE]]:13: error: expected 2-bit unsigned immediate
+  ginvt $4, 0, 1   # CHECK: :[[@LINE]]:16: error: invalid operand for instruction
+  ginvt $4, 0($4)  # CHECK: :[[@LINE]]:14: error: invalid operand for instruction
Index: llvm/trunk/test/MC/Mips/ginv/module-ginv.s
===================================================================
--- llvm/trunk/test/MC/Mips/ginv/module-ginv.s
+++ llvm/trunk/test/MC/Mips/ginv/module-ginv.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 ginv
+
+# Check if the MIPS.abiflags section was correctly emitted:
+# CHECK-OBJ: MIPS ABI Flags {
+# CHECK-OBJ:   ASEs [ (0x20000)
+# CHECK-OBJ:     GINV (0x20000)
+# CHECK-OBJ: }
+
+  .module ginv
+  ginvi $4
+
+# 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: llvm/trunk/test/MC/Mips/ginv/module-noginv.s
===================================================================
--- llvm/trunk/test/MC/Mips/ginv/module-noginv.s
+++ llvm/trunk/test/MC/Mips/ginv/module-noginv.s
@@ -0,0 +1,21 @@
+# RUN: llvm-mc %s -arch=mips -mcpu=mips32r6 -mattr=+ginv | \
+# RUN:   FileCheck %s -check-prefix=CHECK-ASM
+#
+# RUN: llvm-mc %s -arch=mips -mcpu=mips32r6 -filetype=obj -o - -mattr=+ginv | \
+# RUN:   llvm-readobj -mips-abi-flags - | \
+# RUN:   FileCheck %s -check-prefix=CHECK-OBJ
+
+# CHECK-ASM: .module noginv
+
+# Check that MIPS.abiflags has no GINV flag.
+# CHECK-OBJ: MIPS ABI Flags {
+# CHECK-OBJ:   ASEs [ (0x0)
+# CHECK-OBJ-NOT:   ASEs [ (0x20000)
+# CHECK-OBJ-NOT:     GINV (0x20000)
+# CHECK-OBJ: }
+
+  .module noginv
+
+# 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: llvm/trunk/test/MC/Mips/ginv/set-ginv-directive.s
===================================================================
--- llvm/trunk/test/MC/Mips/ginv/set-ginv-directive.s
+++ llvm/trunk/test/MC/Mips/ginv/set-ginv-directive.s
@@ -0,0 +1,7 @@
+# RUN: llvm-mc %s -triple=mips-unknown-linux-gnu -show-encoding \
+# RUN:   -mcpu=mips32r6 -mattr=+ginv | FileCheck %s
+# RUN: llvm-mc %s -triple=mips64-unknown-linux-gnu -show-encoding \
+# RUN:   -mcpu=mips64r6 -mattr=+ginv | FileCheck %s
+
+  .set ginv
+  ginvi $4  # CHECK: ginvi $4  # encoding: [0x7c,0x80,0x00,0x3d]
Index: llvm/trunk/test/MC/Mips/ginv/set-noginv-directive.s
===================================================================
--- llvm/trunk/test/MC/Mips/ginv/set-noginv-directive.s
+++ llvm/trunk/test/MC/Mips/ginv/set-noginv-directive.s
@@ -0,0 +1,9 @@
+# RUN: not llvm-mc %s -triple=mips-unknown-linux-gnu -show-encoding \
+# RUN:     -mcpu=mips32r6 -mattr=+ginv 2>%t1
+# RUN: FileCheck %s < %t1
+# RUN: not llvm-mc %s -triple=mips64-unknown-linux-gnu -show-encoding \
+# RUN:     -mcpu=mips64r6 -mattr=+ginv 2>%t1
+# RUN: FileCheck %s < %t1
+
+  .set noginv
+  ginvi $4, 2  # CHECK: instruction requires a CPU feature not currently enabled
Index: llvm/trunk/test/MC/Mips/ginv/valid-micromips.s
===================================================================
--- llvm/trunk/test/MC/Mips/ginv/valid-micromips.s
+++ llvm/trunk/test/MC/Mips/ginv/valid-micromips.s
@@ -0,0 +1,5 @@
+# RUN: llvm-mc %s -triple=mips-unknown-linux-gnu -show-encoding \
+# RUN:   -mcpu=mips32r6 -mattr=+micromips,+ginv | FileCheck %s
+
+  ginvi $4           # CHECK: ginvi $4         # encoding: [0x00,0x04,0x61,0x7c]
+  ginvt $4, 2        # CHECK: ginvt $4, 2      # encoding: [0x00,0x04,0x75,0x7c]
Index: llvm/trunk/test/MC/Mips/ginv/valid.s
===================================================================
--- llvm/trunk/test/MC/Mips/ginv/valid.s
+++ llvm/trunk/test/MC/Mips/ginv/valid.s
@@ -0,0 +1,7 @@
+# RUN: llvm-mc %s -triple=mips-unknown-linux-gnu -show-encoding \
+# RUN:   -mcpu=mips32r6 -mattr=+ginv | FileCheck %s
+# RUN: llvm-mc %s -triple=mips64-unknown-linux-gnu -show-encoding \
+# RUN:   -mcpu=mips64r6 -mattr=+ginv | FileCheck %s
+
+  ginvi $4           # CHECK: ginvi $4         # encoding: [0x7c,0x80,0x00,0x3d]
+  ginvt $4, 2        # CHECK: ginvt $4, 2      # encoding: [0x7c,0x80,0x02,0xbd]
Index: llvm/trunk/tools/llvm-readobj/ELFDumper.cpp
===================================================================
--- llvm/trunk/tools/llvm-readobj/ELFDumper.cpp
+++ llvm/trunk/tools/llvm-readobj/ELFDumper.cpp
@@ -2233,6 +2233,7 @@
   {"microMIPS",          Mips::AFL_ASE_MICROMIPS},
   {"XPA",                Mips::AFL_ASE_XPA},
   {"CRC",                Mips::AFL_ASE_CRC},
+  {"GINV",               Mips::AFL_ASE_GINV},
 };
 
 static const EnumEntry<unsigned> ElfMipsFpABIType[] = {