diff options
Diffstat (limited to 'contrib/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp')
-rw-r--r-- | contrib/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp | 1127 |
1 files changed, 762 insertions, 365 deletions
diff --git a/contrib/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp b/contrib/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp index b51d020..d054578 100644 --- a/contrib/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp +++ b/contrib/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp @@ -13,6 +13,7 @@ #include "MipsRegisterInfo.h" #include "MipsTargetObjectFile.h" #include "MipsTargetStreamer.h" +#include "MCTargetDesc/MipsBaseInfo.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/MC/MCContext.h" @@ -129,6 +130,9 @@ class MipsAsmParser : public MCTargetAsmParser { #define GET_ASSEMBLER_HEADER #include "MipsGenAsmMatcher.inc" + unsigned + checkEarlyTargetMatchPredicate(MCInst &Inst, + const OperandVector &Operands) override; unsigned checkTargetMatchPredicate(MCInst &Inst) override; bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, @@ -230,7 +234,10 @@ class MipsAsmParser : public MCTargetAsmParser { bool expandUlh(MCInst &Inst, bool Signed, SMLoc IDLoc, MCStreamer &Out, const MCSubtargetInfo *STI); - bool expandUlw(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, + bool expandUsh(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, + const MCSubtargetInfo *STI); + + bool expandUxw(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, const MCSubtargetInfo *STI); bool expandRotation(MCInst &Inst, SMLoc IDLoc, @@ -245,13 +252,19 @@ class MipsAsmParser : public MCTargetAsmParser { bool expandAbs(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, const MCSubtargetInfo *STI); + bool expandLoadStoreDMacro(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, + const MCSubtargetInfo *STI, bool IsLoad); + + bool expandSeq(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, + const MCSubtargetInfo *STI); + + bool expandSeqI(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, + const MCSubtargetInfo *STI); + bool reportParseError(Twine ErrorMsg); bool reportParseError(SMLoc Loc, Twine ErrorMsg); bool parseMemOffset(const MCExpr *&Res, bool isParenExpr); - bool parseRelocOperand(const MCExpr *&Res); - - const MCExpr *evaluateRelocExpr(const MCExpr *Expr, StringRef RelocStr); bool isEvaluated(const MCExpr *Expr); bool parseSetMips0Directive(); @@ -292,6 +305,10 @@ class MipsAsmParser : public MCTargetAsmParser { bool parseDataDirective(unsigned Size, SMLoc L); bool parseDirectiveGpWord(); bool parseDirectiveGpDWord(); + bool parseDirectiveDtpRelWord(); + bool parseDirectiveDtpRelDWord(); + bool parseDirectiveTpRelWord(); + bool parseDirectiveTpRelDWord(); bool parseDirectiveModule(); bool parseDirectiveModuleFP(); bool parseFpABIValue(MipsABIFlagsSection::FpABIKind &FpABI, @@ -395,6 +412,9 @@ public: Match_RequiresDifferentSrcAndDst = FIRST_TARGET_MATCH_RESULT_TY, Match_RequiresDifferentOperands, Match_RequiresNoZeroRegister, + Match_RequiresSameSrcAndDst, + Match_NoFCCRegisterForCurrentISA, + Match_NonZeroOperandForSync, #define GET_OPERAND_DIAGNOSTIC_TYPES #include "MipsGenAsmMatcher.inc" #undef GET_OPERAND_DIAGNOSTIC_TYPES @@ -548,6 +568,64 @@ public: void warnIfNoMacro(SMLoc Loc); bool isLittle() const { return IsLittleEndian; } + + const MCExpr *createTargetUnaryExpr(const MCExpr *E, + AsmToken::TokenKind OperatorToken, + MCContext &Ctx) override { + switch(OperatorToken) { + default: + llvm_unreachable("Unknown token"); + return nullptr; + case AsmToken::PercentCall16: + return MipsMCExpr::create(MipsMCExpr::MEK_GOT_CALL, E, Ctx); + case AsmToken::PercentCall_Hi: + return MipsMCExpr::create(MipsMCExpr::MEK_CALL_HI16, E, Ctx); + case AsmToken::PercentCall_Lo: + return MipsMCExpr::create(MipsMCExpr::MEK_CALL_LO16, E, Ctx); + case AsmToken::PercentDtprel_Hi: + return MipsMCExpr::create(MipsMCExpr::MEK_DTPREL_HI, E, Ctx); + case AsmToken::PercentDtprel_Lo: + return MipsMCExpr::create(MipsMCExpr::MEK_DTPREL_LO, E, Ctx); + case AsmToken::PercentGot: + return MipsMCExpr::create(MipsMCExpr::MEK_GOT, E, Ctx); + case AsmToken::PercentGot_Disp: + return MipsMCExpr::create(MipsMCExpr::MEK_GOT_DISP, E, Ctx); + case AsmToken::PercentGot_Hi: + return MipsMCExpr::create(MipsMCExpr::MEK_GOT_HI16, E, Ctx); + case AsmToken::PercentGot_Lo: + return MipsMCExpr::create(MipsMCExpr::MEK_GOT_LO16, E, Ctx); + case AsmToken::PercentGot_Ofst: + return MipsMCExpr::create(MipsMCExpr::MEK_GOT_OFST, E, Ctx); + case AsmToken::PercentGot_Page: + return MipsMCExpr::create(MipsMCExpr::MEK_GOT_PAGE, E, Ctx); + case AsmToken::PercentGottprel: + return MipsMCExpr::create(MipsMCExpr::MEK_GOTTPREL, E, Ctx); + case AsmToken::PercentGp_Rel: + return MipsMCExpr::create(MipsMCExpr::MEK_GPREL, E, Ctx); + case AsmToken::PercentHi: + return MipsMCExpr::create(MipsMCExpr::MEK_HI, E, Ctx); + case AsmToken::PercentHigher: + return MipsMCExpr::create(MipsMCExpr::MEK_HIGHER, E, Ctx); + case AsmToken::PercentHighest: + return MipsMCExpr::create(MipsMCExpr::MEK_HIGHEST, E, Ctx); + case AsmToken::PercentLo: + return MipsMCExpr::create(MipsMCExpr::MEK_LO, E, Ctx); + case AsmToken::PercentNeg: + return MipsMCExpr::create(MipsMCExpr::MEK_NEG, E, Ctx); + case AsmToken::PercentPcrel_Hi: + return MipsMCExpr::create(MipsMCExpr::MEK_PCREL_HI16, E, Ctx); + case AsmToken::PercentPcrel_Lo: + return MipsMCExpr::create(MipsMCExpr::MEK_PCREL_LO16, E, Ctx); + case AsmToken::PercentTlsgd: + return MipsMCExpr::create(MipsMCExpr::MEK_TLSGD, E, Ctx); + case AsmToken::PercentTlsldm: + return MipsMCExpr::create(MipsMCExpr::MEK_TLSLDM, E, Ctx); + case AsmToken::PercentTprel_Hi: + return MipsMCExpr::create(MipsMCExpr::MEK_TPREL_HI, E, Ctx); + case AsmToken::PercentTprel_Lo: + return MipsMCExpr::create(MipsMCExpr::MEK_TPREL_LO, E, Ctx); + } + } }; } @@ -605,6 +683,7 @@ private: struct RegIdxOp { unsigned Index; /// Index into the register class RegKind Kind; /// Bitfield of the kinds it could possibly be + struct Token Tok; /// The input token this operand originated from. const MCRegisterInfo *RegInfo; }; @@ -632,7 +711,8 @@ private: SMLoc StartLoc, EndLoc; /// Internal constructor for register kinds - static std::unique_ptr<MipsOperand> CreateReg(unsigned Index, RegKind RegKind, + static std::unique_ptr<MipsOperand> CreateReg(unsigned Index, StringRef Str, + RegKind RegKind, const MCRegisterInfo *RegInfo, SMLoc S, SMLoc E, MipsAsmParser &Parser) { @@ -640,6 +720,8 @@ private: Op->RegIdx.Index = Index; Op->RegIdx.RegInfo = RegInfo; Op->RegIdx.Kind = RegKind; + Op->RegIdx.Tok.Data = Str.data(); + Op->RegIdx.Tok.Length = Str.size(); Op->StartLoc = S; Op->EndLoc = E; return Op; @@ -856,9 +938,11 @@ public: assert(N == 1 && "Invalid number of operands!"); Inst.addOperand(MCOperand::createReg(getFGR32Reg())); // FIXME: We ought to do this for -integrated-as without -via-file-asm too. + // FIXME: This should propagate failure up to parseStatement. if (!AsmParser.useOddSPReg() && RegIdx.Index & 1) - AsmParser.Error(StartLoc, "-mno-odd-spreg prohibits the use of odd FPU " - "registers"); + AsmParser.getParser().printError( + StartLoc, "-mno-odd-spreg prohibits the use of odd FPU " + "registers"); } void addFGRH32AsmRegOperands(MCInst &Inst, unsigned N) const { @@ -925,7 +1009,7 @@ public: void addConstantUImmOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); uint64_t Imm = getConstantImm() - Offset; - Imm &= (1 << Bits) - 1; + Imm &= (1ULL << Bits) - 1; Imm += Offset; Imm += AdjustOffset; Inst.addOperand(MCOperand::createImm(Imm)); @@ -1023,7 +1107,8 @@ public: bool isRegIdx() const { return Kind == k_RegisterIndex; } bool isImm() const override { return Kind == k_Immediate; } bool isConstantImm() const { - return isImm() && isa<MCConstantExpr>(getImm()); + int64_t Res; + return isImm() && getImm()->evaluateAsAbsolute(Res); } bool isConstantImmz() const { return isConstantImm() && getConstantImm() == 0; @@ -1099,8 +1184,14 @@ public: } template <unsigned Bits, unsigned ShiftLeftAmount> bool isScaledSImm() const { - return 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. + if (Kind != k_Immediate) + return false; + MCValue Res; + bool Success = getImm()->evaluateAsRelocatable(Res, nullptr, nullptr); + return Success && isShiftedInt<Bits, ShiftLeftAmount>(Res.getConstant()); } bool isRegList16() const { if (!isRegList()) @@ -1188,7 +1279,9 @@ public: int64_t getConstantImm() const { const MCExpr *Val = getImm(); - return static_cast<const MCConstantExpr *>(Val)->getValue(); + int64_t Value = 0; + (void)Val->evaluateAsAbsolute(Value); + return Value; } MipsOperand *getMemBase() const { @@ -1228,66 +1321,66 @@ public: /// Create a numeric register (e.g. $1). The exact register remains /// unresolved until an instruction successfully matches static std::unique_ptr<MipsOperand> - createNumericReg(unsigned Index, const MCRegisterInfo *RegInfo, SMLoc S, - SMLoc E, MipsAsmParser &Parser) { + createNumericReg(unsigned Index, StringRef Str, const MCRegisterInfo *RegInfo, + SMLoc S, SMLoc E, MipsAsmParser &Parser) { DEBUG(dbgs() << "createNumericReg(" << Index << ", ...)\n"); - return CreateReg(Index, RegKind_Numeric, RegInfo, S, E, Parser); + return CreateReg(Index, Str, RegKind_Numeric, RegInfo, S, E, Parser); } /// Create a register that is definitely a GPR. /// This is typically only used for named registers such as $gp. static std::unique_ptr<MipsOperand> - createGPRReg(unsigned Index, const MCRegisterInfo *RegInfo, SMLoc S, SMLoc E, - MipsAsmParser &Parser) { - return CreateReg(Index, RegKind_GPR, RegInfo, S, E, Parser); + createGPRReg(unsigned Index, StringRef Str, const MCRegisterInfo *RegInfo, + SMLoc S, SMLoc E, MipsAsmParser &Parser) { + return CreateReg(Index, Str, RegKind_GPR, RegInfo, S, E, Parser); } /// Create a register that is definitely a FGR. /// This is typically only used for named registers such as $f0. static std::unique_ptr<MipsOperand> - createFGRReg(unsigned Index, const MCRegisterInfo *RegInfo, SMLoc S, SMLoc E, - MipsAsmParser &Parser) { - return CreateReg(Index, RegKind_FGR, RegInfo, S, E, Parser); + createFGRReg(unsigned Index, StringRef Str, const MCRegisterInfo *RegInfo, + SMLoc S, SMLoc E, MipsAsmParser &Parser) { + return CreateReg(Index, Str, RegKind_FGR, RegInfo, S, E, Parser); } /// Create a register that is definitely a HWReg. /// This is typically only used for named registers such as $hwr_cpunum. static std::unique_ptr<MipsOperand> - createHWRegsReg(unsigned Index, const MCRegisterInfo *RegInfo, + createHWRegsReg(unsigned Index, StringRef Str, const MCRegisterInfo *RegInfo, SMLoc S, SMLoc E, MipsAsmParser &Parser) { - return CreateReg(Index, RegKind_HWRegs, RegInfo, S, E, Parser); + return CreateReg(Index, Str, RegKind_HWRegs, RegInfo, S, E, Parser); } /// Create a register that is definitely an FCC. /// This is typically only used for named registers such as $fcc0. static std::unique_ptr<MipsOperand> - createFCCReg(unsigned Index, const MCRegisterInfo *RegInfo, SMLoc S, SMLoc E, - MipsAsmParser &Parser) { - return CreateReg(Index, RegKind_FCC, RegInfo, S, E, Parser); + createFCCReg(unsigned Index, StringRef Str, const MCRegisterInfo *RegInfo, + SMLoc S, SMLoc E, MipsAsmParser &Parser) { + return CreateReg(Index, Str, RegKind_FCC, RegInfo, S, E, Parser); } /// Create a register that is definitely an ACC. /// This is typically only used for named registers such as $ac0. static std::unique_ptr<MipsOperand> - createACCReg(unsigned Index, const MCRegisterInfo *RegInfo, SMLoc S, SMLoc E, - MipsAsmParser &Parser) { - return CreateReg(Index, RegKind_ACC, RegInfo, S, E, Parser); + createACCReg(unsigned Index, StringRef Str, const MCRegisterInfo *RegInfo, + SMLoc S, SMLoc E, MipsAsmParser &Parser) { + return CreateReg(Index, Str, RegKind_ACC, RegInfo, S, E, Parser); } /// Create a register that is definitely an MSA128. /// This is typically only used for named registers such as $w0. static std::unique_ptr<MipsOperand> - createMSA128Reg(unsigned Index, const MCRegisterInfo *RegInfo, SMLoc S, - SMLoc E, MipsAsmParser &Parser) { - return CreateReg(Index, RegKind_MSA128, RegInfo, S, E, Parser); + createMSA128Reg(unsigned Index, StringRef Str, const MCRegisterInfo *RegInfo, + SMLoc S, SMLoc E, MipsAsmParser &Parser) { + return CreateReg(Index, Str, RegKind_MSA128, RegInfo, S, E, Parser); } /// Create a register that is definitely an MSACtrl. /// This is typically only used for named registers such as $msaaccess. static std::unique_ptr<MipsOperand> - createMSACtrlReg(unsigned Index, const MCRegisterInfo *RegInfo, SMLoc S, - SMLoc E, MipsAsmParser &Parser) { - return CreateReg(Index, RegKind_MSACtrl, RegInfo, S, E, Parser); + createMSACtrlReg(unsigned Index, StringRef Str, const MCRegisterInfo *RegInfo, + SMLoc S, SMLoc E, MipsAsmParser &Parser) { + return CreateReg(Index, Str, RegKind_MSACtrl, RegInfo, S, E, Parser); } static std::unique_ptr<MipsOperand> @@ -1369,8 +1462,6 @@ public: bool isFCCAsmReg() const { if (!(isRegIdx() && RegIdx.Kind & RegKind_FCC)) return false; - if (!AsmParser.hasEightFccRegisters()) - return RegIdx.Index == 0; return RegIdx.Index <= 7; } bool isACCAsmReg() const { @@ -1428,10 +1519,11 @@ public: OS << ">"; break; case k_RegisterIndex: - OS << "RegIdx<" << RegIdx.Index << ":" << RegIdx.Kind << ">"; + OS << "RegIdx<" << RegIdx.Index << ":" << RegIdx.Kind << ", " + << StringRef(RegIdx.Tok.Data, RegIdx.Tok.Length) << ">"; break; case k_Token: - OS << Tok.Data; + OS << getToken(); break; case k_RegList: OS << "RegList< "; @@ -1444,6 +1536,22 @@ public: break; } } + + bool isValidForTie(const MipsOperand &Other) const { + if (Kind != Other.Kind) + return false; + + switch (Kind) { + default: + llvm_unreachable("Unexpected kind"); + return false; + case k_RegisterIndex: { + StringRef Token(RegIdx.Tok.Data, RegIdx.Tok.Length); + StringRef OtherToken(Other.RegIdx.Tok.Data, Other.RegIdx.Tok.Length); + return Token == OtherToken; + } + } + } }; // class MipsOperand } // namespace @@ -1526,7 +1634,7 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc, case Mips::BBIT1: case Mips::BBIT132: assert(hasCnMips() && "instruction only valid for octeon cpus"); - // Fall through + LLVM_FALLTHROUGH; case Mips::BEQ: case Mips::BNE: @@ -1572,6 +1680,45 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc, 1LL << (inMicroMipsMode() ? 1 : 2))) return Error(IDLoc, "branch to misaligned address"); break; + case Mips::BGEC: case Mips::BGEC_MMR6: + case Mips::BLTC: case Mips::BLTC_MMR6: + case Mips::BGEUC: case Mips::BGEUC_MMR6: + case Mips::BLTUC: case Mips::BLTUC_MMR6: + case Mips::BEQC: case Mips::BEQC_MMR6: + case Mips::BNEC: case Mips::BNEC_MMR6: + assert(MCID.getNumOperands() == 3 && "unexpected number of operands"); + Offset = Inst.getOperand(2); + if (!Offset.isImm()) + break; // We'll deal with this situation later on when applying fixups. + if (!isIntN(18, Offset.getImm())) + return Error(IDLoc, "branch target out of range"); + if (OffsetToAlignment(Offset.getImm(), 1LL << 2)) + return Error(IDLoc, "branch to misaligned address"); + break; + case Mips::BLEZC: case Mips::BLEZC_MMR6: + case Mips::BGEZC: case Mips::BGEZC_MMR6: + case Mips::BGTZC: case Mips::BGTZC_MMR6: + case Mips::BLTZC: case Mips::BLTZC_MMR6: + assert(MCID.getNumOperands() == 2 && "unexpected number of operands"); + Offset = Inst.getOperand(1); + if (!Offset.isImm()) + break; // We'll deal with this situation later on when applying fixups. + if (!isIntN(18, Offset.getImm())) + return Error(IDLoc, "branch target out of range"); + if (OffsetToAlignment(Offset.getImm(), 1LL << 2)) + return Error(IDLoc, "branch to misaligned address"); + break; + case Mips::BEQZC: case Mips::BEQZC_MMR6: + case Mips::BNEZC: case Mips::BNEZC_MMR6: + assert(MCID.getNumOperands() == 2 && "unexpected number of operands"); + Offset = Inst.getOperand(1); + if (!Offset.isImm()) + break; // We'll deal with this situation later on when applying fixups. + if (!isIntN(23, Offset.getImm())) + return Error(IDLoc, "branch target out of range"); + if (OffsetToAlignment(Offset.getImm(), 1LL << 2)) + return Error(IDLoc, "branch to misaligned address"); + break; case Mips::BEQZ16_MM: case Mips::BEQZC16_MMR6: case Mips::BNEZ16_MM: @@ -1638,6 +1785,17 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc, } } + // For PIC code convert unconditional jump to unconditional branch. + if ((Inst.getOpcode() == Mips::J || Inst.getOpcode() == Mips::J_MM) && + inPicMode()) { + MCInst BInst; + BInst.setOpcode(inMicroMipsMode() ? Mips::BEQ_MM : Mips::BEQ); + BInst.addOperand(MCOperand::createReg(Mips::ZERO)); + BInst.addOperand(MCOperand::createReg(Mips::ZERO)); + BInst.addOperand(Inst.getOperand(0)); + Inst = BInst; + } + // This expansion is not in a function called by tryExpandInstruction() // because the pseudo-instruction doesn't have a distinct opcode. if ((Inst.getOpcode() == Mips::JAL || Inst.getOpcode() == Mips::JAL_MM) && @@ -1658,7 +1816,8 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc, // FIXME: Add support for label+offset operands (currently causes an error). // FIXME: Add support for forward-declared local symbols. // FIXME: Add expansion for when the LargeGOT option is enabled. - if (JalSym->isInSection() || JalSym->isTemporary()) { + if (JalSym->isInSection() || JalSym->isTemporary() || + (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) @@ -1716,7 +1875,8 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc, ExpandedJalSym = true; } - if (MCID.mayLoad() || MCID.mayStore()) { + bool IsPCRelativeLoad = (MCID.TSFlags & MipsII::IsPCRelativeLoad) != 0; + if ((MCID.mayLoad() || MCID.mayStore()) && !IsPCRelativeLoad) { // Check the offset of memory operand, if it is a symbol // reference or immediate we may have to expand instructions. for (unsigned i = 0; i < MCID.getNumOperands(); i++) { @@ -1729,7 +1889,7 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc, if (MemOffset < -32768 || MemOffset > 32767) { // Offset can't exceed 16bit value. expandMemInst(Inst, IDLoc, Out, STI, MCID.mayLoad(), true); - return false; + return getParser().hasPendingError(); } } else if (Op.isExpr()) { const MCExpr *Expr = Op.getExpr(); @@ -1739,11 +1899,11 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc, if (SR->getKind() == MCSymbolRefExpr::VK_None) { // Expand symbol. expandMemInst(Inst, IDLoc, Out, STI, MCID.mayLoad(), false); - return false; + return getParser().hasPendingError(); } } else if (!isEvaluated(Expr)) { expandMemInst(Inst, IDLoc, Out, STI, MCID.mayLoad(), false); - return false; + return getParser().hasPendingError(); } } } @@ -2034,8 +2194,11 @@ MipsAsmParser::tryExpandInstruction(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, return expandUlh(Inst, true, IDLoc, Out, STI) ? MER_Fail : MER_Success; case Mips::Ulhu: return expandUlh(Inst, false, IDLoc, Out, STI) ? MER_Fail : MER_Success; + case Mips::Ush: + return expandUsh(Inst, IDLoc, Out, STI) ? MER_Fail : MER_Success; case Mips::Ulw: - return expandUlw(Inst, IDLoc, Out, STI) ? MER_Fail : MER_Success; + case Mips::Usw: + return expandUxw(Inst, IDLoc, Out, STI) ? MER_Fail : MER_Success; case Mips::NORImm: return expandAliasImmediate(Inst, IDLoc, Out, STI) ? MER_Fail : MER_Success; case Mips::ADDi: @@ -2077,6 +2240,16 @@ MipsAsmParser::tryExpandInstruction(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, return expandDRotationImm(Inst, IDLoc, Out, STI) ? MER_Fail : MER_Success; case Mips::ABSMacro: return expandAbs(Inst, IDLoc, Out, STI) ? MER_Fail : MER_Success; + case Mips::LDMacro: + case Mips::SDMacro: + return expandLoadStoreDMacro(Inst, IDLoc, Out, STI, + Inst.getOpcode() == Mips::LDMacro) + ? MER_Fail + : MER_Success; + case Mips::SEQMacro: + return expandSeq(Inst, IDLoc, Out, STI) ? MER_Fail : MER_Success; + case Mips::SEQIMacro: + return expandSeqI(Inst, IDLoc, Out, STI) ? MER_Fail : MER_Success; } } @@ -2335,6 +2508,7 @@ bool MipsAsmParser::expandLoadAddress(unsigned DstReg, unsigned BaseReg, Error(IDLoc, "la used to load 64-bit address"); // Continue as if we had 'dla' instead. Is32BitAddress = false; + return true; } // dla requires 64-bit addresses. @@ -2561,9 +2735,9 @@ bool MipsAsmParser::expandUncondBranchMMPseudo(MCInst &Inst, SMLoc IDLoc, Inst.setOpcode(hasMips32r6() ? Mips::BC16_MMR6 : Mips::B16_MM); } else { if (!isInt<17>(Offset.getImm())) - Error(IDLoc, "branch target out of range"); + return Error(IDLoc, "branch target out of range"); if (OffsetToAlignment(Offset.getImm(), 1LL << 1)) - Error(IDLoc, "branch to misaligned address"); + return Error(IDLoc, "branch to misaligned address"); Inst.clear(); Inst.setOpcode(Mips::BEQ_MM); Inst.addOperand(MCOperand::createReg(Mips::ZERO)); @@ -3168,146 +3342,158 @@ bool MipsAsmParser::expandTrunc(MCInst &Inst, bool IsDouble, bool Is64FPU, bool MipsAsmParser::expandUlh(MCInst &Inst, bool Signed, SMLoc IDLoc, MCStreamer &Out, const MCSubtargetInfo *STI) { - MipsTargetStreamer &TOut = getTargetStreamer(); - if (hasMips32r6() || hasMips64r6()) { - Error(IDLoc, "instruction not supported on mips32r6 or mips64r6"); - return false; + return Error(IDLoc, "instruction not supported on mips32r6 or mips64r6"); } - warnIfNoMacro(IDLoc); - const MCOperand &DstRegOp = Inst.getOperand(0); assert(DstRegOp.isReg() && "expected register operand kind"); - const MCOperand &SrcRegOp = Inst.getOperand(1); assert(SrcRegOp.isReg() && "expected register operand kind"); - const MCOperand &OffsetImmOp = Inst.getOperand(2); assert(OffsetImmOp.isImm() && "expected immediate operand kind"); + MipsTargetStreamer &TOut = getTargetStreamer(); unsigned DstReg = DstRegOp.getReg(); unsigned SrcReg = SrcRegOp.getReg(); int64_t OffsetValue = OffsetImmOp.getImm(); // NOTE: We always need AT for ULHU, as it is always used as the source // register for one of the LBu's. + warnIfNoMacro(IDLoc); unsigned ATReg = getATReg(IDLoc); if (!ATReg) return true; - // When the value of offset+1 does not fit in 16 bits, we have to load the - // offset in AT, (D)ADDu the original source register (if there was one), and - // then use AT as the source register for the 2 generated LBu's. - bool LoadedOffsetInAT = false; - if (!isInt<16>(OffsetValue + 1) || !isInt<16>(OffsetValue)) { - LoadedOffsetInAT = true; - - if (loadImmediate(OffsetValue, ATReg, Mips::NoRegister, !ABI.ArePtrs64bit(), - true, IDLoc, Out, STI)) + bool IsLargeOffset = !(isInt<16>(OffsetValue + 1) && isInt<16>(OffsetValue)); + if (IsLargeOffset) { + if (loadImmediate(OffsetValue, ATReg, SrcReg, !ABI.ArePtrs64bit(), true, + IDLoc, Out, STI)) return true; - - // NOTE: We do this (D)ADDu here instead of doing it in loadImmediate() - // because it will make our output more similar to GAS'. For example, - // generating an "ori $1, $zero, 32768" followed by an "addu $1, $1, $9", - // instead of just an "ori $1, $9, 32768". - // NOTE: If there is no source register specified in the ULHU, the parser - // will interpret it as $0. - if (SrcReg != Mips::ZERO && SrcReg != Mips::ZERO_64) - TOut.emitAddu(ATReg, ATReg, SrcReg, ABI.ArePtrs64bit(), STI); } - unsigned FirstLbuDstReg = LoadedOffsetInAT ? DstReg : ATReg; - unsigned SecondLbuDstReg = LoadedOffsetInAT ? ATReg : DstReg; - unsigned LbuSrcReg = LoadedOffsetInAT ? ATReg : SrcReg; + int64_t FirstOffset = IsLargeOffset ? 0 : OffsetValue; + int64_t SecondOffset = IsLargeOffset ? 1 : (OffsetValue + 1); + if (isLittle()) + std::swap(FirstOffset, SecondOffset); - int64_t FirstLbuOffset = 0, SecondLbuOffset = 0; - if (isLittle()) { - FirstLbuOffset = LoadedOffsetInAT ? 1 : (OffsetValue + 1); - SecondLbuOffset = LoadedOffsetInAT ? 0 : OffsetValue; - } else { - FirstLbuOffset = LoadedOffsetInAT ? 0 : OffsetValue; - SecondLbuOffset = LoadedOffsetInAT ? 1 : (OffsetValue + 1); - } + unsigned FirstLbuDstReg = IsLargeOffset ? DstReg : ATReg; + unsigned SecondLbuDstReg = IsLargeOffset ? ATReg : DstReg; - unsigned SllReg = LoadedOffsetInAT ? DstReg : ATReg; + unsigned LbuSrcReg = IsLargeOffset ? ATReg : SrcReg; + unsigned SllReg = IsLargeOffset ? DstReg : ATReg; TOut.emitRRI(Signed ? Mips::LB : Mips::LBu, FirstLbuDstReg, LbuSrcReg, - FirstLbuOffset, IDLoc, STI); - - TOut.emitRRI(Mips::LBu, SecondLbuDstReg, LbuSrcReg, SecondLbuOffset, IDLoc, - STI); - + FirstOffset, IDLoc, STI); + TOut.emitRRI(Mips::LBu, SecondLbuDstReg, LbuSrcReg, SecondOffset, IDLoc, STI); TOut.emitRRI(Mips::SLL, SllReg, SllReg, 8, IDLoc, STI); - TOut.emitRRR(Mips::OR, DstReg, DstReg, ATReg, IDLoc, STI); return false; } -bool MipsAsmParser::expandUlw(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, +bool MipsAsmParser::expandUsh(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, const MCSubtargetInfo *STI) { + if (hasMips32r6() || hasMips64r6()) { + return Error(IDLoc, "instruction not supported on mips32r6 or mips64r6"); + } + + const MCOperand &DstRegOp = Inst.getOperand(0); + assert(DstRegOp.isReg() && "expected register operand kind"); + const MCOperand &SrcRegOp = Inst.getOperand(1); + assert(SrcRegOp.isReg() && "expected register operand kind"); + const MCOperand &OffsetImmOp = Inst.getOperand(2); + assert(OffsetImmOp.isImm() && "expected immediate operand kind"); + MipsTargetStreamer &TOut = getTargetStreamer(); + unsigned DstReg = DstRegOp.getReg(); + unsigned SrcReg = SrcRegOp.getReg(); + int64_t OffsetValue = OffsetImmOp.getImm(); + warnIfNoMacro(IDLoc); + unsigned ATReg = getATReg(IDLoc); + if (!ATReg) + return true; + + bool IsLargeOffset = !(isInt<16>(OffsetValue + 1) && isInt<16>(OffsetValue)); + if (IsLargeOffset) { + if (loadImmediate(OffsetValue, ATReg, SrcReg, !ABI.ArePtrs64bit(), true, + IDLoc, Out, STI)) + return true; + } + + int64_t FirstOffset = IsLargeOffset ? 1 : (OffsetValue + 1); + int64_t SecondOffset = IsLargeOffset ? 0 : OffsetValue; + if (isLittle()) + std::swap(FirstOffset, SecondOffset); + + if (IsLargeOffset) { + TOut.emitRRI(Mips::SB, DstReg, ATReg, FirstOffset, IDLoc, STI); + TOut.emitRRI(Mips::SRL, DstReg, DstReg, 8, IDLoc, STI); + TOut.emitRRI(Mips::SB, DstReg, ATReg, SecondOffset, IDLoc, STI); + TOut.emitRRI(Mips::LBu, ATReg, ATReg, 0, IDLoc, STI); + TOut.emitRRI(Mips::SLL, DstReg, DstReg, 8, IDLoc, STI); + TOut.emitRRR(Mips::OR, DstReg, DstReg, ATReg, IDLoc, STI); + } else { + TOut.emitRRI(Mips::SB, DstReg, SrcReg, FirstOffset, IDLoc, STI); + TOut.emitRRI(Mips::SRL, ATReg, DstReg, 8, IDLoc, STI); + TOut.emitRRI(Mips::SB, ATReg, SrcReg, SecondOffset, IDLoc, STI); + } + + return false; +} + +bool MipsAsmParser::expandUxw(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, + const MCSubtargetInfo *STI) { if (hasMips32r6() || hasMips64r6()) { - Error(IDLoc, "instruction not supported on mips32r6 or mips64r6"); - return false; + return Error(IDLoc, "instruction not supported on mips32r6 or mips64r6"); } const MCOperand &DstRegOp = Inst.getOperand(0); assert(DstRegOp.isReg() && "expected register operand kind"); - const MCOperand &SrcRegOp = Inst.getOperand(1); assert(SrcRegOp.isReg() && "expected register operand kind"); - const MCOperand &OffsetImmOp = Inst.getOperand(2); assert(OffsetImmOp.isImm() && "expected immediate operand kind"); + MipsTargetStreamer &TOut = getTargetStreamer(); + unsigned DstReg = DstRegOp.getReg(); unsigned SrcReg = SrcRegOp.getReg(); int64_t OffsetValue = OffsetImmOp.getImm(); - unsigned ATReg = 0; - - // When the value of offset+3 does not fit in 16 bits, we have to load the - // offset in AT, (D)ADDu the original source register (if there was one), and - // then use AT as the source register for the generated LWL and LWR. - bool LoadedOffsetInAT = false; - if (!isInt<16>(OffsetValue + 3) || !isInt<16>(OffsetValue)) { - ATReg = getATReg(IDLoc); - if (!ATReg) - return true; - LoadedOffsetInAT = true; + // Compute left/right load/store offsets. + bool IsLargeOffset = !(isInt<16>(OffsetValue + 3) && isInt<16>(OffsetValue)); + int64_t LxlOffset = IsLargeOffset ? 0 : OffsetValue; + int64_t LxrOffset = IsLargeOffset ? 3 : (OffsetValue + 3); + if (isLittle()) + std::swap(LxlOffset, LxrOffset); + + bool IsLoadInst = (Inst.getOpcode() == Mips::Ulw); + bool DoMove = IsLoadInst && (SrcReg == DstReg) && !IsLargeOffset; + unsigned TmpReg = SrcReg; + if (IsLargeOffset || DoMove) { warnIfNoMacro(IDLoc); - - if (loadImmediate(OffsetValue, ATReg, Mips::NoRegister, !ABI.ArePtrs64bit(), - true, IDLoc, Out, STI)) + TmpReg = getATReg(IDLoc); + if (!TmpReg) return true; + } - // NOTE: We do this (D)ADDu here instead of doing it in loadImmediate() - // because it will make our output more similar to GAS'. For example, - // generating an "ori $1, $zero, 32768" followed by an "addu $1, $1, $9", - // instead of just an "ori $1, $9, 32768". - // NOTE: If there is no source register specified in the ULW, the parser - // will interpret it as $0. - if (SrcReg != Mips::ZERO && SrcReg != Mips::ZERO_64) - TOut.emitAddu(ATReg, ATReg, SrcReg, ABI.ArePtrs64bit(), STI); - } - - unsigned FinalSrcReg = LoadedOffsetInAT ? ATReg : SrcReg; - int64_t LeftLoadOffset = 0, RightLoadOffset = 0; - if (isLittle()) { - LeftLoadOffset = LoadedOffsetInAT ? 3 : (OffsetValue + 3); - RightLoadOffset = LoadedOffsetInAT ? 0 : OffsetValue; - } else { - LeftLoadOffset = LoadedOffsetInAT ? 0 : OffsetValue; - RightLoadOffset = LoadedOffsetInAT ? 3 : (OffsetValue + 3); + if (IsLargeOffset) { + if (loadImmediate(OffsetValue, TmpReg, SrcReg, !ABI.ArePtrs64bit(), true, + IDLoc, Out, STI)) + return true; } - TOut.emitRRI(Mips::LWL, DstRegOp.getReg(), FinalSrcReg, LeftLoadOffset, IDLoc, - STI); + if (DoMove) + std::swap(DstReg, TmpReg); - TOut.emitRRI(Mips::LWR, DstRegOp.getReg(), FinalSrcReg, RightLoadOffset, - IDLoc, STI); + unsigned XWL = IsLoadInst ? Mips::LWL : Mips::SWL; + unsigned XWR = IsLoadInst ? Mips::LWR : Mips::SWR; + TOut.emitRRI(XWL, DstReg, TmpReg, LxlOffset, IDLoc, STI); + TOut.emitRRI(XWR, DstReg, TmpReg, LxrOffset, IDLoc, STI); + + if (DoMove) + TOut.emitRRR(Mips::OR, TmpReg, DstReg, Mips::ZERO, IDLoc, STI); return false; } @@ -3685,8 +3871,198 @@ bool MipsAsmParser::expandAbs(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, return false; } +static unsigned nextReg(unsigned Reg) { + switch (Reg) { + case Mips::ZERO: return Mips::AT; + case Mips::AT: return Mips::V0; + case Mips::V0: return Mips::V1; + case Mips::V1: return Mips::A0; + case Mips::A0: return Mips::A1; + case Mips::A1: return Mips::A2; + case Mips::A2: return Mips::A3; + case Mips::A3: return Mips::T0; + case Mips::T0: return Mips::T1; + case Mips::T1: return Mips::T2; + case Mips::T2: return Mips::T3; + case Mips::T3: return Mips::T4; + case Mips::T4: return Mips::T5; + case Mips::T5: return Mips::T6; + case Mips::T6: return Mips::T7; + case Mips::T7: return Mips::S0; + case Mips::S0: return Mips::S1; + case Mips::S1: return Mips::S2; + case Mips::S2: return Mips::S3; + case Mips::S3: return Mips::S4; + case Mips::S4: return Mips::S5; + case Mips::S5: return Mips::S6; + case Mips::S6: return Mips::S7; + case Mips::S7: return Mips::T8; + case Mips::T8: return Mips::T9; + case Mips::T9: return Mips::K0; + case Mips::K0: return Mips::K1; + case Mips::K1: return Mips::GP; + case Mips::GP: return Mips::SP; + case Mips::SP: return Mips::FP; + case Mips::FP: return Mips::RA; + case Mips::RA: return Mips::ZERO; + default: return 0; + } + +} + +// Expand 'ld $<reg> offset($reg2)' to 'lw $<reg>, offset($reg2); +// lw $<reg+1>>, offset+4($reg2)' +// or expand 'sd $<reg> offset($reg2)' to 'sw $<reg>, offset($reg2); +// sw $<reg+1>>, offset+4($reg2)' +// for O32. +bool MipsAsmParser::expandLoadStoreDMacro(MCInst &Inst, SMLoc IDLoc, + MCStreamer &Out, + const MCSubtargetInfo *STI, + bool IsLoad) { + if (!isABI_O32()) + return true; + + warnIfNoMacro(IDLoc); + + MipsTargetStreamer &TOut = getTargetStreamer(); + unsigned Opcode = IsLoad ? Mips::LW : Mips::SW; + unsigned FirstReg = Inst.getOperand(0).getReg(); + unsigned SecondReg = nextReg(FirstReg); + unsigned BaseReg = Inst.getOperand(1).getReg(); + if (!SecondReg) + return true; + + warnIfRegIndexIsAT(FirstReg, IDLoc); + + assert(Inst.getOperand(2).isImm() && + "Offset for load macro is not immediate!"); + + MCOperand &FirstOffset = Inst.getOperand(2); + signed NextOffset = FirstOffset.getImm() + 4; + MCOperand SecondOffset = MCOperand::createImm(NextOffset); + + if (!isInt<16>(FirstOffset.getImm()) || !isInt<16>(NextOffset)) + return true; + + // For loads, clobber the base register with the second load instead of the + // first if the BaseReg == FirstReg. + if (FirstReg != BaseReg || !IsLoad) { + TOut.emitRRX(Opcode, FirstReg, BaseReg, FirstOffset, IDLoc, STI); + TOut.emitRRX(Opcode, SecondReg, BaseReg, SecondOffset, IDLoc, STI); + } else { + TOut.emitRRX(Opcode, SecondReg, BaseReg, SecondOffset, IDLoc, STI); + TOut.emitRRX(Opcode, FirstReg, BaseReg, FirstOffset, IDLoc, STI); + } + + return false; +} + +bool MipsAsmParser::expandSeq(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, + const MCSubtargetInfo *STI) { + + warnIfNoMacro(IDLoc); + MipsTargetStreamer &TOut = getTargetStreamer(); + + if (Inst.getOperand(1).getReg() != Mips::ZERO && + Inst.getOperand(2).getReg() != Mips::ZERO) { + TOut.emitRRR(Mips::XOR, Inst.getOperand(0).getReg(), + Inst.getOperand(1).getReg(), Inst.getOperand(2).getReg(), + IDLoc, STI); + TOut.emitRRI(Mips::SLTiu, Inst.getOperand(0).getReg(), + Inst.getOperand(0).getReg(), 1, IDLoc, STI); + return false; + } + + unsigned Reg = 0; + if (Inst.getOperand(1).getReg() == Mips::ZERO) { + Reg = Inst.getOperand(2).getReg(); + } else { + Reg = Inst.getOperand(1).getReg(); + } + TOut.emitRRI(Mips::SLTiu, Inst.getOperand(0).getReg(), Reg, 1, IDLoc, STI); + return false; +} + +bool MipsAsmParser::expandSeqI(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, + const MCSubtargetInfo *STI) { + + warnIfNoMacro(IDLoc); + MipsTargetStreamer &TOut = getTargetStreamer(); + + unsigned Opc; + int64_t Imm = Inst.getOperand(2).getImm(); + unsigned Reg = Inst.getOperand(1).getReg(); + + if (Imm == 0) { + TOut.emitRRI(Mips::SLTiu, Inst.getOperand(0).getReg(), + Inst.getOperand(1).getReg(), 1, IDLoc, STI); + return false; + } else { + + if (Reg == Mips::ZERO) { + Warning(IDLoc, "comparison is always false"); + TOut.emitRRR(isGP64bit() ? Mips::DADDu : Mips::ADDu, + Inst.getOperand(0).getReg(), Reg, Reg, IDLoc, STI); + return false; + } + + if (Imm > -0x8000 && Imm < 0) { + Imm = -Imm; + Opc = isGP64bit() ? Mips::DADDiu : Mips::ADDiu; + } else { + Opc = Mips::XORi; + } + } + if (!isUInt<16>(Imm)) { + unsigned ATReg = getATReg(IDLoc); + if (!ATReg) + return true; + + if (loadImmediate(Imm, ATReg, Mips::NoRegister, true, isGP64bit(), IDLoc, + Out, STI)) + return true; + + TOut.emitRRR(Mips::XOR, Inst.getOperand(0).getReg(), + Inst.getOperand(1).getReg(), ATReg, IDLoc, STI); + TOut.emitRRI(Mips::SLTiu, Inst.getOperand(0).getReg(), + Inst.getOperand(0).getReg(), 1, IDLoc, STI); + return false; + } + + TOut.emitRRI(Opc, Inst.getOperand(0).getReg(), Inst.getOperand(1).getReg(), + Imm, IDLoc, STI); + TOut.emitRRI(Mips::SLTiu, Inst.getOperand(0).getReg(), + Inst.getOperand(0).getReg(), 1, IDLoc, STI); + return false; +} + +unsigned +MipsAsmParser::checkEarlyTargetMatchPredicate(MCInst &Inst, + const OperandVector &Operands) { + switch (Inst.getOpcode()) { + default: + return Match_Success; + case Mips::DATI: + case Mips::DAHI: + case Mips::DATI_MM64R6: + case Mips::DAHI_MM64R6: + if (static_cast<MipsOperand &>(*Operands[1]) + .isValidForTie(static_cast<MipsOperand &>(*Operands[2]))) + return Match_Success; + return Match_RequiresSameSrcAndDst; + } +} + unsigned MipsAsmParser::checkTargetMatchPredicate(MCInst &Inst) { switch (Inst.getOpcode()) { + // As described by the MIPSR6 spec, daui must not use the zero operand for + // its source operand. + case Mips::DAUI: + case Mips::DAUI_MM64R6: + if (Inst.getOperand(1).getReg() == Mips::ZERO || + Inst.getOperand(1).getReg() == Mips::ZERO_64) + return Match_RequiresNoZeroRegister; + return Match_Success; // As described by the Mips32r2 spec, the registers Rd and Rs for // jalr.hb must be different. // It also applies for registers Rt and Rs of microMIPSr6 jalrc.hb instruction @@ -3702,6 +4078,10 @@ unsigned MipsAsmParser::checkTargetMatchPredicate(MCInst &Inst) { if (Inst.getOperand(0).getReg() == Inst.getOperand(2).getReg()) return Match_RequiresDifferentSrcAndDst; return Match_Success; + case Mips::SYNC: + if (Inst.getOperand(0).getImm() != 0 && !hasMips32()) + return Match_NonZeroOperandForSync; + return Match_Success; // As described the MIPSR6 spec, the compact branches that compare registers // must: // a) Not use the zero register. @@ -3714,31 +4094,52 @@ unsigned MipsAsmParser::checkTargetMatchPredicate(MCInst &Inst) { // The compact branches that branch iff the signed addition of two registers // would overflow must have rs >= rt. That can be handled like beqc/bnec with // operand swapping. They do not have restriction of using the zero register. - case Mips::BLEZC: - case Mips::BGEZC: - case Mips::BGTZC: - case Mips::BLTZC: - case Mips::BEQZC: - case Mips::BNEZC: - if (Inst.getOperand(0).getReg() == Mips::ZERO) + case Mips::BLEZC: case Mips::BLEZC_MMR6: + case Mips::BGEZC: case Mips::BGEZC_MMR6: + case Mips::BGTZC: case Mips::BGTZC_MMR6: + case Mips::BLTZC: case Mips::BLTZC_MMR6: + case Mips::BEQZC: case Mips::BEQZC_MMR6: + case Mips::BNEZC: case Mips::BNEZC_MMR6: + case Mips::BLEZC64: + case Mips::BGEZC64: + case Mips::BGTZC64: + case Mips::BLTZC64: + case Mips::BEQZC64: + case Mips::BNEZC64: + if (Inst.getOperand(0).getReg() == Mips::ZERO || + Inst.getOperand(0).getReg() == Mips::ZERO_64) return Match_RequiresNoZeroRegister; return Match_Success; - case Mips::BGEC: - case Mips::BLTC: - case Mips::BGEUC: - case Mips::BLTUC: - case Mips::BEQC: - case Mips::BNEC: - if (Inst.getOperand(0).getReg() == Mips::ZERO) + case Mips::BGEC: case Mips::BGEC_MMR6: + case Mips::BLTC: case Mips::BLTC_MMR6: + case Mips::BGEUC: case Mips::BGEUC_MMR6: + case Mips::BLTUC: case Mips::BLTUC_MMR6: + case Mips::BEQC: case Mips::BEQC_MMR6: + case Mips::BNEC: case Mips::BNEC_MMR6: + case Mips::BGEC64: + case Mips::BLTC64: + case Mips::BGEUC64: + case Mips::BLTUC64: + case Mips::BEQC64: + case Mips::BNEC64: + if (Inst.getOperand(0).getReg() == Mips::ZERO || + Inst.getOperand(0).getReg() == Mips::ZERO_64) return Match_RequiresNoZeroRegister; - if (Inst.getOperand(1).getReg() == Mips::ZERO) + if (Inst.getOperand(1).getReg() == Mips::ZERO || + Inst.getOperand(1).getReg() == Mips::ZERO_64) return Match_RequiresNoZeroRegister; if (Inst.getOperand(0).getReg() == Inst.getOperand(1).getReg()) return Match_RequiresDifferentOperands; return Match_Success; - default: - return Match_Success; } + + uint64_t TSFlags = getInstDesc(Inst.getOpcode()).TSFlags; + if ((TSFlags & MipsII::HasFCCRegOperand) && + (Inst.getOperand(0).getReg() != Mips::FCC0) && !hasEightFccRegisters()) + return Match_NoFCCRegisterForCurrentISA; + + return Match_Success; + } static SMLoc RefineErrorLoc(const SMLoc Loc, const OperandVector &Operands, @@ -3784,6 +4185,8 @@ 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"); case Match_MnemonicFail: return Error(IDLoc, "invalid instruction"); case Match_RequiresDifferentSrcAndDst: @@ -3792,6 +4195,11 @@ bool MipsAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, return Error(IDLoc, "registers must be different"); case Match_RequiresNoZeroRegister: return Error(IDLoc, "invalid operand ($zero) for instruction"); + case Match_RequiresSameSrcAndDst: + return Error(IDLoc, "source and destination must match"); + case Match_NoFCCRegisterForCurrentISA: + return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), + "non-zero fcc register doesn't exist in current ISA level"); case Match_Immz: return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), "expected '0'"); case Match_UImm1_0: @@ -3876,6 +4284,9 @@ bool MipsAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, case Match_SImm16_Relaxed: return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), "expected 16-bit signed immediate"); + case Match_SImm19_Lsl2: + return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), + "expected both 19-bit signed immediate and multiple of 4"); case Match_UImm20_0: return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), "expected 20-bit unsigned immediate"); @@ -3886,6 +4297,9 @@ bool MipsAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, case Match_SImm32_Relaxed: return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), "expected 32-bit signed immediate"); + case Match_UImm32_Coerced: + return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), + "expected 32-bit immediate"); case Match_MemSImm9: return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), "expected memory with 9-bit signed offset"); @@ -4131,9 +4545,6 @@ bool MipsAsmParser::parseOperand(OperandVector &Operands, StringRef Mnemonic) { DEBUG(dbgs() << ".. Generic Parser\n"); switch (getLexer().getKind()) { - default: - Error(Parser.getTok().getLoc(), "unexpected token in operand"); - return true; case AsmToken::Dollar: { // Parse the register. SMLoc S = Parser.getTok().getLoc(); @@ -4160,72 +4571,23 @@ bool MipsAsmParser::parseOperand(OperandVector &Operands, StringRef Mnemonic) { Operands.push_back(MipsOperand::CreateImm(Res, S, E, *this)); return false; } - // Else drop to expression parsing. - case AsmToken::LParen: - case AsmToken::Minus: - case AsmToken::Plus: - case AsmToken::Integer: - case AsmToken::Tilde: - case AsmToken::String: { - DEBUG(dbgs() << ".. generic integer\n"); - OperandMatchResultTy ResTy = parseImm(Operands); - return ResTy != MatchOperand_Success; - } - case AsmToken::Percent: { - // It is a symbol reference or constant expression. - const MCExpr *IdVal; + default: { + DEBUG(dbgs() << ".. generic integer expression\n"); + + const MCExpr *Expr; SMLoc S = Parser.getTok().getLoc(); // Start location of the operand. - if (parseRelocOperand(IdVal)) + if (getParser().parseExpression(Expr)) return true; SMLoc E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); - Operands.push_back(MipsOperand::CreateImm(IdVal, S, E, *this)); + Operands.push_back(MipsOperand::CreateImm(Expr, S, E, *this)); return false; - } // case AsmToken::Percent + } } // switch(getLexer().getKind()) return true; } -const MCExpr *MipsAsmParser::evaluateRelocExpr(const MCExpr *Expr, - StringRef RelocStr) { - if (RelocStr == "hi(%neg(%gp_rel") - return MipsMCExpr::createGpOff(MipsMCExpr::MEK_HI, Expr, getContext()); - else if (RelocStr == "lo(%neg(%gp_rel") - return MipsMCExpr::createGpOff(MipsMCExpr::MEK_LO, Expr, getContext()); - - MipsMCExpr::MipsExprKind Kind = - StringSwitch<MipsMCExpr::MipsExprKind>(RelocStr) - .Case("call16", MipsMCExpr::MEK_GOT_CALL) - .Case("call_hi", MipsMCExpr::MEK_CALL_HI16) - .Case("call_lo", MipsMCExpr::MEK_CALL_LO16) - .Case("dtprel_hi", MipsMCExpr::MEK_DTPREL_HI) - .Case("dtprel_lo", MipsMCExpr::MEK_DTPREL_LO) - .Case("got", MipsMCExpr::MEK_GOT) - .Case("got_disp", MipsMCExpr::MEK_GOT_DISP) - .Case("got_hi", MipsMCExpr::MEK_GOT_HI16) - .Case("got_lo", MipsMCExpr::MEK_GOT_LO16) - .Case("got_ofst", MipsMCExpr::MEK_GOT_OFST) - .Case("got_page", MipsMCExpr::MEK_GOT_PAGE) - .Case("gottprel", MipsMCExpr::MEK_GOTTPREL) - .Case("gp_rel", MipsMCExpr::MEK_GPREL) - .Case("hi", MipsMCExpr::MEK_HI) - .Case("higher", MipsMCExpr::MEK_HIGHER) - .Case("highest", MipsMCExpr::MEK_HIGHEST) - .Case("lo", MipsMCExpr::MEK_LO) - .Case("neg", MipsMCExpr::MEK_NEG) - .Case("pcrel_hi", MipsMCExpr::MEK_PCREL_HI16) - .Case("pcrel_lo", MipsMCExpr::MEK_PCREL_LO16) - .Case("tlsgd", MipsMCExpr::MEK_TLSGD) - .Case("tlsldm", MipsMCExpr::MEK_TLSLDM) - .Case("tprel_hi", MipsMCExpr::MEK_TPREL_HI) - .Case("tprel_lo", MipsMCExpr::MEK_TPREL_LO) - .Default(MipsMCExpr::MEK_None); - - assert(Kind != MipsMCExpr::MEK_None); - return MipsMCExpr::create(Kind, Expr, getContext()); -} - bool MipsAsmParser::isEvaluated(const MCExpr *Expr) { switch (Expr->getKind()) { @@ -4247,49 +4609,6 @@ bool MipsAsmParser::isEvaluated(const MCExpr *Expr) { return false; } -bool MipsAsmParser::parseRelocOperand(const MCExpr *&Res) { - MCAsmParser &Parser = getParser(); - Parser.Lex(); // Eat the % token. - const AsmToken &Tok = Parser.getTok(); // Get next token, operation. - if (Tok.isNot(AsmToken::Identifier)) - return true; - - std::string Str = Tok.getIdentifier(); - - Parser.Lex(); // Eat the identifier. - // Now make an expression from the rest of the operand. - const MCExpr *IdVal; - SMLoc EndLoc; - - if (getLexer().getKind() == AsmToken::LParen) { - while (1) { - Parser.Lex(); // Eat the '(' token. - if (getLexer().getKind() == AsmToken::Percent) { - Parser.Lex(); // Eat the % token. - const AsmToken &nextTok = Parser.getTok(); - if (nextTok.isNot(AsmToken::Identifier)) - return true; - Str += "(%"; - Str += nextTok.getIdentifier(); - Parser.Lex(); // Eat the identifier. - if (getLexer().getKind() != AsmToken::LParen) - return true; - } else - break; - } - if (getParser().parseParenExpression(IdVal, EndLoc)) - return true; - - while (getLexer().getKind() == AsmToken::RParen) - Parser.Lex(); // Eat the ')' token. - - } else - return true; // Parenthesis must follow the relocation operand. - - Res = evaluateRelocExpr(IdVal, Str); - return false; -} - bool MipsAsmParser::ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc) { SmallVector<std::unique_ptr<MCParsedAsmOperand>, 1> Operands; @@ -4317,45 +4636,21 @@ bool MipsAsmParser::ParseRegister(unsigned &RegNo, SMLoc &StartLoc, } bool MipsAsmParser::parseMemOffset(const MCExpr *&Res, bool isParenExpr) { - MCAsmParser &Parser = getParser(); SMLoc S; - bool Result = true; - unsigned NumOfLParen = 0; - - while (getLexer().getKind() == AsmToken::LParen) { - Parser.Lex(); - ++NumOfLParen; - } - switch (getLexer().getKind()) { - default: - return true; - case AsmToken::Identifier: - case AsmToken::LParen: - case AsmToken::Integer: - case AsmToken::Minus: - case AsmToken::Plus: - if (isParenExpr) - Result = getParser().parseParenExprOfDepth(NumOfLParen, Res, S); - else - Result = (getParser().parseExpression(Res)); - while (getLexer().getKind() == AsmToken::RParen) - Parser.Lex(); - break; - case AsmToken::Percent: - Result = parseRelocOperand(Res); - } - return Result; + if (isParenExpr) + return getParser().parseParenExprOfDepth(0, Res, S); + return getParser().parseExpression(Res); } -MipsAsmParser::OperandMatchResultTy +OperandMatchResultTy MipsAsmParser::parseMemOperand(OperandVector &Operands) { MCAsmParser &Parser = getParser(); DEBUG(dbgs() << "parseMemOperand\n"); const MCExpr *IdVal = nullptr; SMLoc S; bool isParenExpr = false; - MipsAsmParser::OperandMatchResultTy Res = MatchOperand_NoMatch; + OperandMatchResultTy Res = MatchOperand_NoMatch; // First operand is the offset. S = Parser.getTok().getLoc(); @@ -4383,14 +4678,66 @@ MipsAsmParser::parseMemOperand(OperandVector &Operands) { // Zero register assumed, add a memory operand with ZERO as its base. // "Base" will be managed by k_Memory. - auto Base = MipsOperand::createGPRReg(0, getContext().getRegisterInfo(), - S, E, *this); + auto Base = MipsOperand::createGPRReg( + 0, "0", getContext().getRegisterInfo(), S, E, *this); Operands.push_back( MipsOperand::CreateMem(std::move(Base), IdVal, S, E, *this)); return MatchOperand_Success; } - Error(Parser.getTok().getLoc(), "'(' expected"); - return MatchOperand_ParseFail; + MCBinaryExpr::Opcode Opcode; + // GAS and LLVM treat comparison operators different. GAS will generate -1 + // or 0, while LLVM will generate 0 or 1. Since a comparsion operator is + // highly unlikely to be found in a memory offset expression, we don't + // handle them. + switch (Tok.getKind()) { + case AsmToken::Plus: + Opcode = MCBinaryExpr::Add; + Parser.Lex(); + break; + case AsmToken::Minus: + Opcode = MCBinaryExpr::Sub; + Parser.Lex(); + break; + case AsmToken::Star: + Opcode = MCBinaryExpr::Mul; + Parser.Lex(); + break; + case AsmToken::Pipe: + Opcode = MCBinaryExpr::Or; + Parser.Lex(); + break; + case AsmToken::Amp: + Opcode = MCBinaryExpr::And; + Parser.Lex(); + break; + case AsmToken::LessLess: + Opcode = MCBinaryExpr::Shl; + Parser.Lex(); + break; + case AsmToken::GreaterGreater: + Opcode = MCBinaryExpr::LShr; + Parser.Lex(); + break; + case AsmToken::Caret: + Opcode = MCBinaryExpr::Xor; + Parser.Lex(); + break; + case AsmToken::Slash: + Opcode = MCBinaryExpr::Div; + Parser.Lex(); + break; + case AsmToken::Percent: + Opcode = MCBinaryExpr::Mod; + Parser.Lex(); + break; + default: + Error(Parser.getTok().getLoc(), "'(' or expression expected"); + return MatchOperand_ParseFail; + } + const MCExpr * NextExpr; + if (getParser().parseExpression(NextExpr)) + return MatchOperand_ParseFail; + IdVal = MCBinaryExpr::create(Opcode, IdVal, NextExpr, getContext()); } Parser.Lex(); // Eat the '(' token. @@ -4460,63 +4807,70 @@ bool MipsAsmParser::searchSymbolAlias(OperandVector &Operands) { return false; } -MipsAsmParser::OperandMatchResultTy +OperandMatchResultTy MipsAsmParser::matchAnyRegisterNameWithoutDollar(OperandVector &Operands, StringRef Identifier, SMLoc S) { int Index = matchCPURegisterName(Identifier); if (Index != -1) { Operands.push_back(MipsOperand::createGPRReg( - Index, getContext().getRegisterInfo(), S, getLexer().getLoc(), *this)); + Index, Identifier, getContext().getRegisterInfo(), S, + getLexer().getLoc(), *this)); return MatchOperand_Success; } Index = matchHWRegsRegisterName(Identifier); if (Index != -1) { Operands.push_back(MipsOperand::createHWRegsReg( - Index, getContext().getRegisterInfo(), S, getLexer().getLoc(), *this)); + Index, Identifier, getContext().getRegisterInfo(), S, + getLexer().getLoc(), *this)); return MatchOperand_Success; } Index = matchFPURegisterName(Identifier); if (Index != -1) { Operands.push_back(MipsOperand::createFGRReg( - Index, getContext().getRegisterInfo(), S, getLexer().getLoc(), *this)); + Index, Identifier, getContext().getRegisterInfo(), S, + getLexer().getLoc(), *this)); return MatchOperand_Success; } Index = matchFCCRegisterName(Identifier); if (Index != -1) { Operands.push_back(MipsOperand::createFCCReg( - Index, getContext().getRegisterInfo(), S, getLexer().getLoc(), *this)); + Index, Identifier, getContext().getRegisterInfo(), S, + getLexer().getLoc(), *this)); return MatchOperand_Success; } Index = matchACRegisterName(Identifier); if (Index != -1) { Operands.push_back(MipsOperand::createACCReg( - Index, getContext().getRegisterInfo(), S, getLexer().getLoc(), *this)); + Index, Identifier, getContext().getRegisterInfo(), S, + getLexer().getLoc(), *this)); return MatchOperand_Success; } Index = matchMSA128RegisterName(Identifier); if (Index != -1) { Operands.push_back(MipsOperand::createMSA128Reg( - Index, getContext().getRegisterInfo(), S, getLexer().getLoc(), *this)); + Index, Identifier, getContext().getRegisterInfo(), S, + getLexer().getLoc(), *this)); return MatchOperand_Success; } Index = matchMSA128CtrlRegisterName(Identifier); if (Index != -1) { Operands.push_back(MipsOperand::createMSACtrlReg( - Index, getContext().getRegisterInfo(), S, getLexer().getLoc(), *this)); + Index, Identifier, getContext().getRegisterInfo(), S, + getLexer().getLoc(), *this)); return MatchOperand_Success; } return MatchOperand_NoMatch; } -MipsAsmParser::OperandMatchResultTy +OperandMatchResultTy MipsAsmParser::matchAnyRegisterWithoutDollar(OperandVector &Operands, SMLoc S) { MCAsmParser &Parser = getParser(); auto Token = Parser.getLexer().peekTok(false); @@ -4530,8 +4884,8 @@ MipsAsmParser::matchAnyRegisterWithoutDollar(OperandVector &Operands, SMLoc S) { } else if (Token.is(AsmToken::Integer)) { DEBUG(dbgs() << ".. integer\n"); Operands.push_back(MipsOperand::createNumericReg( - Token.getIntVal(), getContext().getRegisterInfo(), S, Token.getLoc(), - *this)); + Token.getIntVal(), Token.getString(), getContext().getRegisterInfo(), S, + Token.getLoc(), *this)); return MatchOperand_Success; } @@ -4540,7 +4894,7 @@ MipsAsmParser::matchAnyRegisterWithoutDollar(OperandVector &Operands, SMLoc S) { return MatchOperand_NoMatch; } -MipsAsmParser::OperandMatchResultTy +OperandMatchResultTy MipsAsmParser::parseAnyRegister(OperandVector &Operands) { MCAsmParser &Parser = getParser(); DEBUG(dbgs() << "parseAnyRegister\n"); @@ -4568,48 +4922,19 @@ MipsAsmParser::parseAnyRegister(OperandVector &Operands) { return ResTy; } -MipsAsmParser::OperandMatchResultTy -MipsAsmParser::parseImm(OperandVector &Operands) { - MCAsmParser &Parser = getParser(); - switch (getLexer().getKind()) { - default: - return MatchOperand_NoMatch; - case AsmToken::LParen: - case AsmToken::Minus: - case AsmToken::Plus: - case AsmToken::Integer: - case AsmToken::Tilde: - case AsmToken::String: - break; - } - - const MCExpr *IdVal; - SMLoc S = Parser.getTok().getLoc(); - if (getParser().parseExpression(IdVal)) - return MatchOperand_ParseFail; - - SMLoc E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); - Operands.push_back(MipsOperand::CreateImm(IdVal, S, E, *this)); - return MatchOperand_Success; -} - -MipsAsmParser::OperandMatchResultTy +OperandMatchResultTy MipsAsmParser::parseJumpTarget(OperandVector &Operands) { MCAsmParser &Parser = getParser(); DEBUG(dbgs() << "parseJumpTarget\n"); SMLoc S = getLexer().getLoc(); - // Integers and expressions are acceptable - OperandMatchResultTy ResTy = parseImm(Operands); - if (ResTy != MatchOperand_NoMatch) - return ResTy; - // Registers are a valid target and have priority over symbols. - ResTy = parseAnyRegister(Operands); + OperandMatchResultTy ResTy = parseAnyRegister(Operands); if (ResTy != MatchOperand_NoMatch) return ResTy; + // Integers and expressions are acceptable const MCExpr *Expr = nullptr; if (Parser.parseExpression(Expr)) { // We have no way of knowing if a symbol was consumed so we must ParseFail @@ -4620,7 +4945,7 @@ MipsAsmParser::parseJumpTarget(OperandVector &Operands) { return MatchOperand_Success; } -MipsAsmParser::OperandMatchResultTy +OperandMatchResultTy MipsAsmParser::parseInvNum(OperandVector &Operands) { MCAsmParser &Parser = getParser(); const MCExpr *IdVal; @@ -4639,7 +4964,7 @@ MipsAsmParser::parseInvNum(OperandVector &Operands) { return MatchOperand_Success; } -MipsAsmParser::OperandMatchResultTy +OperandMatchResultTy MipsAsmParser::parseRegisterList(OperandVector &Operands) { MCAsmParser &Parser = getParser(); SmallVector<unsigned, 10> Regs; @@ -4725,7 +5050,7 @@ MipsAsmParser::parseRegisterList(OperandVector &Operands) { return MatchOperand_Success; } -MipsAsmParser::OperandMatchResultTy +OperandMatchResultTy MipsAsmParser::parseRegisterPair(OperandVector &Operands) { MCAsmParser &Parser = getParser(); @@ -4741,7 +5066,7 @@ MipsAsmParser::parseRegisterPair(OperandVector &Operands) { return MatchOperand_Success; } -MipsAsmParser::OperandMatchResultTy +OperandMatchResultTy MipsAsmParser::parseMovePRegPair(OperandVector &Operands) { MCAsmParser &Parser = getParser(); SmallVector<std::unique_ptr<MCParsedAsmOperand>, 8> TmpOperands; @@ -4793,12 +5118,10 @@ bool MipsAsmParser::parseParenSuffix(StringRef Name, OperandVector &Operands) { Parser.Lex(); if (parseOperand(Operands, Name)) { SMLoc Loc = getLexer().getLoc(); - Parser.eatToEndOfStatement(); return Error(Loc, "unexpected token in argument list"); } if (Parser.getTok().isNot(AsmToken::RParen)) { SMLoc Loc = getLexer().getLoc(); - Parser.eatToEndOfStatement(); return Error(Loc, "unexpected token, expected ')'"); } Operands.push_back( @@ -4823,12 +5146,10 @@ bool MipsAsmParser::parseBracketSuffix(StringRef Name, Parser.Lex(); if (parseOperand(Operands, Name)) { SMLoc Loc = getLexer().getLoc(); - Parser.eatToEndOfStatement(); return Error(Loc, "unexpected token in argument list"); } if (Parser.getTok().isNot(AsmToken::RBrac)) { SMLoc Loc = getLexer().getLoc(); - Parser.eatToEndOfStatement(); return Error(Loc, "unexpected token, expected ']'"); } Operands.push_back( @@ -4848,7 +5169,6 @@ bool MipsAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name, // Check if we have valid mnemonic if (!mnemonicIsValid(Name, 0)) { - Parser.eatToEndOfStatement(); return Error(NameLoc, "unknown instruction"); } // First operand in MCInst is instruction mnemonic. @@ -4859,7 +5179,6 @@ bool MipsAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name, // Read the first operand. if (parseOperand(Operands, Name)) { SMLoc Loc = getLexer().getLoc(); - Parser.eatToEndOfStatement(); return Error(Loc, "unexpected token in argument list"); } if (getLexer().is(AsmToken::LBrac) && parseBracketSuffix(Name, Operands)) @@ -4871,7 +5190,6 @@ bool MipsAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name, // Parse and remember the operand. if (parseOperand(Operands, Name)) { SMLoc Loc = getLexer().getLoc(); - Parser.eatToEndOfStatement(); return Error(Loc, "unexpected token in argument list"); } // Parse bracket and parenthesis suffixes before we iterate @@ -4885,7 +5203,6 @@ bool MipsAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name, } if (getLexer().isNot(AsmToken::EndOfStatement)) { SMLoc Loc = getLexer().getLoc(); - Parser.eatToEndOfStatement(); return Error(Loc, "unexpected token in argument list"); } Parser.Lex(); // Consume the EndOfStatement. @@ -4895,9 +5212,7 @@ bool MipsAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name, // FIXME: Given that these have the same name, these should both be // consistent on affecting the Parser. bool MipsAsmParser::reportParseError(Twine ErrorMsg) { - MCAsmParser &Parser = getParser(); SMLoc Loc = getLexer().getLoc(); - Parser.eatToEndOfStatement(); return Error(Loc, ErrorMsg); } @@ -5398,7 +5713,6 @@ bool MipsAsmParser::eatComma(StringRef ErrorStr) { MCAsmParser &Parser = getParser(); if (getLexer().isNot(AsmToken::Comma)) { SMLoc Loc = getLexer().getLoc(); - Parser.eatToEndOfStatement(); return Error(Loc, ErrorStr); } @@ -5507,7 +5821,6 @@ bool MipsAsmParser::parseDirectiveCPSetup() { MipsOperand &FuncRegOpnd = static_cast<MipsOperand &>(*TmpReg[0]); if (!FuncRegOpnd.isGPRAsmReg()) { reportParseError(FuncRegOpnd.getStartLoc(), "invalid register"); - Parser.eatToEndOfStatement(); return false; } @@ -5526,7 +5839,6 @@ bool MipsAsmParser::parseDirectiveCPSetup() { if (Parser.parseExpression(OffsetExpr) || !OffsetExpr->evaluateAsAbsolute(OffsetVal)) { reportParseError(ExprLoc, "expected save register or stack offset"); - Parser.eatToEndOfStatement(); return false; } @@ -5536,7 +5848,6 @@ bool MipsAsmParser::parseDirectiveCPSetup() { MipsOperand &SaveOpnd = static_cast<MipsOperand &>(*TmpReg[0]); if (!SaveOpnd.isGPRAsmReg()) { reportParseError(SaveOpnd.getStartLoc(), "invalid register"); - Parser.eatToEndOfStatement(); return false; } Save = SaveOpnd.getGPR32Reg(); @@ -5740,7 +6051,79 @@ bool MipsAsmParser::parseDirectiveGpDWord() { getParser().getStreamer().EmitGPRel64Value(Value); if (getLexer().isNot(AsmToken::EndOfStatement)) - return Error(getLexer().getLoc(), + return Error(getLexer().getLoc(), + "unexpected token, expected end of statement"); + Parser.Lex(); // Eat EndOfStatement token. + return false; +} + +/// parseDirectiveDtpRelWord +/// ::= .dtprelword tls_sym +bool MipsAsmParser::parseDirectiveDtpRelWord() { + MCAsmParser &Parser = getParser(); + const MCExpr *Value; + // EmitDTPRel32Value requires an expression, so we are using base class + // method to evaluate the expression. + if (getParser().parseExpression(Value)) + return true; + getParser().getStreamer().EmitDTPRel32Value(Value); + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return Error(getLexer().getLoc(), + "unexpected token, expected end of statement"); + Parser.Lex(); // Eat EndOfStatement token. + return false; +} + +/// parseDirectiveDtpRelDWord +/// ::= .dtpreldword tls_sym +bool MipsAsmParser::parseDirectiveDtpRelDWord() { + MCAsmParser &Parser = getParser(); + const MCExpr *Value; + // EmitDTPRel64Value requires an expression, so we are using base class + // method to evaluate the expression. + if (getParser().parseExpression(Value)) + return true; + getParser().getStreamer().EmitDTPRel64Value(Value); + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return Error(getLexer().getLoc(), + "unexpected token, expected end of statement"); + Parser.Lex(); // Eat EndOfStatement token. + return false; +} + +/// parseDirectiveTpRelWord +/// ::= .tprelword tls_sym +bool MipsAsmParser::parseDirectiveTpRelWord() { + MCAsmParser &Parser = getParser(); + const MCExpr *Value; + // EmitTPRel32Value requires an expression, so we are using base class + // method to evaluate the expression. + if (getParser().parseExpression(Value)) + return true; + getParser().getStreamer().EmitTPRel32Value(Value); + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return Error(getLexer().getLoc(), + "unexpected token, expected end of statement"); + Parser.Lex(); // Eat EndOfStatement token. + return false; +} + +/// parseDirectiveTpRelDWord +/// ::= .tpreldword tls_sym +bool MipsAsmParser::parseDirectiveTpRelDWord() { + MCAsmParser &Parser = getParser(); + const MCExpr *Value; + // EmitTPRel64Value requires an expression, so we are using base class + // method to evaluate the expression. + if (getParser().parseExpression(Value)) + return true; + getParser().getStreamer().EmitTPRel64Value(Value); + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return Error(getLexer().getLoc(), "unexpected token, expected end of statement"); Parser.Lex(); // Eat EndOfStatement token. return false; @@ -5752,9 +6135,8 @@ bool MipsAsmParser::parseDirectiveOption() { AsmToken Tok = Parser.getTok(); // At the moment only identifiers are supported. if (Tok.isNot(AsmToken::Identifier)) { - Error(Parser.getTok().getLoc(), "unexpected token, expected identifier"); - Parser.eatToEndOfStatement(); - return false; + return Error(Parser.getTok().getLoc(), + "unexpected token, expected identifier"); } StringRef Option = Tok.getIdentifier(); @@ -5766,9 +6148,8 @@ bool MipsAsmParser::parseDirectiveOption() { getTargetStreamer().emitDirectiveOptionPic0(); Parser.Lex(); if (Parser.getTok().isNot(AsmToken::EndOfStatement)) { - Error(Parser.getTok().getLoc(), - "unexpected token, expected end of statement"); - Parser.eatToEndOfStatement(); + return Error(Parser.getTok().getLoc(), + "unexpected token, expected end of statement"); } return false; } @@ -5780,9 +6161,8 @@ bool MipsAsmParser::parseDirectiveOption() { getTargetStreamer().emitDirectiveOptionPic2(); Parser.Lex(); if (Parser.getTok().isNot(AsmToken::EndOfStatement)) { - Error(Parser.getTok().getLoc(), - "unexpected token, expected end of statement"); - Parser.eatToEndOfStatement(); + return Error(Parser.getTok().getLoc(), + "unexpected token, expected end of statement"); } return false; } @@ -5873,8 +6253,7 @@ bool MipsAsmParser::parseDirectiveModule() { return false; // parseDirectiveModule has finished successfully. } else if (Option == "nooddspreg") { if (!isABI_O32()) { - Error(L, "'.module nooddspreg' requires the O32 ABI"); - return false; + return Error(L, "'.module nooddspreg' requires the O32 ABI"); } setModuleFeatureBits(Mips::FeatureNoOddSPReg, "nooddspreg"); @@ -6295,6 +6674,26 @@ bool MipsAsmParser::ParseDirective(AsmToken DirectiveID) { return false; } + if (IDVal == ".dtprelword") { + parseDirectiveDtpRelWord(); + return false; + } + + if (IDVal == ".dtpreldword") { + parseDirectiveDtpRelDWord(); + return false; + } + + if (IDVal == ".tprelword") { + parseDirectiveTpRelWord(); + return false; + } + + if (IDVal == ".tpreldword") { + parseDirectiveTpRelDWord(); + return false; + } + if (IDVal == ".word") { parseDataDirective(4, DirectiveID.getLoc()); return false; @@ -6315,8 +6714,6 @@ bool MipsAsmParser::ParseDirective(AsmToken DirectiveID) { if (Parser.getTok().isNot(AsmToken::EndOfStatement)) { Error(Parser.getTok().getLoc(), "unexpected token, expected end of statement"); - // Clear line - Parser.eatToEndOfStatement(); } return false; } @@ -6367,10 +6764,10 @@ bool MipsAsmParser::parseInternalDirectiveReallowModule() { } extern "C" void LLVMInitializeMipsAsmParser() { - RegisterMCAsmParser<MipsAsmParser> X(TheMipsTarget); - RegisterMCAsmParser<MipsAsmParser> Y(TheMipselTarget); - RegisterMCAsmParser<MipsAsmParser> A(TheMips64Target); - RegisterMCAsmParser<MipsAsmParser> B(TheMips64elTarget); + RegisterMCAsmParser<MipsAsmParser> X(getTheMipsTarget()); + RegisterMCAsmParser<MipsAsmParser> Y(getTheMipselTarget()); + RegisterMCAsmParser<MipsAsmParser> A(getTheMips64Target()); + RegisterMCAsmParser<MipsAsmParser> B(getTheMips64elTarget()); } #define GET_REGISTER_MATCHER |