X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=lib%2FTarget%2FMips%2FAsmParser%2FMipsAsmParser.cpp;h=b425dc8412f4034a6a8b3ed02ee69aff97eda882;hb=24ae56d4c97fe85345481e16329684a947e62c5b;hp=de39107441e04153f97beaf67d04c70397197e21;hpb=974a445bd90795248274493eda5cdbf6721910f7;p=oota-llvm.git diff --git a/lib/Target/Mips/AsmParser/MipsAsmParser.cpp b/lib/Target/Mips/AsmParser/MipsAsmParser.cpp index de39107441e..b425dc8412f 100644 --- a/lib/Target/Mips/AsmParser/MipsAsmParser.cpp +++ b/lib/Target/Mips/AsmParser/MipsAsmParser.cpp @@ -7,6 +7,7 @@ // //===----------------------------------------------------------------------===// +#include "MCTargetDesc/MipsMCExpr.h" #include "MCTargetDesc/MipsMCTargetDesc.h" #include "MipsRegisterInfo.h" #include "MipsTargetStreamer.h" @@ -15,17 +16,21 @@ #include "llvm/MC/MCContext.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCInst.h" +#include "llvm/MC/MCInstBuilder.h" #include "llvm/MC/MCParser/MCAsmLexer.h" #include "llvm/MC/MCParser/MCParsedAsmOperand.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSubtargetInfo.h" #include "llvm/MC/MCSymbol.h" #include "llvm/MC/MCTargetAsmParser.h" +#include "llvm/Support/Debug.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/TargetRegistry.h" using namespace llvm; +#define DEBUG_TYPE "mips-asm-parser" + namespace llvm { class MCInstrInfo; } @@ -46,6 +51,20 @@ public: void setMacro() { macro = true; } void setNomacro() { macro = false; } + // Set of features that are either architecture features or referenced + // by them (e.g.: FeatureNaN2008 implied by FeatureMips32r6). + // The full table can be found in MipsGenSubtargetInfo.inc (MipsFeatureKV[]). + // The reason we need this mask is explained in the selectArch function. + // FIXME: Ideally we would like TableGen to generate this information. + static const uint64_t AllArchRelatedMask = + Mips::FeatureMips1 | Mips::FeatureMips2 | Mips::FeatureMips3 | + Mips::FeatureMips3_32 | Mips::FeatureMips3_32r2 | Mips::FeatureMips4 | + Mips::FeatureMips4_32 | Mips::FeatureMips4_32r2 | Mips::FeatureMips5 | + Mips::FeatureMips5_32r2 | Mips::FeatureMips32 | Mips::FeatureMips32r2 | + Mips::FeatureMips32r6 | Mips::FeatureMips64 | Mips::FeatureMips64r2 | + Mips::FeatureMips64r6 | Mips::FeatureCnMips | Mips::FeatureFP64Bit | + Mips::FeatureGP64Bit | Mips::FeatureNaN2008; + private: unsigned aTReg; bool reorder; @@ -55,137 +74,88 @@ private: namespace { class MipsAsmParser : public MCTargetAsmParser { - MipsTargetStreamer &getTargetStreamer() { - MCTargetStreamer &TS = Parser.getStreamer().getTargetStreamer(); + MCTargetStreamer &TS = *Parser.getStreamer().getTargetStreamer(); return static_cast(TS); } MCSubtargetInfo &STI; MCAsmParser &Parser; MipsAssemblerOptions Options; - bool hasConsumedDollar; + MCSymbol *CurrentFn; // Pointer to the function being parsed. It may be a + // nullptr, which indicates that no function is currently + // selected. This usually happens after an '.end func' + // directive. #define GET_ASSEMBLER_HEADER #include "MipsGenAsmMatcher.inc" - bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, - SmallVectorImpl &Operands, - MCStreamer &Out, unsigned &ErrorInfo, - bool MatchingInlineAsm); - - bool ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc); - - bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name, - SMLoc NameLoc, - SmallVectorImpl &Operands); - - bool ParseDirective(AsmToken DirectiveID); - - MipsAsmParser::OperandMatchResultTy - parseRegs(SmallVectorImpl &Operands, int RegKind); - - MipsAsmParser::OperandMatchResultTy - parseMSARegs(SmallVectorImpl &Operands, int RegKind); - - MipsAsmParser::OperandMatchResultTy - parseMSACtrlRegs(SmallVectorImpl &Operands, - int RegKind); - - MipsAsmParser::OperandMatchResultTy - parseMemOperand(SmallVectorImpl &Operands); - - bool parsePtrReg(SmallVectorImpl &Operands, - int RegKind); - - MipsAsmParser::OperandMatchResultTy - parsePtrReg(SmallVectorImpl &Operands); - - MipsAsmParser::OperandMatchResultTy - parseGPR32(SmallVectorImpl &Operands); - - MipsAsmParser::OperandMatchResultTy - parseGPR64(SmallVectorImpl &Operands); - - MipsAsmParser::OperandMatchResultTy - parseHWRegs(SmallVectorImpl &Operands); - - MipsAsmParser::OperandMatchResultTy - parseCCRRegs(SmallVectorImpl &Operands); - - MipsAsmParser::OperandMatchResultTy - parseAFGR64Regs(SmallVectorImpl &Operands); - - MipsAsmParser::OperandMatchResultTy - parseFGR64Regs(SmallVectorImpl &Operands); - - MipsAsmParser::OperandMatchResultTy - parseFGR32Regs(SmallVectorImpl &Operands); - - MipsAsmParser::OperandMatchResultTy - parseFGRH32Regs(SmallVectorImpl &Operands); + unsigned checkTargetMatchPredicate(MCInst &Inst) override; - MipsAsmParser::OperandMatchResultTy - parseFCCRegs(SmallVectorImpl &Operands); + bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, + OperandVector &Operands, MCStreamer &Out, + uint64_t &ErrorInfo, + bool MatchingInlineAsm) override; - MipsAsmParser::OperandMatchResultTy - parseACC64DSP(SmallVectorImpl &Operands); + /// Parse a register as used in CFI directives + bool ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc) override; - MipsAsmParser::OperandMatchResultTy - parseLO32DSP(SmallVectorImpl &Operands); + bool ParseParenSuffix(StringRef Name, OperandVector &Operands); - MipsAsmParser::OperandMatchResultTy - parseHI32DSP(SmallVectorImpl &Operands); + bool ParseBracketSuffix(StringRef Name, OperandVector &Operands); - MipsAsmParser::OperandMatchResultTy - parseCOP2(SmallVectorImpl &Operands); + bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name, + SMLoc NameLoc, OperandVector &Operands) override; - MipsAsmParser::OperandMatchResultTy - parseMSA128BRegs(SmallVectorImpl &Operands); + bool ParseDirective(AsmToken DirectiveID) override; - MipsAsmParser::OperandMatchResultTy - parseMSA128HRegs(SmallVectorImpl &Operands); + MipsAsmParser::OperandMatchResultTy parseMemOperand(OperandVector &Operands); MipsAsmParser::OperandMatchResultTy - parseMSA128WRegs(SmallVectorImpl &Operands); + MatchAnyRegisterNameWithoutDollar(OperandVector &Operands, + StringRef Identifier, SMLoc S); MipsAsmParser::OperandMatchResultTy - parseMSA128DRegs(SmallVectorImpl &Operands); + MatchAnyRegisterWithoutDollar(OperandVector &Operands, SMLoc S); - MipsAsmParser::OperandMatchResultTy - parseMSA128CtrlRegs(SmallVectorImpl &Operands); + MipsAsmParser::OperandMatchResultTy ParseAnyRegister(OperandVector &Operands); - MipsAsmParser::OperandMatchResultTy - parseInvNum(SmallVectorImpl &Operands); + MipsAsmParser::OperandMatchResultTy ParseImm(OperandVector &Operands); - MipsAsmParser::OperandMatchResultTy - parseLSAImm(SmallVectorImpl &Operands); + MipsAsmParser::OperandMatchResultTy ParseJumpTarget(OperandVector &Operands); - bool searchSymbolAlias(SmallVectorImpl &Operands, - unsigned RegKind); + MipsAsmParser::OperandMatchResultTy parseInvNum(OperandVector &Operands); - bool ParseOperand(SmallVectorImpl &, - StringRef Mnemonic); + MipsAsmParser::OperandMatchResultTy ParseLSAImm(OperandVector &Operands); - int tryParseRegister(bool is64BitReg); + bool searchSymbolAlias(OperandVector &Operands); - bool tryParseRegisterOperand(SmallVectorImpl &Operands, - bool is64BitReg); + bool ParseOperand(OperandVector &, StringRef Mnemonic); bool needsExpansion(MCInst &Inst); - void expandInstruction(MCInst &Inst, SMLoc IDLoc, + // Expands assembly pseudo instructions. + // Returns false on success, true otherwise. + bool expandInstruction(MCInst &Inst, SMLoc IDLoc, SmallVectorImpl &Instructions); - void expandLoadImm(MCInst &Inst, SMLoc IDLoc, + + bool expandLoadImm(MCInst &Inst, SMLoc IDLoc, SmallVectorImpl &Instructions); - void expandLoadAddressImm(MCInst &Inst, SMLoc IDLoc, + + bool expandLoadAddressImm(MCInst &Inst, SMLoc IDLoc, + SmallVectorImpl &Instructions); + + bool expandLoadAddressReg(MCInst &Inst, SMLoc IDLoc, SmallVectorImpl &Instructions); - void expandLoadAddressReg(MCInst &Inst, SMLoc IDLoc, + + void expandLoadAddressSym(MCInst &Inst, SMLoc IDLoc, SmallVectorImpl &Instructions); + void expandMemInst(MCInst &Inst, SMLoc IDLoc, SmallVectorImpl &Instructions, bool isLoad, bool isImmOpnd); - bool reportParseError(StringRef ErrorMsg); + bool reportParseError(Twine ErrorMsg); + bool reportParseError(SMLoc Loc, Twine ErrorMsg); bool parseMemOffset(const MCExpr *&Res, bool isParenExpr); bool parseRelocOperand(const MCExpr *&Res); @@ -193,40 +163,38 @@ class MipsAsmParser : public MCTargetAsmParser { const MCExpr *evaluateRelocExpr(const MCExpr *Expr, StringRef RelocStr); bool isEvaluated(const MCExpr *Expr); + bool parseSetArchDirective(); + bool parseSetFeature(uint64_t Feature); + bool parseDirectiveCPLoad(SMLoc Loc); + bool parseDirectiveCPSetup(); + bool parseDirectiveNaN(); bool parseDirectiveSet(); - bool parseDirectiveMipsHackStocg(); - bool parseDirectiveMipsHackELFFlags(); bool parseDirectiveOption(); bool parseSetAtDirective(); bool parseSetNoAtDirective(); bool parseSetMacroDirective(); bool parseSetNoMacroDirective(); + bool parseSetMsaDirective(); + bool parseSetNoMsaDirective(); bool parseSetReorderDirective(); bool parseSetNoReorderDirective(); + bool parseSetNoMips16Directive(); + bool parseSetFpDirective(); bool parseSetAssignment(); - bool parseDirectiveWord(unsigned Size, SMLoc L); + bool parseDataDirective(unsigned Size, SMLoc L); bool parseDirectiveGpWord(); + bool parseDirectiveGpDWord(); + bool parseDirectiveModule(); + bool parseDirectiveModuleFP(); + bool parseFpABIValue(MipsABIFlagsSection::FpABIKind &FpABI, + StringRef Directive); MCSymbolRefExpr::VariantKind getVariantKind(StringRef Symbol); - bool isMips64() const { - return (STI.getFeatureBits() & Mips::FeatureMips64) != 0; - } - - bool isFP64() const { - return (STI.getFeatureBits() & Mips::FeatureFP64Bit) != 0; - } - - bool isN64() const { return STI.getFeatureBits() & Mips::FeatureN64; } - - bool isMicroMips() const { - return STI.getFeatureBits() & Mips::FeatureMicroMips; - } - - int matchRegisterName(StringRef Symbol, bool is64BitReg); + bool eatComma(StringRef ErrorStr); int matchCPURegisterName(StringRef Symbol); @@ -242,11 +210,11 @@ class MipsAsmParser : public MCTargetAsmParser { int matchMSA128CtrlRegisterName(StringRef Name); - int regKindToRegClass(int RegKind); - unsigned getReg(int RC, int RegNo); - int getATReg(); + unsigned getGPR(int RegNo); + + int getATReg(SMLoc Loc); bool processInstruction(MCInst &Inst, SMLoc IDLoc, SmallVectorImpl &Instructions); @@ -256,17 +224,134 @@ class MipsAsmParser : public MCTargetAsmParser { // Example: INSERT.B $w0[n], $1 => 16 > n >= 0 bool validateMSAIndex(int Val, int RegKind); + // Selects a new architecture by updating the FeatureBits with the necessary + // info including implied dependencies. + // Internally, it clears all the feature bits related to *any* architecture + // and selects the new one using the ToggleFeature functionality of the + // MCSubtargetInfo object that handles implied dependencies. The reason we + // clear all the arch related bits manually is because ToggleFeature only + // clears the features that imply the feature being cleared and not the + // features implied by the feature being cleared. This is easier to see + // with an example: + // -------------------------------------------------- + // | Feature | Implies | + // | -------------------------------------------------| + // | FeatureMips1 | None | + // | FeatureMips2 | FeatureMips1 | + // | FeatureMips3 | FeatureMips2 | FeatureMipsGP64 | + // | FeatureMips4 | FeatureMips3 | + // | ... | | + // -------------------------------------------------- + // + // Setting Mips3 is equivalent to set: (FeatureMips3 | FeatureMips2 | + // FeatureMipsGP64 | FeatureMips1) + // Clearing Mips3 is equivalent to clear (FeatureMips3 | FeatureMips4). + void selectArch(StringRef ArchFeature) { + uint64_t FeatureBits = STI.getFeatureBits(); + FeatureBits &= ~MipsAssemblerOptions::AllArchRelatedMask; + STI.setFeatureBits(FeatureBits); + setAvailableFeatures( + ComputeAvailableFeatures(STI.ToggleFeature(ArchFeature))); + } + + void setFeatureBits(unsigned Feature, StringRef FeatureString) { + if (!(STI.getFeatureBits() & Feature)) { + setAvailableFeatures( + ComputeAvailableFeatures(STI.ToggleFeature(FeatureString))); + } + } + + void clearFeatureBits(unsigned Feature, StringRef FeatureString) { + if (STI.getFeatureBits() & Feature) { + setAvailableFeatures( + ComputeAvailableFeatures(STI.ToggleFeature(FeatureString))); + } + } + public: + enum MipsMatchResultTy { + Match_RequiresDifferentSrcAndDst = FIRST_TARGET_MATCH_RESULT_TY +#define GET_OPERAND_DIAGNOSTIC_TYPES +#include "MipsGenAsmMatcher.inc" +#undef GET_OPERAND_DIAGNOSTIC_TYPES + + }; + MipsAsmParser(MCSubtargetInfo &sti, MCAsmParser &parser, - const MCInstrInfo &MII) - : MCTargetAsmParser(), STI(sti), Parser(parser), - hasConsumedDollar(false) { + const MCInstrInfo &MII, const MCTargetOptions &Options) + : MCTargetAsmParser(), STI(sti), Parser(parser) { // Initialize the set of available features. setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits())); + + getTargetStreamer().updateABIInfo(*this); + + // Assert exactly one ABI was chosen. + assert((((STI.getFeatureBits() & Mips::FeatureO32) != 0) + + ((STI.getFeatureBits() & Mips::FeatureEABI) != 0) + + ((STI.getFeatureBits() & Mips::FeatureN32) != 0) + + ((STI.getFeatureBits() & Mips::FeatureN64) != 0)) == 1); + + if (!isABI_O32() && !useOddSPReg() != 0) + report_fatal_error("-mno-odd-spreg requires the O32 ABI"); + + CurrentFn = nullptr; } MCAsmParser &getParser() const { return Parser; } MCAsmLexer &getLexer() const { return Parser.getLexer(); } + + /// True if all of $fcc0 - $fcc7 exist for the current ISA. + bool hasEightFccRegisters() const { return hasMips4() || hasMips32(); } + + bool isGP64bit() const { return STI.getFeatureBits() & Mips::FeatureGP64Bit; } + bool isFP64bit() const { return STI.getFeatureBits() & Mips::FeatureFP64Bit; } + bool isABI_N32() const { return STI.getFeatureBits() & Mips::FeatureN32; } + bool isABI_N64() const { return STI.getFeatureBits() & Mips::FeatureN64; } + bool isABI_O32() const { return STI.getFeatureBits() & Mips::FeatureO32; } + bool isABI_FPXX() const { return STI.getFeatureBits() & Mips::FeatureFPXX; } + + bool useOddSPReg() const { + return !(STI.getFeatureBits() & Mips::FeatureNoOddSPReg); + } + + bool inMicroMipsMode() const { + return STI.getFeatureBits() & Mips::FeatureMicroMips; + } + bool hasMips1() const { return STI.getFeatureBits() & Mips::FeatureMips1; } + bool hasMips2() const { return STI.getFeatureBits() & Mips::FeatureMips2; } + bool hasMips3() const { return STI.getFeatureBits() & Mips::FeatureMips3; } + bool hasMips4() const { return STI.getFeatureBits() & Mips::FeatureMips4; } + bool hasMips5() const { return STI.getFeatureBits() & Mips::FeatureMips5; } + bool hasMips32() const { + return (STI.getFeatureBits() & Mips::FeatureMips32); + } + bool hasMips64() const { + return (STI.getFeatureBits() & Mips::FeatureMips64); + } + bool hasMips32r2() const { + return (STI.getFeatureBits() & Mips::FeatureMips32r2); + } + bool hasMips64r2() const { + return (STI.getFeatureBits() & Mips::FeatureMips64r2); + } + bool hasMips32r6() const { + return (STI.getFeatureBits() & Mips::FeatureMips32r6); + } + bool hasMips64r6() const { + return (STI.getFeatureBits() & Mips::FeatureMips64r6); + } + bool hasDSP() const { return (STI.getFeatureBits() & Mips::FeatureDSP); } + bool hasDSPR2() const { return (STI.getFeatureBits() & Mips::FeatureDSPR2); } + bool hasMSA() const { return (STI.getFeatureBits() & Mips::FeatureMSA); } + + bool inMips16Mode() const { + return STI.getFeatureBits() & Mips::FeatureMips16; + } + // TODO: see how can we get this info. + bool abiUsesSoftFloat() const { return false; } + + /// Warn if RegNo is the current assembler temporary. + void WarnIfAssemblerTemporary(int RegNo, SMLoc Loc); }; } @@ -275,53 +360,59 @@ namespace { /// MipsOperand - Instances of this class represent a parsed Mips machine /// instruction. class MipsOperand : public MCParsedAsmOperand { - public: - enum RegisterKind { - Kind_None, - Kind_GPR32, - Kind_GPR64, - Kind_HWRegs, - Kind_FGR32Regs, - Kind_FGRH32Regs, - Kind_FGR64Regs, - Kind_AFGR64Regs, - Kind_CCRRegs, - Kind_FCCRegs, - Kind_ACC64DSP, - Kind_LO32DSP, - Kind_HI32DSP, - Kind_COP2, - Kind_MSA128BRegs, - Kind_MSA128HRegs, - Kind_MSA128WRegs, - Kind_MSA128DRegs, - Kind_MSA128CtrlRegs + /// Broad categories of register classes + /// The exact class is finalized by the render method. + enum RegKind { + RegKind_GPR = 1, /// GPR32 and GPR64 (depending on isGP64bit()) + RegKind_FGR = 2, /// FGR32, FGR64, AFGR64 (depending on context and + /// isFP64bit()) + RegKind_FCC = 4, /// FCC + RegKind_MSA128 = 8, /// MSA128[BHWD] (makes no difference which) + RegKind_MSACtrl = 16, /// MSA control registers + RegKind_COP2 = 32, /// COP2 + RegKind_ACC = 64, /// HI32DSP, LO32DSP, and ACC64DSP (depending on + /// context). + RegKind_CCR = 128, /// CCR + RegKind_HWRegs = 256, /// HWRegs + RegKind_COP3 = 512, /// COP3 + + /// Potentially any (e.g. $1) + RegKind_Numeric = RegKind_GPR | RegKind_FGR | RegKind_FCC | RegKind_MSA128 | + RegKind_MSACtrl | RegKind_COP2 | RegKind_ACC | + RegKind_CCR | RegKind_HWRegs | RegKind_COP3 }; private: enum KindTy { - k_CondCode, - k_CoprocNum, - k_Immediate, - k_Memory, - k_PostIndexRegister, - k_Register, - k_PtrReg, - k_Token, - k_LSAImm + k_Immediate, /// An immediate (possibly involving symbol references) + k_Memory, /// Base + Offset Memory Address + k_PhysRegister, /// A physical register from the Mips namespace + k_RegisterIndex, /// A register index in one or more RegKind. + k_Token /// A simple token } Kind; - MipsOperand(KindTy K) : MCParsedAsmOperand(), Kind(K) {} +public: + MipsOperand(KindTy K, MipsAsmParser &Parser) + : MCParsedAsmOperand(), Kind(K), AsmParser(Parser) {} + +private: + /// For diagnostics, and checking the assembler temporary + MipsAsmParser &AsmParser; struct Token { const char *Data; unsigned Length; }; - struct RegOp { - unsigned RegNum; - RegisterKind Kind; + struct PhysRegOp { + unsigned Num; /// Register Number + }; + + struct RegIdxOp { + unsigned Index; /// Index into the register class + RegKind Kind; /// Bitfield of the kinds it could possibly be + const MCRegisterInfo *RegInfo; }; struct ImmOp { @@ -329,33 +420,173 @@ private: }; struct MemOp { - unsigned Base; + MipsOperand *Base; const MCExpr *Off; }; union { struct Token Tok; - struct RegOp Reg; + struct PhysRegOp PhysReg; + struct RegIdxOp RegIdx; struct ImmOp Imm; struct MemOp Mem; }; SMLoc StartLoc, EndLoc; + /// Internal constructor for register kinds + static std::unique_ptr CreateReg(unsigned Index, RegKind RegKind, + const MCRegisterInfo *RegInfo, + SMLoc S, SMLoc E, + MipsAsmParser &Parser) { + auto Op = make_unique(k_RegisterIndex, Parser); + Op->RegIdx.Index = Index; + Op->RegIdx.RegInfo = RegInfo; + Op->RegIdx.Kind = RegKind; + Op->StartLoc = S; + Op->EndLoc = E; + return Op; + } + public: - void addRegOperands(MCInst &Inst, unsigned N) const { - assert(N == 1 && "Invalid number of operands!"); - Inst.addOperand(MCOperand::CreateReg(getReg())); + /// Coerce the register to GPR32 and return the real register for the current + /// target. + unsigned getGPR32Reg() const { + assert(isRegIdx() && (RegIdx.Kind & RegKind_GPR) && "Invalid access!"); + AsmParser.WarnIfAssemblerTemporary(RegIdx.Index, StartLoc); + unsigned ClassID = Mips::GPR32RegClassID; + return RegIdx.RegInfo->getRegClass(ClassID).getRegister(RegIdx.Index); } - void addPtrRegOperands(MCInst &Inst, unsigned N) const { - assert(N == 1 && "Invalid number of operands!"); - Inst.addOperand(MCOperand::CreateReg(getPtrReg())); + /// Coerce the register to GPR64 and return the real register for the current + /// target. + unsigned getGPR64Reg() const { + assert(isRegIdx() && (RegIdx.Kind & RegKind_GPR) && "Invalid access!"); + unsigned ClassID = Mips::GPR64RegClassID; + return RegIdx.RegInfo->getRegClass(ClassID).getRegister(RegIdx.Index); + } + +private: + /// Coerce the register to AFGR64 and return the real register for the current + /// target. + unsigned getAFGR64Reg() const { + assert(isRegIdx() && (RegIdx.Kind & RegKind_FGR) && "Invalid access!"); + if (RegIdx.Index % 2 != 0) + AsmParser.Warning(StartLoc, "Float register should be even."); + return RegIdx.RegInfo->getRegClass(Mips::AFGR64RegClassID) + .getRegister(RegIdx.Index / 2); + } + + /// Coerce the register to FGR64 and return the real register for the current + /// target. + unsigned getFGR64Reg() const { + assert(isRegIdx() && (RegIdx.Kind & RegKind_FGR) && "Invalid access!"); + return RegIdx.RegInfo->getRegClass(Mips::FGR64RegClassID) + .getRegister(RegIdx.Index); + } + + /// Coerce the register to FGR32 and return the real register for the current + /// target. + unsigned getFGR32Reg() const { + assert(isRegIdx() && (RegIdx.Kind & RegKind_FGR) && "Invalid access!"); + return RegIdx.RegInfo->getRegClass(Mips::FGR32RegClassID) + .getRegister(RegIdx.Index); + } + + /// Coerce the register to FGRH32 and return the real register for the current + /// target. + unsigned getFGRH32Reg() const { + assert(isRegIdx() && (RegIdx.Kind & RegKind_FGR) && "Invalid access!"); + return RegIdx.RegInfo->getRegClass(Mips::FGRH32RegClassID) + .getRegister(RegIdx.Index); + } + + /// Coerce the register to FCC and return the real register for the current + /// target. + unsigned getFCCReg() const { + assert(isRegIdx() && (RegIdx.Kind & RegKind_FCC) && "Invalid access!"); + return RegIdx.RegInfo->getRegClass(Mips::FCCRegClassID) + .getRegister(RegIdx.Index); + } + + /// Coerce the register to MSA128 and return the real register for the current + /// target. + unsigned getMSA128Reg() const { + assert(isRegIdx() && (RegIdx.Kind & RegKind_MSA128) && "Invalid access!"); + // It doesn't matter which of the MSA128[BHWD] classes we use. They are all + // identical + unsigned ClassID = Mips::MSA128BRegClassID; + return RegIdx.RegInfo->getRegClass(ClassID).getRegister(RegIdx.Index); + } + + /// Coerce the register to MSACtrl and return the real register for the + /// current target. + unsigned getMSACtrlReg() const { + assert(isRegIdx() && (RegIdx.Kind & RegKind_MSACtrl) && "Invalid access!"); + unsigned ClassID = Mips::MSACtrlRegClassID; + return RegIdx.RegInfo->getRegClass(ClassID).getRegister(RegIdx.Index); + } + + /// Coerce the register to COP2 and return the real register for the + /// current target. + unsigned getCOP2Reg() const { + assert(isRegIdx() && (RegIdx.Kind & RegKind_COP2) && "Invalid access!"); + unsigned ClassID = Mips::COP2RegClassID; + return RegIdx.RegInfo->getRegClass(ClassID).getRegister(RegIdx.Index); + } + + /// Coerce the register to COP3 and return the real register for the + /// current target. + unsigned getCOP3Reg() const { + assert(isRegIdx() && (RegIdx.Kind & RegKind_COP3) && "Invalid access!"); + unsigned ClassID = Mips::COP3RegClassID; + return RegIdx.RegInfo->getRegClass(ClassID).getRegister(RegIdx.Index); + } + + /// Coerce the register to ACC64DSP and return the real register for the + /// current target. + unsigned getACC64DSPReg() const { + assert(isRegIdx() && (RegIdx.Kind & RegKind_ACC) && "Invalid access!"); + unsigned ClassID = Mips::ACC64DSPRegClassID; + return RegIdx.RegInfo->getRegClass(ClassID).getRegister(RegIdx.Index); + } + + /// Coerce the register to HI32DSP and return the real register for the + /// current target. + unsigned getHI32DSPReg() const { + assert(isRegIdx() && (RegIdx.Kind & RegKind_ACC) && "Invalid access!"); + unsigned ClassID = Mips::HI32DSPRegClassID; + return RegIdx.RegInfo->getRegClass(ClassID).getRegister(RegIdx.Index); + } + + /// Coerce the register to LO32DSP and return the real register for the + /// current target. + unsigned getLO32DSPReg() const { + assert(isRegIdx() && (RegIdx.Kind & RegKind_ACC) && "Invalid access!"); + unsigned ClassID = Mips::LO32DSPRegClassID; + return RegIdx.RegInfo->getRegClass(ClassID).getRegister(RegIdx.Index); + } + + /// Coerce the register to CCR and return the real register for the + /// current target. + unsigned getCCRReg() const { + assert(isRegIdx() && (RegIdx.Kind & RegKind_CCR) && "Invalid access!"); + unsigned ClassID = Mips::CCRRegClassID; + return RegIdx.RegInfo->getRegClass(ClassID).getRegister(RegIdx.Index); + } + + /// Coerce the register to HWRegs and return the real register for the + /// current target. + unsigned getHWRegsReg() const { + assert(isRegIdx() && (RegIdx.Kind & RegKind_HWRegs) && "Invalid access!"); + unsigned ClassID = Mips::HWRegsRegClassID; + return RegIdx.RegInfo->getRegClass(ClassID).getRegister(RegIdx.Index); } +public: void addExpr(MCInst &Inst, const MCExpr *Expr) const { // Add as immediate when possible. Null MCExpr = 0. - if (Expr == 0) + if (!Expr) Inst.addOperand(MCOperand::CreateImm(0)); else if (const MCConstantExpr *CE = dyn_cast(Expr)) Inst.addOperand(MCOperand::CreateImm(CE->getValue())); @@ -363,6 +594,100 @@ public: Inst.addOperand(MCOperand::CreateExpr(Expr)); } + void addRegOperands(MCInst &Inst, unsigned N) const { + llvm_unreachable("Use a custom parser instead"); + } + + /// Render the operand to an MCInst as a GPR32 + /// Asserts if the wrong number of operands are requested, or the operand + /// is not a k_RegisterIndex compatible with RegKind_GPR + void addGPR32AsmRegOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::CreateReg(getGPR32Reg())); + } + + /// Render the operand to an MCInst as a GPR64 + /// Asserts if the wrong number of operands are requested, or the operand + /// is not a k_RegisterIndex compatible with RegKind_GPR + void addGPR64AsmRegOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::CreateReg(getGPR64Reg())); + } + + void addAFGR64AsmRegOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::CreateReg(getAFGR64Reg())); + } + + void addFGR64AsmRegOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::CreateReg(getFGR64Reg())); + } + + void addFGR32AsmRegOperands(MCInst &Inst, unsigned N) const { + 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. + if (!AsmParser.useOddSPReg() && RegIdx.Index & 1) + AsmParser.Error(StartLoc, "-mno-odd-spreg prohibits the use of odd FPU " + "registers"); + } + + void addFGRH32AsmRegOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::CreateReg(getFGRH32Reg())); + } + + void addFCCAsmRegOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::CreateReg(getFCCReg())); + } + + void addMSA128AsmRegOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::CreateReg(getMSA128Reg())); + } + + void addMSACtrlAsmRegOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::CreateReg(getMSACtrlReg())); + } + + void addCOP2AsmRegOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::CreateReg(getCOP2Reg())); + } + + void addCOP3AsmRegOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::CreateReg(getCOP3Reg())); + } + + void addACC64DSPAsmRegOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::CreateReg(getACC64DSPReg())); + } + + void addHI32DSPAsmRegOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::CreateReg(getHI32DSPReg())); + } + + void addLO32DSPAsmRegOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::CreateReg(getLO32DSPReg())); + } + + void addCCRAsmRegOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::CreateReg(getCCRReg())); + } + + void addHWRegsAsmRegOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::CreateReg(getHWRegsReg())); + } + void addImmOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); const MCExpr *Expr = getImm(); @@ -372,46 +697,72 @@ public: void addMemOperands(MCInst &Inst, unsigned N) const { assert(N == 2 && "Invalid number of operands!"); - Inst.addOperand(MCOperand::CreateReg(getMemBase())); + Inst.addOperand(MCOperand::CreateReg(getMemBase()->getGPR32Reg())); const MCExpr *Expr = getMemOff(); addExpr(Inst, Expr); } - bool isReg() const { return Kind == k_Register; } - bool isImm() const { return Kind == k_Immediate; } - bool isToken() const { return Kind == k_Token; } - bool isMem() const { return Kind == k_Memory; } - bool isPtrReg() const { return Kind == k_PtrReg; } + bool isReg() const override { + // As a special case until we sort out the definition of div/divu, pretend + // that $0/$zero are k_PhysRegister so that MCK_ZERO works correctly. + if (isGPRAsmReg() && RegIdx.Index == 0) + return true; + + return Kind == k_PhysRegister; + } + bool isRegIdx() const { return Kind == k_RegisterIndex; } + bool isImm() const override { return Kind == k_Immediate; } + bool isConstantImm() const { + return isImm() && dyn_cast(getImm()); + } + bool isToken() const override { + // Note: It's not possible to pretend that other operand kinds are tokens. + // The matcher emitter checks tokens first. + return Kind == k_Token; + } + bool isMem() const override { return Kind == k_Memory; } + bool isConstantMemOff() const { + return isMem() && dyn_cast(getMemOff()); + } + template bool isMemWithSimmOffset() const { + return isMem() && isConstantMemOff() && isInt(getConstantMemOff()); + } bool isInvNum() const { return Kind == k_Immediate; } - bool isLSAImm() const { return Kind == k_LSAImm; } + bool isLSAImm() const { + if (!isConstantImm()) + return false; + int64_t Val = getConstantImm(); + return 1 <= Val && Val <= 4; + } StringRef getToken() const { assert(Kind == k_Token && "Invalid access!"); return StringRef(Tok.Data, Tok.Length); } - unsigned getReg() const { - assert((Kind == k_Register) && "Invalid access!"); - return Reg.RegNum; - } - - unsigned getPtrReg() const { - assert((Kind == k_PtrReg) && "Invalid access!"); - return Reg.RegNum; - } + unsigned getReg() const override { + // As a special case until we sort out the definition of div/divu, pretend + // that $0/$zero are k_PhysRegister so that MCK_ZERO works correctly. + if (Kind == k_RegisterIndex && RegIdx.Index == 0 && + RegIdx.Kind & RegKind_GPR) + return getGPR32Reg(); // FIXME: GPR64 too - void setRegKind(RegisterKind RegKind) { - assert((Kind == k_Register || Kind == k_PtrReg) && "Invalid access!"); - Reg.Kind = RegKind; + assert(Kind == k_PhysRegister && "Invalid access!"); + return PhysReg.Num; } const MCExpr *getImm() const { - assert((Kind == k_Immediate || Kind == k_LSAImm) && "Invalid access!"); + assert((Kind == k_Immediate) && "Invalid access!"); return Imm.Val; } - unsigned getMemBase() const { + int64_t getConstantImm() const { + const MCExpr *Val = getImm(); + return static_cast(Val)->getValue(); + } + + MipsOperand *getMemBase() const { assert((Kind == k_Memory) && "Invalid access!"); return Mem.Base; } @@ -421,8 +772,13 @@ public: return Mem.Off; } - static MipsOperand *CreateToken(StringRef Str, SMLoc S) { - MipsOperand *Op = new MipsOperand(k_Token); + int64_t getConstantMemOff() const { + return static_cast(getMemOff())->getValue(); + } + + static std::unique_ptr CreateToken(StringRef Str, SMLoc S, + MipsAsmParser &Parser) { + auto Op = make_unique(k_Token, Parser); Op->Tok.Data = Str.data(); Op->Tok.Length = Str.size(); Op->StartLoc = S; @@ -430,130 +786,162 @@ public: return Op; } - static MipsOperand *CreateReg(unsigned RegNum, SMLoc S, SMLoc E) { - MipsOperand *Op = new MipsOperand(k_Register); - Op->Reg.RegNum = RegNum; - Op->StartLoc = S; - Op->EndLoc = E; - return Op; - } - - static MipsOperand *CreatePtrReg(unsigned RegNum, SMLoc S, SMLoc E) { - MipsOperand *Op = new MipsOperand(k_PtrReg); - Op->Reg.RegNum = RegNum; - Op->StartLoc = S; - Op->EndLoc = E; - return Op; - } - - static MipsOperand *CreateImm(const MCExpr *Val, SMLoc S, SMLoc E) { - MipsOperand *Op = new MipsOperand(k_Immediate); - Op->Imm.Val = Val; - Op->StartLoc = S; - Op->EndLoc = E; - return Op; - } - - static MipsOperand *CreateLSAImm(const MCExpr *Val, SMLoc S, SMLoc E) { - MipsOperand *Op = new MipsOperand(k_LSAImm); - Op->Imm.Val = Val; - Op->StartLoc = S; - Op->EndLoc = E; - return Op; + /// Create a numeric register (e.g. $1). The exact register remains + /// unresolved until an instruction successfully matches + static std::unique_ptr + CreateNumericReg(unsigned Index, const MCRegisterInfo *RegInfo, SMLoc S, + SMLoc E, MipsAsmParser &Parser) { + DEBUG(dbgs() << "CreateNumericReg(" << Index << ", ...)\n"); + return CreateReg(Index, RegKind_Numeric, RegInfo, S, E, Parser); } - static MipsOperand *CreateMem(unsigned Base, const MCExpr *Off, - SMLoc S, SMLoc E) { - MipsOperand *Op = new MipsOperand(k_Memory); - Op->Mem.Base = Base; - Op->Mem.Off = Off; - Op->StartLoc = S; - Op->EndLoc = E; - return Op; + /// Create a register that is definitely a GPR. + /// This is typically only used for named registers such as $gp. + static std::unique_ptr + CreateGPRReg(unsigned Index, const MCRegisterInfo *RegInfo, SMLoc S, SMLoc E, + MipsAsmParser &Parser) { + return CreateReg(Index, RegKind_GPR, RegInfo, S, E, Parser); } - bool isGPR32Asm() const { - return Kind == k_Register && Reg.Kind == Kind_GPR32; - } - void addRegAsmOperands(MCInst &Inst, unsigned N) const { - Inst.addOperand(MCOperand::CreateReg(Reg.RegNum)); + /// Create a register that is definitely a FGR. + /// This is typically only used for named registers such as $f0. + static std::unique_ptr + CreateFGRReg(unsigned Index, const MCRegisterInfo *RegInfo, SMLoc S, SMLoc E, + MipsAsmParser &Parser) { + return CreateReg(Index, RegKind_FGR, RegInfo, S, E, Parser); } - bool isGPR64Asm() const { - return Kind == k_Register && Reg.Kind == Kind_GPR64; + /// Create a register that is definitely an FCC. + /// This is typically only used for named registers such as $fcc0. + static std::unique_ptr + CreateFCCReg(unsigned Index, const MCRegisterInfo *RegInfo, SMLoc S, SMLoc E, + MipsAsmParser &Parser) { + return CreateReg(Index, RegKind_FCC, RegInfo, S, E, Parser); } - bool isHWRegsAsm() const { - assert((Kind == k_Register) && "Invalid access!"); - return Reg.Kind == Kind_HWRegs; + /// Create a register that is definitely an ACC. + /// This is typically only used for named registers such as $ac0. + static std::unique_ptr + CreateACCReg(unsigned Index, const MCRegisterInfo *RegInfo, SMLoc S, SMLoc E, + MipsAsmParser &Parser) { + return CreateReg(Index, RegKind_ACC, RegInfo, S, E, Parser); } - bool isCCRAsm() const { - assert((Kind == k_Register) && "Invalid access!"); - return Reg.Kind == Kind_CCRRegs; + /// Create a register that is definitely an MSA128. + /// This is typically only used for named registers such as $w0. + static std::unique_ptr + CreateMSA128Reg(unsigned Index, const MCRegisterInfo *RegInfo, SMLoc S, + SMLoc E, MipsAsmParser &Parser) { + return CreateReg(Index, RegKind_MSA128, RegInfo, S, E, Parser); } - bool isAFGR64Asm() const { - return Kind == k_Register && Reg.Kind == Kind_AFGR64Regs; + /// Create a register that is definitely an MSACtrl. + /// This is typically only used for named registers such as $msaaccess. + static std::unique_ptr + CreateMSACtrlReg(unsigned Index, const MCRegisterInfo *RegInfo, SMLoc S, + SMLoc E, MipsAsmParser &Parser) { + return CreateReg(Index, RegKind_MSACtrl, RegInfo, S, E, Parser); } - bool isFGR64Asm() const { - return Kind == k_Register && Reg.Kind == Kind_FGR64Regs; + static std::unique_ptr + CreateImm(const MCExpr *Val, SMLoc S, SMLoc E, MipsAsmParser &Parser) { + auto Op = make_unique(k_Immediate, Parser); + Op->Imm.Val = Val; + Op->StartLoc = S; + Op->EndLoc = E; + return Op; } - bool isFGR32Asm() const { - return (Kind == k_Register) && Reg.Kind == Kind_FGR32Regs; + static std::unique_ptr + CreateMem(std::unique_ptr Base, const MCExpr *Off, SMLoc S, + SMLoc E, MipsAsmParser &Parser) { + auto Op = make_unique(k_Memory, Parser); + Op->Mem.Base = Base.release(); + Op->Mem.Off = Off; + Op->StartLoc = S; + Op->EndLoc = E; + return Op; } - bool isFGRH32Asm() const { - return (Kind == k_Register) && Reg.Kind == Kind_FGRH32Regs; + bool isGPRAsmReg() const { + return isRegIdx() && RegIdx.Kind & RegKind_GPR && RegIdx.Index <= 31; } - - bool isFCCRegsAsm() const { - return (Kind == k_Register) && Reg.Kind == Kind_FCCRegs; + bool isFGRAsmReg() const { + // AFGR64 is $0-$15 but we handle this in getAFGR64() + return isRegIdx() && RegIdx.Kind & RegKind_FGR && RegIdx.Index <= 31; } - - bool isACC64DSPAsm() const { - return Kind == k_Register && Reg.Kind == Kind_ACC64DSP; + bool isHWRegsAsmReg() const { + return isRegIdx() && RegIdx.Kind & RegKind_HWRegs && RegIdx.Index <= 31; } - - bool isLO32DSPAsm() const { - return Kind == k_Register && Reg.Kind == Kind_LO32DSP; + bool isCCRAsmReg() const { + return isRegIdx() && RegIdx.Kind & RegKind_CCR && RegIdx.Index <= 31; } - - bool isHI32DSPAsm() const { - return Kind == k_Register && Reg.Kind == Kind_HI32DSP; + bool isFCCAsmReg() const { + if (!(isRegIdx() && RegIdx.Kind & RegKind_FCC)) + return false; + if (!AsmParser.hasEightFccRegisters()) + return RegIdx.Index == 0; + return RegIdx.Index <= 7; } - - bool isCOP2Asm() const { return Kind == k_Register && Reg.Kind == Kind_COP2; } - - bool isMSA128BAsm() const { - return Kind == k_Register && Reg.Kind == Kind_MSA128BRegs; + bool isACCAsmReg() const { + return isRegIdx() && RegIdx.Kind & RegKind_ACC && RegIdx.Index <= 3; } - - bool isMSA128HAsm() const { - return Kind == k_Register && Reg.Kind == Kind_MSA128HRegs; + bool isCOP2AsmReg() const { + return isRegIdx() && RegIdx.Kind & RegKind_COP2 && RegIdx.Index <= 31; } - - bool isMSA128WAsm() const { - return Kind == k_Register && Reg.Kind == Kind_MSA128WRegs; + bool isCOP3AsmReg() const { + return isRegIdx() && RegIdx.Kind & RegKind_COP3 && RegIdx.Index <= 31; } - - bool isMSA128DAsm() const { - return Kind == k_Register && Reg.Kind == Kind_MSA128DRegs; + bool isMSA128AsmReg() const { + return isRegIdx() && RegIdx.Kind & RegKind_MSA128 && RegIdx.Index <= 31; } - - bool isMSA128CRAsm() const { - return Kind == k_Register && Reg.Kind == Kind_MSA128CtrlRegs; + bool isMSACtrlAsmReg() const { + return isRegIdx() && RegIdx.Kind & RegKind_MSACtrl && RegIdx.Index <= 7; } /// getStartLoc - Get the location of the first token of this operand. - SMLoc getStartLoc() const { return StartLoc; } + SMLoc getStartLoc() const override { return StartLoc; } /// getEndLoc - Get the location of the last token of this operand. - SMLoc getEndLoc() const { return EndLoc; } + SMLoc getEndLoc() const override { return EndLoc; } - virtual void print(raw_ostream &OS) const { - llvm_unreachable("unimplemented!"); + virtual ~MipsOperand() { + switch (Kind) { + case k_Immediate: + break; + case k_Memory: + delete Mem.Base; + break; + case k_PhysRegister: + case k_RegisterIndex: + case k_Token: + break; + } + } + + void print(raw_ostream &OS) const override { + switch (Kind) { + case k_Immediate: + OS << "Imm<"; + Imm.Val->print(OS); + OS << ">"; + break; + case k_Memory: + OS << "Mem<"; + Mem.Base->print(OS); + OS << ", "; + Mem.Off->print(OS); + OS << ">"; + break; + case k_PhysRegister: + OS << "PhysReg<" << PhysReg.Num << ">"; + break; + case k_RegisterIndex: + OS << "RegIdx<" << RegIdx.Index << ":" << RegIdx.Kind << ">"; + break; + case k_Token: + OS << Tok.Data; + break; + } } }; // class MipsOperand } // namespace @@ -568,6 +956,7 @@ static const MCInstrDesc &getInstDesc(unsigned Opcode) { bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc, SmallVectorImpl &Instructions) { const MCInstrDesc &MCID = getInstDesc(Inst.getOpcode()); + Inst.setLoc(IDLoc); if (MCID.isBranch() || MCID.isCall()) { @@ -579,13 +968,16 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc, break; case Mips::BEQ: case Mips::BNE: - assert (MCID.getNumOperands() == 3 && "unexpected number of operands"); + case Mips::BEQ_MM: + case Mips::BNE_MM: + 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(isMicroMips() ? 17 : 18, Offset.getImm())) + if (!isIntN(inMicroMipsMode() ? 17 : 18, Offset.getImm())) return Error(IDLoc, "branch target out of range"); - if (OffsetToAlignment (Offset.getImm(), 1LL << (isMicroMips() ? 1 : 2))) + if (OffsetToAlignment(Offset.getImm(), + 1LL << (inMicroMipsMode() ? 1 : 2))) return Error(IDLoc, "branch to misaligned address"); break; case Mips::BGEZ: @@ -596,18 +988,35 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc, case Mips::BLTZAL: case Mips::BC1F: case Mips::BC1T: - assert (MCID.getNumOperands() == 2 && "unexpected number of operands"); + case Mips::BGEZ_MM: + case Mips::BGTZ_MM: + case Mips::BLEZ_MM: + case Mips::BLTZ_MM: + case Mips::BGEZAL_MM: + case Mips::BLTZAL_MM: + case Mips::BC1F_MM: + case Mips::BC1T_MM: + 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(isMicroMips() ? 17 : 18, Offset.getImm())) + if (!isIntN(inMicroMipsMode() ? 17 : 18, Offset.getImm())) return Error(IDLoc, "branch target out of range"); - if (OffsetToAlignment (Offset.getImm(), 1LL << (isMicroMips() ? 1 : 2))) + if (OffsetToAlignment(Offset.getImm(), + 1LL << (inMicroMipsMode() ? 1 : 2))) return Error(IDLoc, "branch to misaligned address"); break; } } + // SSNOP is deprecated on MIPS32r6/MIPS64r6 + // We still accept it but it is a normal nop. + if (hasMips32r6() && Inst.getOpcode() == Mips::SSNOP) { + std::string ISA = hasMips64r6() ? "MIPS64r6" : "MIPS32r6"; + Warning(IDLoc, "ssnop is deprecated for " + ISA + " and is equivalent to a " + "nop instruction"); + } + if (MCID.hasDelaySlot() && Options.isReorder()) { // If this instruction has a delay slot and .set reorder is active, // emit a NOP after it. @@ -656,7 +1065,7 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc, } // if load/store if (needsExpansion(Inst)) - expandInstruction(Inst, IDLoc, Instructions); + return expandInstruction(Inst, IDLoc, Instructions); else Instructions.push_back(Inst); @@ -669,17 +1078,27 @@ bool MipsAsmParser::needsExpansion(MCInst &Inst) { case Mips::LoadImm32Reg: case Mips::LoadAddr32Imm: case Mips::LoadAddr32Reg: + case Mips::LoadImm64Reg: return true; default: return false; } } -void MipsAsmParser::expandInstruction(MCInst &Inst, SMLoc IDLoc, +bool MipsAsmParser::expandInstruction(MCInst &Inst, SMLoc IDLoc, SmallVectorImpl &Instructions) { switch (Inst.getOpcode()) { + default: + assert(0 && "unimplemented expansion"); + return true; case Mips::LoadImm32Reg: return expandLoadImm(Inst, IDLoc, Instructions); + case Mips::LoadImm64Reg: + if (!isGP64bit()) { + Error(IDLoc, "instruction requires a CPU feature not currently enabled"); + return true; + } + return expandLoadImm(Inst, IDLoc, Instructions); case Mips::LoadAddr32Imm: return expandLoadAddressImm(Inst, IDLoc, Instructions); case Mips::LoadAddr32Reg: @@ -687,7 +1106,38 @@ void MipsAsmParser::expandInstruction(MCInst &Inst, SMLoc IDLoc, } } -void MipsAsmParser::expandLoadImm(MCInst &Inst, SMLoc IDLoc, +namespace { +template +void createShiftOr(MCOperand Operand, unsigned RegNo, SMLoc IDLoc, + SmallVectorImpl &Instructions) { + MCInst tmpInst; + if (PerformShift) { + tmpInst.setOpcode(Mips::DSLL); + tmpInst.addOperand(MCOperand::CreateReg(RegNo)); + tmpInst.addOperand(MCOperand::CreateReg(RegNo)); + tmpInst.addOperand(MCOperand::CreateImm(16)); + tmpInst.setLoc(IDLoc); + Instructions.push_back(tmpInst); + tmpInst.clear(); + } + tmpInst.setOpcode(Mips::ORi); + tmpInst.addOperand(MCOperand::CreateReg(RegNo)); + tmpInst.addOperand(MCOperand::CreateReg(RegNo)); + tmpInst.addOperand(Operand); + tmpInst.setLoc(IDLoc); + Instructions.push_back(tmpInst); +} + +template +void createShiftOr(int64_t Value, unsigned RegNo, SMLoc IDLoc, + SmallVectorImpl &Instructions) { + createShiftOr( + MCOperand::CreateImm(((Value & (0xffffLL << Shift)) >> Shift)), RegNo, + IDLoc, Instructions); +} +} + +bool MipsAsmParser::expandLoadImm(MCInst &Inst, SMLoc IDLoc, SmallVectorImpl &Instructions) { MCInst tmpInst; const MCOperand &ImmOp = Inst.getOperand(1); @@ -695,8 +1145,10 @@ void MipsAsmParser::expandLoadImm(MCInst &Inst, SMLoc IDLoc, const MCOperand &RegOp = Inst.getOperand(0); assert(RegOp.isReg() && "expected register operand kind"); - int ImmValue = ImmOp.getImm(); + int64_t ImmValue = ImmOp.getImm(); tmpInst.setLoc(IDLoc); + // FIXME: gas has a special case for values that are 000...1111, which + // becomes a li -1 and then a dsrl if (0 <= ImmValue && ImmValue <= 65535) { // For 0 <= j <= 65535. // li d,j => ori d,$zero,j @@ -713,30 +1165,86 @@ void MipsAsmParser::expandLoadImm(MCInst &Inst, SMLoc IDLoc, tmpInst.addOperand(MCOperand::CreateReg(Mips::ZERO)); tmpInst.addOperand(MCOperand::CreateImm(ImmValue)); Instructions.push_back(tmpInst); - } else { - // For any other value of j that is representable as a 32-bit integer. + } else if ((ImmValue & 0xffffffff) == ImmValue) { + // For any value of j that is representable as a 32-bit integer, create + // a sequence of: // li d,j => lui d,hi16(j) // ori d,d,lo16(j) tmpInst.setOpcode(Mips::LUi); tmpInst.addOperand(MCOperand::CreateReg(RegOp.getReg())); tmpInst.addOperand(MCOperand::CreateImm((ImmValue & 0xffff0000) >> 16)); Instructions.push_back(tmpInst); - tmpInst.clear(); - tmpInst.setOpcode(Mips::ORi); + createShiftOr<0, false>(ImmValue, RegOp.getReg(), IDLoc, Instructions); + } else if ((ImmValue & (0xffffLL << 48)) == 0) { + if (!isGP64bit()) { + Error(IDLoc, "instruction requires a CPU feature not currently enabled"); + return true; + } + + // <------- lo32 ------> + // <------- hi32 ------> + // <- hi16 -> <- lo16 -> + // _________________________________ + // | | | | + // | 16-bytes | 16-bytes | 16-bytes | + // |__________|__________|__________| + // + // For any value of j that is representable as a 48-bit integer, create + // a sequence of: + // li d,j => lui d,hi16(j) + // ori d,d,hi16(lo32(j)) + // dsll d,d,16 + // ori d,d,lo16(lo32(j)) + tmpInst.setOpcode(Mips::LUi); tmpInst.addOperand(MCOperand::CreateReg(RegOp.getReg())); + tmpInst.addOperand( + MCOperand::CreateImm((ImmValue & (0xffffLL << 32)) >> 32)); + Instructions.push_back(tmpInst); + createShiftOr<16, false>(ImmValue, RegOp.getReg(), IDLoc, Instructions); + createShiftOr<0, true>(ImmValue, RegOp.getReg(), IDLoc, Instructions); + } else { + if (!isGP64bit()) { + Error(IDLoc, "instruction requires a CPU feature not currently enabled"); + return true; + } + + // <------- hi32 ------> <------- lo32 ------> + // <- hi16 -> <- lo16 -> + // ___________________________________________ + // | | | | | + // | 16-bytes | 16-bytes | 16-bytes | 16-bytes | + // |__________|__________|__________|__________| + // + // For any value of j that isn't representable as a 48-bit integer. + // li d,j => lui d,hi16(j) + // ori d,d,lo16(hi32(j)) + // dsll d,d,16 + // ori d,d,hi16(lo32(j)) + // dsll d,d,16 + // ori d,d,lo16(lo32(j)) + tmpInst.setOpcode(Mips::LUi); tmpInst.addOperand(MCOperand::CreateReg(RegOp.getReg())); - tmpInst.addOperand(MCOperand::CreateImm(ImmValue & 0xffff)); - tmpInst.setLoc(IDLoc); + tmpInst.addOperand( + MCOperand::CreateImm((ImmValue & (0xffffLL << 48)) >> 48)); Instructions.push_back(tmpInst); + createShiftOr<32, false>(ImmValue, RegOp.getReg(), IDLoc, Instructions); + createShiftOr<16, true>(ImmValue, RegOp.getReg(), IDLoc, Instructions); + createShiftOr<0, true>(ImmValue, RegOp.getReg(), IDLoc, Instructions); } + return false; } -void +bool MipsAsmParser::expandLoadAddressReg(MCInst &Inst, SMLoc IDLoc, SmallVectorImpl &Instructions) { MCInst tmpInst; const MCOperand &ImmOp = Inst.getOperand(2); - assert(ImmOp.isImm() && "expected immediate operand kind"); + assert((ImmOp.isImm() || ImmOp.isExpr()) && + "expected immediate operand kind"); + if (!ImmOp.isImm()) { + expandLoadAddressSym(Inst, IDLoc, Instructions); + return false; + } const MCOperand &SrcRegOp = Inst.getOperand(1); assert(SrcRegOp.isReg() && "expected register operand kind"); const MCOperand &DstRegOp = Inst.getOperand(0); @@ -772,14 +1280,20 @@ MipsAsmParser::expandLoadAddressReg(MCInst &Inst, SMLoc IDLoc, tmpInst.addOperand(MCOperand::CreateReg(SrcRegOp.getReg())); Instructions.push_back(tmpInst); } + return false; } -void +bool MipsAsmParser::expandLoadAddressImm(MCInst &Inst, SMLoc IDLoc, SmallVectorImpl &Instructions) { MCInst tmpInst; const MCOperand &ImmOp = Inst.getOperand(1); - assert(ImmOp.isImm() && "expected immediate operand kind"); + assert((ImmOp.isImm() || ImmOp.isExpr()) && + "expected immediate operand kind"); + if (!ImmOp.isImm()) { + expandLoadAddressSym(Inst, IDLoc, Instructions); + return false; + } const MCOperand &RegOp = Inst.getOperand(0); assert(RegOp.isReg() && "expected register operand kind"); int ImmValue = ImmOp.getImm(); @@ -806,6 +1320,72 @@ MipsAsmParser::expandLoadAddressImm(MCInst &Inst, SMLoc IDLoc, tmpInst.addOperand(MCOperand::CreateImm(ImmValue & 0xffff)); Instructions.push_back(tmpInst); } + return false; +} + +void +MipsAsmParser::expandLoadAddressSym(MCInst &Inst, SMLoc IDLoc, + SmallVectorImpl &Instructions) { + // FIXME: If we do have a valid at register to use, we should generate a + // slightly shorter sequence here. + MCInst tmpInst; + int ExprOperandNo = 1; + // Sometimes the assembly parser will get the immediate expression as + // a $zero + an immediate. + if (Inst.getNumOperands() == 3) { + assert(Inst.getOperand(1).getReg() == + (isGP64bit() ? Mips::ZERO_64 : Mips::ZERO)); + ExprOperandNo = 2; + } + const MCOperand &SymOp = Inst.getOperand(ExprOperandNo); + assert(SymOp.isExpr() && "expected symbol operand kind"); + const MCOperand &RegOp = Inst.getOperand(0); + unsigned RegNo = RegOp.getReg(); + const MCSymbolRefExpr *Symbol = cast(SymOp.getExpr()); + const MCSymbolRefExpr *HiExpr = + MCSymbolRefExpr::Create(Symbol->getSymbol().getName(), + MCSymbolRefExpr::VK_Mips_ABS_HI, getContext()); + const MCSymbolRefExpr *LoExpr = + MCSymbolRefExpr::Create(Symbol->getSymbol().getName(), + MCSymbolRefExpr::VK_Mips_ABS_LO, getContext()); + if (isGP64bit()) { + // If it's a 64-bit architecture, expand to: + // la d,sym => lui d,highest(sym) + // ori d,d,higher(sym) + // dsll d,d,16 + // ori d,d,hi16(sym) + // dsll d,d,16 + // ori d,d,lo16(sym) + const MCSymbolRefExpr *HighestExpr = + MCSymbolRefExpr::Create(Symbol->getSymbol().getName(), + MCSymbolRefExpr::VK_Mips_HIGHEST, getContext()); + const MCSymbolRefExpr *HigherExpr = + MCSymbolRefExpr::Create(Symbol->getSymbol().getName(), + MCSymbolRefExpr::VK_Mips_HIGHER, getContext()); + + tmpInst.setOpcode(Mips::LUi); + tmpInst.addOperand(MCOperand::CreateReg(RegNo)); + tmpInst.addOperand(MCOperand::CreateExpr(HighestExpr)); + Instructions.push_back(tmpInst); + + createShiftOr(MCOperand::CreateExpr(HigherExpr), RegNo, SMLoc(), + Instructions); + createShiftOr(MCOperand::CreateExpr(HiExpr), RegNo, SMLoc(), + Instructions); + createShiftOr(MCOperand::CreateExpr(LoExpr), RegNo, SMLoc(), + Instructions); + } else { + // Otherwise, expand to: + // la d,sym => lui d,hi16(sym) + // ori d,d,lo16(sym) + tmpInst.setOpcode(Mips::LUi); + tmpInst.addOperand(MCOperand::CreateReg(RegNo)); + tmpInst.addOperand(MCOperand::CreateExpr(HiExpr)); + Instructions.push_back(tmpInst); + + createShiftOr(MCOperand::CreateExpr(LoExpr), RegNo, SMLoc(), + Instructions); + } } void MipsAsmParser::expandMemInst(MCInst &Inst, SMLoc IDLoc, @@ -816,8 +1396,6 @@ void MipsAsmParser::expandMemInst(MCInst &Inst, SMLoc IDLoc, unsigned ImmOffset, HiOffset, LoOffset; const MCExpr *ExprOffset; unsigned TmpRegNum; - unsigned AtRegNum = getReg( - (isMips64()) ? Mips::GPR64RegClassID : Mips::GPR32RegClassID, getATReg()); // 1st operand is either the source or destination register. assert(Inst.getOperand(0).isReg() && "expected register operand kind"); unsigned RegOpNum = Inst.getOperand(0).getReg(); @@ -837,10 +1415,46 @@ void MipsAsmParser::expandMemInst(MCInst &Inst, SMLoc IDLoc, ExprOffset = Inst.getOperand(2).getExpr(); // All instructions will have the same location. TempInst.setLoc(IDLoc); - // 1st instruction in expansion is LUi. For load instruction we can use - // the dst register as a temporary if base and dst are different, - // but for stores we must use $at. - TmpRegNum = (isLoad && (BaseRegNum != RegOpNum)) ? RegOpNum : AtRegNum; + // These are some of the types of expansions we perform here: + // 1) lw $8, sym => lui $8, %hi(sym) + // lw $8, %lo(sym)($8) + // 2) lw $8, offset($9) => lui $8, %hi(offset) + // add $8, $8, $9 + // lw $8, %lo(offset)($9) + // 3) lw $8, offset($8) => lui $at, %hi(offset) + // add $at, $at, $8 + // lw $8, %lo(offset)($at) + // 4) sw $8, sym => lui $at, %hi(sym) + // sw $8, %lo(sym)($at) + // 5) sw $8, offset($8) => lui $at, %hi(offset) + // add $at, $at, $8 + // sw $8, %lo(offset)($at) + // 6) ldc1 $f0, sym => lui $at, %hi(sym) + // ldc1 $f0, %lo(sym)($at) + // + // For load instructions we can use the destination register as a temporary + // if base and dst are different (examples 1 and 2) and if the base register + // is general purpose otherwise we must use $at (example 6) and error if it's + // not available. For stores we must use $at (examples 4 and 5) because we + // must not clobber the source register setting up the offset. + const MCInstrDesc &Desc = getInstDesc(Inst.getOpcode()); + int16_t RegClassOp0 = Desc.OpInfo[0].RegClass; + unsigned RegClassIDOp0 = + getContext().getRegisterInfo()->getRegClass(RegClassOp0).getID(); + bool IsGPR = (RegClassIDOp0 == Mips::GPR32RegClassID) || + (RegClassIDOp0 == Mips::GPR64RegClassID); + if (isLoad && IsGPR && (BaseRegNum != RegOpNum)) + TmpRegNum = RegOpNum; + else { + int AT = getATReg(IDLoc); + // At this point we need AT to perform the expansions and we exit if it is + // not available. + if (!AT) + return; + TmpRegNum = getReg( + (isGP64bit()) ? Mips::GPR64RegClassID : Mips::GPR32RegClassID, AT); + } + TempInst.setOpcode(Mips::LUi); TempInst.addOperand(MCOperand::CreateReg(TmpRegNum)); if (isImmOpnd) @@ -868,7 +1482,7 @@ void MipsAsmParser::expandMemInst(MCInst &Inst, SMLoc IDLoc, TempInst.addOperand(MCOperand::CreateReg(BaseRegNum)); Instructions.push_back(TempInst); TempInst.clear(); - // And finaly, create original instruction with low part + // And finally, create original instruction with low part // of offset and new base. TempInst.setOpcode(Inst.getOpcode()); TempInst.addOperand(MCOperand::CreateReg(RegOpNum)); @@ -890,10 +1504,24 @@ void MipsAsmParser::expandMemInst(MCInst &Inst, SMLoc IDLoc, TempInst.clear(); } -bool MipsAsmParser::MatchAndEmitInstruction( - SMLoc IDLoc, unsigned &Opcode, - SmallVectorImpl &Operands, MCStreamer &Out, - unsigned &ErrorInfo, bool MatchingInlineAsm) { +unsigned MipsAsmParser::checkTargetMatchPredicate(MCInst &Inst) { + // As described by the Mips32r2 spec, the registers Rd and Rs for + // jalr.hb must be different. + unsigned Opcode = Inst.getOpcode(); + + if (Opcode == Mips::JALR_HB && + (Inst.getOperand(0).getReg() == Inst.getOperand(1).getReg())) + return Match_RequiresDifferentSrcAndDst; + + return Match_Success; +} + +bool MipsAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, + OperandVector &Operands, + MCStreamer &Out, + uint64_t &ErrorInfo, + bool MatchingInlineAsm) { + MCInst Inst; SmallVector Instructions; unsigned MatchResult = @@ -906,7 +1534,7 @@ bool MipsAsmParser::MatchAndEmitInstruction( if (processInstruction(Inst, IDLoc, Instructions)) return true; for (unsigned i = 0; i < Instructions.size(); i++) - Out.EmitInstruction(Instructions[i]); + Out.EmitInstruction(Instructions[i], STI); return false; } case Match_MissingFeature: @@ -914,11 +1542,11 @@ bool MipsAsmParser::MatchAndEmitInstruction( return true; case Match_InvalidOperand: { SMLoc ErrorLoc = IDLoc; - if (ErrorInfo != ~0U) { + if (ErrorInfo != ~0ULL) { if (ErrorInfo >= Operands.size()) return Error(IDLoc, "too few operands for instruction"); - ErrorLoc = ((MipsOperand *)Operands[ErrorInfo])->getStartLoc(); + ErrorLoc = ((MipsOperand &)*Operands[ErrorInfo]).getStartLoc(); if (ErrorLoc == SMLoc()) ErrorLoc = IDLoc; } @@ -927,18 +1555,28 @@ bool MipsAsmParser::MatchAndEmitInstruction( } case Match_MnemonicFail: return Error(IDLoc, "invalid instruction"); + case Match_RequiresDifferentSrcAndDst: + return Error(IDLoc, "source and destination must be different"); } return true; } +void MipsAsmParser::WarnIfAssemblerTemporary(int RegIndex, SMLoc Loc) { + if ((RegIndex != 0) && ((int)Options.getATRegNum() == RegIndex)) { + if (RegIndex == 1) + Warning(Loc, "Used $at without \".set noat\""); + else + Warning(Loc, Twine("Used $") + Twine(RegIndex) + " with \".set at=$" + + Twine(RegIndex) + "\""); + } +} + int MipsAsmParser::matchCPURegisterName(StringRef Name) { int CC; - if (Name == "at") - return getATReg(); - CC = StringSwitch(Name) .Case("zero", 0) + .Case("at", 1) .Case("a0", 4) .Case("a1", 5) .Case("a2", 6) @@ -955,9 +1593,10 @@ int MipsAsmParser::matchCPURegisterName(StringRef Name) { .Case("s7", 23) .Case("k0", 26) .Case("k1", 27) + .Case("gp", 28) .Case("sp", 29) .Case("fp", 30) - .Case("gp", 28) + .Case("s8", 30) .Case("ra", 31) .Case("t0", 8) .Case("t1", 9) @@ -971,22 +1610,23 @@ int MipsAsmParser::matchCPURegisterName(StringRef Name) { .Case("t9", 25) .Default(-1); - // Although SGI documentation just cuts out t0-t3 for n32/n64, - // GNU pushes the values of t0-t3 to override the o32/o64 values for t4-t7 - // We are supporting both cases, so for t0-t3 we'll just push them to t4-t7. - if (isMips64() && 8 <= CC && CC <= 11) - CC += 4; - - if (CC == -1 && isMips64()) - CC = StringSwitch(Name) - .Case("a4", 8) - .Case("a5", 9) - .Case("a6", 10) - .Case("a7", 11) - .Case("kt0", 26) - .Case("kt1", 27) - .Case("s8", 30) - .Default(-1); + if (isABI_N32() || isABI_N64()) { + // Although SGI documentation just cuts out t0-t3 for n32/n64, + // GNU pushes the values of t0-t3 to override the o32/o64 values for t4-t7 + // We are supporting both cases, so for t0-t3 we'll just push them to t4-t7. + if (8 <= CC && CC <= 11) + CC += 4; + + if (CC == -1) + CC = StringSwitch(Name) + .Case("a4", 8) + .Case("a5", 9) + .Case("a6", 10) + .Case("a7", 11) + .Case("kt0", 26) + .Case("kt1", 27) + .Default(-1); + } return CC; } @@ -1062,59 +1702,6 @@ int MipsAsmParser::matchMSA128CtrlRegisterName(StringRef Name) { return CC; } -int MipsAsmParser::matchRegisterName(StringRef Name, bool is64BitReg) { - - int CC; - CC = matchCPURegisterName(Name); - if (CC != -1) - return matchRegisterByNumber(CC, is64BitReg ? Mips::GPR64RegClassID - : Mips::GPR32RegClassID); - CC = matchFPURegisterName(Name); - // TODO: decide about fpu register class - if (CC != -1) - return matchRegisterByNumber(CC, isFP64() ? Mips::FGR64RegClassID - : Mips::FGR32RegClassID); - return matchMSA128RegisterName(Name); -} - -int MipsAsmParser::regKindToRegClass(int RegKind) { - - switch (RegKind) { - case MipsOperand::Kind_GPR32: - return Mips::GPR32RegClassID; - case MipsOperand::Kind_GPR64: - return Mips::GPR64RegClassID; - case MipsOperand::Kind_HWRegs: - return Mips::HWRegsRegClassID; - case MipsOperand::Kind_FGR32Regs: - return Mips::FGR32RegClassID; - case MipsOperand::Kind_FGRH32Regs: - return Mips::FGRH32RegClassID; - case MipsOperand::Kind_FGR64Regs: - return Mips::FGR64RegClassID; - case MipsOperand::Kind_AFGR64Regs: - return Mips::AFGR64RegClassID; - case MipsOperand::Kind_CCRRegs: - return Mips::CCRRegClassID; - case MipsOperand::Kind_ACC64DSP: - return Mips::ACC64DSPRegClassID; - case MipsOperand::Kind_FCCRegs: - return Mips::FCCRegClassID; - case MipsOperand::Kind_MSA128BRegs: - return Mips::MSA128BRegClassID; - case MipsOperand::Kind_MSA128HRegs: - return Mips::MSA128HRegClassID; - case MipsOperand::Kind_MSA128WRegs: - return Mips::MSA128WRegClassID; - case MipsOperand::Kind_MSA128DRegs: - return Mips::MSA128DRegClassID; - case MipsOperand::Kind_MSA128CtrlRegs: - return Mips::MSACtrlRegClassID; - default: - return -1; - } -} - bool MipsAssemblerOptions::setATReg(unsigned Reg) { if (Reg > 31) return false; @@ -1123,53 +1710,34 @@ bool MipsAssemblerOptions::setATReg(unsigned Reg) { return true; } -int MipsAsmParser::getATReg() { return Options.getATRegNum(); } +int MipsAsmParser::getATReg(SMLoc Loc) { + int AT = Options.getATRegNum(); + if (AT == 0) + reportParseError(Loc, + "Pseudo instruction requires $at, which is not available"); + return AT; +} unsigned MipsAsmParser::getReg(int RC, int RegNo) { return *(getContext().getRegisterInfo()->getRegClass(RC).begin() + RegNo); } +unsigned MipsAsmParser::getGPR(int RegNo) { + return getReg(isGP64bit() ? Mips::GPR64RegClassID : Mips::GPR32RegClassID, + RegNo); +} + int MipsAsmParser::matchRegisterByNumber(unsigned RegNum, unsigned RegClass) { if (RegNum > - getContext().getRegisterInfo()->getRegClass(RegClass).getNumRegs()) + getContext().getRegisterInfo()->getRegClass(RegClass).getNumRegs() - 1) return -1; return getReg(RegClass, RegNum); } -int MipsAsmParser::tryParseRegister(bool is64BitReg) { - const AsmToken &Tok = Parser.getTok(); - int RegNum = -1; - - if (Tok.is(AsmToken::Identifier)) { - std::string lowerCase = Tok.getString().lower(); - RegNum = matchRegisterName(lowerCase, is64BitReg); - } else if (Tok.is(AsmToken::Integer)) - RegNum = matchRegisterByNumber(static_cast(Tok.getIntVal()), - is64BitReg ? Mips::GPR64RegClassID - : Mips::GPR32RegClassID); - return RegNum; -} - -bool MipsAsmParser::tryParseRegisterOperand( - SmallVectorImpl &Operands, bool is64BitReg) { - - SMLoc S = Parser.getTok().getLoc(); - int RegNo = -1; - - RegNo = tryParseRegister(is64BitReg); - if (RegNo == -1) - return true; - - Operands.push_back( - MipsOperand::CreateReg(RegNo, S, Parser.getTok().getLoc())); - Parser.Lex(); // Eat register token. - return false; -} +bool MipsAsmParser::ParseOperand(OperandVector &Operands, StringRef Mnemonic) { + DEBUG(dbgs() << "ParseOperand\n"); -bool -MipsAsmParser::ParseOperand(SmallVectorImpl &Operands, - StringRef Mnemonic) { // Check if the current operand has a custom associated parser, if so, try to // custom parse the operand, or fallback to the general approach. OperandMatchResultTy ResTy = MatchOperandParserImpl(Operands, Mnemonic); @@ -1181,6 +1749,8 @@ MipsAsmParser::ParseOperand(SmallVectorImpl &Operands, if (ResTy == MatchOperand_ParseFail) return true; + DEBUG(dbgs() << ".. Generic Parser\n"); + switch (getLexer().getKind()) { default: Error(Parser.getTok().getLoc(), "unexpected token in operand"); @@ -1188,29 +1758,15 @@ MipsAsmParser::ParseOperand(SmallVectorImpl &Operands, case AsmToken::Dollar: { // Parse the register. SMLoc S = Parser.getTok().getLoc(); - Parser.Lex(); // Eat dollar token. - // Parse the register operand. - if (!tryParseRegisterOperand(Operands, isMips64())) { - if (getLexer().is(AsmToken::LParen)) { - // Check if it is indexed addressing operand. - Operands.push_back(MipsOperand::CreateToken("(", S)); - Parser.Lex(); // Eat the parenthesis. - if (getLexer().isNot(AsmToken::Dollar)) - return true; - - Parser.Lex(); // Eat the dollar - if (tryParseRegisterOperand(Operands, isMips64())) - return true; - - if (!getLexer().is(AsmToken::RParen)) - return true; - S = Parser.getTok().getLoc(); - Operands.push_back(MipsOperand::CreateToken(")", S)); - Parser.Lex(); - } + // Almost all registers have been parsed by custom parsers. There is only + // one exception to this. $zero (and it's alias $0) will reach this point + // for div, divu, and similar instructions because it is not an operand + // to the instruction definition but an explicit register. Special case + // this situation for now. + if (ParseAnyRegister(Operands) != MatchOperand_NoMatch) return false; - } + // Maybe it is a symbol reference. StringRef Identifier; if (Parser.parseIdentifier(Identifier)) @@ -1222,47 +1778,19 @@ MipsAsmParser::ParseOperand(SmallVectorImpl &Operands, const MCExpr *Res = MCSymbolRefExpr::Create(Sym, MCSymbolRefExpr::VK_None, getContext()); - Operands.push_back(MipsOperand::CreateImm(Res, S, E)); + Operands.push_back(MipsOperand::CreateImm(Res, S, E, *this)); return false; } - case AsmToken::Identifier: - // For instruction aliases like "bc1f $Label" dedicated parser will - // eat the '$' sign before failing. So in order to look for appropriate - // label we must check first if we have already consumed '$'. - if (hasConsumedDollar) { - hasConsumedDollar = false; - SMLoc S = Parser.getTok().getLoc(); - StringRef Identifier; - if (Parser.parseIdentifier(Identifier)) - return true; - SMLoc E = - SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); - MCSymbol *Sym = getContext().GetOrCreateSymbol("$" + Identifier); - // Create a symbol reference. - const MCExpr *Res = - MCSymbolRefExpr::Create(Sym, MCSymbolRefExpr::VK_None, getContext()); - - Operands.push_back(MipsOperand::CreateImm(Res, S, E)); - return false; - } - // Look for the existing symbol, we should check if - // we need to assigne the propper RegisterKind. - if (searchSymbolAlias(Operands, MipsOperand::Kind_None)) - 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: { - // Quoted label names. - const MCExpr *IdVal; - SMLoc S = Parser.getTok().getLoc(); - if (getParser().parseExpression(IdVal)) - return true; - SMLoc E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); - Operands.push_back(MipsOperand::CreateImm(IdVal, S, E)); - return false; + DEBUG(dbgs() << ".. generic integer\n"); + OperandMatchResultTy ResTy = ParseImm(Operands); + return ResTy != MatchOperand_Success; } case AsmToken::Percent: { // It is a symbol reference or constant expression. @@ -1273,7 +1801,7 @@ MipsAsmParser::ParseOperand(SmallVectorImpl &Operands, SMLoc E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); - Operands.push_back(MipsOperand::CreateImm(IdVal, S, E)); + Operands.push_back(MipsOperand::CreateImm(IdVal, S, E, *this)); return false; } // case AsmToken::Percent } // switch(getLexer().getKind()) @@ -1285,23 +1813,30 @@ const MCExpr *MipsAsmParser::evaluateRelocExpr(const MCExpr *Expr, const MCExpr *Res; // Check the type of the expression. if (const MCConstantExpr *MCE = dyn_cast(Expr)) { - // It's a constant, evaluate lo or hi value. - if (RelocStr == "lo") { - short Val = MCE->getValue(); - Res = MCConstantExpr::Create(Val, getContext()); - } else if (RelocStr == "hi") { - int Val = MCE->getValue(); - int LoSign = Val & 0x8000; - Val = (Val & 0xffff0000) >> 16; - // Lower part is treated as a signed int, so if it is negative - // we must add 1 to the hi part to compensate. - if (LoSign) - Val++; - Res = MCConstantExpr::Create(Val, getContext()); - } else { - llvm_unreachable("Invalid RelocStr value"); + // It's a constant, evaluate reloc value. + int16_t Val; + switch (getVariantKind(RelocStr)) { + case MCSymbolRefExpr::VK_Mips_ABS_LO: + // Get the 1st 16-bits. + Val = MCE->getValue() & 0xffff; + break; + case MCSymbolRefExpr::VK_Mips_ABS_HI: + // Get the 2nd 16-bits. Also add 1 if bit 15 is 1, to compensate for low + // 16 bits being negative. + Val = ((MCE->getValue() + 0x8000) >> 16) & 0xffff; + break; + case MCSymbolRefExpr::VK_Mips_HIGHER: + // Get the 3rd 16-bits. + Val = ((MCE->getValue() + 0x80008000LL) >> 32) & 0xffff; + break; + case MCSymbolRefExpr::VK_Mips_HIGHEST: + // Get the 4th 16-bits. + Val = ((MCE->getValue() + 0x800080008000LL) >> 48) & 0xffff; + break; + default: + report_fatal_error("Unsupported reloc value!"); } - return Res; + return MCConstantExpr::Create(Val, getContext()); } if (const MCSymbolRefExpr *MSRE = dyn_cast(Expr)) { @@ -1313,6 +1848,12 @@ const MCExpr *MipsAsmParser::evaluateRelocExpr(const MCExpr *Expr, } if (const MCBinaryExpr *BE = dyn_cast(Expr)) { + MCSymbolRefExpr::VariantKind VK = getVariantKind(RelocStr); + + // Try to create target expression. + if (MipsMCExpr::isSupportedBinaryExpr(VK, BE)) + return MipsMCExpr::Create(VK, Expr, getContext()); + const MCExpr *LExp = evaluateRelocExpr(BE->getLHS(), RelocStr); const MCExpr *RExp = evaluateRelocExpr(BE->getRHS(), RelocStr); Res = MCBinaryExpr::Create(BE->getOpcode(), LExp, RExp, getContext()); @@ -1343,8 +1884,8 @@ bool MipsAsmParser::isEvaluated(const MCExpr *Expr) { } case MCExpr::Unary: return isEvaluated(cast(Expr)->getSubExpr()); - default: - return false; + case MCExpr::Target: + return true; } return false; } @@ -1393,9 +1934,27 @@ bool MipsAsmParser::parseRelocOperand(const MCExpr *&Res) { bool MipsAsmParser::ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc) { - StartLoc = Parser.getTok().getLoc(); - RegNo = tryParseRegister(isMips64()); - EndLoc = Parser.getTok().getLoc(); + SmallVector, 1> Operands; + OperandMatchResultTy ResTy = ParseAnyRegister(Operands); + if (ResTy == MatchOperand_Success) { + assert(Operands.size() == 1); + MipsOperand &Operand = static_cast(*Operands.front()); + StartLoc = Operand.getStartLoc(); + EndLoc = Operand.getEndLoc(); + + // AFAIK, we only support numeric registers and named GPR's in CFI + // directives. + // Don't worry about eating tokens before failing. Using an unrecognised + // register is a parse error. + if (Operand.isGPRAsmReg()) { + // Resolve to GPR32 or GPR64 appropriately. + RegNo = isGP64bit() ? Operand.getGPR64Reg() : Operand.getGPR32Reg(); + } + + return (RegNo == (unsigned)-1); + } + + assert(Operands.size() == 0); return (RegNo == (unsigned)-1); } @@ -1427,10 +1986,10 @@ bool MipsAsmParser::parseMemOffset(const MCExpr *&Res, bool isParenExpr) { return Result; } -MipsAsmParser::OperandMatchResultTy MipsAsmParser::parseMemOperand( - SmallVectorImpl &Operands) { - - const MCExpr *IdVal = 0; +MipsAsmParser::OperandMatchResultTy +MipsAsmParser::parseMemOperand(OperandVector &Operands) { + DEBUG(dbgs() << "parseMemOperand\n"); + const MCExpr *IdVal = nullptr; SMLoc S; bool isParenExpr = false; MipsAsmParser::OperandMatchResultTy Res = MatchOperand_NoMatch; @@ -1448,11 +2007,11 @@ MipsAsmParser::OperandMatchResultTy MipsAsmParser::parseMemOperand( const AsmToken &Tok = Parser.getTok(); // Get the next token. if (Tok.isNot(AsmToken::LParen)) { - MipsOperand *Mnemonic = static_cast(Operands[0]); - if (Mnemonic->getToken() == "la") { + MipsOperand &Mnemonic = static_cast(*Operands[0]); + if (Mnemonic.getToken() == "la") { SMLoc E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); - Operands.push_back(MipsOperand::CreateImm(IdVal, S, E)); + Operands.push_back(MipsOperand::CreateImm(IdVal, S, E, *this)); return MatchOperand_Success; } if (Tok.is(AsmToken::EndOfStatement)) { @@ -1460,8 +2019,11 @@ MipsAsmParser::OperandMatchResultTy MipsAsmParser::parseMemOperand( SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); // Zero register assumed, add a memory operand with ZERO as its base. - Operands.push_back(MipsOperand::CreateMem( - isMips64() ? Mips::ZERO_64 : Mips::ZERO, IdVal, S, E)); + // "Base" will be managed by k_Memory. + auto Base = MipsOperand::CreateGPRReg(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"); @@ -1471,8 +2033,7 @@ MipsAsmParser::OperandMatchResultTy MipsAsmParser::parseMemOperand( Parser.Lex(); // Eat the '(' token. } - Res = parseRegs(Operands, isMips64() ? (int)MipsOperand::Kind_GPR64 - : (int)MipsOperand::Kind_GPR32); + Res = ParseAnyRegister(Operands); if (Res != MatchOperand_Success) return Res; @@ -1485,13 +2046,14 @@ MipsAsmParser::OperandMatchResultTy MipsAsmParser::parseMemOperand( Parser.Lex(); // Eat the ')' token. - if (IdVal == 0) + if (!IdVal) IdVal = MCConstantExpr::Create(0, getContext()); // Replace the register operand with the memory operand. - MipsOperand *op = static_cast(Operands.back()); - int RegNo = op->getReg(); + std::unique_ptr op( + static_cast(Operands.back().release())); // Remove the register from the operands. + // "op" will be managed by k_Memory. Operands.pop_back(); // Add the memory operand. if (const MCBinaryExpr *BE = dyn_cast(IdVal)) { @@ -1503,603 +2065,195 @@ MipsAsmParser::OperandMatchResultTy MipsAsmParser::parseMemOperand( getContext()); } - Operands.push_back(MipsOperand::CreateMem(RegNo, IdVal, S, E)); - delete op; + Operands.push_back(MipsOperand::CreateMem(std::move(op), IdVal, S, E, *this)); return MatchOperand_Success; } -bool MipsAsmParser::parsePtrReg(SmallVectorImpl &Operands, - int RegKind) { - // If the first token is not '$' we have an error. - if (Parser.getTok().isNot(AsmToken::Dollar)) - return false; - - SMLoc S = Parser.getTok().getLoc(); - Parser.Lex(); - AsmToken::TokenKind TkKind = getLexer().getKind(); - int Reg; +bool MipsAsmParser::searchSymbolAlias(OperandVector &Operands) { - if (TkKind == AsmToken::Integer) { - Reg = matchRegisterByNumber(Parser.getTok().getIntVal(), - regKindToRegClass(RegKind)); - if (Reg == -1) - return false; - } else if (TkKind == AsmToken::Identifier) { - if ((Reg = matchCPURegisterName(Parser.getTok().getString().lower())) == -1) + 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; - Reg = getReg(regKindToRegClass(RegKind), Reg); - } else { - return false; + if (Expr->getKind() == MCExpr::SymbolRef) { + const MCSymbolRefExpr *Ref = static_cast(Expr); + StringRef DefSymbol = Ref->getSymbol().getName(); + if (DefSymbol.startswith("$")) { + OperandMatchResultTy ResTy = + MatchAnyRegisterNameWithoutDollar(Operands, DefSymbol.substr(1), S); + if (ResTy == MatchOperand_Success) { + Parser.Lex(); + return true; + } else if (ResTy == MatchOperand_ParseFail) + llvm_unreachable("Should never ParseFail"); + return false; + } + } else if (Expr->getKind() == MCExpr::Constant) { + Parser.Lex(); + const MCConstantExpr *Const = static_cast(Expr); + Operands.push_back( + MipsOperand::CreateImm(Const, S, Parser.getTok().getLoc(), *this)); + return true; + } } - - MipsOperand *Op = MipsOperand::CreatePtrReg(Reg, S, Parser.getTok().getLoc()); - Op->setRegKind((MipsOperand::RegisterKind)RegKind); - Operands.push_back(Op); - Parser.Lex(); - return true; + return false; } MipsAsmParser::OperandMatchResultTy -MipsAsmParser::parsePtrReg(SmallVectorImpl &Operands) { - MipsOperand::RegisterKind RegKind = - isN64() ? MipsOperand::Kind_GPR64 : MipsOperand::Kind_GPR32; - - // Parse index register. - if (!parsePtrReg(Operands, RegKind)) - return MatchOperand_NoMatch; +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)); + return MatchOperand_Success; + } - // Parse '('. - if (Parser.getTok().isNot(AsmToken::LParen)) - return MatchOperand_NoMatch; + Index = matchFPURegisterName(Identifier); + if (Index != -1) { + Operands.push_back(MipsOperand::CreateFGRReg( + Index, getContext().getRegisterInfo(), S, getLexer().getLoc(), *this)); + return MatchOperand_Success; + } - Operands.push_back(MipsOperand::CreateToken("(", getLexer().getLoc())); - Parser.Lex(); + Index = matchFCCRegisterName(Identifier); + if (Index != -1) { + Operands.push_back(MipsOperand::CreateFCCReg( + Index, getContext().getRegisterInfo(), S, getLexer().getLoc(), *this)); + return MatchOperand_Success; + } - // Parse base register. - if (!parsePtrReg(Operands, RegKind)) - return MatchOperand_NoMatch; + Index = matchACRegisterName(Identifier); + if (Index != -1) { + Operands.push_back(MipsOperand::CreateACCReg( + Index, getContext().getRegisterInfo(), S, getLexer().getLoc(), *this)); + return MatchOperand_Success; + } - // Parse ')'. - if (Parser.getTok().isNot(AsmToken::RParen)) - return MatchOperand_NoMatch; + Index = matchMSA128RegisterName(Identifier); + if (Index != -1) { + Operands.push_back(MipsOperand::CreateMSA128Reg( + Index, getContext().getRegisterInfo(), S, getLexer().getLoc(), *this)); + return MatchOperand_Success; + } - Operands.push_back(MipsOperand::CreateToken(")", getLexer().getLoc())); - Parser.Lex(); + Index = matchMSA128CtrlRegisterName(Identifier); + if (Index != -1) { + Operands.push_back(MipsOperand::CreateMSACtrlReg( + Index, getContext().getRegisterInfo(), S, getLexer().getLoc(), *this)); + return MatchOperand_Success; + } - return MatchOperand_Success; + return MatchOperand_NoMatch; } MipsAsmParser::OperandMatchResultTy -MipsAsmParser::parseRegs(SmallVectorImpl &Operands, - int RegKind) { - MipsOperand::RegisterKind Kind = (MipsOperand::RegisterKind)RegKind; - if (getLexer().getKind() == AsmToken::Identifier && !hasConsumedDollar) { - if (searchSymbolAlias(Operands, Kind)) - return MatchOperand_Success; - return MatchOperand_NoMatch; - } - SMLoc S = Parser.getTok().getLoc(); - // If the first token is not '$', we have an error. - if (Parser.getTok().isNot(AsmToken::Dollar) && !hasConsumedDollar) - return MatchOperand_NoMatch; - if (!hasConsumedDollar) { - Parser.Lex(); // Eat the '$' - hasConsumedDollar = true; - } - if (getLexer().getKind() == AsmToken::Identifier) { - int RegNum = -1; - std::string RegName = Parser.getTok().getString().lower(); - // Match register by name - switch (RegKind) { - case MipsOperand::Kind_GPR32: - case MipsOperand::Kind_GPR64: - RegNum = matchCPURegisterName(RegName); - break; - case MipsOperand::Kind_AFGR64Regs: - case MipsOperand::Kind_FGR64Regs: - case MipsOperand::Kind_FGR32Regs: - case MipsOperand::Kind_FGRH32Regs: - RegNum = matchFPURegisterName(RegName); - if (RegKind == MipsOperand::Kind_AFGR64Regs) - RegNum /= 2; - else if (RegKind == MipsOperand::Kind_FGRH32Regs && !isFP64()) - if (RegNum != -1 && RegNum % 2 != 0) - Warning(S, "Float register should be even."); - break; - case MipsOperand::Kind_FCCRegs: - RegNum = matchFCCRegisterName(RegName); - break; - case MipsOperand::Kind_ACC64DSP: - RegNum = matchACRegisterName(RegName); - break; - default: - break; // No match, value is set to -1. - } - // No match found, return _NoMatch to give a chance to other round. - if (RegNum < 0) - return MatchOperand_NoMatch; - - int RegVal = getReg(regKindToRegClass(Kind), RegNum); - if (RegVal == -1) - return MatchOperand_NoMatch; - - MipsOperand *Op = - MipsOperand::CreateReg(RegVal, S, Parser.getTok().getLoc()); - Op->setRegKind(Kind); - Operands.push_back(Op); - hasConsumedDollar = false; - Parser.Lex(); // Eat the register name. - return MatchOperand_Success; - } else if (getLexer().getKind() == AsmToken::Integer) { - unsigned RegNum = Parser.getTok().getIntVal(); - if (Kind == MipsOperand::Kind_HWRegs) { - if (RegNum != 29) - return MatchOperand_NoMatch; - // Only hwreg 29 is supported, found at index 0. - RegNum = 0; - } - int Reg = matchRegisterByNumber(RegNum, regKindToRegClass(Kind)); - if (Reg == -1) - return MatchOperand_NoMatch; - MipsOperand *Op = MipsOperand::CreateReg(Reg, S, Parser.getTok().getLoc()); - Op->setRegKind(Kind); - Operands.push_back(Op); - hasConsumedDollar = false; - Parser.Lex(); // Eat the register number. - if ((RegKind == MipsOperand::Kind_GPR32) && - (getLexer().is(AsmToken::LParen))) { - // Check if it is indexed addressing operand. - Operands.push_back(MipsOperand::CreateToken("(", getLexer().getLoc())); - Parser.Lex(); // Eat the parenthesis. - if (parseRegs(Operands, RegKind) != MatchOperand_Success) - return MatchOperand_NoMatch; - if (getLexer().isNot(AsmToken::RParen)) - return MatchOperand_NoMatch; - Operands.push_back(MipsOperand::CreateToken(")", getLexer().getLoc())); - Parser.Lex(); - } +MipsAsmParser::MatchAnyRegisterWithoutDollar(OperandVector &Operands, SMLoc S) { + auto Token = Parser.getLexer().peekTok(false); + + if (Token.is(AsmToken::Identifier)) { + 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"); + Operands.push_back(MipsOperand::CreateNumericReg( + Token.getIntVal(), getContext().getRegisterInfo(), S, Token.getLoc(), + *this)); return MatchOperand_Success; } + + DEBUG(dbgs() << Parser.getTok().getKind() << "\n"); + return MatchOperand_NoMatch; } -bool MipsAsmParser::validateMSAIndex(int Val, int RegKind) { - MipsOperand::RegisterKind Kind = (MipsOperand::RegisterKind)RegKind; +MipsAsmParser::OperandMatchResultTy +MipsAsmParser::ParseAnyRegister(OperandVector &Operands) { + DEBUG(dbgs() << "ParseAnyRegister\n"); - if (Val < 0) - return false; + auto Token = Parser.getTok(); - switch (Kind) { - default: - return false; - case MipsOperand::Kind_MSA128BRegs: - return Val < 16; - case MipsOperand::Kind_MSA128HRegs: - return Val < 8; - case MipsOperand::Kind_MSA128WRegs: - return Val < 4; - case MipsOperand::Kind_MSA128DRegs: - return Val < 2; + SMLoc S = Token.getLoc(); + + if (Token.isNot(AsmToken::Dollar)) { + DEBUG(dbgs() << ".. !$ -> try sym aliasing\n"); + if (Token.is(AsmToken::Identifier)) { + if (searchSymbolAlias(Operands)) + return MatchOperand_Success; + } + DEBUG(dbgs() << ".. !symalias -> NoMatch\n"); + return MatchOperand_NoMatch; } + DEBUG(dbgs() << ".. $\n"); + + OperandMatchResultTy ResTy = MatchAnyRegisterWithoutDollar(Operands, S); + if (ResTy == MatchOperand_Success) { + Parser.Lex(); // $ + Parser.Lex(); // identifier + } + return ResTy; } MipsAsmParser::OperandMatchResultTy -MipsAsmParser::parseMSARegs(SmallVectorImpl &Operands, - int RegKind) { - MipsOperand::RegisterKind Kind = (MipsOperand::RegisterKind)RegKind; - SMLoc S = Parser.getTok().getLoc(); - std::string RegName; - - if (Parser.getTok().isNot(AsmToken::Dollar)) - return MatchOperand_NoMatch; - - switch (RegKind) { +MipsAsmParser::ParseImm(OperandVector &Operands) { + switch (getLexer().getKind()) { default: - return MatchOperand_ParseFail; - case MipsOperand::Kind_MSA128BRegs: - case MipsOperand::Kind_MSA128HRegs: - case MipsOperand::Kind_MSA128WRegs: - case MipsOperand::Kind_MSA128DRegs: + return MatchOperand_NoMatch; + case AsmToken::LParen: + case AsmToken::Minus: + case AsmToken::Plus: + case AsmToken::Integer: + case AsmToken::Tilde: + case AsmToken::String: break; } - Parser.Lex(); // Eat the '$'. - if (getLexer().getKind() == AsmToken::Identifier) - RegName = Parser.getTok().getString().lower(); - else - return MatchOperand_ParseFail; - - int RegNum = matchMSA128RegisterName(RegName); - - if (RegNum < 0 || RegNum > 31) - return MatchOperand_ParseFail; - - int RegVal = getReg(regKindToRegClass(Kind), RegNum); - if (RegVal == -1) + const MCExpr *IdVal; + SMLoc S = Parser.getTok().getLoc(); + if (getParser().parseExpression(IdVal)) return MatchOperand_ParseFail; - MipsOperand *Op = MipsOperand::CreateReg(RegVal, S, Parser.getTok().getLoc()); - Op->setRegKind(Kind); - Operands.push_back(Op); - - Parser.Lex(); // Eat the register identifier. - - // MSA registers may be suffixed with an index in the form of: - // 1) Immediate expression. - // 2) General Purpose Register. - // Examples: - // 1) copy_s.b $29,$w0[0] - // 2) sld.b $w0,$w1[$1] - - if (Parser.getTok().isNot(AsmToken::LBrac)) - return MatchOperand_Success; - - MipsOperand *Mnemonic = static_cast(Operands[0]); - - Operands.push_back(MipsOperand::CreateToken("[", Parser.getTok().getLoc())); - Parser.Lex(); // Parse the '[' token. - - if (Parser.getTok().is(AsmToken::Dollar)) { - // This must be a GPR. - MipsOperand *RegOp; - SMLoc VIdx = Parser.getTok().getLoc(); - Parser.Lex(); // Parse the '$' token. - - // GPR have aliases and we must account for that. Example: $30 == $fp - if (getLexer().getKind() == AsmToken::Integer) { - unsigned RegNum = Parser.getTok().getIntVal(); - int Reg = matchRegisterByNumber( - RegNum, regKindToRegClass(MipsOperand::Kind_GPR32)); - if (Reg == -1) { - Error(VIdx, "invalid general purpose register"); - return MatchOperand_ParseFail; - } - - RegOp = MipsOperand::CreateReg(Reg, VIdx, Parser.getTok().getLoc()); - } else if (getLexer().getKind() == AsmToken::Identifier) { - int RegNum = -1; - std::string RegName = Parser.getTok().getString().lower(); - - RegNum = matchCPURegisterName(RegName); - if (RegNum == -1) { - Error(VIdx, "general purpose register expected"); - return MatchOperand_ParseFail; - } - RegNum = getReg(regKindToRegClass(MipsOperand::Kind_GPR32), RegNum); - RegOp = MipsOperand::CreateReg(RegNum, VIdx, Parser.getTok().getLoc()); - } else - return MatchOperand_ParseFail; - - RegOp->setRegKind(MipsOperand::Kind_GPR32); - Operands.push_back(RegOp); - Parser.Lex(); // Eat the register identifier. - - if (Parser.getTok().isNot(AsmToken::RBrac)) - return MatchOperand_ParseFail; + SMLoc E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); + Operands.push_back(MipsOperand::CreateImm(IdVal, S, E, *this)); + return MatchOperand_Success; +} - Operands.push_back(MipsOperand::CreateToken("]", Parser.getTok().getLoc())); - Parser.Lex(); // Parse the ']' token. +MipsAsmParser::OperandMatchResultTy +MipsAsmParser::ParseJumpTarget(OperandVector &Operands) { + DEBUG(dbgs() << "ParseJumpTarget\n"); - return MatchOperand_Success; - } + SMLoc S = getLexer().getLoc(); - // The index must be a constant expression then. - SMLoc VIdx = Parser.getTok().getLoc(); - const MCExpr *ImmVal; + // Integers and expressions are acceptable + OperandMatchResultTy ResTy = ParseImm(Operands); + if (ResTy != MatchOperand_NoMatch) + return ResTy; - if (getParser().parseExpression(ImmVal)) - return MatchOperand_ParseFail; + // Registers are a valid target and have priority over symbols. + ResTy = ParseAnyRegister(Operands); + if (ResTy != MatchOperand_NoMatch) + return ResTy; - const MCConstantExpr *expr = dyn_cast(ImmVal); - if (!expr || !validateMSAIndex((int)expr->getValue(), Kind)) { - Error(VIdx, "invalid immediate value"); + const MCExpr *Expr = nullptr; + if (Parser.parseExpression(Expr)) { + // We have no way of knowing if a symbol was consumed so we must ParseFail return MatchOperand_ParseFail; } - - SMLoc E = Parser.getTok().getEndLoc(); - - if (Parser.getTok().isNot(AsmToken::RBrac)) - return MatchOperand_ParseFail; - - bool insve = - Mnemonic->getToken() == "insve.b" || Mnemonic->getToken() == "insve.h" || - Mnemonic->getToken() == "insve.w" || Mnemonic->getToken() == "insve.d"; - - // The second vector index of insve instructions is always 0. - if (insve && Operands.size() > 6) { - if (expr->getValue() != 0) { - Error(VIdx, "immediate value must be 0"); - return MatchOperand_ParseFail; - } - Operands.push_back(MipsOperand::CreateToken("0", VIdx)); - } else - Operands.push_back(MipsOperand::CreateImm(expr, VIdx, E)); - - Operands.push_back(MipsOperand::CreateToken("]", Parser.getTok().getLoc())); - - Parser.Lex(); // Parse the ']' token. - + Operands.push_back( + MipsOperand::CreateImm(Expr, S, getLexer().getLoc(), *this)); return MatchOperand_Success; } MipsAsmParser::OperandMatchResultTy -MipsAsmParser::parseMSACtrlRegs(SmallVectorImpl &Operands, - int RegKind) { - MipsOperand::RegisterKind Kind = (MipsOperand::RegisterKind)RegKind; - - if (Kind != MipsOperand::Kind_MSA128CtrlRegs) - return MatchOperand_NoMatch; - - if (Parser.getTok().isNot(AsmToken::Dollar)) - return MatchOperand_ParseFail; - - SMLoc S = Parser.getTok().getLoc(); - - Parser.Lex(); // Eat the '$' symbol. - - int RegNum = -1; - if (getLexer().getKind() == AsmToken::Identifier) - RegNum = matchMSA128CtrlRegisterName(Parser.getTok().getString().lower()); - else if (getLexer().getKind() == AsmToken::Integer) - RegNum = Parser.getTok().getIntVal(); - else - return MatchOperand_ParseFail; - - if (RegNum < 0 || RegNum > 7) - return MatchOperand_ParseFail; - - int RegVal = getReg(regKindToRegClass(Kind), RegNum); - if (RegVal == -1) - return MatchOperand_ParseFail; - - MipsOperand *RegOp = - MipsOperand::CreateReg(RegVal, S, Parser.getTok().getLoc()); - RegOp->setRegKind(MipsOperand::Kind_MSA128CtrlRegs); - Operands.push_back(RegOp); - Parser.Lex(); // Eat the register identifier. - - return MatchOperand_Success; -} - -MipsAsmParser::OperandMatchResultTy -MipsAsmParser::parseGPR64(SmallVectorImpl &Operands) { - - if (!isMips64()) - return MatchOperand_NoMatch; - return parseRegs(Operands, (int)MipsOperand::Kind_GPR64); -} - -MipsAsmParser::OperandMatchResultTy -MipsAsmParser::parseGPR32(SmallVectorImpl &Operands) { - return parseRegs(Operands, (int)MipsOperand::Kind_GPR32); -} - -MipsAsmParser::OperandMatchResultTy MipsAsmParser::parseAFGR64Regs( - SmallVectorImpl &Operands) { - - if (isFP64()) - return MatchOperand_NoMatch; - return parseRegs(Operands, (int)MipsOperand::Kind_AFGR64Regs); -} - -MipsAsmParser::OperandMatchResultTy -MipsAsmParser::parseFGR64Regs(SmallVectorImpl &Operands) { - if (!isFP64()) - return MatchOperand_NoMatch; - return parseRegs(Operands, (int)MipsOperand::Kind_FGR64Regs); -} - -MipsAsmParser::OperandMatchResultTy -MipsAsmParser::parseFGR32Regs(SmallVectorImpl &Operands) { - return parseRegs(Operands, (int)MipsOperand::Kind_FGR32Regs); -} - -MipsAsmParser::OperandMatchResultTy MipsAsmParser::parseFGRH32Regs( - SmallVectorImpl &Operands) { - return parseRegs(Operands, (int)MipsOperand::Kind_FGRH32Regs); -} - -MipsAsmParser::OperandMatchResultTy -MipsAsmParser::parseFCCRegs(SmallVectorImpl &Operands) { - return parseRegs(Operands, (int)MipsOperand::Kind_FCCRegs); -} - -MipsAsmParser::OperandMatchResultTy -MipsAsmParser::parseACC64DSP(SmallVectorImpl &Operands) { - return parseRegs(Operands, (int)MipsOperand::Kind_ACC64DSP); -} - -MipsAsmParser::OperandMatchResultTy -MipsAsmParser::parseLO32DSP(SmallVectorImpl &Operands) { - // If the first token is not '$' we have an error. - if (Parser.getTok().isNot(AsmToken::Dollar)) - return MatchOperand_NoMatch; - - SMLoc S = Parser.getTok().getLoc(); - Parser.Lex(); // Eat the '$' - - const AsmToken &Tok = Parser.getTok(); // Get next token. - - if (Tok.isNot(AsmToken::Identifier)) - return MatchOperand_NoMatch; - - if (!Tok.getIdentifier().startswith("ac")) - return MatchOperand_NoMatch; - - StringRef NumString = Tok.getIdentifier().substr(2); - - unsigned IntVal; - if (NumString.getAsInteger(10, IntVal)) - return MatchOperand_NoMatch; - - unsigned Reg = matchRegisterByNumber(IntVal, Mips::LO32DSPRegClassID); - - MipsOperand *Op = MipsOperand::CreateReg(Reg, S, Parser.getTok().getLoc()); - Op->setRegKind(MipsOperand::Kind_LO32DSP); - Operands.push_back(Op); - - Parser.Lex(); // Eat the register number. - return MatchOperand_Success; -} - -MipsAsmParser::OperandMatchResultTy -MipsAsmParser::parseHI32DSP(SmallVectorImpl &Operands) { - // If the first token is not '$' we have an error. - if (Parser.getTok().isNot(AsmToken::Dollar)) - return MatchOperand_NoMatch; - - SMLoc S = Parser.getTok().getLoc(); - Parser.Lex(); // Eat the '$' - - const AsmToken &Tok = Parser.getTok(); // Get next token. - - if (Tok.isNot(AsmToken::Identifier)) - return MatchOperand_NoMatch; - - if (!Tok.getIdentifier().startswith("ac")) - return MatchOperand_NoMatch; - - StringRef NumString = Tok.getIdentifier().substr(2); - - unsigned IntVal; - if (NumString.getAsInteger(10, IntVal)) - return MatchOperand_NoMatch; - - unsigned Reg = matchRegisterByNumber(IntVal, Mips::HI32DSPRegClassID); - - MipsOperand *Op = MipsOperand::CreateReg(Reg, S, Parser.getTok().getLoc()); - Op->setRegKind(MipsOperand::Kind_HI32DSP); - Operands.push_back(Op); - - Parser.Lex(); // Eat the register number. - return MatchOperand_Success; -} - -MipsAsmParser::OperandMatchResultTy -MipsAsmParser::parseCOP2(SmallVectorImpl &Operands) { - // If the first token is not '$' we have an error. - if (Parser.getTok().isNot(AsmToken::Dollar)) - return MatchOperand_NoMatch; - - SMLoc S = Parser.getTok().getLoc(); - Parser.Lex(); // Eat the '$' - - const AsmToken &Tok = Parser.getTok(); // Get next token. - - if (Tok.isNot(AsmToken::Integer)) - return MatchOperand_NoMatch; - - unsigned IntVal = Tok.getIntVal(); - - unsigned Reg = matchRegisterByNumber(IntVal, Mips::COP2RegClassID); - - MipsOperand *Op = MipsOperand::CreateReg(Reg, S, Parser.getTok().getLoc()); - Op->setRegKind(MipsOperand::Kind_COP2); - Operands.push_back(Op); - - Parser.Lex(); // Eat the register number. - return MatchOperand_Success; -} - -MipsAsmParser::OperandMatchResultTy MipsAsmParser::parseMSA128BRegs( - SmallVectorImpl &Operands) { - return parseMSARegs(Operands, (int)MipsOperand::Kind_MSA128BRegs); -} - -MipsAsmParser::OperandMatchResultTy MipsAsmParser::parseMSA128HRegs( - SmallVectorImpl &Operands) { - return parseMSARegs(Operands, (int)MipsOperand::Kind_MSA128HRegs); -} - -MipsAsmParser::OperandMatchResultTy MipsAsmParser::parseMSA128WRegs( - SmallVectorImpl &Operands) { - return parseMSARegs(Operands, (int)MipsOperand::Kind_MSA128WRegs); -} - -MipsAsmParser::OperandMatchResultTy MipsAsmParser::parseMSA128DRegs( - SmallVectorImpl &Operands) { - return parseMSARegs(Operands, (int)MipsOperand::Kind_MSA128DRegs); -} - -MipsAsmParser::OperandMatchResultTy MipsAsmParser::parseMSA128CtrlRegs( - SmallVectorImpl &Operands) { - return parseMSACtrlRegs(Operands, (int)MipsOperand::Kind_MSA128CtrlRegs); -} - -bool MipsAsmParser::searchSymbolAlias( - SmallVectorImpl &Operands, unsigned RegKind) { - - 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 (Expr->getKind() == MCExpr::SymbolRef) { - MipsOperand::RegisterKind Kind = (MipsOperand::RegisterKind)RegKind; - const MCSymbolRefExpr *Ref = static_cast(Expr); - const StringRef DefSymbol = Ref->getSymbol().getName(); - if (DefSymbol.startswith("$")) { - int RegNum = -1; - APInt IntVal(32, -1); - if (!DefSymbol.substr(1).getAsInteger(10, IntVal)) - RegNum = matchRegisterByNumber(IntVal.getZExtValue(), - isMips64() ? Mips::GPR64RegClassID - : Mips::GPR32RegClassID); - else { - // Lookup for the register with the corresponding name. - switch (Kind) { - case MipsOperand::Kind_AFGR64Regs: - case MipsOperand::Kind_FGR64Regs: - RegNum = matchFPURegisterName(DefSymbol.substr(1)); - break; - case MipsOperand::Kind_FGR32Regs: - RegNum = matchFPURegisterName(DefSymbol.substr(1)); - break; - case MipsOperand::Kind_GPR64: - case MipsOperand::Kind_GPR32: - default: - RegNum = matchCPURegisterName(DefSymbol.substr(1)); - break; - } - if (RegNum > -1) - RegNum = getReg(regKindToRegClass(Kind), RegNum); - } - if (RegNum > -1) { - Parser.Lex(); - MipsOperand *op = - MipsOperand::CreateReg(RegNum, S, Parser.getTok().getLoc()); - op->setRegKind(Kind); - Operands.push_back(op); - return true; - } - } - } else if (Expr->getKind() == MCExpr::Constant) { - Parser.Lex(); - const MCConstantExpr *Const = static_cast(Expr); - MipsOperand *op = - MipsOperand::CreateImm(Const, S, Parser.getTok().getLoc()); - Operands.push_back(op); - return true; - } - } - return false; -} - -MipsAsmParser::OperandMatchResultTy -MipsAsmParser::parseHWRegs(SmallVectorImpl &Operands) { - return parseRegs(Operands, (int)MipsOperand::Kind_HWRegs); -} - -MipsAsmParser::OperandMatchResultTy -MipsAsmParser::parseCCRRegs(SmallVectorImpl &Operands) { - return parseRegs(Operands, (int)MipsOperand::Kind_CCRRegs); -} - -MipsAsmParser::OperandMatchResultTy -MipsAsmParser::parseInvNum(SmallVectorImpl &Operands) { +MipsAsmParser::parseInvNum(OperandVector &Operands) { const MCExpr *IdVal; // If the first token is '$' we may have register operand. if (Parser.getTok().is(AsmToken::Dollar)) @@ -2112,12 +2266,12 @@ MipsAsmParser::parseInvNum(SmallVectorImpl &Operands) { int64_t Val = MCE->getValue(); SMLoc E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); Operands.push_back(MipsOperand::CreateImm( - MCConstantExpr::Create(0 - Val, getContext()), S, E)); + MCConstantExpr::Create(0 - Val, getContext()), S, E, *this)); return MatchOperand_Success; } MipsAsmParser::OperandMatchResultTy -MipsAsmParser::parseLSAImm(SmallVectorImpl &Operands) { +MipsAsmParser::ParseLSAImm(OperandVector &Operands) { switch (getLexer().getKind()) { default: return MatchOperand_NoMatch; @@ -2150,8 +2304,8 @@ MipsAsmParser::parseLSAImm(SmallVectorImpl &Operands) { return MatchOperand_ParseFail; } - Operands.push_back(MipsOperand::CreateLSAImm(Expr, S, - Parser.getTok().getLoc())); + Operands.push_back( + MipsOperand::CreateImm(Expr, S, Parser.getTok().getLoc(), *this)); return MatchOperand_Success; } @@ -2176,21 +2330,91 @@ MCSymbolRefExpr::VariantKind MipsAsmParser::getVariantKind(StringRef Symbol) { .Case("got_ofst", MCSymbolRefExpr::VK_Mips_GOT_OFST) .Case("hi(%neg(%gp_rel", MCSymbolRefExpr::VK_Mips_GPOFF_HI) .Case("lo(%neg(%gp_rel", MCSymbolRefExpr::VK_Mips_GPOFF_LO) + .Case("got_hi", MCSymbolRefExpr::VK_Mips_GOT_HI16) + .Case("got_lo", MCSymbolRefExpr::VK_Mips_GOT_LO16) + .Case("call_hi", MCSymbolRefExpr::VK_Mips_CALL_HI16) + .Case("call_lo", MCSymbolRefExpr::VK_Mips_CALL_LO16) + .Case("higher", MCSymbolRefExpr::VK_Mips_HIGHER) + .Case("highest", MCSymbolRefExpr::VK_Mips_HIGHEST) + .Case("pcrel_hi", MCSymbolRefExpr::VK_Mips_PCREL_HI16) + .Case("pcrel_lo", MCSymbolRefExpr::VK_Mips_PCREL_LO16) .Default(MCSymbolRefExpr::VK_None); + assert(VK != MCSymbolRefExpr::VK_None); + return VK; } -bool MipsAsmParser::ParseInstruction( - ParseInstructionInfo &Info, StringRef Name, SMLoc NameLoc, - SmallVectorImpl &Operands) { +/// Sometimes (i.e. load/stores) the operand may be followed immediately by +/// either this. +/// ::= '(', register, ')' +/// handle it before we iterate so we don't get tripped up by the lack of +/// a comma. +bool MipsAsmParser::ParseParenSuffix(StringRef Name, OperandVector &Operands) { + if (getLexer().is(AsmToken::LParen)) { + Operands.push_back( + MipsOperand::CreateToken("(", getLexer().getLoc(), *this)); + 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( + MipsOperand::CreateToken(")", getLexer().getLoc(), *this)); + Parser.Lex(); + } + return false; +} + +/// Sometimes (i.e. in MSA) the operand may be followed immediately by +/// either one of these. +/// ::= '[', register, ']' +/// ::= '[', integer, ']' +/// handle it before we iterate so we don't get tripped up by the lack of +/// a comma. +bool MipsAsmParser::ParseBracketSuffix(StringRef Name, + OperandVector &Operands) { + if (getLexer().is(AsmToken::LBrac)) { + Operands.push_back( + MipsOperand::CreateToken("[", getLexer().getLoc(), *this)); + 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( + MipsOperand::CreateToken("]", getLexer().getLoc(), *this)); + Parser.Lex(); + } + return false; +} + +bool MipsAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name, + SMLoc NameLoc, OperandVector &Operands) { + DEBUG(dbgs() << "ParseInstruction\n"); + + // We have reached first instruction, module directive are now forbidden. + getTargetStreamer().forbidModuleDirective(); + // Check if we have valid mnemonic if (!mnemonicIsValid(Name, 0)) { Parser.eatToEndOfStatement(); return Error(NameLoc, "Unknown instruction"); } // First operand in MCInst is instruction mnemonic. - Operands.push_back(MipsOperand::CreateToken(Name, NameLoc)); + Operands.push_back(MipsOperand::CreateToken(Name, NameLoc, *this)); // Read the remaining operands. if (getLexer().isNot(AsmToken::EndOfStatement)) { @@ -2200,6 +2424,9 @@ bool MipsAsmParser::ParseInstruction( Parser.eatToEndOfStatement(); return Error(Loc, "unexpected token in argument list"); } + if (getLexer().is(AsmToken::LBrac) && ParseBracketSuffix(Name, Operands)) + return true; + // AFAIK, parenthesis suffixes are never on the first operand while (getLexer().is(AsmToken::Comma)) { Parser.Lex(); // Eat the comma. @@ -2209,6 +2436,13 @@ bool MipsAsmParser::ParseInstruction( Parser.eatToEndOfStatement(); return Error(Loc, "unexpected token in argument list"); } + // Parse bracket and parenthesis suffixes before we iterate + if (getLexer().is(AsmToken::LBrac)) { + if (ParseBracketSuffix(Name, Operands)) + return true; + } else if (getLexer().is(AsmToken::LParen) && + ParseParenSuffix(Name, Operands)) + return true; } } if (getLexer().isNot(AsmToken::EndOfStatement)) { @@ -2220,12 +2454,16 @@ bool MipsAsmParser::ParseInstruction( return false; } -bool MipsAsmParser::reportParseError(StringRef ErrorMsg) { +bool MipsAsmParser::reportParseError(Twine ErrorMsg) { SMLoc Loc = getLexer().getLoc(); Parser.eatToEndOfStatement(); return Error(Loc, ErrorMsg); } +bool MipsAsmParser::reportParseError(SMLoc Loc, Twine ErrorMsg) { + return Error(Loc, ErrorMsg); +} + bool MipsAsmParser::parseSetNoAtDirective() { // Line should look like: ".set noat". // set at reg to 0. @@ -2267,7 +2505,7 @@ bool MipsAsmParser::parseSetAtDirective() { return false; } - if (AtRegNo < 1 || AtRegNo > 31) { + if (AtRegNo < 0 || AtRegNo > 31) { reportParseError("unexpected token in statement"); return false; } @@ -2298,6 +2536,7 @@ bool MipsAsmParser::parseSetReorderDirective() { return false; } Options.setReorder(); + getTargetStreamer().emitDirectiveSetReorder(); Parser.Lex(); // Consume the EndOfStatement. return false; } @@ -2310,6 +2549,7 @@ bool MipsAsmParser::parseSetNoReorderDirective() { return false; } Options.setNoreorder(); + getTargetStreamer().emitDirectiveSetNoReorder(); Parser.Lex(); // Consume the EndOfStatement. return false; } @@ -2342,6 +2582,68 @@ bool MipsAsmParser::parseSetNoMacroDirective() { return false; } +bool MipsAsmParser::parseSetMsaDirective() { + Parser.Lex(); + + // If this is not the end of the statement, report an error. + if (getLexer().isNot(AsmToken::EndOfStatement)) + return reportParseError("unexpected token in statement"); + + setFeatureBits(Mips::FeatureMSA, "msa"); + getTargetStreamer().emitDirectiveSetMsa(); + return false; +} + +bool MipsAsmParser::parseSetNoMsaDirective() { + Parser.Lex(); + + // If this is not the end of the statement, report an error. + if (getLexer().isNot(AsmToken::EndOfStatement)) + return reportParseError("unexpected token in statement"); + + clearFeatureBits(Mips::FeatureMSA, "msa"); + getTargetStreamer().emitDirectiveSetNoMsa(); + return false; +} + +bool MipsAsmParser::parseSetNoMips16Directive() { + Parser.Lex(); + // If this is not the end of the statement, report an error. + if (getLexer().isNot(AsmToken::EndOfStatement)) { + reportParseError("unexpected token in statement"); + return false; + } + // For now do nothing. + Parser.Lex(); // Consume the EndOfStatement. + return false; +} + +bool MipsAsmParser::parseSetFpDirective() { + MipsABIFlagsSection::FpABIKind FpAbiVal; + // Line can be: .set fp=32 + // .set fp=xx + // .set fp=64 + Parser.Lex(); // Eat fp token + AsmToken Tok = Parser.getTok(); + if (Tok.isNot(AsmToken::Equal)) { + reportParseError("unexpected token in statement"); + return false; + } + Parser.Lex(); // Eat '=' token. + Tok = Parser.getTok(); + + if (!parseFpABIValue(FpAbiVal, ".set")) + return false; + + if (getLexer().isNot(AsmToken::EndOfStatement)) { + reportParseError("unexpected token in statement"); + return false; + } + getTargetStreamer().emitDirectiveSetFp(FpAbiVal); + Parser.Lex(); // Consume the EndOfStatement. + return false; +} + bool MipsAsmParser::parseSetAssignment() { StringRef Name; const MCExpr *Value; @@ -2353,7 +2655,7 @@ bool MipsAsmParser::parseSetAssignment() { return reportParseError("unexpected token in .set directive"); Lex(); // Eat comma - if (Parser.parseExpression(Value)) + if (Parser.parseExpression(Value)) return reportParseError("expected valid expression after comma"); // Check if the Name already exists as a symbol. @@ -2366,71 +2668,292 @@ bool MipsAsmParser::parseSetAssignment() { return false; } -bool MipsAsmParser::parseDirectiveSet() { - - // Get the next token. - const AsmToken &Tok = Parser.getTok(); - - if (Tok.getString() == "noat") { - return parseSetNoAtDirective(); - } else if (Tok.getString() == "at") { - return parseSetAtDirective(); - } else if (Tok.getString() == "reorder") { - return parseSetReorderDirective(); - } else if (Tok.getString() == "noreorder") { - return parseSetNoReorderDirective(); - } else if (Tok.getString() == "macro") { - return parseSetMacroDirective(); - } else if (Tok.getString() == "nomacro") { - return parseSetNoMacroDirective(); - } else if (Tok.getString() == "nomips16") { - // Ignore this directive for now. - Parser.eatToEndOfStatement(); - return false; - } else if (Tok.getString() == "nomicromips") { - // Ignore this directive for now. - Parser.eatToEndOfStatement(); - return false; - } else { - // It is just an identifier, look for an assignment. - parseSetAssignment(); - return false; - } +bool MipsAsmParser::parseSetArchDirective() { + Parser.Lex(); + if (getLexer().isNot(AsmToken::Equal)) + return reportParseError("unexpected token, expected equals sign"); - return true; + Parser.Lex(); + StringRef Arch; + if (Parser.parseIdentifier(Arch)) + return reportParseError("expected arch identifier"); + + StringRef ArchFeatureName = + StringSwitch(Arch) + .Case("mips1", "mips1") + .Case("mips2", "mips2") + .Case("mips3", "mips3") + .Case("mips4", "mips4") + .Case("mips5", "mips5") + .Case("mips32", "mips32") + .Case("mips32r2", "mips32r2") + .Case("mips32r6", "mips32r6") + .Case("mips64", "mips64") + .Case("mips64r2", "mips64r2") + .Case("mips64r6", "mips64r6") + .Case("cnmips", "cnmips") + .Case("r4000", "mips3") // This is an implementation of Mips3. + .Default(""); + + if (ArchFeatureName.empty()) + return reportParseError("unsupported architecture"); + + selectArch(ArchFeatureName); + getTargetStreamer().emitDirectiveSetArch(Arch); + return false; } -bool MipsAsmParser::parseDirectiveMipsHackStocg() { - MCAsmParser &Parser = getParser(); - StringRef Name; - if (Parser.parseIdentifier(Name)) - reportParseError("expected identifier"); +bool MipsAsmParser::parseSetFeature(uint64_t Feature) { + Parser.Lex(); + if (getLexer().isNot(AsmToken::EndOfStatement)) + return reportParseError("unexpected token in .set directive"); - MCSymbol *Sym = getContext().GetOrCreateSymbol(Name); - if (getLexer().isNot(AsmToken::Comma)) - return TokError("unexpected token"); - Lex(); + switch (Feature) { + default: + llvm_unreachable("Unimplemented feature"); + case Mips::FeatureDSP: + setFeatureBits(Mips::FeatureDSP, "dsp"); + getTargetStreamer().emitDirectiveSetDsp(); + break; + case Mips::FeatureMicroMips: + getTargetStreamer().emitDirectiveSetMicroMips(); + break; + case Mips::FeatureMips16: + getTargetStreamer().emitDirectiveSetMips16(); + break; + case Mips::FeatureMips1: + selectArch("mips1"); + getTargetStreamer().emitDirectiveSetMips1(); + break; + case Mips::FeatureMips2: + selectArch("mips2"); + getTargetStreamer().emitDirectiveSetMips2(); + break; + case Mips::FeatureMips3: + selectArch("mips3"); + getTargetStreamer().emitDirectiveSetMips3(); + break; + case Mips::FeatureMips4: + selectArch("mips4"); + getTargetStreamer().emitDirectiveSetMips4(); + break; + case Mips::FeatureMips5: + selectArch("mips5"); + getTargetStreamer().emitDirectiveSetMips5(); + break; + case Mips::FeatureMips32: + selectArch("mips32"); + getTargetStreamer().emitDirectiveSetMips32(); + break; + case Mips::FeatureMips32r2: + selectArch("mips32r2"); + getTargetStreamer().emitDirectiveSetMips32R2(); + break; + case Mips::FeatureMips32r6: + selectArch("mips32r6"); + getTargetStreamer().emitDirectiveSetMips32R6(); + break; + case Mips::FeatureMips64: + selectArch("mips64"); + getTargetStreamer().emitDirectiveSetMips64(); + break; + case Mips::FeatureMips64r2: + selectArch("mips64r2"); + getTargetStreamer().emitDirectiveSetMips64R2(); + break; + case Mips::FeatureMips64r6: + selectArch("mips64r6"); + getTargetStreamer().emitDirectiveSetMips64R6(); + break; + } + return false; +} - int64_t Flags = 0; - if (Parser.parseAbsoluteExpression(Flags)) - return TokError("unexpected token"); +bool MipsAsmParser::eatComma(StringRef ErrorStr) { + if (getLexer().isNot(AsmToken::Comma)) { + SMLoc Loc = getLexer().getLoc(); + Parser.eatToEndOfStatement(); + return Error(Loc, ErrorStr); + } + + Parser.Lex(); // Eat the comma. + return true; +} + +bool MipsAsmParser::parseDirectiveCPLoad(SMLoc Loc) { + if (Options.isReorder()) + Warning(Loc, ".cpload in reorder section"); + + // FIXME: Warn if cpload is used in Mips16 mode. + + SmallVector, 1> Reg; + OperandMatchResultTy ResTy = ParseAnyRegister(Reg); + if (ResTy == MatchOperand_NoMatch || ResTy == MatchOperand_ParseFail) { + reportParseError("expected register containing function address"); + return false; + } + + MipsOperand &RegOpnd = static_cast(*Reg[0]); + if (!RegOpnd.isGPRAsmReg()) { + reportParseError(RegOpnd.getStartLoc(), "invalid register"); + return false; + } - getTargetStreamer().emitMipsHackSTOCG(Sym, Flags); + getTargetStreamer().emitDirectiveCpload(RegOpnd.getGPR32Reg()); return false; } -bool MipsAsmParser::parseDirectiveMipsHackELFFlags() { - int64_t Flags = 0; - if (Parser.parseAbsoluteExpression(Flags)) - return TokError("unexpected token"); +bool MipsAsmParser::parseDirectiveCPSetup() { + unsigned FuncReg; + unsigned Save; + bool SaveIsReg = true; - getTargetStreamer().emitMipsHackELFFlags(Flags); + SmallVector, 1> TmpReg; + OperandMatchResultTy ResTy = ParseAnyRegister(TmpReg); + if (ResTy == MatchOperand_NoMatch) { + reportParseError("expected register containing function address"); + Parser.eatToEndOfStatement(); + return false; + } + + MipsOperand &FuncRegOpnd = static_cast(*TmpReg[0]); + if (!FuncRegOpnd.isGPRAsmReg()) { + reportParseError(FuncRegOpnd.getStartLoc(), "invalid register"); + Parser.eatToEndOfStatement(); + return false; + } + + FuncReg = FuncRegOpnd.getGPR32Reg(); + TmpReg.clear(); + + if (!eatComma("expected comma parsing directive")) + return true; + + ResTy = ParseAnyRegister(TmpReg); + if (ResTy == MatchOperand_NoMatch) { + const AsmToken &Tok = Parser.getTok(); + if (Tok.is(AsmToken::Integer)) { + Save = Tok.getIntVal(); + SaveIsReg = false; + Parser.Lex(); + } else { + reportParseError("expected save register or stack offset"); + Parser.eatToEndOfStatement(); + return false; + } + } else { + MipsOperand &SaveOpnd = static_cast(*TmpReg[0]); + if (!SaveOpnd.isGPRAsmReg()) { + reportParseError(SaveOpnd.getStartLoc(), "invalid register"); + Parser.eatToEndOfStatement(); + return false; + } + Save = SaveOpnd.getGPR32Reg(); + } + + if (!eatComma("expected comma parsing directive")) + return true; + + StringRef Name; + if (Parser.parseIdentifier(Name)) + reportParseError("expected identifier"); + MCSymbol *Sym = getContext().GetOrCreateSymbol(Name); + + getTargetStreamer().emitDirectiveCpsetup(FuncReg, Save, *Sym, SaveIsReg); return false; } -/// parseDirectiveWord +bool MipsAsmParser::parseDirectiveNaN() { + if (getLexer().isNot(AsmToken::EndOfStatement)) { + const AsmToken &Tok = Parser.getTok(); + + if (Tok.getString() == "2008") { + Parser.Lex(); + getTargetStreamer().emitDirectiveNaN2008(); + return false; + } else if (Tok.getString() == "legacy") { + Parser.Lex(); + getTargetStreamer().emitDirectiveNaNLegacy(); + return false; + } + } + // If we don't recognize the option passed to the .nan + // directive (e.g. no option or unknown option), emit an error. + reportParseError("invalid option in .nan directive"); + return false; +} + +bool MipsAsmParser::parseDirectiveSet() { + + // Get the next token. + const AsmToken &Tok = Parser.getTok(); + + if (Tok.getString() == "noat") { + return parseSetNoAtDirective(); + } else if (Tok.getString() == "at") { + return parseSetAtDirective(); + } else if (Tok.getString() == "arch") { + return parseSetArchDirective(); + } else if (Tok.getString() == "fp") { + return parseSetFpDirective(); + } else if (Tok.getString() == "reorder") { + return parseSetReorderDirective(); + } else if (Tok.getString() == "noreorder") { + return parseSetNoReorderDirective(); + } else if (Tok.getString() == "macro") { + return parseSetMacroDirective(); + } else if (Tok.getString() == "nomacro") { + return parseSetNoMacroDirective(); + } else if (Tok.getString() == "mips16") { + return parseSetFeature(Mips::FeatureMips16); + } else if (Tok.getString() == "nomips16") { + return parseSetNoMips16Directive(); + } else if (Tok.getString() == "nomicromips") { + getTargetStreamer().emitDirectiveSetNoMicroMips(); + Parser.eatToEndOfStatement(); + return false; + } else if (Tok.getString() == "micromips") { + return parseSetFeature(Mips::FeatureMicroMips); + } else if (Tok.getString() == "mips1") { + return parseSetFeature(Mips::FeatureMips1); + } else if (Tok.getString() == "mips2") { + return parseSetFeature(Mips::FeatureMips2); + } else if (Tok.getString() == "mips3") { + return parseSetFeature(Mips::FeatureMips3); + } else if (Tok.getString() == "mips4") { + return parseSetFeature(Mips::FeatureMips4); + } else if (Tok.getString() == "mips5") { + return parseSetFeature(Mips::FeatureMips5); + } else if (Tok.getString() == "mips32") { + return parseSetFeature(Mips::FeatureMips32); + } else if (Tok.getString() == "mips32r2") { + return parseSetFeature(Mips::FeatureMips32r2); + } else if (Tok.getString() == "mips32r6") { + return parseSetFeature(Mips::FeatureMips32r6); + } else if (Tok.getString() == "mips64") { + return parseSetFeature(Mips::FeatureMips64); + } else if (Tok.getString() == "mips64r2") { + return parseSetFeature(Mips::FeatureMips64r2); + } else if (Tok.getString() == "mips64r6") { + return parseSetFeature(Mips::FeatureMips64r6); + } else if (Tok.getString() == "dsp") { + return parseSetFeature(Mips::FeatureDSP); + } else if (Tok.getString() == "msa") { + return parseSetMsaDirective(); + } else if (Tok.getString() == "nomsa") { + return parseSetNoMsaDirective(); + } else { + // It is just an identifier, look for an assignment. + parseSetAssignment(); + return false; + } + + return true; +} + +/// parseDataDirective /// ::= .word [ expression (, expression)* ] -bool MipsAsmParser::parseDirectiveWord(unsigned Size, SMLoc L) { +bool MipsAsmParser::parseDataDirective(unsigned Size, SMLoc L) { if (getLexer().isNot(AsmToken::EndOfStatement)) { for (;;) { const MCExpr *Value; @@ -2469,6 +2992,22 @@ bool MipsAsmParser::parseDirectiveGpWord() { return false; } +/// parseDirectiveGpDWord +/// ::= .gpdword local_sym +bool MipsAsmParser::parseDirectiveGpDWord() { + const MCExpr *Value; + // EmitGPRel64Value requires an expression, so we are using base class + // method to evaluate the expression. + if (getParser().parseExpression(Value)) + return true; + getParser().getStreamer().EmitGPRel64Value(Value); + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return Error(getLexer().getLoc(), "unexpected token in directive"); + Parser.Lex(); // Eat EndOfStatement token. + return false; +} + bool MipsAsmParser::parseDirectiveOption() { // Get the option token. AsmToken Tok = Parser.getTok(); @@ -2492,31 +3031,305 @@ bool MipsAsmParser::parseDirectiveOption() { return false; } + if (Option == "pic2") { + getTargetStreamer().emitDirectiveOptionPic2(); + Parser.Lex(); + if (Parser.getTok().isNot(AsmToken::EndOfStatement)) { + Error(Parser.getTok().getLoc(), + "unexpected token in .option pic2 directive"); + Parser.eatToEndOfStatement(); + } + return false; + } + // Unknown option. Warning(Parser.getTok().getLoc(), "unknown option in .option directive"); Parser.eatToEndOfStatement(); return false; } -bool MipsAsmParser::ParseDirective(AsmToken DirectiveID) { +/// parseDirectiveModule +/// ::= .module oddspreg +/// ::= .module nooddspreg +/// ::= .module fp=value +bool MipsAsmParser::parseDirectiveModule() { + MCAsmLexer &Lexer = getLexer(); + SMLoc L = Lexer.getLoc(); + + if (!getTargetStreamer().isModuleDirectiveAllowed()) { + // TODO : get a better message. + reportParseError(".module directive must appear before any code"); + return false; + } + + if (Lexer.is(AsmToken::Identifier)) { + StringRef Option = Parser.getTok().getString(); + Parser.Lex(); + + if (Option == "oddspreg") { + getTargetStreamer().emitDirectiveModuleOddSPReg(true, isABI_O32()); + clearFeatureBits(Mips::FeatureNoOddSPReg, "nooddspreg"); + + if (getLexer().isNot(AsmToken::EndOfStatement)) { + reportParseError("Expected end of statement"); + return false; + } + + return false; + } else if (Option == "nooddspreg") { + if (!isABI_O32()) { + Error(L, "'.module nooddspreg' requires the O32 ABI"); + return false; + } + + getTargetStreamer().emitDirectiveModuleOddSPReg(false, isABI_O32()); + setFeatureBits(Mips::FeatureNoOddSPReg, "nooddspreg"); + + if (getLexer().isNot(AsmToken::EndOfStatement)) { + reportParseError("Expected end of statement"); + return false; + } + + return false; + } else if (Option == "fp") { + return parseDirectiveModuleFP(); + } + + return Error(L, "'" + Twine(Option) + "' is not a valid .module option."); + } + + return false; +} + +/// parseDirectiveModuleFP +/// ::= =32 +/// ::= =xx +/// ::= =64 +bool MipsAsmParser::parseDirectiveModuleFP() { + MCAsmLexer &Lexer = getLexer(); + + if (Lexer.isNot(AsmToken::Equal)) { + reportParseError("unexpected token in statement"); + return false; + } + Parser.Lex(); // Eat '=' token. + + MipsABIFlagsSection::FpABIKind FpABI; + if (!parseFpABIValue(FpABI, ".module")) + return false; + + if (getLexer().isNot(AsmToken::EndOfStatement)) { + reportParseError("unexpected token in statement"); + return false; + } + + // Emit appropriate flags. + getTargetStreamer().emitDirectiveModuleFP(FpABI, isABI_O32()); + Parser.Lex(); // Consume the EndOfStatement. + return false; +} + +bool MipsAsmParser::parseFpABIValue(MipsABIFlagsSection::FpABIKind &FpABI, + StringRef Directive) { + MCAsmLexer &Lexer = getLexer(); + + if (Lexer.is(AsmToken::Identifier)) { + StringRef Value = Parser.getTok().getString(); + Parser.Lex(); + + if (Value != "xx") { + reportParseError("unsupported value, expected 'xx', '32' or '64'"); + return false; + } + + if (!isABI_O32()) { + reportParseError("'" + Directive + " fp=xx' requires the O32 ABI"); + return false; + } + + FpABI = MipsABIFlagsSection::FpABIKind::XX; + return true; + } + + if (Lexer.is(AsmToken::Integer)) { + unsigned Value = Parser.getTok().getIntVal(); + Parser.Lex(); + + if (Value != 32 && Value != 64) { + reportParseError("unsupported value, expected 'xx', '32' or '64'"); + return false; + } + + if (Value == 32) { + if (!isABI_O32()) { + reportParseError("'" + Directive + " fp=32' requires the O32 ABI"); + return false; + } + FpABI = MipsABIFlagsSection::FpABIKind::S32; + } else + FpABI = MipsABIFlagsSection::FpABIKind::S64; + + return true; + } + + return false; +} + +bool MipsAsmParser::ParseDirective(AsmToken DirectiveID) { StringRef IDVal = DirectiveID.getString(); + if (IDVal == ".cpload") + return parseDirectiveCPLoad(DirectiveID.getLoc()); + if (IDVal == ".dword") { + parseDataDirective(8, DirectiveID.getLoc()); + return false; + } if (IDVal == ".ent") { - // Ignore this directive for now. - Parser.Lex(); + StringRef SymbolName; + + if (Parser.parseIdentifier(SymbolName)) { + reportParseError("expected identifier after .ent"); + return false; + } + + // There's an undocumented extension that allows an integer to + // follow the name of the procedure which AFAICS is ignored by GAS. + // Example: .ent foo,2 + if (getLexer().isNot(AsmToken::EndOfStatement)) { + if (getLexer().isNot(AsmToken::Comma)) { + // Even though we accept this undocumented extension for compatibility + // reasons, the additional integer argument does not actually change + // the behaviour of the '.ent' directive, so we would like to discourage + // its use. We do this by not referring to the extended version in + // error messages which are not directly related to its use. + reportParseError("unexpected token, expected end of statement"); + return false; + } + Parser.Lex(); // Eat the comma. + const MCExpr *DummyNumber; + int64_t DummyNumberVal; + // If the user was explicitly trying to use the extended version, + // we still give helpful extension-related error messages. + if (Parser.parseExpression(DummyNumber)) { + reportParseError("expected number after comma"); + return false; + } + if (!DummyNumber->EvaluateAsAbsolute(DummyNumberVal)) { + reportParseError("expected an absolute expression after comma"); + return false; + } + } + + // 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; + } + + MCSymbol *Sym = getContext().GetOrCreateSymbol(SymbolName); + + getTargetStreamer().emitDirectiveEnt(*Sym); + CurrentFn = Sym; return false; } if (IDVal == ".end") { - // Ignore this directive for now. - Parser.Lex(); + StringRef SymbolName; + + if (Parser.parseIdentifier(SymbolName)) { + reportParseError("expected identifier after .end"); + return false; + } + + if (getLexer().isNot(AsmToken::EndOfStatement)) { + reportParseError("unexpected token, expected end of statement"); + return false; + } + + if (CurrentFn == nullptr) { + reportParseError(".end used without .ent"); + return false; + } + + if ((SymbolName != CurrentFn->getName())) { + reportParseError(".end symbol does not match .ent symbol"); + return false; + } + + getTargetStreamer().emitDirectiveEnd(SymbolName); + CurrentFn = nullptr; return false; } if (IDVal == ".frame") { - // Ignore this directive for now. - Parser.eatToEndOfStatement(); + // .frame $stack_reg, frame_size_in_bytes, $return_reg + SmallVector, 1> TmpReg; + OperandMatchResultTy ResTy = ParseAnyRegister(TmpReg); + if (ResTy == MatchOperand_NoMatch || ResTy == MatchOperand_ParseFail) { + reportParseError("expected stack register"); + return false; + } + + MipsOperand &StackRegOpnd = static_cast(*TmpReg[0]); + if (!StackRegOpnd.isGPRAsmReg()) { + reportParseError(StackRegOpnd.getStartLoc(), + "expected general purpose register"); + return false; + } + unsigned StackReg = StackRegOpnd.getGPR32Reg(); + + if (Parser.getTok().is(AsmToken::Comma)) + Parser.Lex(); + else { + reportParseError("unexpected token, expected comma"); + return false; + } + + // Parse the frame size. + const MCExpr *FrameSize; + int64_t FrameSizeVal; + + if (Parser.parseExpression(FrameSize)) { + reportParseError("expected frame size value"); + return false; + } + + if (!FrameSize->EvaluateAsAbsolute(FrameSizeVal)) { + reportParseError("frame size not an absolute expression"); + return false; + } + + if (Parser.getTok().is(AsmToken::Comma)) + Parser.Lex(); + else { + reportParseError("unexpected token, expected comma"); + return false; + } + + // Parse the return register. + TmpReg.clear(); + ResTy = ParseAnyRegister(TmpReg); + if (ResTy == MatchOperand_NoMatch || ResTy == MatchOperand_ParseFail) { + reportParseError("expected return register"); + return false; + } + + MipsOperand &ReturnRegOpnd = static_cast(*TmpReg[0]); + if (!ReturnRegOpnd.isGPRAsmReg()) { + reportParseError(ReturnRegOpnd.getStartLoc(), + "expected general purpose register"); + return false; + } + + // 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; + } + + getTargetStreamer().emitFrame(StackReg, FrameSizeVal, + ReturnRegOpnd.getGPR32Reg()); return false; } @@ -2524,34 +3337,81 @@ bool MipsAsmParser::ParseDirective(AsmToken DirectiveID) { return parseDirectiveSet(); } - if (IDVal == ".fmask") { - // Ignore this directive for now. - Parser.eatToEndOfStatement(); - return false; - } + if (IDVal == ".mask" || IDVal == ".fmask") { + // .mask bitmask, frame_offset + // bitmask: One bit for each register used. + // frame_offset: Offset from Canonical Frame Address ($sp on entry) where + // first register is expected to be saved. + // Examples: + // .mask 0x80000000, -4 + // .fmask 0x80000000, -4 + // - if (IDVal == ".mask") { - // Ignore this directive for now. - Parser.eatToEndOfStatement(); + // Parse the bitmask + const MCExpr *BitMask; + int64_t BitMaskVal; + + if (Parser.parseExpression(BitMask)) { + reportParseError("expected bitmask value"); + return false; + } + + if (!BitMask->EvaluateAsAbsolute(BitMaskVal)) { + reportParseError("bitmask not an absolute expression"); + return false; + } + + if (Parser.getTok().is(AsmToken::Comma)) + Parser.Lex(); + else { + reportParseError("unexpected token, expected comma"); + return false; + } + + // Parse the frame_offset + const MCExpr *FrameOffset; + int64_t FrameOffsetVal; + + if (Parser.parseExpression(FrameOffset)) { + reportParseError("expected frame offset value"); + return false; + } + + if (!FrameOffset->EvaluateAsAbsolute(FrameOffsetVal)) { + reportParseError("frame offset not an absolute expression"); + return false; + } + + // 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; + } + + if (IDVal == ".mask") + getTargetStreamer().emitMask(BitMaskVal, FrameOffsetVal); + else + getTargetStreamer().emitFMask(BitMaskVal, FrameOffsetVal); return false; } + if (IDVal == ".nan") + return parseDirectiveNaN(); + if (IDVal == ".gpword") { - // Ignore this directive for now. parseDirectiveGpWord(); return false; } - if (IDVal == ".word") { - parseDirectiveWord(4, DirectiveID.getLoc()); + if (IDVal == ".gpdword") { + parseDirectiveGpDWord(); return false; } - if (IDVal == ".mips_hack_stocg") - return parseDirectiveMipsHackStocg(); - - if (IDVal == ".mips_hack_elf_flags") - return parseDirectiveMipsHackELFFlags(); + if (IDVal == ".word") { + parseDataDirective(4, DirectiveID.getLoc()); + return false; + } if (IDVal == ".option") return parseDirectiveOption(); @@ -2566,6 +3426,12 @@ bool MipsAsmParser::ParseDirective(AsmToken DirectiveID) { return false; } + if (IDVal == ".cpsetup") + return parseDirectiveCPSetup(); + + if (IDVal == ".module") + return parseDirectiveModule(); + return true; }