aboutsummaryrefslogtreecommitdiff
path: root/lib/Target/Lanai/AsmParser/LanaiAsmParser.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Target/Lanai/AsmParser/LanaiAsmParser.cpp')
-rw-r--r--lib/Target/Lanai/AsmParser/LanaiAsmParser.cpp1213
1 files changed, 1213 insertions, 0 deletions
diff --git a/lib/Target/Lanai/AsmParser/LanaiAsmParser.cpp b/lib/Target/Lanai/AsmParser/LanaiAsmParser.cpp
new file mode 100644
index 000000000000..cbb96d8b05b2
--- /dev/null
+++ b/lib/Target/Lanai/AsmParser/LanaiAsmParser.cpp
@@ -0,0 +1,1213 @@
+//===-- LanaiAsmParser.cpp - Parse Lanai 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 "Lanai.h"
+#include "MCTargetDesc/LanaiMCExpr.h"
+#include "MCTargetDesc/LanaiMCTargetDesc.h"
+#include "llvm/ADT/STLExtras.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/MCStreamer.h"
+#include "llvm/MC/MCSubtargetInfo.h"
+#include "llvm/MC/MCSymbol.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/TargetRegistry.h"
+
+namespace llvm {
+namespace {
+struct LanaiOperand;
+
+class LanaiAsmParser : public MCTargetAsmParser {
+ // Parse operands
+ std::unique_ptr<LanaiOperand> parseRegister();
+
+ std::unique_ptr<LanaiOperand> parseImmediate();
+
+ std::unique_ptr<LanaiOperand> parseIdentifier();
+
+ unsigned parseAluOperator(bool PreOp, bool PostOp);
+
+ // Split the mnemonic stripping conditional code and quantifiers
+ StringRef splitMnemonic(StringRef Name, SMLoc NameLoc,
+ OperandVector *Operands);
+
+ bool parsePrePost(StringRef Type, int *OffsetValue);
+
+ bool ParseDirective(AsmToken DirectiveID) override;
+
+ bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
+ SMLoc NameLoc, OperandVector &Operands) override;
+
+ bool ParseRegister(unsigned &RegNum, SMLoc &StartLoc, SMLoc &EndLoc) override;
+
+ bool MatchAndEmitInstruction(SMLoc IdLoc, unsigned &Opcode,
+ OperandVector &Operands, MCStreamer &Out,
+ uint64_t &ErrorInfo,
+ bool MatchingInlineAsm) override;
+
+// Auto-generated instruction matching functions
+#define GET_ASSEMBLER_HEADER
+#include "LanaiGenAsmMatcher.inc"
+
+ OperandMatchResultTy parseOperand(OperandVector *Operands,
+ StringRef Mnemonic);
+
+ OperandMatchResultTy parseMemoryOperand(OperandVector &Operands);
+
+public:
+ LanaiAsmParser(const MCSubtargetInfo &STI, MCAsmParser &Parser,
+ const MCInstrInfo &MII, const MCTargetOptions &Options)
+ : MCTargetAsmParser(Options, STI), Parser(Parser),
+ Lexer(Parser.getLexer()), SubtargetInfo(STI) {
+ setAvailableFeatures(
+ ComputeAvailableFeatures(SubtargetInfo.getFeatureBits()));
+ }
+
+private:
+ MCAsmParser &Parser;
+ MCAsmLexer &Lexer;
+
+ const MCSubtargetInfo &SubtargetInfo;
+};
+
+// Auto-generated by TableGen
+static unsigned MatchRegisterName(llvm::StringRef Name);
+
+// LanaiOperand - Instances of this class represented a parsed machine
+// instruction
+struct LanaiOperand : public MCParsedAsmOperand {
+ enum KindTy {
+ TOKEN,
+ REGISTER,
+ IMMEDIATE,
+ MEMORY_IMM,
+ MEMORY_REG_IMM,
+ MEMORY_REG_REG,
+ } Kind;
+
+ SMLoc StartLoc, EndLoc;
+
+ struct Token {
+ const char *Data;
+ unsigned Length;
+ };
+
+ struct RegOp {
+ unsigned RegNum;
+ };
+
+ struct ImmOp {
+ const MCExpr *Value;
+ };
+
+ struct MemOp {
+ unsigned BaseReg;
+ unsigned OffsetReg;
+ unsigned AluOp;
+ const MCExpr *Offset;
+ };
+
+ union {
+ struct Token Tok;
+ struct RegOp Reg;
+ struct ImmOp Imm;
+ struct MemOp Mem;
+ };
+
+ explicit LanaiOperand(KindTy Kind) : MCParsedAsmOperand(), Kind(Kind) {}
+
+public:
+ // The functions below are used by the autogenerated ASM matcher and hence to
+ // be of the form expected.
+
+ // 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; }
+
+ unsigned getReg() const override {
+ assert(isReg() && "Invalid type access!");
+ return Reg.RegNum;
+ }
+
+ const MCExpr *getImm() const {
+ assert(isImm() && "Invalid type access!");
+ return Imm.Value;
+ }
+
+ StringRef getToken() const {
+ assert(isToken() && "Invalid type access!");
+ return StringRef(Tok.Data, Tok.Length);
+ }
+
+ unsigned getMemBaseReg() const {
+ assert(isMem() && "Invalid type access!");
+ return Mem.BaseReg;
+ }
+
+ unsigned getMemOffsetReg() const {
+ assert(isMem() && "Invalid type access!");
+ return Mem.OffsetReg;
+ }
+
+ const MCExpr *getMemOffset() const {
+ assert(isMem() && "Invalid type access!");
+ return Mem.Offset;
+ }
+
+ unsigned getMemOp() const {
+ assert(isMem() && "Invalid type access!");
+ return Mem.AluOp;
+ }
+
+ // Functions for testing operand type
+ bool isReg() const override { return Kind == REGISTER; }
+
+ bool isImm() const override { return Kind == IMMEDIATE; }
+
+ bool isMem() const override {
+ return isMemImm() || isMemRegImm() || isMemRegReg();
+ }
+
+ bool isMemImm() const { return Kind == MEMORY_IMM; }
+
+ bool isMemRegImm() const { return Kind == MEMORY_REG_IMM; }
+
+ bool isMemRegReg() const { return Kind == MEMORY_REG_REG; }
+
+ bool isMemSpls() const { return isMemRegImm() || isMemRegReg(); }
+
+ bool isToken() const override { return Kind == TOKEN; }
+
+ bool isBrImm() {
+ if (!isImm())
+ return false;
+
+ // Constant case
+ const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(Imm.Value);
+ if (!MCE)
+ return true;
+ int64_t Value = MCE->getValue();
+ // Check if value fits in 25 bits with 2 least significant bits 0.
+ return isShiftedUInt<23, 2>(static_cast<int32_t>(Value));
+ }
+
+ bool isBrTarget() { return isBrImm() || isToken(); }
+
+ bool isCallTarget() { return isImm() || isToken(); }
+
+ bool isHiImm16() {
+ if (!isImm())
+ return false;
+
+ // Constant case
+ if (const MCConstantExpr *ConstExpr = dyn_cast<MCConstantExpr>(Imm.Value)) {
+ int64_t Value = ConstExpr->getValue();
+ return Value != 0 && isShiftedUInt<16, 16>(Value);
+ }
+
+ // Symbolic reference expression
+ if (const LanaiMCExpr *SymbolRefExpr = dyn_cast<LanaiMCExpr>(Imm.Value))
+ return SymbolRefExpr->getKind() == LanaiMCExpr::VK_Lanai_ABS_HI;
+
+ // Binary expression
+ if (const MCBinaryExpr *BinaryExpr = dyn_cast<MCBinaryExpr>(Imm.Value))
+ if (const LanaiMCExpr *SymbolRefExpr =
+ dyn_cast<LanaiMCExpr>(BinaryExpr->getLHS()))
+ return SymbolRefExpr->getKind() == LanaiMCExpr::VK_Lanai_ABS_HI;
+
+ return false;
+ }
+
+ bool isHiImm16And() {
+ if (!isImm())
+ return false;
+
+ const MCConstantExpr *ConstExpr = dyn_cast<MCConstantExpr>(Imm.Value);
+ if (ConstExpr) {
+ int64_t Value = ConstExpr->getValue();
+ // Check if in the form 0xXYZWffff
+ return (Value != 0) && ((Value & ~0xffff0000) == 0xffff);
+ }
+ return false;
+ }
+
+ bool isLoImm16() {
+ if (!isImm())
+ return false;
+
+ // Constant case
+ if (const MCConstantExpr *ConstExpr = dyn_cast<MCConstantExpr>(Imm.Value)) {
+ int64_t Value = ConstExpr->getValue();
+ // Check if value fits in 16 bits
+ return isUInt<16>(static_cast<int32_t>(Value));
+ }
+
+ // Symbolic reference expression
+ if (const LanaiMCExpr *SymbolRefExpr = dyn_cast<LanaiMCExpr>(Imm.Value))
+ return SymbolRefExpr->getKind() == LanaiMCExpr::VK_Lanai_ABS_LO;
+
+ // Binary expression
+ if (const MCBinaryExpr *BinaryExpr = dyn_cast<MCBinaryExpr>(Imm.Value))
+ if (const LanaiMCExpr *SymbolRefExpr =
+ dyn_cast<LanaiMCExpr>(BinaryExpr->getLHS()))
+ return SymbolRefExpr->getKind() == LanaiMCExpr::VK_Lanai_ABS_LO;
+
+ return false;
+ }
+
+ bool isLoImm16Signed() {
+ if (!isImm())
+ return false;
+
+ // Constant case
+ if (const MCConstantExpr *ConstExpr = dyn_cast<MCConstantExpr>(Imm.Value)) {
+ int64_t Value = ConstExpr->getValue();
+ // Check if value fits in 16 bits or value of the form 0xffffxyzw
+ return isInt<16>(static_cast<int32_t>(Value));
+ }
+
+ // Symbolic reference expression
+ if (const LanaiMCExpr *SymbolRefExpr = dyn_cast<LanaiMCExpr>(Imm.Value))
+ return SymbolRefExpr->getKind() == LanaiMCExpr::VK_Lanai_ABS_LO;
+
+ // Binary expression
+ if (const MCBinaryExpr *BinaryExpr = dyn_cast<MCBinaryExpr>(Imm.Value))
+ if (const LanaiMCExpr *SymbolRefExpr =
+ dyn_cast<LanaiMCExpr>(BinaryExpr->getLHS()))
+ return SymbolRefExpr->getKind() == LanaiMCExpr::VK_Lanai_ABS_LO;
+
+ return false;
+ }
+
+ bool isLoImm16And() {
+ if (!isImm())
+ return false;
+
+ const MCConstantExpr *ConstExpr = dyn_cast<MCConstantExpr>(Imm.Value);
+ if (ConstExpr) {
+ int64_t Value = ConstExpr->getValue();
+ // Check if in the form 0xffffXYZW
+ return ((Value & ~0xffff) == 0xffff0000);
+ }
+ return false;
+ }
+
+ bool isImmShift() {
+ if (!isImm())
+ return false;
+
+ const MCConstantExpr *ConstExpr = dyn_cast<MCConstantExpr>(Imm.Value);
+ if (!ConstExpr)
+ return false;
+ int64_t Value = ConstExpr->getValue();
+ return (Value >= -31) && (Value <= 31);
+ }
+
+ bool isLoImm21() {
+ if (!isImm())
+ return false;
+
+ // Constant case
+ if (const MCConstantExpr *ConstExpr = dyn_cast<MCConstantExpr>(Imm.Value)) {
+ int64_t Value = ConstExpr->getValue();
+ return isUInt<21>(Value);
+ }
+
+ // Symbolic reference expression
+ if (const LanaiMCExpr *SymbolRefExpr = dyn_cast<LanaiMCExpr>(Imm.Value))
+ return SymbolRefExpr->getKind() == LanaiMCExpr::VK_Lanai_None;
+ if (const MCSymbolRefExpr *SymbolRefExpr =
+ dyn_cast<MCSymbolRefExpr>(Imm.Value)) {
+ return SymbolRefExpr->getKind() == MCSymbolRefExpr::VK_None;
+ }
+
+ // Binary expression
+ if (const MCBinaryExpr *BinaryExpr = dyn_cast<MCBinaryExpr>(Imm.Value)) {
+ if (const LanaiMCExpr *SymbolRefExpr =
+ dyn_cast<LanaiMCExpr>(BinaryExpr->getLHS()))
+ return SymbolRefExpr->getKind() == LanaiMCExpr::VK_Lanai_None;
+ if (const MCSymbolRefExpr *SymbolRefExpr =
+ dyn_cast<MCSymbolRefExpr>(BinaryExpr->getLHS()))
+ return SymbolRefExpr->getKind() == MCSymbolRefExpr::VK_None;
+ }
+
+ return false;
+ }
+
+ bool isImm10() {
+ if (!isImm())
+ return false;
+
+ const MCConstantExpr *ConstExpr = dyn_cast<MCConstantExpr>(Imm.Value);
+ if (!ConstExpr)
+ return false;
+ int64_t Value = ConstExpr->getValue();
+ return isInt<10>(Value);
+ }
+
+ bool isCondCode() {
+ if (!isImm())
+ return false;
+
+ const MCConstantExpr *ConstExpr = dyn_cast<MCConstantExpr>(Imm.Value);
+ if (!ConstExpr)
+ return false;
+ uint64_t Value = ConstExpr->getValue();
+ // The condition codes are between 0 (ICC_T) and 15 (ICC_LE). If the
+ // unsigned value of the immediate is less than LPCC::UNKNOWN (16) then
+ // value corresponds to a valid condition code.
+ return Value < LPCC::UNKNOWN;
+ }
+
+ void addExpr(MCInst &Inst, const MCExpr *Expr) const {
+ // Add as immediates where possible. Null MCExpr = 0
+ if (Expr == nullptr)
+ Inst.addOperand(MCOperand::createImm(0));
+ else if (const MCConstantExpr *ConstExpr = dyn_cast<MCConstantExpr>(Expr))
+ Inst.addOperand(
+ MCOperand::createImm(static_cast<int32_t>(ConstExpr->getValue())));
+ else
+ Inst.addOperand(MCOperand::createExpr(Expr));
+ }
+
+ 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 addBrTargetOperands(MCInst &Inst, unsigned N) const {
+ assert(N == 1 && "Invalid number of operands!");
+ addExpr(Inst, getImm());
+ }
+
+ void addCallTargetOperands(MCInst &Inst, unsigned N) const {
+ assert(N == 1 && "Invalid number of operands!");
+ addExpr(Inst, getImm());
+ }
+
+ void addCondCodeOperands(MCInst &Inst, unsigned N) const {
+ assert(N == 1 && "Invalid number of operands!");
+ addExpr(Inst, getImm());
+ }
+
+ void addMemImmOperands(MCInst &Inst, unsigned N) const {
+ assert(N == 1 && "Invalid number of operands!");
+ const MCExpr *Expr = getMemOffset();
+ addExpr(Inst, Expr);
+ }
+
+ void addMemRegImmOperands(MCInst &Inst, unsigned N) const {
+ assert(N == 3 && "Invalid number of operands!");
+ Inst.addOperand(MCOperand::createReg(getMemBaseReg()));
+ const MCExpr *Expr = getMemOffset();
+ addExpr(Inst, Expr);
+ Inst.addOperand(MCOperand::createImm(getMemOp()));
+ }
+
+ void addMemRegRegOperands(MCInst &Inst, unsigned N) const {
+ assert(N == 3 && "Invalid number of operands!");
+ Inst.addOperand(MCOperand::createReg(getMemBaseReg()));
+ assert(getMemOffsetReg() != 0 && "Invalid offset");
+ Inst.addOperand(MCOperand::createReg(getMemOffsetReg()));
+ Inst.addOperand(MCOperand::createImm(getMemOp()));
+ }
+
+ void addMemSplsOperands(MCInst &Inst, unsigned N) const {
+ if (isMemRegImm())
+ addMemRegImmOperands(Inst, N);
+ if (isMemRegReg())
+ addMemRegRegOperands(Inst, N);
+ }
+
+ void addImmShiftOperands(MCInst &Inst, unsigned N) const {
+ assert(N == 1 && "Invalid number of operands!");
+ addExpr(Inst, getImm());
+ }
+
+ void addImm10Operands(MCInst &Inst, unsigned N) const {
+ assert(N == 1 && "Invalid number of operands!");
+ addExpr(Inst, getImm());
+ }
+
+ void addLoImm16Operands(MCInst &Inst, unsigned N) const {
+ assert(N == 1 && "Invalid number of operands!");
+ if (const MCConstantExpr *ConstExpr = dyn_cast<MCConstantExpr>(getImm()))
+ Inst.addOperand(
+ MCOperand::createImm(static_cast<int32_t>(ConstExpr->getValue())));
+ else if (isa<LanaiMCExpr>(getImm())) {
+#ifndef NDEBUG
+ const LanaiMCExpr *SymbolRefExpr = dyn_cast<LanaiMCExpr>(getImm());
+ assert(SymbolRefExpr->getKind() == LanaiMCExpr::VK_Lanai_ABS_LO);
+#endif
+ Inst.addOperand(MCOperand::createExpr(getImm()));
+ } else if (isa<MCBinaryExpr>(getImm())) {
+#ifndef NDEBUG
+ const MCBinaryExpr *BinaryExpr = dyn_cast<MCBinaryExpr>(getImm());
+ assert(dyn_cast<LanaiMCExpr>(BinaryExpr->getLHS()) &&
+ dyn_cast<LanaiMCExpr>(BinaryExpr->getLHS())->getKind() ==
+ LanaiMCExpr::VK_Lanai_ABS_LO);
+#endif
+ Inst.addOperand(MCOperand::createExpr(getImm()));
+ } else
+ assert(false && "Operand type not supported.");
+ }
+
+ void addLoImm16AndOperands(MCInst &Inst, unsigned N) const {
+ assert(N == 1 && "Invalid number of operands!");
+ if (const MCConstantExpr *ConstExpr = dyn_cast<MCConstantExpr>(getImm()))
+ Inst.addOperand(MCOperand::createImm(ConstExpr->getValue() & 0xffff));
+ else
+ assert(false && "Operand type not supported.");
+ }
+
+ void addHiImm16Operands(MCInst &Inst, unsigned N) const {
+ assert(N == 1 && "Invalid number of operands!");
+ if (const MCConstantExpr *ConstExpr = dyn_cast<MCConstantExpr>(getImm()))
+ Inst.addOperand(MCOperand::createImm(ConstExpr->getValue() >> 16));
+ else if (isa<LanaiMCExpr>(getImm())) {
+#ifndef NDEBUG
+ const LanaiMCExpr *SymbolRefExpr = dyn_cast<LanaiMCExpr>(getImm());
+ assert(SymbolRefExpr->getKind() == LanaiMCExpr::VK_Lanai_ABS_HI);
+#endif
+ Inst.addOperand(MCOperand::createExpr(getImm()));
+ } else if (isa<MCBinaryExpr>(getImm())) {
+#ifndef NDEBUG
+ const MCBinaryExpr *BinaryExpr = dyn_cast<MCBinaryExpr>(getImm());
+ assert(dyn_cast<LanaiMCExpr>(BinaryExpr->getLHS()) &&
+ dyn_cast<LanaiMCExpr>(BinaryExpr->getLHS())->getKind() ==
+ LanaiMCExpr::VK_Lanai_ABS_HI);
+#endif
+ Inst.addOperand(MCOperand::createExpr(getImm()));
+ } else
+ assert(false && "Operand type not supported.");
+ }
+
+ void addHiImm16AndOperands(MCInst &Inst, unsigned N) const {
+ assert(N == 1 && "Invalid number of operands!");
+ if (const MCConstantExpr *ConstExpr = dyn_cast<MCConstantExpr>(getImm()))
+ Inst.addOperand(MCOperand::createImm(ConstExpr->getValue() >> 16));
+ else
+ assert(false && "Operand type not supported.");
+ }
+
+ void addLoImm21Operands(MCInst &Inst, unsigned N) const {
+ assert(N == 1 && "Invalid number of operands!");
+ if (const MCConstantExpr *ConstExpr = dyn_cast<MCConstantExpr>(getImm()))
+ Inst.addOperand(MCOperand::createImm(ConstExpr->getValue() & 0x1fffff));
+ else if (isa<LanaiMCExpr>(getImm())) {
+#ifndef NDEBUG
+ const LanaiMCExpr *SymbolRefExpr = dyn_cast<LanaiMCExpr>(getImm());
+ assert(SymbolRefExpr &&
+ SymbolRefExpr->getKind() == LanaiMCExpr::VK_Lanai_None);
+#endif
+ Inst.addOperand(MCOperand::createExpr(getImm()));
+ } else if (isa<MCSymbolRefExpr>(getImm())) {
+#ifndef NDEBUG
+ const MCSymbolRefExpr *SymbolRefExpr =
+ dyn_cast<MCSymbolRefExpr>(getImm());
+ assert(SymbolRefExpr &&
+ SymbolRefExpr->getKind() == MCSymbolRefExpr::VK_None);
+#endif
+ Inst.addOperand(MCOperand::createExpr(getImm()));
+ } else if (isa<MCBinaryExpr>(getImm())) {
+#ifndef NDEBUG
+ const MCBinaryExpr *BinaryExpr = dyn_cast<MCBinaryExpr>(getImm());
+ const LanaiMCExpr *SymbolRefExpr =
+ dyn_cast<LanaiMCExpr>(BinaryExpr->getLHS());
+ assert(SymbolRefExpr &&
+ SymbolRefExpr->getKind() == LanaiMCExpr::VK_Lanai_None);
+#endif
+ Inst.addOperand(MCOperand::createExpr(getImm()));
+ } else
+ assert(false && "Operand type not supported.");
+ }
+
+ void print(raw_ostream &OS) const override {
+ switch (Kind) {
+ case IMMEDIATE:
+ OS << "Imm: " << getImm() << "\n";
+ break;
+ case TOKEN:
+ OS << "Token: " << getToken() << "\n";
+ break;
+ case REGISTER:
+ OS << "Reg: %r" << getReg() << "\n";
+ break;
+ case MEMORY_IMM:
+ OS << "MemImm: " << *getMemOffset() << "\n";
+ break;
+ case MEMORY_REG_IMM:
+ OS << "MemRegImm: " << getMemBaseReg() << "+" << *getMemOffset() << "\n";
+ break;
+ case MEMORY_REG_REG:
+ assert(getMemOffset() == nullptr);
+ OS << "MemRegReg: " << getMemBaseReg() << "+"
+ << "%r" << getMemOffsetReg() << "\n";
+ break;
+ }
+ }
+
+ static std::unique_ptr<LanaiOperand> CreateToken(StringRef Str, SMLoc Start) {
+ auto Op = make_unique<LanaiOperand>(TOKEN);
+ Op->Tok.Data = Str.data();
+ Op->Tok.Length = Str.size();
+ Op->StartLoc = Start;
+ Op->EndLoc = Start;
+ return Op;
+ }
+
+ static std::unique_ptr<LanaiOperand> createReg(unsigned RegNum, SMLoc Start,
+ SMLoc End) {
+ auto Op = make_unique<LanaiOperand>(REGISTER);
+ Op->Reg.RegNum = RegNum;
+ Op->StartLoc = Start;
+ Op->EndLoc = End;
+ return Op;
+ }
+
+ static std::unique_ptr<LanaiOperand> createImm(const MCExpr *Value,
+ SMLoc Start, SMLoc End) {
+ auto Op = make_unique<LanaiOperand>(IMMEDIATE);
+ Op->Imm.Value = Value;
+ Op->StartLoc = Start;
+ Op->EndLoc = End;
+ return Op;
+ }
+
+ static std::unique_ptr<LanaiOperand>
+ MorphToMemImm(std::unique_ptr<LanaiOperand> Op) {
+ const MCExpr *Imm = Op->getImm();
+ Op->Kind = MEMORY_IMM;
+ Op->Mem.BaseReg = 0;
+ Op->Mem.AluOp = LPAC::ADD;
+ Op->Mem.OffsetReg = 0;
+ Op->Mem.Offset = Imm;
+ return Op;
+ }
+
+ static std::unique_ptr<LanaiOperand>
+ MorphToMemRegReg(unsigned BaseReg, std::unique_ptr<LanaiOperand> Op,
+ unsigned AluOp) {
+ unsigned OffsetReg = Op->getReg();
+ Op->Kind = MEMORY_REG_REG;
+ Op->Mem.BaseReg = BaseReg;
+ Op->Mem.AluOp = AluOp;
+ Op->Mem.OffsetReg = OffsetReg;
+ Op->Mem.Offset = nullptr;
+ return Op;
+ }
+
+ static std::unique_ptr<LanaiOperand>
+ MorphToMemRegImm(unsigned BaseReg, std::unique_ptr<LanaiOperand> Op,
+ unsigned AluOp) {
+ const MCExpr *Imm = Op->getImm();
+ Op->Kind = MEMORY_REG_IMM;
+ Op->Mem.BaseReg = BaseReg;
+ Op->Mem.AluOp = AluOp;
+ Op->Mem.OffsetReg = 0;
+ Op->Mem.Offset = Imm;
+ return Op;
+ }
+};
+
+bool LanaiAsmParser::ParseDirective(AsmToken /*DirectiveId*/) { return true; }
+
+bool LanaiAsmParser::MatchAndEmitInstruction(SMLoc IdLoc, unsigned &Opcode,
+ OperandVector &Operands,
+ MCStreamer &Out,
+ uint64_t &ErrorInfo,
+ bool MatchingInlineAsm) {
+ MCInst Inst;
+ SMLoc ErrorLoc;
+
+ switch (MatchInstructionImpl(Operands, Inst, ErrorInfo, MatchingInlineAsm)) {
+ case Match_Success:
+ Out.EmitInstruction(Inst, SubtargetInfo);
+ Opcode = Inst.getOpcode();
+ return false;
+ case Match_MissingFeature:
+ return Error(IdLoc, "Instruction use requires option to be enabled");
+ case Match_MnemonicFail:
+ return Error(IdLoc, "Unrecognized instruction mnemonic");
+ case Match_InvalidOperand: {
+ ErrorLoc = IdLoc;
+ if (ErrorInfo != ~0U) {
+ if (ErrorInfo >= Operands.size())
+ return Error(IdLoc, "Too few operands for instruction");
+
+ ErrorLoc = ((LanaiOperand &)*Operands[ErrorInfo]).getStartLoc();
+ if (ErrorLoc == SMLoc())
+ ErrorLoc = IdLoc;
+ }
+ return Error(ErrorLoc, "Invalid operand for instruction");
+ }
+ default:
+ break;
+ }
+
+ llvm_unreachable("Unknown match type detected!");
+}
+
+// Both '%rN' and 'rN' are parsed as valid registers. This was done to remain
+// backwards compatible with GCC and the different ways inline assembly is
+// handled.
+// TODO: see if there isn't a better way to do this.
+std::unique_ptr<LanaiOperand> LanaiAsmParser::parseRegister() {
+ SMLoc Start = Parser.getTok().getLoc();
+ SMLoc End = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);
+
+ unsigned RegNum;
+ // Eat the '%'.
+ if (Lexer.getKind() == AsmToken::Percent)
+ Parser.Lex();
+ if (Lexer.getKind() == AsmToken::Identifier) {
+ RegNum = MatchRegisterName(Lexer.getTok().getIdentifier());
+ if (RegNum == 0)
+ return 0;
+ Parser.Lex(); // Eat identifier token
+ return LanaiOperand::createReg(RegNum, Start, End);
+ }
+ return 0;
+}
+
+bool LanaiAsmParser::ParseRegister(unsigned &RegNum, SMLoc &StartLoc,
+ SMLoc &EndLoc) {
+ const AsmToken &Tok = getParser().getTok();
+ StartLoc = Tok.getLoc();
+ EndLoc = Tok.getEndLoc();
+ std::unique_ptr<LanaiOperand> Op = parseRegister();
+ if (Op != nullptr)
+ RegNum = Op->getReg();
+ return (Op == nullptr);
+}
+
+std::unique_ptr<LanaiOperand> LanaiAsmParser::parseIdentifier() {
+ SMLoc Start = Parser.getTok().getLoc();
+ SMLoc End = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);
+ const MCExpr *Res, *RHS = 0;
+ LanaiMCExpr::VariantKind Kind = LanaiMCExpr::VK_Lanai_None;
+
+ if (Lexer.getKind() != AsmToken::Identifier)
+ return 0;
+
+ StringRef Identifier;
+ if (Parser.parseIdentifier(Identifier))
+ return 0;
+
+ // Check if identifier has a modifier
+ if (Identifier.equals_lower("hi"))
+ Kind = LanaiMCExpr::VK_Lanai_ABS_HI;
+ else if (Identifier.equals_lower("lo"))
+ Kind = LanaiMCExpr::VK_Lanai_ABS_LO;
+
+ // If the identifier corresponds to a variant then extract the real
+ // identifier.
+ if (Kind != LanaiMCExpr::VK_Lanai_None) {
+ if (Lexer.getKind() != AsmToken::LParen) {
+ Error(Lexer.getLoc(), "Expected '('");
+ return 0;
+ }
+ Lexer.Lex(); // lex '('
+
+ // Parse identifier
+ if (Parser.parseIdentifier(Identifier))
+ return 0;
+ }
+
+ // If addition parse the RHS.
+ if (Lexer.getKind() == AsmToken::Plus && Parser.parseExpression(RHS))
+ return 0;
+
+ // For variants parse the final ')'
+ if (Kind != LanaiMCExpr::VK_Lanai_None) {
+ if (Lexer.getKind() != AsmToken::RParen) {
+ Error(Lexer.getLoc(), "Expected ')'");
+ return 0;
+ }
+ Lexer.Lex(); // lex ')'
+ }
+
+ End = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);
+ MCSymbol *Sym = getContext().getOrCreateSymbol(Identifier);
+ const MCExpr *Expr = MCSymbolRefExpr::create(Sym, getContext());
+ Res = LanaiMCExpr::create(Kind, Expr, getContext());
+
+ // Nest if this was an addition
+ if (RHS)
+ Res = MCBinaryExpr::createAdd(Res, RHS, getContext());
+
+ return LanaiOperand::createImm(Res, Start, End);
+}
+
+std::unique_ptr<LanaiOperand> LanaiAsmParser::parseImmediate() {
+ SMLoc Start = Parser.getTok().getLoc();
+ SMLoc End = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);
+
+ const MCExpr *ExprVal;
+ switch (Lexer.getKind()) {
+ case AsmToken::Identifier:
+ return parseIdentifier();
+ case AsmToken::Plus:
+ case AsmToken::Minus:
+ case AsmToken::Integer:
+ case AsmToken::Dot:
+ if (!Parser.parseExpression(ExprVal))
+ return LanaiOperand::createImm(ExprVal, Start, End);
+ default:
+ return 0;
+ }
+}
+
+static unsigned AluWithPrePost(unsigned AluCode, bool PreOp, bool PostOp) {
+ if (PreOp)
+ return LPAC::makePreOp(AluCode);
+ if (PostOp)
+ return LPAC::makePostOp(AluCode);
+ return AluCode;
+}
+
+unsigned LanaiAsmParser::parseAluOperator(bool PreOp, bool PostOp) {
+ StringRef IdString;
+ Parser.parseIdentifier(IdString);
+ unsigned AluCode = LPAC::stringToLanaiAluCode(IdString);
+ if (AluCode == LPAC::UNKNOWN) {
+ Error(Parser.getTok().getLoc(), "Can't parse ALU operator");
+ return 0;
+ }
+ return AluCode;
+}
+
+static int SizeForSuffix(StringRef T) {
+ return StringSwitch<int>(T).EndsWith(".h", 2).EndsWith(".b", 1).Default(4);
+}
+
+bool LanaiAsmParser::parsePrePost(StringRef Type, int *OffsetValue) {
+ bool PreOrPost = false;
+ if (Lexer.getKind() == Lexer.peekTok(true).getKind()) {
+ PreOrPost = true;
+ if (Lexer.is(AsmToken::Minus))
+ *OffsetValue = -SizeForSuffix(Type);
+ else if (Lexer.is(AsmToken::Plus))
+ *OffsetValue = SizeForSuffix(Type);
+ else
+ return false;
+
+ // Eat the '-' '-' or '+' '+'
+ Parser.Lex();
+ Parser.Lex();
+ } else if (Lexer.is(AsmToken::Star)) {
+ Parser.Lex(); // Eat the '*'
+ PreOrPost = true;
+ }
+
+ return PreOrPost;
+}
+
+bool shouldBeSls(const LanaiOperand &Op) {
+ // The instruction should be encoded as an SLS if the constant is word
+ // aligned and will fit in 21 bits
+ if (const MCConstantExpr *ConstExpr = dyn_cast<MCConstantExpr>(Op.getImm())) {
+ int64_t Value = ConstExpr->getValue();
+ return (Value % 4 == 0) && (Value >= 0) && (Value <= 0x1fffff);
+ }
+ // The instruction should be encoded as an SLS if the operand is a symbolic
+ // reference with no variant.
+ if (const LanaiMCExpr *SymbolRefExpr = dyn_cast<LanaiMCExpr>(Op.getImm()))
+ return SymbolRefExpr->getKind() == LanaiMCExpr::VK_Lanai_None;
+ // The instruction should be encoded as an SLS if the operand is a binary
+ // expression with the left-hand side being a symbolic reference with no
+ // variant.
+ if (const MCBinaryExpr *BinaryExpr = dyn_cast<MCBinaryExpr>(Op.getImm())) {
+ const LanaiMCExpr *LHSSymbolRefExpr =
+ dyn_cast<LanaiMCExpr>(BinaryExpr->getLHS());
+ return (LHSSymbolRefExpr &&
+ LHSSymbolRefExpr->getKind() == LanaiMCExpr::VK_Lanai_None);
+ }
+ return false;
+}
+
+// Matches memory operand. Returns true if error encountered.
+LanaiAsmParser::OperandMatchResultTy
+LanaiAsmParser::parseMemoryOperand(OperandVector &Operands) {
+ // Try to match a memory operand.
+ // The memory operands are of the form:
+ // (1) Register|Immediate|'' '[' '*'? Register '*'? ']' or
+ // ^
+ // (2) '[' '*'? Register '*'? AluOperator Register ']'
+ // ^
+ // (3) '[' '--'|'++' Register '--'|'++' ']'
+ //
+ // (4) '[' Immediate ']' (for SLS)
+
+ // Store the type for use in parsing pre/post increment/decrement operators
+ StringRef Type;
+ if (Operands[0]->isToken())
+ Type = static_cast<LanaiOperand *>(Operands[0].get())->getToken();
+
+ // Use 0 if no offset given
+ int OffsetValue = 0;
+ unsigned BaseReg = 0;
+ unsigned AluOp = LPAC::ADD;
+ bool PostOp = false, PreOp = false;
+
+ // Try to parse the offset
+ std::unique_ptr<LanaiOperand> Op = parseRegister();
+ if (!Op)
+ Op = parseImmediate();
+
+ // Only continue if next token is '['
+ if (Lexer.isNot(AsmToken::LBrac)) {
+ if (!Op)
+ return MatchOperand_NoMatch;
+
+ // The start of this custom parsing overlaps with register/immediate so
+ // consider this as a successful match of an operand of that type as the
+ // token stream can't be rewound to allow them to match separately.
+ Operands.push_back(std::move(Op));
+ return MatchOperand_Success;
+ }
+
+ Parser.Lex(); // Eat the '['.
+ std::unique_ptr<LanaiOperand> Offset = nullptr;
+ if (Op)
+ Offset.swap(Op);
+
+ // Determine if a pre operation
+ PreOp = parsePrePost(Type, &OffsetValue);
+
+ Op = parseRegister();
+ if (!Op) {
+ if (!Offset) {
+ if ((Op = parseImmediate()) && Lexer.is(AsmToken::RBrac)) {
+ Parser.Lex(); // Eat the ']'
+
+ // Memory address operations aligned to word boundary are encoded as
+ // SLS, the rest as RM.
+ if (shouldBeSls(*Op)) {
+ Operands.push_back(LanaiOperand::MorphToMemImm(std::move(Op)));
+ } else {
+ if (!Op->isLoImm16Signed()) {
+ Error(Parser.getTok().getLoc(),
+ "Memory address is not word "
+ "aligned and larger than class RM can handle");
+ return MatchOperand_ParseFail;
+ }
+ Operands.push_back(LanaiOperand::MorphToMemRegImm(
+ Lanai::R0, std::move(Op), LPAC::ADD));
+ }
+ return MatchOperand_Success;
+ }
+ }
+
+ Error(Parser.getTok().getLoc(),
+ "Unknown operand, expected register or immediate");
+ return MatchOperand_ParseFail;
+ }
+ BaseReg = Op->getReg();
+
+ // Determine if a post operation
+ if (!PreOp)
+ PostOp = parsePrePost(Type, &OffsetValue);
+
+ // If ] match form (1) else match form (2)
+ if (Lexer.is(AsmToken::RBrac)) {
+ Parser.Lex(); // Eat the ']'.
+ if (!Offset) {
+ SMLoc Start = Parser.getTok().getLoc();
+ SMLoc End =
+ SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);
+ const MCConstantExpr *OffsetConstExpr =
+ MCConstantExpr::create(OffsetValue, getContext());
+ Offset = LanaiOperand::createImm(OffsetConstExpr, Start, End);
+ }
+ } else {
+ if (Offset || OffsetValue != 0) {
+ Error(Parser.getTok().getLoc(), "Expected ']'");
+ return MatchOperand_ParseFail;
+ }
+
+ // Parse operator
+ AluOp = parseAluOperator(PreOp, PostOp);
+
+ // Second form requires offset register
+ Offset = parseRegister();
+ if (!BaseReg || Lexer.isNot(AsmToken::RBrac)) {
+ Error(Parser.getTok().getLoc(), "Expected ']'");
+ return MatchOperand_ParseFail;
+ }
+ Parser.Lex(); // Eat the ']'.
+ }
+
+ // First form has addition as operator. Add pre- or post-op indicator as
+ // needed.
+ AluOp = AluWithPrePost(AluOp, PreOp, PostOp);
+
+ // Ensure immediate offset is not too large
+ if (Offset->isImm() && !Offset->isLoImm16Signed()) {
+ Error(Parser.getTok().getLoc(),
+ "Memory address is not word "
+ "aligned and larger than class RM can handle");
+ return MatchOperand_ParseFail;
+ }
+
+ Operands.push_back(
+ Offset->isImm()
+ ? LanaiOperand::MorphToMemRegImm(BaseReg, std::move(Offset), AluOp)
+ : LanaiOperand::MorphToMemRegReg(BaseReg, std::move(Offset), AluOp));
+
+ 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.
+LanaiAsmParser::OperandMatchResultTy
+LanaiAsmParser::parseOperand(OperandVector *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 Result = MatchOperandParserImpl(*Operands, Mnemonic);
+
+ if (Result == MatchOperand_Success)
+ return Result;
+ if (Result == MatchOperand_ParseFail) {
+ Parser.eatToEndOfStatement();
+ return Result;
+ }
+
+ // Attempt to parse token as register
+ std::unique_ptr<LanaiOperand> Op = parseRegister();
+
+ // Attempt to parse token as immediate
+ if (!Op)
+ Op = parseImmediate();
+
+ // If the token could not be parsed then fail
+ if (!Op) {
+ Error(Parser.getTok().getLoc(), "Unknown operand");
+ Parser.eatToEndOfStatement();
+ return MatchOperand_ParseFail;
+ }
+
+ // Push back parsed operand into list of operands
+ Operands->push_back(std::move(Op));
+
+ return MatchOperand_Success;
+}
+
+// Split the mnemonic into ASM operand, conditional code and instruction
+// qualifier (half-word, byte).
+StringRef LanaiAsmParser::splitMnemonic(StringRef Name, SMLoc NameLoc,
+ OperandVector *Operands) {
+ size_t Next = Name.find('.');
+
+ StringRef Mnemonic = Name;
+
+ bool IsBRR = false;
+ if (Name.endswith(".r")) {
+ Mnemonic = Name.substr(0, Name.size() - 2);
+ IsBRR = true;
+ }
+
+ // Match b?? and s?? (BR, BRR, and SCC instruction classes).
+ if (Mnemonic[0] == 'b' ||
+ (Mnemonic[0] == 's' && !Mnemonic.startswith("sel") &&
+ !Mnemonic.startswith("st"))) {
+ // Parse instructions with a conditional code. For example, 'bne' is
+ // converted into two operands 'b' and 'ne'.
+ LPCC::CondCode CondCode =
+ LPCC::suffixToLanaiCondCode(Mnemonic.substr(1, Next));
+ if (CondCode != LPCC::UNKNOWN) {
+ Mnemonic = Mnemonic.slice(0, 1);
+ Operands->push_back(LanaiOperand::CreateToken(Mnemonic, NameLoc));
+ Operands->push_back(LanaiOperand::createImm(
+ MCConstantExpr::create(CondCode, getContext()), NameLoc, NameLoc));
+ if (IsBRR) {
+ Operands->push_back(LanaiOperand::CreateToken(".r", NameLoc));
+ }
+ return Mnemonic;
+ }
+ }
+
+ // Parse other instructions with condition codes (RR instructions).
+ // We ignore .f here and assume they are flag-setting operations, not
+ // conditional codes (except for select instructions where flag-setting
+ // variants are not yet implemented).
+ if (Mnemonic.startswith("sel") ||
+ (!Mnemonic.endswith(".f") && !Mnemonic.startswith("st"))) {
+ LPCC::CondCode CondCode = LPCC::suffixToLanaiCondCode(Mnemonic);
+ if (CondCode != LPCC::UNKNOWN) {
+ size_t Next = Mnemonic.rfind('.', Name.size());
+ // 'sel' doesn't use a predicate operand whose printer adds the period,
+ // but instead has the period as part of the identifier (i.e., 'sel.' is
+ // expected by the generated matcher). If the mnemonic starts with 'sel'
+ // then include the period as part of the mnemonic, else don't include it
+ // as part of the mnemonic.
+ if (Mnemonic.startswith("sel")) {
+ Mnemonic = Mnemonic.substr(0, Next + 1);
+ } else {
+ Mnemonic = Mnemonic.substr(0, Next);
+ }
+ Operands->push_back(LanaiOperand::CreateToken(Mnemonic, NameLoc));
+ Operands->push_back(LanaiOperand::createImm(
+ MCConstantExpr::create(CondCode, getContext()), NameLoc, NameLoc));
+ return Mnemonic;
+ }
+ }
+
+ Operands->push_back(LanaiOperand::CreateToken(Mnemonic, NameLoc));
+ if (IsBRR) {
+ Operands->push_back(LanaiOperand::CreateToken(".r", NameLoc));
+ }
+
+ return Mnemonic;
+}
+
+bool IsMemoryAssignmentError(const OperandVector &Operands) {
+ // Detects if a memory operation has an erroneous base register modification.
+ // Memory operations are detected by matching the types of operands.
+ //
+ // TODO: This test is focussed on one specific instance (ld/st).
+ // Extend it to handle more cases or be more robust.
+ bool Modifies = false;
+
+ int Offset = 0;
+
+ if (Operands.size() < 5)
+ return false;
+ else if (Operands[0]->isToken() && Operands[1]->isReg() &&
+ Operands[2]->isImm() && Operands[3]->isImm() && Operands[4]->isReg())
+ Offset = 0;
+ else if (Operands[0]->isToken() && Operands[1]->isToken() &&
+ Operands[2]->isReg() && Operands[3]->isImm() &&
+ Operands[4]->isImm() && Operands[5]->isReg())
+ Offset = 1;
+ else
+ return false;
+
+ int PossibleAluOpIdx = Offset + 3;
+ int PossibleBaseIdx = Offset + 1;
+ int PossibleDestIdx = Offset + 4;
+ if (LanaiOperand *PossibleAluOp =
+ static_cast<LanaiOperand *>(Operands[PossibleAluOpIdx].get()))
+ if (PossibleAluOp->isImm())
+ if (const MCConstantExpr *ConstExpr =
+ dyn_cast<MCConstantExpr>(PossibleAluOp->getImm()))
+ Modifies = LPAC::modifiesOp(ConstExpr->getValue());
+ return Modifies && Operands[PossibleBaseIdx]->isReg() &&
+ Operands[PossibleDestIdx]->isReg() &&
+ Operands[PossibleBaseIdx]->getReg() ==
+ Operands[PossibleDestIdx]->getReg();
+}
+
+static bool IsRegister(const MCParsedAsmOperand &op) {
+ return static_cast<const LanaiOperand &>(op).isReg();
+}
+
+static bool MaybePredicatedInst(const OperandVector &Operands) {
+ if (Operands.size() < 4 || !IsRegister(*Operands[1]) ||
+ !IsRegister(*Operands[2]))
+ return false;
+ return StringSwitch<bool>(
+ static_cast<const LanaiOperand &>(*Operands[0]).getToken())
+ .StartsWith("addc", true)
+ .StartsWith("add", true)
+ .StartsWith("and", true)
+ .StartsWith("sh", true)
+ .StartsWith("subb", true)
+ .StartsWith("sub", true)
+ .StartsWith("or", true)
+ .StartsWith("xor", true)
+ .Default(false);
+}
+
+bool LanaiAsmParser::ParseInstruction(ParseInstructionInfo & /*Info*/,
+ StringRef Name, SMLoc NameLoc,
+ OperandVector &Operands) {
+ // First operand is token for instruction
+ StringRef Mnemonic = splitMnemonic(Name, NameLoc, &Operands);
+
+ // If there are no more operands, then finish
+ if (Lexer.is(AsmToken::EndOfStatement))
+ return false;
+
+ // Parse first operand
+ if (parseOperand(&Operands, Mnemonic) != MatchOperand_Success)
+ return true;
+
+ // If it is a st instruction with one 1 operand then it is a "store true".
+ // Transform <"st"> to <"s">, <LPCC:ICC_T>
+ if (Lexer.is(AsmToken::EndOfStatement) && Name == "st" &&
+ Operands.size() == 2) {
+ Operands.erase(Operands.begin(), Operands.begin() + 1);
+ Operands.insert(Operands.begin(), LanaiOperand::CreateToken("s", NameLoc));
+ Operands.insert(Operands.begin() + 1,
+ LanaiOperand::createImm(
+ MCConstantExpr::create(LPCC::ICC_T, getContext()),
+ NameLoc, NameLoc));
+ }
+
+ // If the instruction is a bt instruction with 1 operand (in assembly) then it
+ // is an unconditional branch instruction and the first two elements of
+ // operands need to be merged.
+ if (Lexer.is(AsmToken::EndOfStatement) && Name.startswith("bt") &&
+ Operands.size() == 3) {
+ Operands.erase(Operands.begin(), Operands.begin() + 2);
+ Operands.insert(Operands.begin(), LanaiOperand::CreateToken("bt", NameLoc));
+ }
+
+ // Parse until end of statement, consuming commas between operands
+ while (Lexer.isNot(AsmToken::EndOfStatement) && Lexer.is(AsmToken::Comma)) {
+ // Consume comma token
+ Lex();
+
+ // Parse next operand
+ if (parseOperand(&Operands, Mnemonic) != MatchOperand_Success)
+ return true;
+ }
+
+ if (IsMemoryAssignmentError(Operands)) {
+ Error(Parser.getTok().getLoc(),
+ "the destination register can't equal the base register in an "
+ "instruction that modifies the base register.");
+ return true;
+ }
+
+ // Insert always true operand for instruction that may be predicated but
+ // are not. Currently the autogenerated parser always expects a predicate.
+ if (MaybePredicatedInst(Operands)) {
+ Operands.insert(Operands.begin() + 1,
+ LanaiOperand::createImm(
+ MCConstantExpr::create(LPCC::ICC_T, getContext()),
+ NameLoc, NameLoc));
+ }
+
+ return false;
+}
+
+#define GET_REGISTER_MATCHER
+#define GET_MATCHER_IMPLEMENTATION
+#include "LanaiGenAsmMatcher.inc"
+} // namespace
+
+extern "C" void LLVMInitializeLanaiAsmParser() {
+ RegisterMCAsmParser<LanaiAsmParser> x(TheLanaiTarget);
+}
+
+} // namespace llvm