//===-- RISCVAsmParser.cpp - Parse RISCV assembly to MCInst instructions --===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "MCTargetDesc/RISCVBaseInfo.h" #include "MCTargetDesc/RISCVMCExpr.h" #include "MCTargetDesc/RISCVMCTargetDesc.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCInst.h" #include "llvm/MC/MCParser/MCAsmLexer.h" #include "llvm/MC/MCParser/MCParsedAsmOperand.h" #include "llvm/MC/MCParser/MCTargetAsmParser.h" #include "llvm/MC/MCRegisterInfo.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSubtargetInfo.h" #include "llvm/Support/Casting.h" #include "llvm/Support/TargetRegistry.h" using namespace llvm; namespace { struct RISCVOperand; class RISCVAsmParser : public MCTargetAsmParser { SMLoc getLoc() const { return getParser().getTok().getLoc(); } bool isRV64() const { return getSTI().hasFeature(RISCV::Feature64Bit); } unsigned validateTargetOperandClass(MCParsedAsmOperand &Op, unsigned Kind) override; bool generateImmOutOfRangeError(OperandVector &Operands, uint64_t ErrorInfo, int Lower, int Upper, Twine Msg); bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, OperandVector &Operands, MCStreamer &Out, uint64_t &ErrorInfo, bool MatchingInlineAsm) override; bool ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc) override; bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name, SMLoc NameLoc, OperandVector &Operands) override; bool ParseDirective(AsmToken DirectiveID) override; // Auto-generated instruction matching functions #define GET_ASSEMBLER_HEADER #include "RISCVGenAsmMatcher.inc" OperandMatchResultTy parseImmediate(OperandVector &Operands); OperandMatchResultTy parseRegister(OperandVector &Operands, bool AllowParens = false); OperandMatchResultTy parseMemOpBaseReg(OperandVector &Operands); OperandMatchResultTy parseOperandWithModifier(OperandVector &Operands); bool parseOperand(OperandVector &Operands); public: enum RISCVMatchResultTy { Match_Dummy = FIRST_TARGET_MATCH_RESULT_TY, #define GET_OPERAND_DIAGNOSTIC_TYPES #include "RISCVGenAsmMatcher.inc" #undef GET_OPERAND_DIAGNOSTIC_TYPES }; static bool classifySymbolRef(const MCExpr *Expr, RISCVMCExpr::VariantKind &Kind, int64_t &Addend); RISCVAsmParser(const MCSubtargetInfo &STI, MCAsmParser &Parser, const MCInstrInfo &MII, const MCTargetOptions &Options) : MCTargetAsmParser(Options, STI, MII) { setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits())); } }; /// RISCVOperand - Instances of this class represent a parsed machine /// instruction struct RISCVOperand : public MCParsedAsmOperand { enum KindTy { Token, Register, Immediate, } Kind; bool IsRV64; struct RegOp { unsigned RegNum; }; struct ImmOp { const MCExpr *Val; }; SMLoc StartLoc, EndLoc; union { StringRef Tok; RegOp Reg; ImmOp Imm; }; RISCVOperand(KindTy K) : MCParsedAsmOperand(), Kind(K) {} public: RISCVOperand(const RISCVOperand &o) : MCParsedAsmOperand() { Kind = o.Kind; IsRV64 = o.IsRV64; StartLoc = o.StartLoc; EndLoc = o.EndLoc; switch (Kind) { case Register: Reg = o.Reg; break; case Immediate: Imm = o.Imm; break; case Token: Tok = o.Tok; break; } } bool isToken() const override { return Kind == Token; } bool isReg() const override { return Kind == Register; } bool isImm() const override { return Kind == Immediate; } bool isMem() const override { return false; } bool evaluateConstantImm(int64_t &Imm, RISCVMCExpr::VariantKind &VK) const { const MCExpr *Val = getImm(); bool Ret = false; if (auto *RE = dyn_cast(Val)) { Ret = RE->evaluateAsConstant(Imm); VK = RE->getKind(); } else if (auto CE = dyn_cast(Val)) { Ret = true; VK = RISCVMCExpr::VK_RISCV_None; Imm = CE->getValue(); } return Ret; } // True if operand is a symbol with no modifiers, or a constant with no // modifiers and isShiftedInt(Op). template bool isBareSimmNLsb0() const { int64_t Imm; RISCVMCExpr::VariantKind VK; if (!isImm()) return false; bool IsConstantImm = evaluateConstantImm(Imm, VK); bool IsValid; if (!IsConstantImm) IsValid = RISCVAsmParser::classifySymbolRef(getImm(), VK, Imm); else IsValid = isShiftedInt(Imm); return IsValid && VK == RISCVMCExpr::VK_RISCV_None; } // Predicate methods for AsmOperands defined in RISCVInstrInfo.td /// Return true if the operand is a valid for the fence instruction e.g. /// ('iorw'). bool isFenceArg() const { if (!isImm()) return false; const MCExpr *Val = getImm(); auto *SVal = dyn_cast(Val); if (!SVal || SVal->getKind() != MCSymbolRefExpr::VK_None) return false; StringRef Str = SVal->getSymbol().getName(); // Letters must be unique, taken from 'iorw', and in ascending order. This // holds as long as each individual character is one of 'iorw' and is // greater than the previous character. char Prev = '\0'; for (char c : Str) { if (c != 'i' && c != 'o' && c != 'r' && c != 'w') return false; if (c <= Prev) return false; Prev = c; } return true; } /// Return true if the operand is a valid floating point rounding mode. bool isFRMArg() const { if (!isImm()) return false; const MCExpr *Val = getImm(); auto *SVal = dyn_cast(Val); if (!SVal || SVal->getKind() != MCSymbolRefExpr::VK_None) return false; StringRef Str = SVal->getSymbol().getName(); return RISCVFPRndMode::stringToRoundingMode(Str) != RISCVFPRndMode::Invalid; } bool isUImmLog2XLen() const { int64_t Imm; RISCVMCExpr::VariantKind VK; if (!isImm()) return false; if (!evaluateConstantImm(Imm, VK) || VK != RISCVMCExpr::VK_RISCV_None) return false; return (isRV64() && isUInt<6>(Imm)) || isUInt<5>(Imm); } bool isUImmLog2XLenNonZero() const { int64_t Imm; RISCVMCExpr::VariantKind VK; if (!isImm()) return false; if (!evaluateConstantImm(Imm, VK) || VK != RISCVMCExpr::VK_RISCV_None) return false; if (Imm == 0) return false; return (isRV64() && isUInt<6>(Imm)) || isUInt<5>(Imm); } bool isUImm5() const { int64_t Imm; RISCVMCExpr::VariantKind VK; if (!isImm()) return false; bool IsConstantImm = evaluateConstantImm(Imm, VK); return IsConstantImm && isUInt<5>(Imm) && VK == RISCVMCExpr::VK_RISCV_None; } bool isUImm5NonZero() const { int64_t Imm; RISCVMCExpr::VariantKind VK; if (!isImm()) return false; bool IsConstantImm = evaluateConstantImm(Imm, VK); return IsConstantImm && isUInt<5>(Imm) && (Imm != 0) && VK == RISCVMCExpr::VK_RISCV_None; } bool isSImm6() const { RISCVMCExpr::VariantKind VK; int64_t Imm; bool IsValid; bool IsConstantImm = evaluateConstantImm(Imm, VK); if (!IsConstantImm) IsValid = RISCVAsmParser::classifySymbolRef(getImm(), VK, Imm); else IsValid = isInt<6>(Imm); return IsValid && (VK == RISCVMCExpr::VK_RISCV_None || VK == RISCVMCExpr::VK_RISCV_LO); } bool isUImm6NonZero() const { int64_t Imm; RISCVMCExpr::VariantKind VK; bool IsConstantImm = evaluateConstantImm(Imm, VK); return IsConstantImm && isUInt<6>(Imm) && (Imm != 0) && VK == RISCVMCExpr::VK_RISCV_None; } bool isUImm7Lsb00() const { int64_t Imm; RISCVMCExpr::VariantKind VK; bool IsConstantImm = evaluateConstantImm(Imm, VK); return IsConstantImm && isShiftedUInt<5, 2>(Imm) && VK == RISCVMCExpr::VK_RISCV_None; } bool isUImm8Lsb00() const { int64_t Imm; RISCVMCExpr::VariantKind VK; bool IsConstantImm = evaluateConstantImm(Imm, VK); return IsConstantImm && isShiftedUInt<6, 2>(Imm) && VK == RISCVMCExpr::VK_RISCV_None; } bool isUImm8Lsb000() const { int64_t Imm; RISCVMCExpr::VariantKind VK; bool IsConstantImm = evaluateConstantImm(Imm, VK); return IsConstantImm && isShiftedUInt<5, 3>(Imm) && VK == RISCVMCExpr::VK_RISCV_None; } bool isSImm9Lsb0() const { return isBareSimmNLsb0<9>(); } bool isUImm9Lsb000() const { int64_t Imm; RISCVMCExpr::VariantKind VK; bool IsConstantImm = evaluateConstantImm(Imm, VK); return IsConstantImm && isShiftedUInt<6, 3>(Imm) && VK == RISCVMCExpr::VK_RISCV_None; } bool isUImm10Lsb00NonZero() const { int64_t Imm; RISCVMCExpr::VariantKind VK; bool IsConstantImm = evaluateConstantImm(Imm, VK); return IsConstantImm && isShiftedUInt<8, 2>(Imm) && (Imm != 0) && VK == RISCVMCExpr::VK_RISCV_None; } bool isSImm12() const { RISCVMCExpr::VariantKind VK; int64_t Imm; bool IsValid; if (!isImm()) return false; bool IsConstantImm = evaluateConstantImm(Imm, VK); if (!IsConstantImm) IsValid = RISCVAsmParser::classifySymbolRef(getImm(), VK, Imm); else IsValid = isInt<12>(Imm); return IsValid && (VK == RISCVMCExpr::VK_RISCV_None || VK == RISCVMCExpr::VK_RISCV_LO); } bool isSImm12Lsb0() const { return isBareSimmNLsb0<12>(); } bool isUImm12() const { int64_t Imm; RISCVMCExpr::VariantKind VK; if (!isImm()) return false; bool IsConstantImm = evaluateConstantImm(Imm, VK); return IsConstantImm && isUInt<12>(Imm) && VK == RISCVMCExpr::VK_RISCV_None; } bool isSImm13Lsb0() const { return isBareSimmNLsb0<13>(); } bool isSImm10Lsb0000() const { int64_t Imm; RISCVMCExpr::VariantKind VK; bool IsConstantImm = evaluateConstantImm(Imm, VK); return IsConstantImm && isShiftedInt<6, 4>(Imm) && VK == RISCVMCExpr::VK_RISCV_None; } bool isUImm20() const { RISCVMCExpr::VariantKind VK; int64_t Imm; bool IsValid; if (!isImm()) return false; bool IsConstantImm = evaluateConstantImm(Imm, VK); if (!IsConstantImm) IsValid = RISCVAsmParser::classifySymbolRef(getImm(), VK, Imm); else IsValid = isUInt<20>(Imm); return IsValid && (VK == RISCVMCExpr::VK_RISCV_None || VK == RISCVMCExpr::VK_RISCV_HI || VK == RISCVMCExpr::VK_RISCV_PCREL_HI); } bool isSImm21Lsb0() const { return isBareSimmNLsb0<21>(); } /// getStartLoc - Gets location of the first token of this operand SMLoc getStartLoc() const override { return StartLoc; } /// getEndLoc - Gets location of the last token of this operand SMLoc getEndLoc() const override { return EndLoc; } /// True if this operand is for an RV64 instruction bool isRV64() const { return IsRV64; } unsigned getReg() const override { assert(Kind == Register && "Invalid type access!"); return Reg.RegNum; } const MCExpr *getImm() const { assert(Kind == Immediate && "Invalid type access!"); return Imm.Val; } StringRef getToken() const { assert(Kind == Token && "Invalid type access!"); return Tok; } void print(raw_ostream &OS) const override { switch (Kind) { case Immediate: OS << *getImm(); break; case Register: OS << ""; break; case Token: OS << "'" << getToken() << "'"; break; } } static std::unique_ptr createToken(StringRef Str, SMLoc S, bool IsRV64) { auto Op = make_unique(Token); Op->Tok = Str; Op->StartLoc = S; Op->EndLoc = S; Op->IsRV64 = IsRV64; return Op; } static std::unique_ptr createReg(unsigned RegNo, SMLoc S, SMLoc E, bool IsRV64) { auto Op = make_unique(Register); Op->Reg.RegNum = RegNo; Op->StartLoc = S; Op->EndLoc = E; Op->IsRV64 = IsRV64; return Op; } static std::unique_ptr createImm(const MCExpr *Val, SMLoc S, SMLoc E, bool IsRV64) { auto Op = make_unique(Immediate); Op->Imm.Val = Val; Op->StartLoc = S; Op->EndLoc = E; Op->IsRV64 = IsRV64; return Op; } void addExpr(MCInst &Inst, const MCExpr *Expr) const { assert(Expr && "Expr shouldn't be null!"); int64_t Imm = 0; bool IsConstant = false; if (auto *RE = dyn_cast(Expr)) { IsConstant = RE->evaluateAsConstant(Imm); } else if (auto *CE = dyn_cast(Expr)) { IsConstant = true; Imm = CE->getValue(); } if (IsConstant) Inst.addOperand(MCOperand::createImm(Imm)); else Inst.addOperand(MCOperand::createExpr(Expr)); } // Used by the TableGen Code void addRegOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); Inst.addOperand(MCOperand::createReg(getReg())); } void addImmOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); addExpr(Inst, getImm()); } void addFenceArgOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); // isFenceArg has validated the operand, meaning this cast is safe auto SE = cast(getImm()); unsigned Imm = 0; for (char c : SE->getSymbol().getName()) { switch (c) { default: llvm_unreachable("FenceArg must contain only [iorw]"); case 'i': Imm |= RISCVFenceField::I; break; case 'o': Imm |= RISCVFenceField::O; break; case 'r': Imm |= RISCVFenceField::R; break; case 'w': Imm |= RISCVFenceField::W; break; } } Inst.addOperand(MCOperand::createImm(Imm)); } // Returns the rounding mode represented by this RISCVOperand. Should only // be called after checking isFRMArg. RISCVFPRndMode::RoundingMode getRoundingMode() const { // isFRMArg has validated the operand, meaning this cast is safe. auto SE = cast(getImm()); RISCVFPRndMode::RoundingMode FRM = RISCVFPRndMode::stringToRoundingMode(SE->getSymbol().getName()); assert(FRM != RISCVFPRndMode::Invalid && "Invalid rounding mode"); return FRM; } void addFRMArgOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); Inst.addOperand(MCOperand::createImm(getRoundingMode())); } }; } // end anonymous namespace. #define GET_REGISTER_MATCHER #define GET_MATCHER_IMPLEMENTATION #include "RISCVGenAsmMatcher.inc" // Return the matching FPR64 register for the given FPR32. // FIXME: Ideally this function could be removed in favour of using // information from TableGen. unsigned convertFPR32ToFPR64(unsigned Reg) { switch (Reg) { default: llvm_unreachable("Not a recognised FPR32 register"); case RISCV::F0_32: return RISCV::F0_64; case RISCV::F1_32: return RISCV::F1_64; case RISCV::F2_32: return RISCV::F2_64; case RISCV::F3_32: return RISCV::F3_64; case RISCV::F4_32: return RISCV::F4_64; case RISCV::F5_32: return RISCV::F5_64; case RISCV::F6_32: return RISCV::F6_64; case RISCV::F7_32: return RISCV::F7_64; case RISCV::F8_32: return RISCV::F8_64; case RISCV::F9_32: return RISCV::F9_64; case RISCV::F10_32: return RISCV::F10_64; case RISCV::F11_32: return RISCV::F11_64; case RISCV::F12_32: return RISCV::F12_64; case RISCV::F13_32: return RISCV::F13_64; case RISCV::F14_32: return RISCV::F14_64; case RISCV::F15_32: return RISCV::F15_64; case RISCV::F16_32: return RISCV::F16_64; case RISCV::F17_32: return RISCV::F17_64; case RISCV::F18_32: return RISCV::F18_64; case RISCV::F19_32: return RISCV::F19_64; case RISCV::F20_32: return RISCV::F20_64; case RISCV::F21_32: return RISCV::F21_64; case RISCV::F22_32: return RISCV::F22_64; case RISCV::F23_32: return RISCV::F23_64; case RISCV::F24_32: return RISCV::F24_64; case RISCV::F25_32: return RISCV::F25_64; case RISCV::F26_32: return RISCV::F26_64; case RISCV::F27_32: return RISCV::F27_64; case RISCV::F28_32: return RISCV::F28_64; case RISCV::F29_32: return RISCV::F29_64; case RISCV::F30_32: return RISCV::F30_64; case RISCV::F31_32: return RISCV::F31_64; } } unsigned RISCVAsmParser::validateTargetOperandClass(MCParsedAsmOperand &AsmOp, unsigned Kind) { RISCVOperand &Op = static_cast(AsmOp); if (!Op.isReg()) return Match_InvalidOperand; unsigned Reg = Op.getReg(); bool IsRegFPR32 = RISCVMCRegisterClasses[RISCV::FPR32RegClassID].contains(Reg); bool IsRegFPR32C = RISCVMCRegisterClasses[RISCV::FPR32CRegClassID].contains(Reg); // As the parser couldn't differentiate an FPR32 from an FPR64, coerce the // register from FPR32 to FPR64 or FPR32C to FPR64C if necessary. if ((IsRegFPR32 && Kind == MCK_FPR64) || (IsRegFPR32C && Kind == MCK_FPR64C)) { Op.Reg.RegNum = convertFPR32ToFPR64(Reg); return Match_Success; } return Match_InvalidOperand; } bool RISCVAsmParser::generateImmOutOfRangeError( OperandVector &Operands, uint64_t ErrorInfo, int Lower, int Upper, Twine Msg = "immediate must be an integer in the range") { SMLoc ErrorLoc = ((RISCVOperand &)*Operands[ErrorInfo]).getStartLoc(); return Error(ErrorLoc, Msg + " [" + Twine(Lower) + ", " + Twine(Upper) + "]"); } bool RISCVAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, OperandVector &Operands, MCStreamer &Out, uint64_t &ErrorInfo, bool MatchingInlineAsm) { MCInst Inst; switch (MatchInstructionImpl(Operands, Inst, ErrorInfo, MatchingInlineAsm)) { default: break; case Match_Success: Inst.setLoc(IDLoc); Out.EmitInstruction(Inst, getSTI()); return false; case Match_MissingFeature: return Error(IDLoc, "instruction use requires an option to be enabled"); case Match_MnemonicFail: return Error(IDLoc, "unrecognized instruction mnemonic"); case Match_InvalidOperand: { SMLoc ErrorLoc = IDLoc; if (ErrorInfo != ~0U) { if (ErrorInfo >= Operands.size()) return Error(ErrorLoc, "too few operands for instruction"); ErrorLoc = ((RISCVOperand &)*Operands[ErrorInfo]).getStartLoc(); if (ErrorLoc == SMLoc()) ErrorLoc = IDLoc; } return Error(ErrorLoc, "invalid operand for instruction"); } case Match_InvalidUImmLog2XLen: if (isRV64()) return generateImmOutOfRangeError(Operands, ErrorInfo, 0, (1 << 6) - 1); return generateImmOutOfRangeError(Operands, ErrorInfo, 0, (1 << 5) - 1); case Match_InvalidUImmLog2XLenNonZero: if (isRV64()) return generateImmOutOfRangeError(Operands, ErrorInfo, 1, (1 << 6) - 1); return generateImmOutOfRangeError(Operands, ErrorInfo, 1, (1 << 5) - 1); case Match_InvalidUImm5: return generateImmOutOfRangeError(Operands, ErrorInfo, 0, (1 << 5) - 1); case Match_InvalidSImm6: return generateImmOutOfRangeError(Operands, ErrorInfo, -(1 << 5), (1 << 5) - 1); case Match_InvalidUImm6NonZero: return generateImmOutOfRangeError(Operands, ErrorInfo, 1, (1 << 6) - 1); case Match_InvalidUImm7Lsb00: return generateImmOutOfRangeError( Operands, ErrorInfo, 0, (1 << 7) - 4, "immediate must be a multiple of 4 bytes in the range"); case Match_InvalidUImm8Lsb00: return generateImmOutOfRangeError( Operands, ErrorInfo, 0, (1 << 8) - 4, "immediate must be a multiple of 4 bytes in the range"); case Match_InvalidUImm8Lsb000: return generateImmOutOfRangeError( Operands, ErrorInfo, 0, (1 << 8) - 8, "immediate must be a multiple of 8 bytes in the range"); case Match_InvalidSImm9Lsb0: return generateImmOutOfRangeError( Operands, ErrorInfo, -(1 << 8), (1 << 8) - 2, "immediate must be a multiple of 2 bytes in the range"); case Match_InvalidUImm9Lsb000: return generateImmOutOfRangeError( Operands, ErrorInfo, 0, (1 << 9) - 8, "immediate must be a multiple of 8 bytes in the range"); case Match_InvalidUImm10Lsb00NonZero: return generateImmOutOfRangeError( Operands, ErrorInfo, 4, (1 << 10) - 4, "immediate must be a multiple of 4 bytes in the range"); case Match_InvalidSImm10Lsb0000: return generateImmOutOfRangeError( Operands, ErrorInfo, -(1 << 9), (1 << 9) - 16, "immediate must be a multiple of 16 bytes in the range"); case Match_InvalidSImm12: return generateImmOutOfRangeError(Operands, ErrorInfo, -(1 << 11), (1 << 11) - 1); case Match_InvalidSImm12Lsb0: return generateImmOutOfRangeError( Operands, ErrorInfo, -(1 << 11), (1 << 11) - 2, "immediate must be a multiple of 2 bytes in the range"); case Match_InvalidUImm12: return generateImmOutOfRangeError(Operands, ErrorInfo, 0, (1 << 12) - 1); case Match_InvalidSImm13Lsb0: return generateImmOutOfRangeError( Operands, ErrorInfo, -(1 << 12), (1 << 12) - 2, "immediate must be a multiple of 2 bytes in the range"); case Match_InvalidUImm20: return generateImmOutOfRangeError(Operands, ErrorInfo, 0, (1 << 20) - 1); case Match_InvalidSImm21Lsb0: return generateImmOutOfRangeError( Operands, ErrorInfo, -(1 << 20), (1 << 20) - 2, "immediate must be a multiple of 2 bytes in the range"); case Match_InvalidFenceArg: { SMLoc ErrorLoc = ((RISCVOperand &)*Operands[ErrorInfo]).getStartLoc(); return Error( ErrorLoc, "operand must be formed of letters selected in-order from 'iorw'"); } case Match_InvalidFRMArg: { SMLoc ErrorLoc = ((RISCVOperand &)*Operands[ErrorInfo]).getStartLoc(); return Error( ErrorLoc, "operand must be a valid floating point rounding mode mnemonic"); } } llvm_unreachable("Unknown match type detected!"); } bool RISCVAsmParser::ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc) { const AsmToken &Tok = getParser().getTok(); StartLoc = Tok.getLoc(); EndLoc = Tok.getEndLoc(); RegNo = 0; StringRef Name = getLexer().getTok().getIdentifier(); if (!MatchRegisterName(Name) || !MatchRegisterAltName(Name)) { getParser().Lex(); // Eat identifier token. return false; } return Error(StartLoc, "invalid register name"); } OperandMatchResultTy RISCVAsmParser::parseRegister(OperandVector &Operands, bool AllowParens) { SMLoc FirstS = getLoc(); bool HadParens = false; AsmToken Buf[2]; // If this a parenthesised register name is allowed, parse it atomically if (AllowParens && getLexer().is(AsmToken::LParen)) { size_t ReadCount = getLexer().peekTokens(Buf); if (ReadCount == 2 && Buf[1].getKind() == AsmToken::RParen) { HadParens = true; getParser().Lex(); // Eat '(' } } switch (getLexer().getKind()) { default: return MatchOperand_NoMatch; case AsmToken::Identifier: StringRef Name = getLexer().getTok().getIdentifier(); unsigned RegNo = MatchRegisterName(Name); if (RegNo == 0) { RegNo = MatchRegisterAltName(Name); if (RegNo == 0) { if (HadParens) getLexer().UnLex(Buf[0]); return MatchOperand_NoMatch; } } if (HadParens) Operands.push_back(RISCVOperand::createToken("(", FirstS, isRV64())); SMLoc S = getLoc(); SMLoc E = SMLoc::getFromPointer(S.getPointer() - 1); getLexer().Lex(); Operands.push_back(RISCVOperand::createReg(RegNo, S, E, isRV64())); } if (HadParens) { getParser().Lex(); // Eat ')' Operands.push_back(RISCVOperand::createToken(")", getLoc(), isRV64())); } return MatchOperand_Success; } OperandMatchResultTy RISCVAsmParser::parseImmediate(OperandVector &Operands) { SMLoc S = getLoc(); SMLoc E = SMLoc::getFromPointer(S.getPointer() - 1); const MCExpr *Res; switch (getLexer().getKind()) { default: return MatchOperand_NoMatch; case AsmToken::LParen: case AsmToken::Minus: case AsmToken::Plus: case AsmToken::Integer: case AsmToken::String: if (getParser().parseExpression(Res)) return MatchOperand_ParseFail; break; case AsmToken::Identifier: { StringRef Identifier; if (getParser().parseIdentifier(Identifier)) return MatchOperand_ParseFail; MCSymbol *Sym = getContext().getOrCreateSymbol(Identifier); Res = MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, getContext()); break; } case AsmToken::Percent: return parseOperandWithModifier(Operands); } Operands.push_back(RISCVOperand::createImm(Res, S, E, isRV64())); return MatchOperand_Success; } OperandMatchResultTy RISCVAsmParser::parseOperandWithModifier(OperandVector &Operands) { SMLoc S = getLoc(); SMLoc E = SMLoc::getFromPointer(S.getPointer() - 1); if (getLexer().getKind() != AsmToken::Percent) { Error(getLoc(), "expected '%' for operand modifier"); return MatchOperand_ParseFail; } getParser().Lex(); // Eat '%' if (getLexer().getKind() != AsmToken::Identifier) { Error(getLoc(), "expected valid identifier for operand modifier"); return MatchOperand_ParseFail; } StringRef Identifier = getParser().getTok().getIdentifier(); RISCVMCExpr::VariantKind VK = RISCVMCExpr::getVariantKindForName(Identifier); if (VK == RISCVMCExpr::VK_RISCV_Invalid) { Error(getLoc(), "unrecognized operand modifier"); return MatchOperand_ParseFail; } getParser().Lex(); // Eat the identifier if (getLexer().getKind() != AsmToken::LParen) { Error(getLoc(), "expected '('"); return MatchOperand_ParseFail; } getParser().Lex(); // Eat '(' const MCExpr *SubExpr; if (getParser().parseParenExpression(SubExpr, E)) { return MatchOperand_ParseFail; } const MCExpr *ModExpr = RISCVMCExpr::create(SubExpr, VK, getContext()); Operands.push_back(RISCVOperand::createImm(ModExpr, S, E, isRV64())); return MatchOperand_Success; } OperandMatchResultTy RISCVAsmParser::parseMemOpBaseReg(OperandVector &Operands) { if (getLexer().isNot(AsmToken::LParen)) { Error(getLoc(), "expected '('"); return MatchOperand_ParseFail; } getParser().Lex(); // Eat '(' Operands.push_back(RISCVOperand::createToken("(", getLoc(), isRV64())); if (parseRegister(Operands) != MatchOperand_Success) { Error(getLoc(), "expected register"); return MatchOperand_ParseFail; } if (getLexer().isNot(AsmToken::RParen)) { Error(getLoc(), "expected ')'"); return MatchOperand_ParseFail; } getParser().Lex(); // Eat ')' Operands.push_back(RISCVOperand::createToken(")", getLoc(), isRV64())); return MatchOperand_Success; } /// Looks at a token type and creates the relevant operand /// from this information, adding to Operands. /// If operand was parsed, returns false, else true. bool RISCVAsmParser::parseOperand(OperandVector &Operands) { // Attempt to parse token as register if (parseRegister(Operands, true) == MatchOperand_Success) return false; // Attempt to parse token as an immediate if (parseImmediate(Operands) == MatchOperand_Success) { // Parse memory base register if present if (getLexer().is(AsmToken::LParen)) return parseMemOpBaseReg(Operands) != MatchOperand_Success; return false; } // Finally we have exhausted all options and must declare defeat. Error(getLoc(), "unknown operand"); return true; } bool RISCVAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name, SMLoc NameLoc, OperandVector &Operands) { // First operand is token for instruction Operands.push_back(RISCVOperand::createToken(Name, NameLoc, isRV64())); // If there are no more operands, then finish if (getLexer().is(AsmToken::EndOfStatement)) return false; // Parse first operand if (parseOperand(Operands)) return true; // Parse until end of statement, consuming commas between operands while (getLexer().is(AsmToken::Comma)) { // Consume comma token getLexer().Lex(); // Parse next operand if (parseOperand(Operands)) return true; } if (getLexer().isNot(AsmToken::EndOfStatement)) { SMLoc Loc = getLexer().getLoc(); getParser().eatToEndOfStatement(); return Error(Loc, "unexpected token"); } getParser().Lex(); // Consume the EndOfStatement. return false; } bool RISCVAsmParser::classifySymbolRef(const MCExpr *Expr, RISCVMCExpr::VariantKind &Kind, int64_t &Addend) { Kind = RISCVMCExpr::VK_RISCV_None; Addend = 0; if (const RISCVMCExpr *RE = dyn_cast(Expr)) { Kind = RE->getKind(); Expr = RE->getSubExpr(); } // It's a simple symbol reference or constant with no addend. if (isa(Expr) || isa(Expr)) return true; const MCBinaryExpr *BE = dyn_cast(Expr); if (!BE) return false; if (!isa(BE->getLHS())) return false; if (BE->getOpcode() != MCBinaryExpr::Add && BE->getOpcode() != MCBinaryExpr::Sub) return false; // We are able to support the subtraction of two symbol references if (BE->getOpcode() == MCBinaryExpr::Sub && isa(BE->getRHS())) return true; // See if the addend is is a constant, otherwise there's more going // on here than we can deal with. auto AddendExpr = dyn_cast(BE->getRHS()); if (!AddendExpr) return false; Addend = AddendExpr->getValue(); if (BE->getOpcode() == MCBinaryExpr::Sub) Addend = -Addend; // It's some symbol reference + a constant addend return Kind != RISCVMCExpr::VK_RISCV_Invalid; } bool RISCVAsmParser::ParseDirective(AsmToken DirectiveID) { return true; } extern "C" void LLVMInitializeRISCVAsmParser() { RegisterMCAsmParser X(getTheRISCV32Target()); RegisterMCAsmParser Y(getTheRISCV64Target()); }