diff options
Diffstat (limited to 'contrib/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp')
-rw-r--r-- | contrib/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp | 2715 |
1 files changed, 1613 insertions, 1102 deletions
diff --git a/contrib/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp b/contrib/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp index cdae6c2f37e5..53b30f9210b0 100644 --- a/contrib/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp +++ b/contrib/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp @@ -7,24 +7,30 @@ // //===----------------------------------------------------------------------===// +#include "MCTargetDesc/MipsMCExpr.h" #include "MCTargetDesc/MipsMCTargetDesc.h" #include "MipsRegisterInfo.h" #include "MipsTargetStreamer.h" +#include "llvm/ADT/APInt.h" #include "llvm/ADT/StringSwitch.h" #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" -#include "llvm/ADT/APInt.h" using namespace llvm; +#define DEBUG_TYPE "mips-asm-parser" + namespace llvm { class MCInstrInfo; } @@ -54,137 +60,81 @@ private: namespace { class MipsAsmParser : public MCTargetAsmParser { - MipsTargetStreamer &getTargetStreamer() { - MCTargetStreamer &TS = Parser.getStreamer().getTargetStreamer(); + MCTargetStreamer &TS = *Parser.getStreamer().getTargetStreamer(); return static_cast<MipsTargetStreamer &>(TS); } MCSubtargetInfo &STI; MCAsmParser &Parser; MipsAssemblerOptions Options; - bool hasConsumedDollar; #define GET_ASSEMBLER_HEADER #include "MipsGenAsmMatcher.inc" - bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, - SmallVectorImpl<MCParsedAsmOperand *> &Operands, - MCStreamer &Out, unsigned &ErrorInfo, - bool MatchingInlineAsm); - - bool ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc); - - bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name, - SMLoc NameLoc, - SmallVectorImpl<MCParsedAsmOperand *> &Operands); - - bool ParseDirective(AsmToken DirectiveID); - - MipsAsmParser::OperandMatchResultTy - parseRegs(SmallVectorImpl<MCParsedAsmOperand *> &Operands, int RegKind); - - MipsAsmParser::OperandMatchResultTy - parseMSARegs(SmallVectorImpl<MCParsedAsmOperand *> &Operands, int RegKind); - - MipsAsmParser::OperandMatchResultTy - parseMSACtrlRegs(SmallVectorImpl<MCParsedAsmOperand *> &Operands, - int RegKind); - - MipsAsmParser::OperandMatchResultTy - parseMemOperand(SmallVectorImpl<MCParsedAsmOperand *> &Operands); - - bool parsePtrReg(SmallVectorImpl<MCParsedAsmOperand *> &Operands, - int RegKind); - - MipsAsmParser::OperandMatchResultTy - parsePtrReg(SmallVectorImpl<MCParsedAsmOperand *> &Operands); - - MipsAsmParser::OperandMatchResultTy - parseGPR32(SmallVectorImpl<MCParsedAsmOperand *> &Operands); - - MipsAsmParser::OperandMatchResultTy - parseGPR64(SmallVectorImpl<MCParsedAsmOperand *> &Operands); - - MipsAsmParser::OperandMatchResultTy - parseHWRegs(SmallVectorImpl<MCParsedAsmOperand *> &Operands); - - MipsAsmParser::OperandMatchResultTy - parseCCRRegs(SmallVectorImpl<MCParsedAsmOperand *> &Operands); - - MipsAsmParser::OperandMatchResultTy - parseAFGR64Regs(SmallVectorImpl<MCParsedAsmOperand *> &Operands); - - MipsAsmParser::OperandMatchResultTy - parseFGR64Regs(SmallVectorImpl<MCParsedAsmOperand *> &Operands); - - MipsAsmParser::OperandMatchResultTy - parseFGR32Regs(SmallVectorImpl<MCParsedAsmOperand *> &Operands); - - MipsAsmParser::OperandMatchResultTy - parseFGRH32Regs(SmallVectorImpl<MCParsedAsmOperand *> &Operands); + unsigned checkTargetMatchPredicate(MCInst &Inst) override; - MipsAsmParser::OperandMatchResultTy - parseFCCRegs(SmallVectorImpl<MCParsedAsmOperand *> &Operands); + bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, + OperandVector &Operands, MCStreamer &Out, + unsigned &ErrorInfo, + bool MatchingInlineAsm) override; - MipsAsmParser::OperandMatchResultTy - parseACC64DSP(SmallVectorImpl<MCParsedAsmOperand *> &Operands); + /// Parse a register as used in CFI directives + bool ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc) override; - MipsAsmParser::OperandMatchResultTy - parseLO32DSP(SmallVectorImpl<MCParsedAsmOperand *> &Operands); + bool ParseParenSuffix(StringRef Name, OperandVector &Operands); - MipsAsmParser::OperandMatchResultTy - parseHI32DSP(SmallVectorImpl<MCParsedAsmOperand *> &Operands); + bool ParseBracketSuffix(StringRef Name, OperandVector &Operands); - MipsAsmParser::OperandMatchResultTy - parseCOP2(SmallVectorImpl<MCParsedAsmOperand *> &Operands); + bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name, + SMLoc NameLoc, OperandVector &Operands) override; - MipsAsmParser::OperandMatchResultTy - parseMSA128BRegs(SmallVectorImpl<MCParsedAsmOperand *> &Operands); + bool ParseDirective(AsmToken DirectiveID) override; - MipsAsmParser::OperandMatchResultTy - parseMSA128HRegs(SmallVectorImpl<MCParsedAsmOperand *> &Operands); + MipsAsmParser::OperandMatchResultTy parseMemOperand(OperandVector &Operands); MipsAsmParser::OperandMatchResultTy - parseMSA128WRegs(SmallVectorImpl<MCParsedAsmOperand *> &Operands); + MatchAnyRegisterNameWithoutDollar(OperandVector &Operands, + StringRef Identifier, SMLoc S); MipsAsmParser::OperandMatchResultTy - parseMSA128DRegs(SmallVectorImpl<MCParsedAsmOperand *> &Operands); + MatchAnyRegisterWithoutDollar(OperandVector &Operands, SMLoc S); - MipsAsmParser::OperandMatchResultTy - parseMSA128CtrlRegs(SmallVectorImpl<MCParsedAsmOperand *> &Operands); + MipsAsmParser::OperandMatchResultTy ParseAnyRegister(OperandVector &Operands); - MipsAsmParser::OperandMatchResultTy - parseInvNum(SmallVectorImpl<MCParsedAsmOperand *> &Operands); + MipsAsmParser::OperandMatchResultTy ParseImm(OperandVector &Operands); - MipsAsmParser::OperandMatchResultTy - parseLSAImm(SmallVectorImpl<MCParsedAsmOperand *> &Operands); + MipsAsmParser::OperandMatchResultTy ParseJumpTarget(OperandVector &Operands); - bool searchSymbolAlias(SmallVectorImpl<MCParsedAsmOperand*> &Operands, - unsigned RegKind); + MipsAsmParser::OperandMatchResultTy parseInvNum(OperandVector &Operands); - bool ParseOperand(SmallVectorImpl<MCParsedAsmOperand *> &, - StringRef Mnemonic); + MipsAsmParser::OperandMatchResultTy ParseLSAImm(OperandVector &Operands); - int tryParseRegister(bool is64BitReg); + bool searchSymbolAlias(OperandVector &Operands); - bool tryParseRegisterOperand(SmallVectorImpl<MCParsedAsmOperand *> &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<MCInst> &Instructions); - void expandLoadImm(MCInst &Inst, SMLoc IDLoc, + + bool expandLoadImm(MCInst &Inst, SMLoc IDLoc, SmallVectorImpl<MCInst> &Instructions); - void expandLoadAddressImm(MCInst &Inst, SMLoc IDLoc, + + bool expandLoadAddressImm(MCInst &Inst, SMLoc IDLoc, SmallVectorImpl<MCInst> &Instructions); - void expandLoadAddressReg(MCInst &Inst, SMLoc IDLoc, + + bool expandLoadAddressReg(MCInst &Inst, SMLoc IDLoc, SmallVectorImpl<MCInst> &Instructions); + void expandMemInst(MCInst &Inst, SMLoc IDLoc, SmallVectorImpl<MCInst> &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); @@ -192,9 +142,12 @@ class MipsAsmParser : public MCTargetAsmParser { const MCExpr *evaluateRelocExpr(const MCExpr *Expr, StringRef RelocStr); bool isEvaluated(const MCExpr *Expr); + 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(); @@ -202,25 +155,22 @@ class MipsAsmParser : public MCTargetAsmParser { bool parseSetNoMacroDirective(); 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; } - - int matchRegisterName(StringRef Symbol, bool is64BitReg); + bool eatComma(StringRef ErrorStr); int matchCPURegisterName(StringRef Symbol); @@ -236,11 +186,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<MCInst> &Instructions); @@ -250,17 +200,102 @@ class MipsAsmParser : public MCTargetAsmParser { // Example: INSERT.B $w0[n], $1 => 16 > n >= 0 bool validateMSAIndex(int Val, int RegKind); + 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"); } 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); }; } @@ -269,53 +304,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 { @@ -323,33 +364,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<MipsOperand> CreateReg(unsigned Index, RegKind RegKind, + const MCRegisterInfo *RegInfo, + SMLoc S, SMLoc E, + MipsAsmParser &Parser) { + auto Op = make_unique<MipsOperand>(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<MCConstantExpr>(Expr)) Inst.addOperand(MCOperand::CreateImm(CE->getValue())); @@ -357,6 +538,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(); @@ -366,46 +641,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<MCConstantExpr>(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<MCConstantExpr>(getMemOff()); + } + template <unsigned Bits> bool isMemWithSimmOffset() const { + return isMem() && isConstantMemOff() && isInt<Bits>(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<const MCConstantExpr *>(Val)->getValue(); + } + + MipsOperand *getMemBase() const { assert((Kind == k_Memory) && "Invalid access!"); return Mem.Base; } @@ -415,8 +716,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<const MCConstantExpr *>(getMemOff())->getValue(); + } + + static std::unique_ptr<MipsOperand> CreateToken(StringRef Str, SMLoc S, + MipsAsmParser &Parser) { + auto Op = make_unique<MipsOperand>(k_Token, Parser); Op->Tok.Data = Str.data(); Op->Tok.Length = Str.size(); Op->StartLoc = S; @@ -424,130 +730,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<MipsOperand> + 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<MipsOperand> + 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<MipsOperand> + 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<MipsOperand> + 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<MipsOperand> + 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<MipsOperand> + 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<MipsOperand> + 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<MipsOperand> + CreateImm(const MCExpr *Val, SMLoc S, SMLoc E, MipsAsmParser &Parser) { + auto Op = make_unique<MipsOperand>(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<MipsOperand> + CreateMem(std::unique_ptr<MipsOperand> Base, const MCExpr *Off, SMLoc S, + SMLoc E, MipsAsmParser &Parser) { + auto Op = make_unique<MipsOperand>(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 @@ -562,7 +900,67 @@ static const MCInstrDesc &getInstDesc(unsigned Opcode) { bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc, SmallVectorImpl<MCInst> &Instructions) { const MCInstrDesc &MCID = getInstDesc(Inst.getOpcode()); + Inst.setLoc(IDLoc); + + if (MCID.isBranch() || MCID.isCall()) { + const unsigned Opcode = Inst.getOpcode(); + MCOperand Offset; + + switch (Opcode) { + default: + break; + case Mips::BEQ: + case Mips::BNE: + 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(inMicroMipsMode() ? 17 : 18, Offset.getImm())) + return Error(IDLoc, "branch target out of range"); + if (OffsetToAlignment(Offset.getImm(), + 1LL << (inMicroMipsMode() ? 1 : 2))) + return Error(IDLoc, "branch to misaligned address"); + break; + case Mips::BGEZ: + case Mips::BGTZ: + case Mips::BLEZ: + case Mips::BLTZ: + case Mips::BGEZAL: + case Mips::BLTZAL: + case Mips::BC1F: + case Mips::BC1T: + 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(inMicroMipsMode() ? 17 : 18, Offset.getImm())) + return Error(IDLoc, "branch target out of range"); + 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. @@ -611,7 +1009,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); @@ -624,17 +1022,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<MCInst> &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: @@ -642,7 +1050,31 @@ void MipsAsmParser::expandInstruction(MCInst &Inst, SMLoc IDLoc, } } -void MipsAsmParser::expandLoadImm(MCInst &Inst, SMLoc IDLoc, +namespace { +template <int Shift, bool PerformShift> +void createShiftOr(int64_t Value, unsigned RegNo, SMLoc IDLoc, + SmallVectorImpl<MCInst> &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( + MCOperand::CreateImm(((Value & (0xffffLL << Shift)) >> Shift))); + tmpInst.setLoc(IDLoc); + Instructions.push_back(tmpInst); +} +} + +bool MipsAsmParser::expandLoadImm(MCInst &Inst, SMLoc IDLoc, SmallVectorImpl<MCInst> &Instructions) { MCInst tmpInst; const MCOperand &ImmOp = Inst.getOperand(1); @@ -650,8 +1082,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 @@ -668,25 +1102,76 @@ 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<MCInst> &Instructions) { MCInst tmpInst; @@ -727,9 +1212,10 @@ 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<MCInst> &Instructions) { MCInst tmpInst; @@ -761,6 +1247,7 @@ MipsAsmParser::expandLoadAddressImm(MCInst &Inst, SMLoc IDLoc, tmpInst.addOperand(MCOperand::CreateImm(ImmValue & 0xffff)); Instructions.push_back(tmpInst); } + return false; } void MipsAsmParser::expandMemInst(MCInst &Inst, SMLoc IDLoc, @@ -771,8 +1258,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(); @@ -792,10 +1277,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) @@ -823,7 +1344,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)); @@ -845,10 +1366,24 @@ void MipsAsmParser::expandMemInst(MCInst &Inst, SMLoc IDLoc, TempInst.clear(); } -bool MipsAsmParser::MatchAndEmitInstruction( - SMLoc IDLoc, unsigned &Opcode, - SmallVectorImpl<MCParsedAsmOperand *> &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, + unsigned &ErrorInfo, + bool MatchingInlineAsm) { + MCInst Inst; SmallVector<MCInst, 8> Instructions; unsigned MatchResult = @@ -861,7 +1396,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: @@ -873,7 +1408,7 @@ bool MipsAsmParser::MatchAndEmitInstruction( 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; } @@ -882,18 +1417,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<unsigned>(Name) .Case("zero", 0) + .Case("at", 1) .Case("a0", 4) .Case("a1", 5) .Case("a2", 6) @@ -910,9 +1455,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) @@ -926,22 +1472,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<unsigned>(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<unsigned>(Name) + .Case("a4", 8) + .Case("a5", 9) + .Case("a6", 10) + .Case("a7", 11) + .Case("kt0", 26) + .Case("kt1", 27) + .Default(-1); + } return CC; } @@ -1017,59 +1564,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; @@ -1078,53 +1572,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<unsigned>(Tok.getIntVal()), - is64BitReg ? Mips::GPR64RegClassID - : Mips::GPR32RegClassID); - return RegNum; -} - -bool MipsAsmParser::tryParseRegisterOperand( - SmallVectorImpl<MCParsedAsmOperand *> &Operands, bool is64BitReg) { - - SMLoc S = Parser.getTok().getLoc(); - int RegNo = -1; - - RegNo = tryParseRegister(is64BitReg); - if (RegNo == -1) - return true; +bool MipsAsmParser::ParseOperand(OperandVector &Operands, StringRef Mnemonic) { + DEBUG(dbgs() << "ParseOperand\n"); - Operands.push_back( - MipsOperand::CreateReg(RegNo, S, Parser.getTok().getLoc())); - Parser.Lex(); // Eat register token. - return false; -} - -bool -MipsAsmParser::ParseOperand(SmallVectorImpl<MCParsedAsmOperand *> &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); @@ -1136,6 +1611,8 @@ MipsAsmParser::ParseOperand(SmallVectorImpl<MCParsedAsmOperand *> &Operands, if (ResTy == MatchOperand_ParseFail) return true; + DEBUG(dbgs() << ".. Generic Parser\n"); + switch (getLexer().getKind()) { default: Error(Parser.getTok().getLoc(), "unexpected token in operand"); @@ -1143,29 +1620,15 @@ MipsAsmParser::ParseOperand(SmallVectorImpl<MCParsedAsmOperand *> &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)) @@ -1177,47 +1640,19 @@ MipsAsmParser::ParseOperand(SmallVectorImpl<MCParsedAsmOperand *> &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. @@ -1228,7 +1663,7 @@ MipsAsmParser::ParseOperand(SmallVectorImpl<MCParsedAsmOperand *> &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()) @@ -1240,23 +1675,30 @@ const MCExpr *MipsAsmParser::evaluateRelocExpr(const MCExpr *Expr, const MCExpr *Res; // Check the type of the expression. if (const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(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<MCSymbolRefExpr>(Expr)) { @@ -1268,6 +1710,12 @@ const MCExpr *MipsAsmParser::evaluateRelocExpr(const MCExpr *Expr, } if (const MCBinaryExpr *BE = dyn_cast<MCBinaryExpr>(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()); @@ -1298,8 +1746,8 @@ bool MipsAsmParser::isEvaluated(const MCExpr *Expr) { } case MCExpr::Unary: return isEvaluated(cast<MCUnaryExpr>(Expr)->getSubExpr()); - default: - return false; + case MCExpr::Target: + return true; } return false; } @@ -1348,9 +1796,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<std::unique_ptr<MCParsedAsmOperand>, 1> Operands; + OperandMatchResultTy ResTy = ParseAnyRegister(Operands); + if (ResTy == MatchOperand_Success) { + assert(Operands.size() == 1); + MipsOperand &Operand = static_cast<MipsOperand &>(*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); } @@ -1382,10 +1848,10 @@ bool MipsAsmParser::parseMemOffset(const MCExpr *&Res, bool isParenExpr) { return Result; } -MipsAsmParser::OperandMatchResultTy MipsAsmParser::parseMemOperand( - SmallVectorImpl<MCParsedAsmOperand *> &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; @@ -1403,11 +1869,11 @@ MipsAsmParser::OperandMatchResultTy MipsAsmParser::parseMemOperand( const AsmToken &Tok = Parser.getTok(); // Get the next token. if (Tok.isNot(AsmToken::LParen)) { - MipsOperand *Mnemonic = static_cast<MipsOperand *>(Operands[0]); - if (Mnemonic->getToken() == "la") { + MipsOperand &Mnemonic = static_cast<MipsOperand &>(*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)) { @@ -1415,8 +1881,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"); @@ -1426,8 +1895,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; @@ -1440,13 +1908,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<MipsOperand *>(Operands.back()); - int RegNo = op->getReg(); + std::unique_ptr<MipsOperand> op( + static_cast<MipsOperand *>(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<MCBinaryExpr>(IdVal)) { @@ -1458,603 +1927,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<MCParsedAsmOperand *> &Operands, - int RegKind) { - // If the first token is not '$' we have an error. - if (Parser.getTok().isNot(AsmToken::Dollar)) - return false; +bool MipsAsmParser::searchSymbolAlias(OperandVector &Operands) { - SMLoc S = Parser.getTok().getLoc(); - Parser.Lex(); - AsmToken::TokenKind TkKind = getLexer().getKind(); - int Reg; - - 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<const MCSymbolRefExpr *>(Expr); + const 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<const MCConstantExpr *>(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; -} - -MipsAsmParser::OperandMatchResultTy -MipsAsmParser::parsePtrReg(SmallVectorImpl<MCParsedAsmOperand *> &Operands) { - MipsOperand::RegisterKind RegKind = - isN64() ? MipsOperand::Kind_GPR64 : MipsOperand::Kind_GPR32; - - // Parse index register. - if (!parsePtrReg(Operands, RegKind)) - return MatchOperand_NoMatch; - - // Parse '('. - if (Parser.getTok().isNot(AsmToken::LParen)) - return MatchOperand_NoMatch; - - Operands.push_back(MipsOperand::CreateToken("(", getLexer().getLoc())); - Parser.Lex(); - - // Parse base register. - if (!parsePtrReg(Operands, RegKind)) - return MatchOperand_NoMatch; - - // Parse ')'. - if (Parser.getTok().isNot(AsmToken::RParen)) - return MatchOperand_NoMatch; - - Operands.push_back(MipsOperand::CreateToken(")", getLexer().getLoc())); - Parser.Lex(); - - return MatchOperand_Success; + return false; } MipsAsmParser::OperandMatchResultTy -MipsAsmParser::parseRegs(SmallVectorImpl<MCParsedAsmOperand *> &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::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; } - return MatchOperand_NoMatch; -} - -bool MipsAsmParser::validateMSAIndex(int Val, int RegKind) { - MipsOperand::RegisterKind Kind = (MipsOperand::RegisterKind)RegKind; - if (Val < 0) - return false; - - 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; + Index = matchFPURegisterName(Identifier); + if (Index != -1) { + Operands.push_back(MipsOperand::CreateFGRReg( + Index, getContext().getRegisterInfo(), S, getLexer().getLoc(), *this)); + return MatchOperand_Success; } -} -MipsAsmParser::OperandMatchResultTy -MipsAsmParser::parseMSARegs(SmallVectorImpl<MCParsedAsmOperand *> &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) { - default: - return MatchOperand_ParseFail; - case MipsOperand::Kind_MSA128BRegs: - case MipsOperand::Kind_MSA128HRegs: - case MipsOperand::Kind_MSA128WRegs: - case MipsOperand::Kind_MSA128DRegs: - break; + Index = matchFCCRegisterName(Identifier); + if (Index != -1) { + Operands.push_back(MipsOperand::CreateFCCReg( + Index, getContext().getRegisterInfo(), S, getLexer().getLoc(), *this)); + return MatchOperand_Success; } - 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) - 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)) + Index = matchACRegisterName(Identifier); + if (Index != -1) { + Operands.push_back(MipsOperand::CreateACCReg( + Index, getContext().getRegisterInfo(), S, getLexer().getLoc(), *this)); return MatchOperand_Success; + } - MipsOperand *Mnemonic = static_cast<MipsOperand *>(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; - - Operands.push_back(MipsOperand::CreateToken("]", Parser.getTok().getLoc())); - Parser.Lex(); // Parse the ']' token. - + Index = matchMSA128RegisterName(Identifier); + if (Index != -1) { + Operands.push_back(MipsOperand::CreateMSA128Reg( + Index, getContext().getRegisterInfo(), S, getLexer().getLoc(), *this)); return MatchOperand_Success; } - // The index must be a constant expression then. - SMLoc VIdx = Parser.getTok().getLoc(); - const MCExpr *ImmVal; - - if (getParser().parseExpression(ImmVal)) - return MatchOperand_ParseFail; - - const MCConstantExpr *expr = dyn_cast<MCConstantExpr>(ImmVal); - if (!expr || !validateMSAIndex((int)expr->getValue(), Kind)) { - Error(VIdx, "invalid immediate value"); - return MatchOperand_ParseFail; + Index = matchMSA128CtrlRegisterName(Identifier); + if (Index != -1) { + Operands.push_back(MipsOperand::CreateMSACtrlReg( + Index, getContext().getRegisterInfo(), S, getLexer().getLoc(), *this)); + return MatchOperand_Success; } - 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. - - return MatchOperand_Success; -} - -MipsAsmParser::OperandMatchResultTy -MipsAsmParser::parseMSACtrlRegs(SmallVectorImpl<MCParsedAsmOperand *> &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<MCParsedAsmOperand *> &Operands) { - - if (!isMips64()) - return MatchOperand_NoMatch; - return parseRegs(Operands, (int)MipsOperand::Kind_GPR64); -} - -MipsAsmParser::OperandMatchResultTy -MipsAsmParser::parseGPR32(SmallVectorImpl<MCParsedAsmOperand *> &Operands) { - return parseRegs(Operands, (int)MipsOperand::Kind_GPR32); -} - -MipsAsmParser::OperandMatchResultTy MipsAsmParser::parseAFGR64Regs( - SmallVectorImpl<MCParsedAsmOperand *> &Operands) { - - if (isFP64()) - return MatchOperand_NoMatch; - return parseRegs(Operands, (int)MipsOperand::Kind_AFGR64Regs); -} - -MipsAsmParser::OperandMatchResultTy -MipsAsmParser::parseFGR64Regs(SmallVectorImpl<MCParsedAsmOperand *> &Operands) { - if (!isFP64()) - return MatchOperand_NoMatch; - return parseRegs(Operands, (int)MipsOperand::Kind_FGR64Regs); + return MatchOperand_NoMatch; } MipsAsmParser::OperandMatchResultTy -MipsAsmParser::parseFGR32Regs(SmallVectorImpl<MCParsedAsmOperand *> &Operands) { - return parseRegs(Operands, (int)MipsOperand::Kind_FGR32Regs); -} - -MipsAsmParser::OperandMatchResultTy MipsAsmParser::parseFGRH32Regs( - SmallVectorImpl<MCParsedAsmOperand *> &Operands) { - return parseRegs(Operands, (int)MipsOperand::Kind_FGRH32Regs); -} +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; + } -MipsAsmParser::OperandMatchResultTy -MipsAsmParser::parseFCCRegs(SmallVectorImpl<MCParsedAsmOperand *> &Operands) { - return parseRegs(Operands, (int)MipsOperand::Kind_FCCRegs); -} + DEBUG(dbgs() << Parser.getTok().getKind() << "\n"); -MipsAsmParser::OperandMatchResultTy -MipsAsmParser::parseACC64DSP(SmallVectorImpl<MCParsedAsmOperand *> &Operands) { - return parseRegs(Operands, (int)MipsOperand::Kind_ACC64DSP); + return MatchOperand_NoMatch; } MipsAsmParser::OperandMatchResultTy -MipsAsmParser::parseLO32DSP(SmallVectorImpl<MCParsedAsmOperand *> &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; +MipsAsmParser::ParseAnyRegister(OperandVector &Operands) { + DEBUG(dbgs() << "ParseAnyRegister\n"); - if (!Tok.getIdentifier().startswith("ac")) - return MatchOperand_NoMatch; + auto Token = Parser.getTok(); - StringRef NumString = Tok.getIdentifier().substr(2); + SMLoc S = Token.getLoc(); - unsigned IntVal; - if (NumString.getAsInteger(10, IntVal)) + 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"); - 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; + OperandMatchResultTy ResTy = MatchAnyRegisterWithoutDollar(Operands, S); + if (ResTy == MatchOperand_Success) { + Parser.Lex(); // $ + Parser.Lex(); // identifier + } + return ResTy; } MipsAsmParser::OperandMatchResultTy -MipsAsmParser::parseHI32DSP(SmallVectorImpl<MCParsedAsmOperand *> &Operands) { - // If the first token is not '$' we have an error. - if (Parser.getTok().isNot(AsmToken::Dollar)) +MipsAsmParser::ParseImm(OperandVector &Operands) { + switch (getLexer().getKind()) { + default: return MatchOperand_NoMatch; + case AsmToken::LParen: + case AsmToken::Minus: + case AsmToken::Plus: + case AsmToken::Integer: + case AsmToken::Tilde: + case AsmToken::String: + break; + } + const MCExpr *IdVal; SMLoc S = Parser.getTok().getLoc(); - 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); + if (getParser().parseExpression(IdVal)) + return MatchOperand_ParseFail; - Parser.Lex(); // Eat the register number. + SMLoc E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); + Operands.push_back(MipsOperand::CreateImm(IdVal, S, E, *this)); return MatchOperand_Success; } MipsAsmParser::OperandMatchResultTy -MipsAsmParser::parseCOP2(SmallVectorImpl<MCParsedAsmOperand *> &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); +MipsAsmParser::ParseJumpTarget(OperandVector &Operands) { + DEBUG(dbgs() << "ParseJumpTarget\n"); - Parser.Lex(); // Eat the register number. - return MatchOperand_Success; -} - -MipsAsmParser::OperandMatchResultTy MipsAsmParser::parseMSA128BRegs( - SmallVectorImpl<MCParsedAsmOperand *> &Operands) { - return parseMSARegs(Operands, (int)MipsOperand::Kind_MSA128BRegs); -} - -MipsAsmParser::OperandMatchResultTy MipsAsmParser::parseMSA128HRegs( - SmallVectorImpl<MCParsedAsmOperand *> &Operands) { - return parseMSARegs(Operands, (int)MipsOperand::Kind_MSA128HRegs); -} - -MipsAsmParser::OperandMatchResultTy MipsAsmParser::parseMSA128WRegs( - SmallVectorImpl<MCParsedAsmOperand *> &Operands) { - return parseMSARegs(Operands, (int)MipsOperand::Kind_MSA128WRegs); -} - -MipsAsmParser::OperandMatchResultTy MipsAsmParser::parseMSA128DRegs( - SmallVectorImpl<MCParsedAsmOperand *> &Operands) { - return parseMSARegs(Operands, (int)MipsOperand::Kind_MSA128DRegs); -} + SMLoc S = getLexer().getLoc(); -MipsAsmParser::OperandMatchResultTy MipsAsmParser::parseMSA128CtrlRegs( - SmallVectorImpl<MCParsedAsmOperand *> &Operands) { - return parseMSACtrlRegs(Operands, (int)MipsOperand::Kind_MSA128CtrlRegs); -} + // Integers and expressions are acceptable + OperandMatchResultTy ResTy = ParseImm(Operands); + if (ResTy != MatchOperand_NoMatch) + return ResTy; -bool MipsAsmParser::searchSymbolAlias( - SmallVectorImpl<MCParsedAsmOperand *> &Operands, unsigned RegKind) { + // Registers are a valid target and have priority over symbols. + ResTy = ParseAnyRegister(Operands); + if (ResTy != MatchOperand_NoMatch) + return ResTy; - 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<const MCSymbolRefExpr *>(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<const MCConstantExpr *>(Expr); - MipsOperand *op = - MipsOperand::CreateImm(Const, S, Parser.getTok().getLoc()); - Operands.push_back(op); - return true; - } + 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; } - return false; -} - -MipsAsmParser::OperandMatchResultTy -MipsAsmParser::parseHWRegs(SmallVectorImpl<MCParsedAsmOperand *> &Operands) { - return parseRegs(Operands, (int)MipsOperand::Kind_HWRegs); -} - -MipsAsmParser::OperandMatchResultTy -MipsAsmParser::parseCCRRegs(SmallVectorImpl<MCParsedAsmOperand *> &Operands) { - return parseRegs(Operands, (int)MipsOperand::Kind_CCRRegs); + Operands.push_back( + MipsOperand::CreateImm(Expr, S, getLexer().getLoc(), *this)); + return MatchOperand_Success; } MipsAsmParser::OperandMatchResultTy -MipsAsmParser::parseInvNum(SmallVectorImpl<MCParsedAsmOperand *> &Operands) { +MipsAsmParser::parseInvNum(OperandVector &Operands) { const MCExpr *IdVal; // If the first token is '$' we may have register operand. if (Parser.getTok().is(AsmToken::Dollar)) @@ -2067,12 +2128,12 @@ MipsAsmParser::parseInvNum(SmallVectorImpl<MCParsedAsmOperand *> &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<MCParsedAsmOperand *> &Operands) { +MipsAsmParser::ParseLSAImm(OperandVector &Operands) { switch (getLexer().getKind()) { default: return MatchOperand_NoMatch; @@ -2105,8 +2166,8 @@ MipsAsmParser::parseLSAImm(SmallVectorImpl<MCParsedAsmOperand *> &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; } @@ -2131,21 +2192,90 @@ 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<MCParsedAsmOperand *> &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 after + // this is forbidden. + getTargetStreamer().setCanHaveModuleDir(false); // 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)) { @@ -2155,6 +2285,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. @@ -2164,6 +2297,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)) { @@ -2175,12 +2315,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. @@ -2222,7 +2366,7 @@ bool MipsAsmParser::parseSetAtDirective() { return false; } - if (AtRegNo < 1 || AtRegNo > 31) { + if (AtRegNo < 0 || AtRegNo > 31) { reportParseError("unexpected token in statement"); return false; } @@ -2253,6 +2397,7 @@ bool MipsAsmParser::parseSetReorderDirective() { return false; } Options.setReorder(); + getTargetStreamer().emitDirectiveSetReorder(); Parser.Lex(); // Consume the EndOfStatement. return false; } @@ -2265,6 +2410,7 @@ bool MipsAsmParser::parseSetNoReorderDirective() { return false; } Options.setNoreorder(); + getTargetStreamer().emitDirectiveSetNoReorder(); Parser.Lex(); // Consume the EndOfStatement. return false; } @@ -2297,6 +2443,44 @@ bool MipsAsmParser::parseSetNoMacroDirective() { 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; @@ -2308,22 +2492,7 @@ bool MipsAsmParser::parseSetAssignment() { return reportParseError("unexpected token in .set directive"); Lex(); // Eat comma - if (getLexer().is(AsmToken::Dollar)) { - MCSymbol *Symbol; - SMLoc DollarLoc = getLexer().getLoc(); - // Consume the dollar sign, and check for a following identifier. - Parser.Lex(); - // We have a '$' followed by something, make sure they are adjacent. - if (DollarLoc.getPointer() + 1 != getTok().getLoc().getPointer()) - return true; - StringRef Res = - StringRef(DollarLoc.getPointer(), - getTok().getEndLoc().getPointer() - DollarLoc.getPointer()); - Symbol = getContext().GetOrCreateSymbol(Res); - Parser.Lex(); - Value = - MCSymbolRefExpr::Create(Symbol, MCSymbolRefExpr::VK_None, getContext()); - } else if (Parser.parseExpression(Value)) + if (Parser.parseExpression(Value)) return reportParseError("expected valid expression after comma"); // Check if the Name already exists as a symbol. @@ -2336,6 +2505,154 @@ bool MipsAsmParser::parseSetAssignment() { return false; } +bool MipsAsmParser::parseSetFeature(uint64_t Feature) { + Parser.Lex(); + if (getLexer().isNot(AsmToken::EndOfStatement)) + return reportParseError("unexpected token in .set directive"); + + 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::FeatureMips32r2: + setFeatureBits(Mips::FeatureMips32r2, "mips32r2"); + getTargetStreamer().emitDirectiveSetMips32R2(); + break; + case Mips::FeatureMips64: + setFeatureBits(Mips::FeatureMips64, "mips64"); + getTargetStreamer().emitDirectiveSetMips64(); + break; + case Mips::FeatureMips64r2: + setFeatureBits(Mips::FeatureMips64r2, "mips64r2"); + getTargetStreamer().emitDirectiveSetMips64R2(); + break; + } + return false; +} + +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<std::unique_ptr<MCParsedAsmOperand>, 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<MipsOperand &>(*Reg[0]); + if (!RegOpnd.isGPRAsmReg()) { + reportParseError(RegOpnd.getStartLoc(), "invalid register"); + return false; + } + + getTargetStreamer().emitDirectiveCpload(RegOpnd.getGPR32Reg()); + return false; +} + +bool MipsAsmParser::parseDirectiveCPSetup() { + unsigned FuncReg; + unsigned Save; + bool SaveIsReg = true; + + SmallVector<std::unique_ptr<MCParsedAsmOperand>, 1> TmpReg; + OperandMatchResultTy ResTy = ParseAnyRegister(TmpReg); + if (ResTy == MatchOperand_NoMatch) { + reportParseError("expected register containing function address"); + Parser.eatToEndOfStatement(); + return false; + } + + MipsOperand &FuncRegOpnd = static_cast<MipsOperand &>(*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<MipsOperand &>(*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; +} + +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. @@ -2345,6 +2662,8 @@ bool MipsAsmParser::parseDirectiveSet() { return parseSetNoAtDirective(); } else if (Tok.getString() == "at") { return parseSetAtDirective(); + } else if (Tok.getString() == "fp") { + return parseSetFpDirective(); } else if (Tok.getString() == "reorder") { return parseSetReorderDirective(); } else if (Tok.getString() == "noreorder") { @@ -2353,14 +2672,24 @@ bool MipsAsmParser::parseDirectiveSet() { return parseSetMacroDirective(); } else if (Tok.getString() == "nomacro") { return parseSetNoMacroDirective(); + } else if (Tok.getString() == "mips16") { + return parseSetFeature(Mips::FeatureMips16); } else if (Tok.getString() == "nomips16") { - // Ignore this directive for now. - Parser.eatToEndOfStatement(); - return false; + return parseSetNoMips16Directive(); } else if (Tok.getString() == "nomicromips") { - // Ignore this directive for now. + getTargetStreamer().emitDirectiveSetNoMicroMips(); Parser.eatToEndOfStatement(); return false; + } else if (Tok.getString() == "micromips") { + return parseSetFeature(Mips::FeatureMicroMips); + } else if (Tok.getString() == "mips32r2") { + return parseSetFeature(Mips::FeatureMips32r2); + } else if (Tok.getString() == "mips64") { + return parseSetFeature(Mips::FeatureMips64); + } else if (Tok.getString() == "mips64r2") { + return parseSetFeature(Mips::FeatureMips64r2); + } else if (Tok.getString() == "dsp") { + return parseSetFeature(Mips::FeatureDSP); } else { // It is just an identifier, look for an assignment. parseSetAssignment(); @@ -2370,37 +2699,9 @@ bool MipsAsmParser::parseDirectiveSet() { return true; } -bool MipsAsmParser::parseDirectiveMipsHackStocg() { - MCAsmParser &Parser = getParser(); - StringRef Name; - if (Parser.parseIdentifier(Name)) - reportParseError("expected identifier"); - - MCSymbol *Sym = getContext().GetOrCreateSymbol(Name); - if (getLexer().isNot(AsmToken::Comma)) - return TokError("unexpected token"); - Lex(); - - int64_t Flags = 0; - if (Parser.parseAbsoluteExpression(Flags)) - return TokError("unexpected token"); - - getTargetStreamer().emitMipsHackSTOCG(Sym, Flags); - return false; -} - -bool MipsAsmParser::parseDirectiveMipsHackELFFlags() { - int64_t Flags = 0; - if (Parser.parseAbsoluteExpression(Flags)) - return TokError("unexpected token"); - - getTargetStreamer().emitMipsHackELFFlags(Flags); - return false; -} - -/// parseDirectiveWord +/// 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; @@ -2439,10 +2740,200 @@ bool MipsAsmParser::parseDirectiveGpWord() { return false; } -bool MipsAsmParser::ParseDirective(AsmToken DirectiveID) { +/// 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(); + // At the moment only identifiers are supported. + if (Tok.isNot(AsmToken::Identifier)) { + Error(Parser.getTok().getLoc(), "unexpected token in .option directive"); + Parser.eatToEndOfStatement(); + return false; + } + + StringRef Option = Tok.getIdentifier(); + + if (Option == "pic0") { + getTargetStreamer().emitDirectiveOptionPic0(); + Parser.Lex(); + if (Parser.getTok().isNot(AsmToken::EndOfStatement)) { + Error(Parser.getTok().getLoc(), + "unexpected token in .option pic0 directive"); + Parser.eatToEndOfStatement(); + } + 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; +} + +/// parseDirectiveModule +/// ::= .module oddspreg +/// ::= .module nooddspreg +/// ::= .module fp=value +bool MipsAsmParser::parseDirectiveModule() { + MCAsmLexer &Lexer = getLexer(); + SMLoc L = Lexer.getLoc(); + + if (!getTargetStreamer().getCanHaveModuleDir()) { + // 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(); @@ -2477,22 +2968,42 @@ bool MipsAsmParser::ParseDirective(AsmToken DirectiveID) { return false; } + if (IDVal == ".nan") + return parseDirectiveNaN(); + if (IDVal == ".gpword") { - // Ignore this directive for now. parseDirectiveGpWord(); return false; } + if (IDVal == ".gpdword") { + parseDirectiveGpDWord(); + return false; + } + if (IDVal == ".word") { - parseDirectiveWord(4, DirectiveID.getLoc()); + parseDataDirective(4, DirectiveID.getLoc()); + return false; + } + + if (IDVal == ".option") + return parseDirectiveOption(); + + if (IDVal == ".abicalls") { + getTargetStreamer().emitDirectiveAbiCalls(); + if (Parser.getTok().isNot(AsmToken::EndOfStatement)) { + Error(Parser.getTok().getLoc(), "unexpected token in directive"); + // Clear line + Parser.eatToEndOfStatement(); + } return false; } - if (IDVal == ".mips_hack_stocg") - return parseDirectiveMipsHackStocg(); + if (IDVal == ".cpsetup") + return parseDirectiveCPSetup(); - if (IDVal == ".mips_hack_elf_flags") - return parseDirectiveMipsHackELFFlags(); + if (IDVal == ".module") + return parseDirectiveModule(); return true; } |