summaryrefslogtreecommitdiff
path: root/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp')
-rw-r--r--lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp946
1 files changed, 946 insertions, 0 deletions
diff --git a/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp b/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
new file mode 100644
index 000000000000..3299a53ff5ba
--- /dev/null
+++ b/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
@@ -0,0 +1,946 @@
+//===-- 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<RISCVMCExpr>(Val)) {
+ Ret = RE->evaluateAsConstant(Imm);
+ VK = RE->getKind();
+ } else if (auto CE = dyn_cast<MCConstantExpr>(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<N-1, 1>(Op).
+ template <int N> 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<N - 1, 1>(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<MCSymbolRefExpr>(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<MCSymbolRefExpr>(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 << "<register x";
+ OS << getReg() << ">";
+ break;
+ case Token:
+ OS << "'" << getToken() << "'";
+ break;
+ }
+ }
+
+ static std::unique_ptr<RISCVOperand> createToken(StringRef Str, SMLoc S,
+ bool IsRV64) {
+ auto Op = make_unique<RISCVOperand>(Token);
+ Op->Tok = Str;
+ Op->StartLoc = S;
+ Op->EndLoc = S;
+ Op->IsRV64 = IsRV64;
+ return Op;
+ }
+
+ static std::unique_ptr<RISCVOperand> createReg(unsigned RegNo, SMLoc S,
+ SMLoc E, bool IsRV64) {
+ auto Op = make_unique<RISCVOperand>(Register);
+ Op->Reg.RegNum = RegNo;
+ Op->StartLoc = S;
+ Op->EndLoc = E;
+ Op->IsRV64 = IsRV64;
+ return Op;
+ }
+
+ static std::unique_ptr<RISCVOperand> createImm(const MCExpr *Val, SMLoc S,
+ SMLoc E, bool IsRV64) {
+ auto Op = make_unique<RISCVOperand>(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<RISCVMCExpr>(Expr)) {
+ IsConstant = RE->evaluateAsConstant(Imm);
+ } else if (auto *CE = dyn_cast<MCConstantExpr>(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<MCSymbolRefExpr>(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<MCSymbolRefExpr>(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<RISCVOperand &>(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<RISCVMCExpr>(Expr)) {
+ Kind = RE->getKind();
+ Expr = RE->getSubExpr();
+ }
+
+ // It's a simple symbol reference or constant with no addend.
+ if (isa<MCConstantExpr>(Expr) || isa<MCSymbolRefExpr>(Expr))
+ return true;
+
+ const MCBinaryExpr *BE = dyn_cast<MCBinaryExpr>(Expr);
+ if (!BE)
+ return false;
+
+ if (!isa<MCSymbolRefExpr>(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<MCSymbolRefExpr>(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<MCConstantExpr>(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<RISCVAsmParser> X(getTheRISCV32Target());
+ RegisterMCAsmParser<RISCVAsmParser> Y(getTheRISCV64Target());
+}