diff options
Diffstat (limited to 'contrib/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp')
| -rw-r--r-- | contrib/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp | 813 | 
1 files changed, 532 insertions, 281 deletions
diff --git a/contrib/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp b/contrib/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp index f36a4317b1b9..2acf701b43cb 100644 --- a/contrib/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp +++ b/contrib/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp @@ -146,10 +146,15 @@ class MipsAsmParser : public MCTargetAsmParser {    /// If true, then CpSaveLocation is a register, otherwise it's an offset.    bool     CpSaveLocationIsRegister; +  // Map of register aliases created via the .set directive. +  StringMap<AsmToken> RegisterSets; +    // Print a warning along with its fix-it message at the given range.    void printWarningWithFixIt(const Twine &Msg, const Twine &FixMsg,                               SMRange Range, bool ShowColors = true); +  void ConvertXWPOperands(MCInst &Inst, const OperandVector &Operands); +  #define GET_ASSEMBLER_HEADER  #include "MipsGenAsmMatcher.inc" @@ -182,12 +187,14 @@ class MipsAsmParser : public MCTargetAsmParser {    matchAnyRegisterNameWithoutDollar(OperandVector &Operands,                                      StringRef Identifier, SMLoc S);    OperandMatchResultTy matchAnyRegisterWithoutDollar(OperandVector &Operands, +                                                     const AsmToken &Token, +                                                     SMLoc S); +  OperandMatchResultTy matchAnyRegisterWithoutDollar(OperandVector &Operands,                                                       SMLoc S);    OperandMatchResultTy parseAnyRegister(OperandVector &Operands);    OperandMatchResultTy parseImm(OperandVector &Operands);    OperandMatchResultTy parseJumpTarget(OperandVector &Operands);    OperandMatchResultTy parseInvNum(OperandVector &Operands); -  OperandMatchResultTy parseRegisterPair(OperandVector &Operands);    OperandMatchResultTy parseMovePRegPair(OperandVector &Operands);    OperandMatchResultTy parseRegisterList(OperandVector &Operands); @@ -235,13 +242,7 @@ class MipsAsmParser : public MCTargetAsmParser {                                    const MCSubtargetInfo *STI);    void expandMemInst(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, -                     const MCSubtargetInfo *STI, bool IsLoad, bool IsImmOpnd); - -  void expandLoadInst(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, -                      const MCSubtargetInfo *STI, bool IsImmOpnd); - -  void expandStoreInst(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, -                       const MCSubtargetInfo *STI, bool IsImmOpnd); +                     const MCSubtargetInfo *STI, bool IsLoad);    bool expandLoadStoreMultiple(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out,                                 const MCSubtargetInfo *STI); @@ -255,9 +256,9 @@ class MipsAsmParser : public MCTargetAsmParser {    bool expandCondBranches(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out,                            const MCSubtargetInfo *STI); -  bool expandDiv(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, -                 const MCSubtargetInfo *STI, const bool IsMips64, -                 const bool Signed); +  bool expandDivRem(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, +                    const MCSubtargetInfo *STI, const bool IsMips64, +                    const bool Signed);    bool expandTrunc(MCInst &Inst, bool IsDouble, bool Is64FPU, SMLoc IDLoc,                     MCStreamer &Out, const MCSubtargetInfo *STI); @@ -348,10 +349,12 @@ class MipsAsmParser : public MCTargetAsmParser {    bool parseSetHardFloatDirective();    bool parseSetMtDirective();    bool parseSetNoMtDirective(); +  bool parseSetNoCRCDirective(); +  bool parseSetNoVirtDirective(); +  bool parseSetNoGINVDirective();    bool parseSetAssignment(); -  bool parseDataDirective(unsigned Size, SMLoc L);    bool parseDirectiveGpWord();    bool parseDirectiveGpDWord();    bool parseDirectiveDtpRelWord(); @@ -466,6 +469,7 @@ public:      Match_RequiresSameSrcAndDst,      Match_NoFCCRegisterForCurrentISA,      Match_NonZeroOperandForSync, +    Match_NonZeroOperandForMTCX,      Match_RequiresPosSizeRange0_32,      Match_RequiresPosSizeRange33_64,      Match_RequiresPosSizeUImm6, @@ -482,6 +486,9 @@ public:      MCAsmParserExtension::Initialize(parser);      parser.addAliasForDirective(".asciiz", ".asciz"); +    parser.addAliasForDirective(".hword", ".2byte"); +    parser.addAliasForDirective(".word", ".4byte"); +    parser.addAliasForDirective(".dword", ".8byte");      // Initialize the set of available features.      setAvailableFeatures(ComputeAvailableFeatures(getSTI().getFeatureBits())); @@ -507,14 +514,13 @@ public:      CpRestoreOffset = -1;      const Triple &TheTriple = sti.getTargetTriple(); -    if ((TheTriple.getArch() == Triple::mips) || -        (TheTriple.getArch() == Triple::mips64)) -      IsLittleEndian = false; -    else -      IsLittleEndian = true; +    IsLittleEndian = TheTriple.isLittleEndian();      if (getSTI().getCPU() == "mips64r6" && inMicroMipsMode())        report_fatal_error("microMIPS64R6 is not supported", false); + +    if (!isABI_O32() && inMicroMipsMode()) +      report_fatal_error("microMIPS64 is not supported", false);    }    /// True if all of $fcc0 - $fcc7 exist for the current ISA. @@ -643,6 +649,18 @@ public:      return getSTI().getFeatureBits()[Mips::FeatureMT];    } +  bool hasCRC() const { +    return getSTI().getFeatureBits()[Mips::FeatureCRC]; +  } + +  bool hasVirt() const { +    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); @@ -1297,6 +1315,20 @@ public:      return IsReloc && isShiftedInt<Bits, ShiftAmount>(Res.getConstant());    } +  bool isMemWithPtrSizeOffset() const { +    if (!isMem()) +      return false; +    if (!getMemBase()->isGPRAsmReg()) +      return false; +    const unsigned PtrBits = AsmParser.getABI().ArePtrs64bit() ? 64 : 32; +    if (isa<MCTargetExpr>(getMemOff()) || +        (isConstantMemOff() && isIntN(PtrBits, getConstantMemOff()))) +      return true; +    MCValue Res; +    bool IsReloc = getMemOff()->evaluateAsRelocatable(Res, nullptr, nullptr); +    return IsReloc && isIntN(PtrBits, Res.getConstant()); +  } +    bool isMemWithGRPMM16Base() const {      return isMem() && getMemBase()->isMM16AsmReg();    } @@ -1326,9 +1358,11 @@ public:    template <unsigned Bits, unsigned ShiftLeftAmount>    bool isScaledSImm() const { -    if (isConstantImm() && isShiftedInt<Bits, ShiftLeftAmount>(getConstantImm())) +    if (isConstantImm() && +        isShiftedInt<Bits, ShiftLeftAmount>(getConstantImm()))        return true; -    // Operand can also be a symbol or symbol plus offset in case of relocations. +    // Operand can also be a symbol or symbol plus +    // offset in case of relocations.      if (Kind != k_Immediate)        return false;      MCValue Res; @@ -1405,10 +1439,6 @@ public:      return StringRef(Tok.Data, Tok.Length);    } -  bool isRegPair() const { -    return Kind == k_RegPair && RegIdx.Index <= 30; -  } -    unsigned getReg() const override {      // As a special case until we sort out the definition of div/divu, accept      // $0/$zero here so that MCK_ZERO works correctly. @@ -1471,7 +1501,7 @@ public:    static std::unique_ptr<MipsOperand>    createNumericReg(unsigned Index, StringRef Str, const MCRegisterInfo *RegInfo,                     SMLoc S, SMLoc E, MipsAsmParser &Parser) { -    DEBUG(dbgs() << "createNumericReg(" << Index << ", ...)\n"); +    LLVM_DEBUG(dbgs() << "createNumericReg(" << Index << ", ...)\n");      return CreateReg(Index, Str, RegKind_Numeric, RegInfo, S, E, Parser);    } @@ -2034,7 +2064,8 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,      // FIXME: Add support for forward-declared local symbols.      // FIXME: Add expansion for when the LargeGOT option is enabled.      if (JalSym->isInSection() || JalSym->isTemporary() || -        (JalSym->isELF() && cast<MCSymbolELF>(JalSym)->getBinding() == ELF::STB_LOCAL)) { +        (JalSym->isELF() && +         cast<MCSymbolELF>(JalSym)->getBinding() == ELF::STB_LOCAL)) {        if (isABI_O32()) {          // If it's a local symbol and the O32 ABI is being used, we expand to:          //  lw $25, 0($gp) @@ -2102,10 +2133,10 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,            (OpInfo.OperandType == MCOI::OPERAND_UNKNOWN)) {          MCOperand &Op = Inst.getOperand(i);          if (Op.isImm()) { -          int MemOffset = Op.getImm(); +          int64_t MemOffset = Op.getImm();            if (MemOffset < -32768 || MemOffset > 32767) {              // Offset can't exceed 16bit value. -            expandMemInst(Inst, IDLoc, Out, STI, MCID.mayLoad(), true); +            expandMemInst(Inst, IDLoc, Out, STI, MCID.mayLoad());              return getParser().hasPendingError();            }          } else if (Op.isExpr()) { @@ -2115,11 +2146,11 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,                  static_cast<const MCSymbolRefExpr *>(Expr);              if (SR->getKind() == MCSymbolRefExpr::VK_None) {                // Expand symbol. -              expandMemInst(Inst, IDLoc, Out, STI, MCID.mayLoad(), false); +              expandMemInst(Inst, IDLoc, Out, STI, MCID.mayLoad());                return getParser().hasPendingError();              }            } else if (!isEvaluated(Expr)) { -            expandMemInst(Inst, IDLoc, Out, STI, MCID.mayLoad(), false); +            expandMemInst(Inst, IDLoc, Out, STI, MCID.mayLoad());              return getParser().hasPendingError();            }          } @@ -2128,7 +2159,7 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,    }   // if load/store    if (inMicroMipsMode()) { -    if (MCID.mayLoad()) { +    if (MCID.mayLoad() && Inst.getOpcode() != Mips::LWP_MM) {        // Try to create 16-bit GP relative load instruction.        for (unsigned i = 0; i < MCID.getNumOperands(); i++) {          const MCOperandInfo &OpInfo = MCID.OpInfo[i]; @@ -2245,13 +2276,18 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,            return Error(IDLoc, "immediate operand value out of range");          break;        case Mips::ADDIUPC_MM: -        MCOperand Opnd = Inst.getOperand(1); +        Opnd = Inst.getOperand(1);          if (!Opnd.isImm())            return Error(IDLoc, "expected immediate operand kind"); -        int Imm = Opnd.getImm(); +        Imm = Opnd.getImm();          if ((Imm % 4 != 0) || !isInt<25>(Imm))            return Error(IDLoc, "immediate operand value out of range");          break; +      case Mips::LWP_MM: +      case Mips::SWP_MM: +        if (Inst.getOperand(0).getReg() == Mips::RA) +          return Error(IDLoc, "invalid operand for instruction"); +        break;      }    } @@ -2392,20 +2428,28 @@ MipsAsmParser::tryExpandInstruction(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out,      return expandCondBranches(Inst, IDLoc, Out, STI) ? MER_Fail : MER_Success;    case Mips::SDivMacro:    case Mips::SDivIMacro: -    return expandDiv(Inst, IDLoc, Out, STI, false, true) ? MER_Fail -                                                         : MER_Success; +  case Mips::SRemMacro: +  case Mips::SRemIMacro: +    return expandDivRem(Inst, IDLoc, Out, STI, false, true) ? MER_Fail +                                                            : MER_Success;    case Mips::DSDivMacro:    case Mips::DSDivIMacro: -    return expandDiv(Inst, IDLoc, Out, STI, true, true) ? MER_Fail -                                                        : MER_Success; +  case Mips::DSRemMacro: +  case Mips::DSRemIMacro: +    return expandDivRem(Inst, IDLoc, Out, STI, true, true) ? MER_Fail +                                                           : MER_Success;    case Mips::UDivMacro:    case Mips::UDivIMacro: -    return expandDiv(Inst, IDLoc, Out, STI, false, false) ? MER_Fail -                                                          : MER_Success; +  case Mips::URemMacro: +  case Mips::URemIMacro: +    return expandDivRem(Inst, IDLoc, Out, STI, false, false) ? MER_Fail +                                                             : MER_Success;    case Mips::DUDivMacro:    case Mips::DUDivIMacro: -    return expandDiv(Inst, IDLoc, Out, STI, true, false) ? MER_Fail -                                                         : MER_Success; +  case Mips::DURemMacro: +  case Mips::DURemIMacro: +    return expandDivRem(Inst, IDLoc, Out, STI, true, false) ? MER_Fail +                                                            : MER_Success;    case Mips::PseudoTRUNC_W_S:      return expandTrunc(Inst, false, false, IDLoc, Out, STI) ? MER_Fail                                                              : MER_Success; @@ -3522,21 +3566,17 @@ bool MipsAsmParser::expandBranchImm(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out,  }  void MipsAsmParser::expandMemInst(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, -                                  const MCSubtargetInfo *STI, bool IsLoad, -                                  bool IsImmOpnd) { -  if (IsLoad) { -    expandLoadInst(Inst, IDLoc, Out, STI, IsImmOpnd); -    return; -  } -  expandStoreInst(Inst, IDLoc, Out, STI, IsImmOpnd); -} +                                  const MCSubtargetInfo *STI, bool IsLoad) { +  const MCOperand &DstRegOp = Inst.getOperand(0); +  assert(DstRegOp.isReg() && "expected register operand kind"); +  const MCOperand &BaseRegOp = Inst.getOperand(1); +  assert(BaseRegOp.isReg() && "expected register operand kind"); +  const MCOperand &OffsetOp = Inst.getOperand(2); -void MipsAsmParser::expandLoadInst(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, -                                   const MCSubtargetInfo *STI, bool IsImmOpnd) {    MipsTargetStreamer &TOut = getTargetStreamer(); - -  unsigned DstReg = Inst.getOperand(0).getReg(); -  unsigned BaseReg = Inst.getOperand(1).getReg(); +  unsigned DstReg = DstRegOp.getReg(); +  unsigned BaseReg = BaseRegOp.getReg(); +  unsigned TmpReg = DstReg;    const MCInstrDesc &Desc = getInstDesc(Inst.getOpcode());    int16_t DstRegClass = Desc.OpInfo[0].RegClass; @@ -3545,75 +3585,51 @@ void MipsAsmParser::expandLoadInst(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out,    bool IsGPR = (DstRegClassID == Mips::GPR32RegClassID) ||                 (DstRegClassID == Mips::GPR64RegClassID); -  if (IsImmOpnd) { -    // Try to use DstReg as the temporary. -    if (IsGPR && (BaseReg != DstReg)) { -      TOut.emitLoadWithImmOffset(Inst.getOpcode(), DstReg, BaseReg, -                                 Inst.getOperand(2).getImm(), DstReg, IDLoc, -                                 STI); -      return; -    } - -    // At this point we need AT to perform the expansions and we exit if it is -    // not available. -    unsigned ATReg = getATReg(IDLoc); -    if (!ATReg) +  if (!IsLoad || !IsGPR || (BaseReg == DstReg)) { +    // At this point we need AT to perform the expansions +    // and we exit if it is not available. +    TmpReg = getATReg(IDLoc); +    if (!TmpReg)        return; - -    TOut.emitLoadWithImmOffset(Inst.getOpcode(), DstReg, BaseReg, -                               Inst.getOperand(2).getImm(), ATReg, IDLoc, STI); -    return;    } -  const MCExpr *ExprOffset = Inst.getOperand(2).getExpr(); -  MCOperand LoOperand = MCOperand::createExpr( -      MipsMCExpr::create(MipsMCExpr::MEK_LO, ExprOffset, getContext())); -  MCOperand HiOperand = MCOperand::createExpr( -      MipsMCExpr::create(MipsMCExpr::MEK_HI, ExprOffset, getContext())); +  if (OffsetOp.isImm()) { +    int64_t LoOffset = OffsetOp.getImm() & 0xffff; +    int64_t HiOffset = OffsetOp.getImm() & ~0xffff; -  // Try to use DstReg as the temporary. -  if (IsGPR && (BaseReg != DstReg)) { -    TOut.emitLoadWithSymOffset(Inst.getOpcode(), DstReg, BaseReg, HiOperand, -                               LoOperand, DstReg, IDLoc, STI); -    return; -  } +    // If msb of LoOffset is 1(negative number) we must increment +    // HiOffset to account for the sign-extension of the low part. +    if (LoOffset & 0x8000) +      HiOffset += 0x10000; -  // At this point we need AT to perform the expansions and we exit if it is -  // not available. -  unsigned ATReg = getATReg(IDLoc); -  if (!ATReg) -    return; +    bool IsLargeOffset = HiOffset != 0; -  TOut.emitLoadWithSymOffset(Inst.getOpcode(), DstReg, BaseReg, HiOperand, -                             LoOperand, ATReg, IDLoc, STI); -} - -void MipsAsmParser::expandStoreInst(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, -                                    const MCSubtargetInfo *STI, -                                    bool IsImmOpnd) { -  MipsTargetStreamer &TOut = getTargetStreamer(); - -  unsigned SrcReg = Inst.getOperand(0).getReg(); -  unsigned BaseReg = Inst.getOperand(1).getReg(); +    if (IsLargeOffset) { +      bool Is32BitImm = (HiOffset >> 32) == 0; +      if (loadImmediate(HiOffset, TmpReg, Mips::NoRegister, Is32BitImm, true, +                        IDLoc, Out, STI)) +        return; +    } -  if (IsImmOpnd) { -    TOut.emitStoreWithImmOffset(Inst.getOpcode(), SrcReg, BaseReg, -                                Inst.getOperand(2).getImm(), -                                [&]() { return getATReg(IDLoc); }, IDLoc, STI); -    return; +    if (BaseReg != Mips::ZERO && BaseReg != Mips::ZERO_64) +      TOut.emitRRR(isGP64bit() ? Mips::DADDu : Mips::ADDu, TmpReg, TmpReg, +                   BaseReg, IDLoc, STI); +    TOut.emitRRI(Inst.getOpcode(), DstReg, TmpReg, LoOffset, IDLoc, STI); +  } else { +    assert(OffsetOp.isExpr() && "expected expression operand kind"); +    const MCExpr *ExprOffset = OffsetOp.getExpr(); +    MCOperand LoOperand = MCOperand::createExpr( +        MipsMCExpr::create(MipsMCExpr::MEK_LO, ExprOffset, getContext())); +    MCOperand HiOperand = MCOperand::createExpr( +        MipsMCExpr::create(MipsMCExpr::MEK_HI, ExprOffset, getContext())); + +    if (IsLoad) +      TOut.emitLoadWithSymOffset(Inst.getOpcode(), DstReg, BaseReg, HiOperand, +                                 LoOperand, TmpReg, IDLoc, STI); +    else +      TOut.emitStoreWithSymOffset(Inst.getOpcode(), DstReg, BaseReg, HiOperand, +                                  LoOperand, TmpReg, IDLoc, STI);    } - -  unsigned ATReg = getATReg(IDLoc); -  if (!ATReg) -    return; - -  const MCExpr *ExprOffset = Inst.getOperand(2).getExpr(); -  MCOperand LoOperand = MCOperand::createExpr( -      MipsMCExpr::create(MipsMCExpr::MEK_LO, ExprOffset, getContext())); -  MCOperand HiOperand = MCOperand::createExpr( -      MipsMCExpr::create(MipsMCExpr::MEK_HI, ExprOffset, getContext())); -  TOut.emitStoreWithSymOffset(Inst.getOpcode(), SrcReg, BaseReg, HiOperand, -                              LoOperand, ATReg, IDLoc, STI);  }  bool MipsAsmParser::expandLoadStoreMultiple(MCInst &Inst, SMLoc IDLoc, @@ -3734,7 +3750,8 @@ bool MipsAsmParser::expandCondBranches(MCInst &Inst, SMLoc IDLoc,    case Mips::BLTUL:      AcceptsEquality = false;      ReverseOrderSLT = false; -    IsUnsigned = ((PseudoOpcode == Mips::BLTU) || (PseudoOpcode == Mips::BLTUL)); +    IsUnsigned = +        ((PseudoOpcode == Mips::BLTU) || (PseudoOpcode == Mips::BLTUL));      IsLikely = ((PseudoOpcode == Mips::BLTL) || (PseudoOpcode == Mips::BLTUL));      ZeroSrcOpcode = Mips::BGTZ;      ZeroTrgOpcode = Mips::BLTZ; @@ -3745,7 +3762,8 @@ bool MipsAsmParser::expandCondBranches(MCInst &Inst, SMLoc IDLoc,    case Mips::BLEUL:      AcceptsEquality = true;      ReverseOrderSLT = true; -    IsUnsigned = ((PseudoOpcode == Mips::BLEU) || (PseudoOpcode == Mips::BLEUL)); +    IsUnsigned = +        ((PseudoOpcode == Mips::BLEU) || (PseudoOpcode == Mips::BLEUL));      IsLikely = ((PseudoOpcode == Mips::BLEL) || (PseudoOpcode == Mips::BLEUL));      ZeroSrcOpcode = Mips::BGEZ;      ZeroTrgOpcode = Mips::BLEZ; @@ -3756,7 +3774,8 @@ bool MipsAsmParser::expandCondBranches(MCInst &Inst, SMLoc IDLoc,    case Mips::BGEUL:      AcceptsEquality = true;      ReverseOrderSLT = false; -    IsUnsigned = ((PseudoOpcode == Mips::BGEU) || (PseudoOpcode == Mips::BGEUL)); +    IsUnsigned = +        ((PseudoOpcode == Mips::BGEU) || (PseudoOpcode == Mips::BGEUL));      IsLikely = ((PseudoOpcode == Mips::BGEL) || (PseudoOpcode == Mips::BGEUL));      ZeroSrcOpcode = Mips::BLEZ;      ZeroTrgOpcode = Mips::BGEZ; @@ -3767,7 +3786,8 @@ bool MipsAsmParser::expandCondBranches(MCInst &Inst, SMLoc IDLoc,    case Mips::BGTUL:      AcceptsEquality = false;      ReverseOrderSLT = true; -    IsUnsigned = ((PseudoOpcode == Mips::BGTU) || (PseudoOpcode == Mips::BGTUL)); +    IsUnsigned = +        ((PseudoOpcode == Mips::BGTU) || (PseudoOpcode == Mips::BGTUL));      IsLikely = ((PseudoOpcode == Mips::BGTL) || (PseudoOpcode == Mips::BGTUL));      ZeroSrcOpcode = Mips::BLTZ;      ZeroTrgOpcode = Mips::BGTZ; @@ -3885,7 +3905,7 @@ bool MipsAsmParser::expandCondBranches(MCInst &Inst, SMLoc IDLoc,    // This is accomplished by using a BNEZ with the result of the SLT.    //    // The other 2 pseudo-branches are opposites of the above 2 (BGE with BLT -  // and BLE with BGT), so we change the BNEZ into a a BEQZ. +  // and BLE with BGT), so we change the BNEZ into a BEQZ.    // Because only BGE and BLE branch on equality, we can use the    // AcceptsEquality variable to decide when to emit the BEQZ.    // Note that the order of the SLT arguments doesn't change between @@ -3912,9 +3932,9 @@ bool MipsAsmParser::expandCondBranches(MCInst &Inst, SMLoc IDLoc,  // The destination register can only be $zero when expanding (S)DivIMacro or  // D(S)DivMacro. -bool MipsAsmParser::expandDiv(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, -                              const MCSubtargetInfo *STI, const bool IsMips64, -                              const bool Signed) { +bool MipsAsmParser::expandDivRem(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, +                                 const MCSubtargetInfo *STI, const bool IsMips64, +                                 const bool Signed) {    MipsTargetStreamer &TOut = getTargetStreamer();    warnIfNoMacro(IDLoc); @@ -3954,6 +3974,17 @@ bool MipsAsmParser::expandDiv(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out,    bool UseTraps = useTraps(); +  unsigned Opcode = Inst.getOpcode(); +  bool isDiv = Opcode == Mips::SDivMacro || Opcode == Mips::SDivIMacro || +               Opcode == Mips::UDivMacro || Opcode == Mips::UDivIMacro || +               Opcode == Mips::DSDivMacro || Opcode == Mips::DSDivIMacro || +               Opcode == Mips::DUDivMacro || Opcode == Mips::DUDivIMacro; + +  bool isRem = Opcode == Mips::SRemMacro || Opcode == Mips::SRemIMacro || +               Opcode == Mips::URemMacro || Opcode == Mips::URemIMacro || +               Opcode == Mips::DSRemMacro || Opcode == Mips::DSRemIMacro || +               Opcode == Mips::DURemMacro || Opcode == Mips::DURemIMacro; +    if (RtOp.isImm()) {      unsigned ATReg = getATReg(IDLoc);      if (!ATReg) @@ -3967,10 +3998,13 @@ bool MipsAsmParser::expandDiv(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out,        return false;      } -    if (ImmValue == 1) { +    if (isRem && (ImmValue == 1 || (Signed && (ImmValue == -1)))) { +      TOut.emitRRR(Mips::OR, RdReg, ZeroReg, ZeroReg, IDLoc, STI); +      return false; +    } else if (isDiv && ImmValue == 1) {        TOut.emitRRR(Mips::OR, RdReg, RsReg, Mips::ZERO, IDLoc, STI);        return false; -    } else if (Signed && ImmValue == -1) { +    } else if (isDiv && Signed && ImmValue == -1) {        TOut.emitRRR(SubOp, RdReg, ZeroReg, RsReg, IDLoc, STI);        return false;      } else { @@ -3978,16 +4012,16 @@ bool MipsAsmParser::expandDiv(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out,                          false, Inst.getLoc(), Out, STI))          return true;        TOut.emitRR(DivOp, RsReg, ATReg, IDLoc, STI); -      TOut.emitR(Mips::MFLO, RdReg, IDLoc, STI); +      TOut.emitR(isDiv ? Mips::MFLO : Mips::MFHI, RdReg, IDLoc, STI);        return false;      }      return true;    } -  // If the macro expansion of (d)div(u) would always trap or break, insert -  // the trap/break and exit. This gives a different result to GAS. GAS has -  // an inconsistency/missed optimization in that not all cases are handled -  // equivalently. As the observed behaviour is the same, we're ok. +  // If the macro expansion of (d)div(u) or (d)rem(u) would always trap or +  // break, insert the trap/break and exit. This gives a different result to +  // GAS. GAS has an inconsistency/missed optimization in that not all cases +  // are handled equivalently. As the observed behaviour is the same, we're ok.    if (RtReg == Mips::ZERO || RtReg == Mips::ZERO_64) {      if (UseTraps) {        TOut.emitRRI(Mips::TEQ, ZeroReg, ZeroReg, 0x7, IDLoc, STI); @@ -3997,6 +4031,13 @@ bool MipsAsmParser::expandDiv(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out,      return false;    } +  // (d)rem(u) $0, $X, $Y is a special case. Like div $zero, $X, $Y, it does +  // not expand to macro sequence. +  if (isRem && (RdReg == Mips::ZERO || RdReg == Mips::ZERO_64)) { +    TOut.emitRR(DivOp, RsReg, RtReg, IDLoc, STI); +    return false; +  } +    // Temporary label for first branch traget    MCContext &Context = TOut.getStreamer().getContext();    MCSymbol *BrTarget; @@ -4020,7 +4061,7 @@ bool MipsAsmParser::expandDiv(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out,      if (!UseTraps)        TOut.getStreamer().EmitLabel(BrTarget); -    TOut.emitR(Mips::MFLO, RdReg, IDLoc, STI); +    TOut.emitR(isDiv ? Mips::MFLO : Mips::MFHI, RdReg, IDLoc, STI);      return false;    } @@ -4043,7 +4084,7 @@ bool MipsAsmParser::expandDiv(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out,    if (IsMips64) {      TOut.emitRRI(Mips::ADDiu, ATReg, ZeroReg, 1, IDLoc, STI); -    TOut.emitRRI(Mips::DSLL32, ATReg, ATReg, 0x1f, IDLoc, STI); +    TOut.emitDSLL(ATReg, ATReg, 63, IDLoc, STI);    } else {      TOut.emitRI(Mips::LUi, ATReg, (uint16_t)0x8000, IDLoc, STI);    } @@ -4053,12 +4094,12 @@ bool MipsAsmParser::expandDiv(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out,    else {      // Branch to the mflo instruction.      TOut.emitRRX(Mips::BNE, RsReg, ATReg, LabelOpEnd, IDLoc, STI); -    TOut.emitRRI(Mips::SLL, ZeroReg, ZeroReg, 0, IDLoc, STI); +    TOut.emitNop(IDLoc, STI);      TOut.emitII(Mips::BREAK, 0x6, 0, IDLoc, STI);    }    TOut.getStreamer().EmitLabel(BrTargetEnd); -  TOut.emitR(Mips::MFLO, RdReg, IDLoc, STI); +  TOut.emitR(isDiv ? Mips::MFLO : Mips::MFHI, RdReg, IDLoc, STI);    return false;  } @@ -4287,7 +4328,8 @@ bool MipsAsmParser::expandAliasImmediate(MCInst &Inst, SMLoc IDLoc,      DstReg = ATReg;    } -  if (!loadImmediate(ImmValue, DstReg, Mips::NoRegister, Is32Bit, false, Inst.getLoc(), Out, STI)) { +  if (!loadImmediate(ImmValue, DstReg, Mips::NoRegister, Is32Bit, false, +                     Inst.getLoc(), Out, STI)) {      switch (FinalOpcode) {      default:        llvm_unreachable("unimplemented expansion"); @@ -4675,7 +4717,8 @@ bool MipsAsmParser::expandMulImm(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out,    if (!ATReg)      return true; -  loadImmediate(ImmValue, ATReg, Mips::NoRegister, true, false, IDLoc, Out, STI); +  loadImmediate(ImmValue, ATReg, Mips::NoRegister, true, false, IDLoc, Out, +                STI);    TOut.emitRR(Inst.getOpcode() == Mips::MULImmMacro ? Mips::MULT : Mips::DMULT,                SrcReg, ATReg, IDLoc, STI); @@ -5143,7 +5186,6 @@ unsigned MipsAsmParser::checkTargetMatchPredicate(MCInst &Inst) {        return Match_RequiresDifferentSrcAndDst;      return Match_Success;    case Mips::LWP_MM: -  case Mips::LWP_MMR6:      if (Inst.getOperand(0).getReg() == Inst.getOperand(2).getReg())        return Match_RequiresDifferentSrcAndDst;      return Match_Success; @@ -5151,6 +5193,13 @@ unsigned MipsAsmParser::checkTargetMatchPredicate(MCInst &Inst) {      if (Inst.getOperand(0).getImm() != 0 && !hasMips32())        return Match_NonZeroOperandForSync;      return Match_Success; +  case Mips::MFC0: +  case Mips::MTC0: +  case Mips::MTC2: +  case Mips::MFC2: +    if (Inst.getOperand(2).getImm() != 0 && !hasMips32()) +      return Match_NonZeroOperandForMTCX; +    return Match_Success;    // As described the MIPSR6 spec, the compact branches that compare registers    // must:    // a) Not use the zero register. @@ -5238,6 +5287,13 @@ unsigned MipsAsmParser::checkTargetMatchPredicate(MCInst &Inst) {        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; @@ -5291,7 +5347,10 @@ bool MipsAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,      return Error(ErrorLoc, "invalid operand for instruction");    }    case Match_NonZeroOperandForSync: -    return Error(IDLoc, "s-type must be zero or unspecified for pre-MIPS32 ISAs"); +    return Error(IDLoc, +                 "s-type must be zero or unspecified for pre-MIPS32 ISAs"); +  case Match_NonZeroOperandForMTCX: +    return Error(IDLoc, "selector must be zero for pre-MIPS32 ISAs");    case Match_MnemonicFail:      return Error(IDLoc, "invalid instruction");    case Match_RequiresDifferentSrcAndDst: @@ -5430,6 +5489,9 @@ bool MipsAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,    case Match_MemSImm16:      return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo),                   "expected memory with 16-bit signed offset"); +  case Match_MemSImmPtr: +    return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), +                 "expected memory with 32-bit signed offset");    case Match_RequiresPosSizeRange0_32: {      SMLoc ErrorStart = Operands[3]->getStartLoc();      SMLoc ErrorEnd = Operands[4]->getEndLoc(); @@ -5464,6 +5526,17 @@ void MipsAsmParser::warnIfNoMacro(SMLoc Loc) {      Warning(Loc, "macro instruction expanded into multiple instructions");  } +void MipsAsmParser::ConvertXWPOperands(MCInst &Inst, +                                       const OperandVector &Operands) { +  assert( +      (Inst.getOpcode() == Mips::LWP_MM || Inst.getOpcode() == Mips::SWP_MM) && +      "Unexpected instruction!"); +  ((MipsOperand &)*Operands[1]).addGPR32ZeroAsmRegOperands(Inst, 1); +  int NextReg = nextReg(((MipsOperand &)*Operands[1]).getGPR32Reg()); +  Inst.addOperand(MCOperand::createReg(NextReg)); +  ((MipsOperand &)*Operands[2]).addMemOperands(Inst, 2); +} +  void  MipsAsmParser::printWarningWithFixIt(const Twine &Msg, const Twine &FixMsg,                                       SMRange Range, bool ShowColors) { @@ -5654,7 +5727,7 @@ unsigned MipsAsmParser::getReg(int RC, int RegNo) {  bool MipsAsmParser::parseOperand(OperandVector &Operands, StringRef Mnemonic) {    MCAsmParser &Parser = getParser(); -  DEBUG(dbgs() << "parseOperand\n"); +  LLVM_DEBUG(dbgs() << "parseOperand\n");    // Check if the current operand has a custom associated parser, if so, try to    // custom parse the operand, or fallback to the general approach. @@ -5667,7 +5740,7 @@ bool MipsAsmParser::parseOperand(OperandVector &Operands, StringRef Mnemonic) {    if (ResTy == MatchOperand_ParseFail)      return true; -  DEBUG(dbgs() << ".. Generic Parser\n"); +  LLVM_DEBUG(dbgs() << ".. Generic Parser\n");    switch (getLexer().getKind()) {    case AsmToken::Dollar: { @@ -5697,7 +5770,7 @@ bool MipsAsmParser::parseOperand(OperandVector &Operands, StringRef Mnemonic) {      return false;    }    default: { -    DEBUG(dbgs() << ".. generic integer expression\n"); +    LLVM_DEBUG(dbgs() << ".. generic integer expression\n");      const MCExpr *Expr;      SMLoc S = Parser.getTok().getLoc(); // Start location of the operand. @@ -5770,7 +5843,7 @@ bool MipsAsmParser::parseMemOffset(const MCExpr *&Res, bool isParenExpr) {  OperandMatchResultTy  MipsAsmParser::parseMemOperand(OperandVector &Operands) {    MCAsmParser &Parser = getParser(); -  DEBUG(dbgs() << "parseMemOperand\n"); +  LLVM_DEBUG(dbgs() << "parseMemOperand\n");    const MCExpr *IdVal = nullptr;    SMLoc S;    bool isParenExpr = false; @@ -5906,13 +5979,12 @@ MipsAsmParser::parseMemOperand(OperandVector &Operands) {  bool MipsAsmParser::searchSymbolAlias(OperandVector &Operands) {    MCAsmParser &Parser = getParser();    MCSymbol *Sym = getContext().lookupSymbol(Parser.getTok().getIdentifier()); -  if (Sym) { -    SMLoc S = Parser.getTok().getLoc(); -    const MCExpr *Expr; -    if (Sym->isVariable()) -      Expr = Sym->getVariableValue(); -    else -      return false; +  if (!Sym) +    return false; + +  SMLoc S = Parser.getTok().getLoc(); +  if (Sym->isVariable()) { +    const MCExpr *Expr = Sym->getVariableValue();      if (Expr->getKind() == MCExpr::SymbolRef) {        const MCSymbolRefExpr *Ref = static_cast<const MCSymbolRefExpr *>(Expr);        StringRef DefSymbol = Ref->getSymbol().getName(); @@ -5922,12 +5994,26 @@ bool MipsAsmParser::searchSymbolAlias(OperandVector &Operands) {          if (ResTy == MatchOperand_Success) {            Parser.Lex();            return true; -        } else if (ResTy == MatchOperand_ParseFail) +        } +        if (ResTy == MatchOperand_ParseFail)            llvm_unreachable("Should never ParseFail"); -        return false; +      } +    } +  } else if (Sym->isUnset()) { +    // If symbol is unset, it might be created in the `parseSetAssignment` +    // routine as an alias for a numeric register name. +    // Lookup in the aliases list. +    auto Entry = RegisterSets.find(Sym->getName()); +    if (Entry != RegisterSets.end()) { +      OperandMatchResultTy ResTy = +          matchAnyRegisterWithoutDollar(Operands, Entry->getValue(), S); +      if (ResTy == MatchOperand_Success) { +        Parser.Lex(); +        return true;        }      }    } +    return false;  } @@ -5995,48 +6081,59 @@ MipsAsmParser::matchAnyRegisterNameWithoutDollar(OperandVector &Operands,  }  OperandMatchResultTy -MipsAsmParser::matchAnyRegisterWithoutDollar(OperandVector &Operands, SMLoc S) { -  MCAsmParser &Parser = getParser(); -  auto Token = Parser.getLexer().peekTok(false); - +MipsAsmParser::matchAnyRegisterWithoutDollar(OperandVector &Operands, +                                             const AsmToken &Token, SMLoc S) {    if (Token.is(AsmToken::Identifier)) { -    DEBUG(dbgs() << ".. identifier\n"); +    LLVM_DEBUG(dbgs() << ".. identifier\n");      StringRef Identifier = Token.getIdentifier();      OperandMatchResultTy ResTy =          matchAnyRegisterNameWithoutDollar(Operands, Identifier, S);      return ResTy;    } else if (Token.is(AsmToken::Integer)) { -    DEBUG(dbgs() << ".. integer\n"); +    LLVM_DEBUG(dbgs() << ".. integer\n"); +    int64_t RegNum = Token.getIntVal(); +    if (RegNum < 0 || RegNum > 31) { +      // Show the error, but treat invalid register +      // number as a normal one to continue parsing +      // and catch other possible errors. +      Error(getLexer().getLoc(), "invalid register number"); +    }      Operands.push_back(MipsOperand::createNumericReg( -        Token.getIntVal(), Token.getString(), getContext().getRegisterInfo(), S, +        RegNum, Token.getString(), getContext().getRegisterInfo(), S,          Token.getLoc(), *this));      return MatchOperand_Success;    } -  DEBUG(dbgs() << Parser.getTok().getKind() << "\n"); +  LLVM_DEBUG(dbgs() << Token.getKind() << "\n");    return MatchOperand_NoMatch;  }  OperandMatchResultTy +MipsAsmParser::matchAnyRegisterWithoutDollar(OperandVector &Operands, SMLoc S) { +  auto Token = getLexer().peekTok(false); +  return matchAnyRegisterWithoutDollar(Operands, Token, S); +} + +OperandMatchResultTy  MipsAsmParser::parseAnyRegister(OperandVector &Operands) {    MCAsmParser &Parser = getParser(); -  DEBUG(dbgs() << "parseAnyRegister\n"); +  LLVM_DEBUG(dbgs() << "parseAnyRegister\n");    auto Token = Parser.getTok();    SMLoc S = Token.getLoc();    if (Token.isNot(AsmToken::Dollar)) { -    DEBUG(dbgs() << ".. !$ -> try sym aliasing\n"); +    LLVM_DEBUG(dbgs() << ".. !$ -> try sym aliasing\n");      if (Token.is(AsmToken::Identifier)) {        if (searchSymbolAlias(Operands))          return MatchOperand_Success;      } -    DEBUG(dbgs() << ".. !symalias -> NoMatch\n"); +    LLVM_DEBUG(dbgs() << ".. !symalias -> NoMatch\n");      return MatchOperand_NoMatch;    } -  DEBUG(dbgs() << ".. $\n"); +  LLVM_DEBUG(dbgs() << ".. $\n");    OperandMatchResultTy ResTy = matchAnyRegisterWithoutDollar(Operands, S);    if (ResTy == MatchOperand_Success) { @@ -6049,7 +6146,7 @@ MipsAsmParser::parseAnyRegister(OperandVector &Operands) {  OperandMatchResultTy  MipsAsmParser::parseJumpTarget(OperandVector &Operands) {    MCAsmParser &Parser = getParser(); -  DEBUG(dbgs() << "parseJumpTarget\n"); +  LLVM_DEBUG(dbgs() << "parseJumpTarget\n");    SMLoc S = getLexer().getLoc(); @@ -6182,22 +6279,6 @@ MipsAsmParser::parseRegisterList(OperandVector &Operands) {  }  OperandMatchResultTy -MipsAsmParser::parseRegisterPair(OperandVector &Operands) { -  MCAsmParser &Parser = getParser(); - -  SMLoc S = Parser.getTok().getLoc(); -  if (parseAnyRegister(Operands) != MatchOperand_Success) -    return MatchOperand_ParseFail; - -  SMLoc E = Parser.getTok().getLoc(); -  MipsOperand Op = static_cast<MipsOperand &>(*Operands.back()); - -  Operands.pop_back(); -  Operands.push_back(MipsOperand::CreateRegPair(Op, S, E, *this)); -  return MatchOperand_Success; -} - -OperandMatchResultTy  MipsAsmParser::parseMovePRegPair(OperandVector &Operands) {    MCAsmParser &Parser = getParser();    SmallVector<std::unique_ptr<MCParsedAsmOperand>, 8> TmpOperands; @@ -6293,7 +6374,7 @@ bool MipsAsmParser::parseBracketSuffix(StringRef Name,  bool MipsAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,                                       SMLoc NameLoc, OperandVector &Operands) {    MCAsmParser &Parser = getParser(); -  DEBUG(dbgs() << "ParseInstruction\n"); +  LLVM_DEBUG(dbgs() << "ParseInstruction\n");    // We have reached first instruction, module directive are now forbidden.    getTargetStreamer().forbidModuleDirective(); @@ -6655,6 +6736,57 @@ bool MipsAsmParser::parseSetNoMtDirective() {    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::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::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(); @@ -6720,17 +6852,30 @@ bool MipsAsmParser::parseSetAssignment() {    MCAsmParser &Parser = getParser();    if (Parser.parseIdentifier(Name)) -    reportParseError("expected identifier after .set"); +    return reportParseError("expected identifier after .set");    if (getLexer().isNot(AsmToken::Comma))      return reportParseError("unexpected token, expected comma");    Lex(); // Eat comma -  if (Parser.parseExpression(Value)) +  if (getLexer().is(AsmToken::Dollar) && +      getLexer().peekTok().is(AsmToken::Integer)) { +    // Parse assignment of a numeric register: +    //   .set r1,$1 +    Parser.Lex(); // Eat $. +    RegisterSets[Name] = Parser.getTok(); +    Parser.Lex(); // Eat identifier. +    getContext().getOrCreateSymbol(Name); +  } else if (!Parser.parseExpression(Value)) { +    // Parse assignment of an expression including +    // symbolic registers: +    //   .set  $tmp, $BB0-$BB1 +    //   .set  r2, $f2 +    MCSymbol *Sym = getContext().getOrCreateSymbol(Name); +    Sym->setVariableValue(Value); +  } else {      return reportParseError("expected valid expression after comma"); - -  MCSymbol *Sym = getContext().getOrCreateSymbol(Name); -  Sym->setVariableValue(Value); +  }    return false;  } @@ -6876,6 +7021,18 @@ bool MipsAsmParser::parseSetFeature(uint64_t Feature) {      selectArch("mips64r6");      getTargetStreamer().emitDirectiveSetMips64R6();      break; +  case Mips::FeatureCRC: +    setFeatureBits(Mips::FeatureCRC, "crc"); +    getTargetStreamer().emitDirectiveSetCRC(); +    break; +  case Mips::FeatureVirt: +    setFeatureBits(Mips::FeatureVirt, "virt"); +    getTargetStreamer().emitDirectiveSetVirt(); +    break; +  case Mips::FeatureGINV: +    setFeatureBits(Mips::FeatureGINV, "ginv"); +    getTargetStreamer().emitDirectiveSetGINV(); +    break;    }    return false;  } @@ -7075,143 +7232,131 @@ bool MipsAsmParser::parseDirectiveNaN() {  }  bool MipsAsmParser::parseDirectiveSet() { -  MCAsmParser &Parser = getParser(); -  // Get the next token. -  const AsmToken &Tok = Parser.getTok(); +  const AsmToken &Tok = getParser().getTok(); +  StringRef IdVal = Tok.getString(); +  SMLoc Loc = Tok.getLoc(); -  if (Tok.getString() == "noat") { +  if (IdVal == "noat")      return parseSetNoAtDirective(); -  } else if (Tok.getString() == "at") { +  if (IdVal == "at")      return parseSetAtDirective(); -  } else if (Tok.getString() == "arch") { +  if (IdVal == "arch")      return parseSetArchDirective(); -  } else if (Tok.getString() == "bopt") { -    Warning(Tok.getLoc(), "'bopt' feature is unsupported"); +  if (IdVal == "bopt") { +    Warning(Loc, "'bopt' feature is unsupported");      getParser().Lex();      return false; -  } else if (Tok.getString() == "nobopt") { +  } +  if (IdVal == "nobopt") {      // We're already running in nobopt mode, so nothing to do.      getParser().Lex();      return false; -  } else if (Tok.getString() == "fp") { +  } +  if (IdVal == "fp")      return parseSetFpDirective(); -  } else if (Tok.getString() == "oddspreg") { +  if (IdVal == "oddspreg")      return parseSetOddSPRegDirective(); -  } else if (Tok.getString() == "nooddspreg") { +  if (IdVal == "nooddspreg")      return parseSetNoOddSPRegDirective(); -  } else if (Tok.getString() == "pop") { +  if (IdVal == "pop")      return parseSetPopDirective(); -  } else if (Tok.getString() == "push") { +  if (IdVal == "push")      return parseSetPushDirective(); -  } else if (Tok.getString() == "reorder") { +  if (IdVal == "reorder")      return parseSetReorderDirective(); -  } else if (Tok.getString() == "noreorder") { +  if (IdVal == "noreorder")      return parseSetNoReorderDirective(); -  } else if (Tok.getString() == "macro") { +  if (IdVal == "macro")      return parseSetMacroDirective(); -  } else if (Tok.getString() == "nomacro") { +  if (IdVal == "nomacro")      return parseSetNoMacroDirective(); -  } else if (Tok.getString() == "mips16") { +  if (IdVal == "mips16")      return parseSetMips16Directive(); -  } else if (Tok.getString() == "nomips16") { +  if (IdVal == "nomips16")      return parseSetNoMips16Directive(); -  } else if (Tok.getString() == "nomicromips") { +  if (IdVal == "nomicromips") {      clearFeatureBits(Mips::FeatureMicroMips, "micromips");      getTargetStreamer().emitDirectiveSetNoMicroMips(); -    Parser.eatToEndOfStatement(); +    getParser().eatToEndOfStatement();      return false; -  } else if (Tok.getString() == "micromips") { +  } +  if (IdVal == "micromips") {      if (hasMips64r6()) { -      Error(Tok.getLoc(), ".set micromips directive is not supported with MIPS64R6"); +      Error(Loc, ".set micromips directive is not supported with MIPS64R6");        return false;      }      return parseSetFeature(Mips::FeatureMicroMips); -  } else if (Tok.getString() == "mips0") { +  } +  if (IdVal == "mips0")      return parseSetMips0Directive(); -  } else if (Tok.getString() == "mips1") { +  if (IdVal == "mips1")      return parseSetFeature(Mips::FeatureMips1); -  } else if (Tok.getString() == "mips2") { +  if (IdVal == "mips2")      return parseSetFeature(Mips::FeatureMips2); -  } else if (Tok.getString() == "mips3") { +  if (IdVal == "mips3")      return parseSetFeature(Mips::FeatureMips3); -  } else if (Tok.getString() == "mips4") { +  if (IdVal == "mips4")      return parseSetFeature(Mips::FeatureMips4); -  } else if (Tok.getString() == "mips5") { +  if (IdVal == "mips5")      return parseSetFeature(Mips::FeatureMips5); -  } else if (Tok.getString() == "mips32") { +  if (IdVal == "mips32")      return parseSetFeature(Mips::FeatureMips32); -  } else if (Tok.getString() == "mips32r2") { +  if (IdVal == "mips32r2")      return parseSetFeature(Mips::FeatureMips32r2); -  } else if (Tok.getString() == "mips32r3") { +  if (IdVal == "mips32r3")      return parseSetFeature(Mips::FeatureMips32r3); -  } else if (Tok.getString() == "mips32r5") { +  if (IdVal == "mips32r5")      return parseSetFeature(Mips::FeatureMips32r5); -  } else if (Tok.getString() == "mips32r6") { +  if (IdVal == "mips32r6")      return parseSetFeature(Mips::FeatureMips32r6); -  } else if (Tok.getString() == "mips64") { +  if (IdVal == "mips64")      return parseSetFeature(Mips::FeatureMips64); -  } else if (Tok.getString() == "mips64r2") { +  if (IdVal == "mips64r2")      return parseSetFeature(Mips::FeatureMips64r2); -  } else if (Tok.getString() == "mips64r3") { +  if (IdVal == "mips64r3")      return parseSetFeature(Mips::FeatureMips64r3); -  } else if (Tok.getString() == "mips64r5") { +  if (IdVal == "mips64r5")      return parseSetFeature(Mips::FeatureMips64r5); -  } else if (Tok.getString() == "mips64r6") { +  if (IdVal == "mips64r6") {      if (inMicroMipsMode()) { -      Error(Tok.getLoc(), "MIPS64R6 is not supported with microMIPS"); +      Error(Loc, "MIPS64R6 is not supported with microMIPS");        return false;      }      return parseSetFeature(Mips::FeatureMips64r6); -  } else if (Tok.getString() == "dsp") { +  } +  if (IdVal == "dsp")      return parseSetFeature(Mips::FeatureDSP); -  } else if (Tok.getString() == "dspr2") { +  if (IdVal == "dspr2")      return parseSetFeature(Mips::FeatureDSPR2); -  } else if (Tok.getString() == "nodsp") { +  if (IdVal == "nodsp")      return parseSetNoDspDirective(); -  } else if (Tok.getString() == "msa") { +  if (IdVal == "msa")      return parseSetMsaDirective(); -  } else if (Tok.getString() == "nomsa") { +  if (IdVal == "nomsa")      return parseSetNoMsaDirective(); -  } else if (Tok.getString() == "mt") { +  if (IdVal == "mt")      return parseSetMtDirective(); -  } else if (Tok.getString() == "nomt") { +  if (IdVal == "nomt")      return parseSetNoMtDirective(); -  } else if (Tok.getString() == "softfloat") { +  if (IdVal == "softfloat")      return parseSetSoftFloatDirective(); -  } else if (Tok.getString() == "hardfloat") { +  if (IdVal == "hardfloat")      return parseSetHardFloatDirective(); -  } else { -    // It is just an identifier, look for an assignment. -    parseSetAssignment(); -    return false; -  } - -  return true; -} - -/// parseDataDirective -///  ::= .word [ expression (, expression)* ] -bool MipsAsmParser::parseDataDirective(unsigned Size, SMLoc L) { -  MCAsmParser &Parser = getParser(); -  if (getLexer().isNot(AsmToken::EndOfStatement)) { -    while (true) { -      const MCExpr *Value; -      if (getParser().parseExpression(Value)) -        return true; - -      getParser().getStreamer().EmitValue(Value, Size); - -      if (getLexer().is(AsmToken::EndOfStatement)) -        break; - -      if (getLexer().isNot(AsmToken::Comma)) -        return Error(L, "unexpected token, expected comma"); -      Parser.Lex(); -    } -  } - -  Parser.Lex(); -  return false; +  if (IdVal == "crc") +    return parseSetFeature(Mips::FeatureCRC); +  if (IdVal == "nocrc") +    return parseSetNoCRCDirective(); +  if (IdVal == "virt") +    return parseSetFeature(Mips::FeatureVirt); +  if (IdVal == "novirt") +    return parseSetNoVirtDirective(); +  if (IdVal == "ginv") +    return parseSetFeature(Mips::FeatureGINV); +  if (IdVal == "noginv") +    return parseSetNoGINVDirective(); + +  // It is just an identifier, look for an assignment. +  return parseSetAssignment();  }  /// parseDirectiveGpWord @@ -7426,6 +7571,12 @@ bool MipsAsmParser::parseSSectionDirective(StringRef Section, unsigned Type) {  ///  ::= .module softfloat  ///  ::= .module hardfloat  ///  ::= .module mt +///  ::= .module crc +///  ::= .module nocrc +///  ::= .module virt +///  ::= .module novirt +///  ::= .module ginv +///  ::= .module noginv  bool MipsAsmParser::parseDirectiveModule() {    MCAsmParser &Parser = getParser();    MCAsmLexer &Lexer = getLexer(); @@ -7544,6 +7695,120 @@ bool MipsAsmParser::parseDirectiveModule() {      }      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 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 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.");    } @@ -7673,10 +7938,6 @@ bool MipsAsmParser::ParseDirective(AsmToken DirectiveID) {      parseDirectiveCpRestore(DirectiveID.getLoc());      return false;    } -  if (IDVal == ".dword") { -    parseDataDirective(8, DirectiveID.getLoc()); -    return false; -  }    if (IDVal == ".ent") {      StringRef SymbolName; @@ -7924,16 +8185,6 @@ bool MipsAsmParser::ParseDirective(AsmToken DirectiveID) {      return false;    } -  if (IDVal == ".word") { -    parseDataDirective(4, DirectiveID.getLoc()); -    return false; -  } - -  if (IDVal == ".hword") { -    parseDataDirective(2, DirectiveID.getLoc()); -    return false; -  } -    if (IDVal == ".option") {      parseDirectiveOption();      return false;  | 
