Path: blob/main/contrib/llvm-project/llvm/lib/Target/Lanai/AsmParser/LanaiAsmParser.cpp
35295 views
//===-- LanaiAsmParser.cpp - Parse Lanai assembly to MCInst instructions --===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "LanaiAluCode.h"9#include "LanaiCondCode.h"10#include "LanaiInstrInfo.h"11#include "MCTargetDesc/LanaiMCExpr.h"12#include "TargetInfo/LanaiTargetInfo.h"13#include "llvm/ADT/STLExtras.h"14#include "llvm/ADT/StringRef.h"15#include "llvm/ADT/StringSwitch.h"16#include "llvm/MC/MCContext.h"17#include "llvm/MC/MCExpr.h"18#include "llvm/MC/MCInst.h"19#include "llvm/MC/MCParser/MCAsmLexer.h"20#include "llvm/MC/MCParser/MCAsmParser.h"21#include "llvm/MC/MCParser/MCParsedAsmOperand.h"22#include "llvm/MC/MCParser/MCTargetAsmParser.h"23#include "llvm/MC/MCStreamer.h"24#include "llvm/MC/MCSubtargetInfo.h"25#include "llvm/MC/MCSymbol.h"26#include "llvm/MC/TargetRegistry.h"27#include "llvm/Support/Casting.h"28#include "llvm/Support/ErrorHandling.h"29#include "llvm/Support/MathExtras.h"30#include "llvm/Support/SMLoc.h"31#include "llvm/Support/raw_ostream.h"32#include <algorithm>33#include <cassert>34#include <cstddef>35#include <cstdint>36#include <memory>37#include <optional>3839using namespace llvm;4041// Auto-generated by TableGen42static MCRegister MatchRegisterName(StringRef Name);4344namespace {4546struct LanaiOperand;4748class LanaiAsmParser : public MCTargetAsmParser {49// Parse operands50std::unique_ptr<LanaiOperand> parseRegister(bool RestoreOnFailure = false);5152std::unique_ptr<LanaiOperand> parseImmediate();5354std::unique_ptr<LanaiOperand> parseIdentifier();5556unsigned parseAluOperator(bool PreOp, bool PostOp);5758// Split the mnemonic stripping conditional code and quantifiers59StringRef splitMnemonic(StringRef Name, SMLoc NameLoc,60OperandVector *Operands);6162bool parsePrePost(StringRef Type, int *OffsetValue);6364bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name,65SMLoc NameLoc, OperandVector &Operands) override;6667bool parseRegister(MCRegister &Reg, SMLoc &StartLoc, SMLoc &EndLoc) override;68ParseStatus tryParseRegister(MCRegister &Reg, SMLoc &StartLoc,69SMLoc &EndLoc) override;7071bool MatchAndEmitInstruction(SMLoc IdLoc, unsigned &Opcode,72OperandVector &Operands, MCStreamer &Out,73uint64_t &ErrorInfo,74bool MatchingInlineAsm) override;7576// Auto-generated instruction matching functions77#define GET_ASSEMBLER_HEADER78#include "LanaiGenAsmMatcher.inc"7980ParseStatus parseOperand(OperandVector *Operands, StringRef Mnemonic);8182ParseStatus parseMemoryOperand(OperandVector &Operands);8384public:85LanaiAsmParser(const MCSubtargetInfo &STI, MCAsmParser &Parser,86const MCInstrInfo &MII, const MCTargetOptions &Options)87: MCTargetAsmParser(Options, STI, MII), Parser(Parser),88Lexer(Parser.getLexer()), SubtargetInfo(STI) {89setAvailableFeatures(90ComputeAvailableFeatures(SubtargetInfo.getFeatureBits()));91}9293private:94MCAsmParser &Parser;95MCAsmLexer &Lexer;9697const MCSubtargetInfo &SubtargetInfo;98};99100// LanaiOperand - Instances of this class represented a parsed machine101// instruction102struct LanaiOperand : public MCParsedAsmOperand {103enum KindTy {104TOKEN,105REGISTER,106IMMEDIATE,107MEMORY_IMM,108MEMORY_REG_IMM,109MEMORY_REG_REG,110} Kind;111112SMLoc StartLoc, EndLoc;113114struct Token {115const char *Data;116unsigned Length;117};118119struct RegOp {120unsigned RegNum;121};122123struct ImmOp {124const MCExpr *Value;125};126127struct MemOp {128unsigned BaseReg;129unsigned OffsetReg;130unsigned AluOp;131const MCExpr *Offset;132};133134union {135struct Token Tok;136struct RegOp Reg;137struct ImmOp Imm;138struct MemOp Mem;139};140141explicit LanaiOperand(KindTy Kind) : Kind(Kind) {}142143public:144// The functions below are used by the autogenerated ASM matcher and hence to145// be of the form expected.146147// getStartLoc - Gets location of the first token of this operand148SMLoc getStartLoc() const override { return StartLoc; }149150// getEndLoc - Gets location of the last token of this operand151SMLoc getEndLoc() const override { return EndLoc; }152153MCRegister getReg() const override {154assert(isReg() && "Invalid type access!");155return Reg.RegNum;156}157158const MCExpr *getImm() const {159assert(isImm() && "Invalid type access!");160return Imm.Value;161}162163StringRef getToken() const {164assert(isToken() && "Invalid type access!");165return StringRef(Tok.Data, Tok.Length);166}167168unsigned getMemBaseReg() const {169assert(isMem() && "Invalid type access!");170return Mem.BaseReg;171}172173unsigned getMemOffsetReg() const {174assert(isMem() && "Invalid type access!");175return Mem.OffsetReg;176}177178const MCExpr *getMemOffset() const {179assert(isMem() && "Invalid type access!");180return Mem.Offset;181}182183unsigned getMemOp() const {184assert(isMem() && "Invalid type access!");185return Mem.AluOp;186}187188// Functions for testing operand type189bool isReg() const override { return Kind == REGISTER; }190191bool isImm() const override { return Kind == IMMEDIATE; }192193bool isMem() const override {194return isMemImm() || isMemRegImm() || isMemRegReg();195}196197bool isMemImm() const { return Kind == MEMORY_IMM; }198199bool isMemRegImm() const { return Kind == MEMORY_REG_IMM; }200201bool isMemRegReg() const { return Kind == MEMORY_REG_REG; }202203bool isMemSpls() const { return isMemRegImm() || isMemRegReg(); }204205bool isToken() const override { return Kind == TOKEN; }206207bool isBrImm() {208if (!isImm())209return false;210211// Constant case212const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(Imm.Value);213if (!MCE)214return true;215int64_t Value = MCE->getValue();216// Check if value fits in 25 bits with 2 least significant bits 0.217return isShiftedUInt<23, 2>(static_cast<int32_t>(Value));218}219220bool isBrTarget() { return isBrImm() || isToken(); }221222bool isCallTarget() { return isImm() || isToken(); }223224bool isHiImm16() {225if (!isImm())226return false;227228// Constant case229if (const MCConstantExpr *ConstExpr = dyn_cast<MCConstantExpr>(Imm.Value)) {230int64_t Value = ConstExpr->getValue();231return Value != 0 && isShiftedUInt<16, 16>(Value);232}233234// Symbolic reference expression235if (const LanaiMCExpr *SymbolRefExpr = dyn_cast<LanaiMCExpr>(Imm.Value))236return SymbolRefExpr->getKind() == LanaiMCExpr::VK_Lanai_ABS_HI;237238// Binary expression239if (const MCBinaryExpr *BinaryExpr = dyn_cast<MCBinaryExpr>(Imm.Value))240if (const LanaiMCExpr *SymbolRefExpr =241dyn_cast<LanaiMCExpr>(BinaryExpr->getLHS()))242return SymbolRefExpr->getKind() == LanaiMCExpr::VK_Lanai_ABS_HI;243244return false;245}246247bool isHiImm16And() {248if (!isImm())249return false;250251const MCConstantExpr *ConstExpr = dyn_cast<MCConstantExpr>(Imm.Value);252if (ConstExpr) {253int64_t Value = ConstExpr->getValue();254// Check if in the form 0xXYZWffff255return (Value != 0) && ((Value & ~0xffff0000) == 0xffff);256}257return false;258}259260bool isLoImm16() {261if (!isImm())262return false;263264// Constant case265if (const MCConstantExpr *ConstExpr = dyn_cast<MCConstantExpr>(Imm.Value)) {266int64_t Value = ConstExpr->getValue();267// Check if value fits in 16 bits268return isUInt<16>(static_cast<int32_t>(Value));269}270271// Symbolic reference expression272if (const LanaiMCExpr *SymbolRefExpr = dyn_cast<LanaiMCExpr>(Imm.Value))273return SymbolRefExpr->getKind() == LanaiMCExpr::VK_Lanai_ABS_LO;274275// Binary expression276if (const MCBinaryExpr *BinaryExpr = dyn_cast<MCBinaryExpr>(Imm.Value))277if (const LanaiMCExpr *SymbolRefExpr =278dyn_cast<LanaiMCExpr>(BinaryExpr->getLHS()))279return SymbolRefExpr->getKind() == LanaiMCExpr::VK_Lanai_ABS_LO;280281return false;282}283284bool isLoImm16Signed() {285if (!isImm())286return false;287288// Constant case289if (const MCConstantExpr *ConstExpr = dyn_cast<MCConstantExpr>(Imm.Value)) {290int64_t Value = ConstExpr->getValue();291// Check if value fits in 16 bits or value of the form 0xffffxyzw292return isInt<16>(static_cast<int32_t>(Value));293}294295// Symbolic reference expression296if (const LanaiMCExpr *SymbolRefExpr = dyn_cast<LanaiMCExpr>(Imm.Value))297return SymbolRefExpr->getKind() == LanaiMCExpr::VK_Lanai_ABS_LO;298299// Binary expression300if (const MCBinaryExpr *BinaryExpr = dyn_cast<MCBinaryExpr>(Imm.Value))301if (const LanaiMCExpr *SymbolRefExpr =302dyn_cast<LanaiMCExpr>(BinaryExpr->getLHS()))303return SymbolRefExpr->getKind() == LanaiMCExpr::VK_Lanai_ABS_LO;304305return false;306}307308bool isLoImm16And() {309if (!isImm())310return false;311312const MCConstantExpr *ConstExpr = dyn_cast<MCConstantExpr>(Imm.Value);313if (ConstExpr) {314int64_t Value = ConstExpr->getValue();315// Check if in the form 0xffffXYZW316return ((Value & ~0xffff) == 0xffff0000);317}318return false;319}320321bool isImmShift() {322if (!isImm())323return false;324325const MCConstantExpr *ConstExpr = dyn_cast<MCConstantExpr>(Imm.Value);326if (!ConstExpr)327return false;328int64_t Value = ConstExpr->getValue();329return (Value >= -31) && (Value <= 31);330}331332bool isLoImm21() {333if (!isImm())334return false;335336// Constant case337if (const MCConstantExpr *ConstExpr = dyn_cast<MCConstantExpr>(Imm.Value)) {338int64_t Value = ConstExpr->getValue();339return isUInt<21>(Value);340}341342// Symbolic reference expression343if (const LanaiMCExpr *SymbolRefExpr = dyn_cast<LanaiMCExpr>(Imm.Value))344return SymbolRefExpr->getKind() == LanaiMCExpr::VK_Lanai_None;345if (const MCSymbolRefExpr *SymbolRefExpr =346dyn_cast<MCSymbolRefExpr>(Imm.Value)) {347return SymbolRefExpr->getKind() == MCSymbolRefExpr::VK_None;348}349350// Binary expression351if (const MCBinaryExpr *BinaryExpr = dyn_cast<MCBinaryExpr>(Imm.Value)) {352if (const LanaiMCExpr *SymbolRefExpr =353dyn_cast<LanaiMCExpr>(BinaryExpr->getLHS()))354return SymbolRefExpr->getKind() == LanaiMCExpr::VK_Lanai_None;355if (const MCSymbolRefExpr *SymbolRefExpr =356dyn_cast<MCSymbolRefExpr>(BinaryExpr->getLHS()))357return SymbolRefExpr->getKind() == MCSymbolRefExpr::VK_None;358}359360return false;361}362363bool isImm10() {364if (!isImm())365return false;366367const MCConstantExpr *ConstExpr = dyn_cast<MCConstantExpr>(Imm.Value);368if (!ConstExpr)369return false;370int64_t Value = ConstExpr->getValue();371return isInt<10>(Value);372}373374bool isCondCode() {375if (!isImm())376return false;377378const MCConstantExpr *ConstExpr = dyn_cast<MCConstantExpr>(Imm.Value);379if (!ConstExpr)380return false;381uint64_t Value = ConstExpr->getValue();382// The condition codes are between 0 (ICC_T) and 15 (ICC_LE). If the383// unsigned value of the immediate is less than LPCC::UNKNOWN (16) then384// value corresponds to a valid condition code.385return Value < LPCC::UNKNOWN;386}387388void addExpr(MCInst &Inst, const MCExpr *Expr) const {389// Add as immediates where possible. Null MCExpr = 0390if (Expr == nullptr)391Inst.addOperand(MCOperand::createImm(0));392else if (const MCConstantExpr *ConstExpr = dyn_cast<MCConstantExpr>(Expr))393Inst.addOperand(394MCOperand::createImm(static_cast<int32_t>(ConstExpr->getValue())));395else396Inst.addOperand(MCOperand::createExpr(Expr));397}398399void addRegOperands(MCInst &Inst, unsigned N) const {400assert(N == 1 && "Invalid number of operands!");401Inst.addOperand(MCOperand::createReg(getReg()));402}403404void addImmOperands(MCInst &Inst, unsigned N) const {405assert(N == 1 && "Invalid number of operands!");406addExpr(Inst, getImm());407}408409void addBrTargetOperands(MCInst &Inst, unsigned N) const {410assert(N == 1 && "Invalid number of operands!");411addExpr(Inst, getImm());412}413414void addCallTargetOperands(MCInst &Inst, unsigned N) const {415assert(N == 1 && "Invalid number of operands!");416addExpr(Inst, getImm());417}418419void addCondCodeOperands(MCInst &Inst, unsigned N) const {420assert(N == 1 && "Invalid number of operands!");421addExpr(Inst, getImm());422}423424void addMemImmOperands(MCInst &Inst, unsigned N) const {425assert(N == 1 && "Invalid number of operands!");426const MCExpr *Expr = getMemOffset();427addExpr(Inst, Expr);428}429430void addMemRegImmOperands(MCInst &Inst, unsigned N) const {431assert(N == 3 && "Invalid number of operands!");432Inst.addOperand(MCOperand::createReg(getMemBaseReg()));433const MCExpr *Expr = getMemOffset();434addExpr(Inst, Expr);435Inst.addOperand(MCOperand::createImm(getMemOp()));436}437438void addMemRegRegOperands(MCInst &Inst, unsigned N) const {439assert(N == 3 && "Invalid number of operands!");440Inst.addOperand(MCOperand::createReg(getMemBaseReg()));441assert(getMemOffsetReg() != 0 && "Invalid offset");442Inst.addOperand(MCOperand::createReg(getMemOffsetReg()));443Inst.addOperand(MCOperand::createImm(getMemOp()));444}445446void addMemSplsOperands(MCInst &Inst, unsigned N) const {447if (isMemRegImm())448addMemRegImmOperands(Inst, N);449if (isMemRegReg())450addMemRegRegOperands(Inst, N);451}452453void addImmShiftOperands(MCInst &Inst, unsigned N) const {454assert(N == 1 && "Invalid number of operands!");455addExpr(Inst, getImm());456}457458void addImm10Operands(MCInst &Inst, unsigned N) const {459assert(N == 1 && "Invalid number of operands!");460addExpr(Inst, getImm());461}462463void addLoImm16Operands(MCInst &Inst, unsigned N) const {464assert(N == 1 && "Invalid number of operands!");465if (const MCConstantExpr *ConstExpr = dyn_cast<MCConstantExpr>(getImm()))466Inst.addOperand(467MCOperand::createImm(static_cast<int32_t>(ConstExpr->getValue())));468else if (isa<LanaiMCExpr>(getImm())) {469#ifndef NDEBUG470const LanaiMCExpr *SymbolRefExpr = dyn_cast<LanaiMCExpr>(getImm());471assert(SymbolRefExpr &&472SymbolRefExpr->getKind() == LanaiMCExpr::VK_Lanai_ABS_LO);473#endif474Inst.addOperand(MCOperand::createExpr(getImm()));475} else if (isa<MCBinaryExpr>(getImm())) {476#ifndef NDEBUG477const MCBinaryExpr *BinaryExpr = dyn_cast<MCBinaryExpr>(getImm());478assert(BinaryExpr && isa<LanaiMCExpr>(BinaryExpr->getLHS()) &&479cast<LanaiMCExpr>(BinaryExpr->getLHS())->getKind() ==480LanaiMCExpr::VK_Lanai_ABS_LO);481#endif482Inst.addOperand(MCOperand::createExpr(getImm()));483} else484assert(false && "Operand type not supported.");485}486487void addLoImm16AndOperands(MCInst &Inst, unsigned N) const {488assert(N == 1 && "Invalid number of operands!");489if (const MCConstantExpr *ConstExpr = dyn_cast<MCConstantExpr>(getImm()))490Inst.addOperand(MCOperand::createImm(ConstExpr->getValue() & 0xffff));491else492assert(false && "Operand type not supported.");493}494495void addHiImm16Operands(MCInst &Inst, unsigned N) const {496assert(N == 1 && "Invalid number of operands!");497if (const MCConstantExpr *ConstExpr = dyn_cast<MCConstantExpr>(getImm()))498Inst.addOperand(MCOperand::createImm(ConstExpr->getValue() >> 16));499else if (isa<LanaiMCExpr>(getImm())) {500#ifndef NDEBUG501const LanaiMCExpr *SymbolRefExpr = dyn_cast<LanaiMCExpr>(getImm());502assert(SymbolRefExpr &&503SymbolRefExpr->getKind() == LanaiMCExpr::VK_Lanai_ABS_HI);504#endif505Inst.addOperand(MCOperand::createExpr(getImm()));506} else if (isa<MCBinaryExpr>(getImm())) {507#ifndef NDEBUG508const MCBinaryExpr *BinaryExpr = dyn_cast<MCBinaryExpr>(getImm());509assert(BinaryExpr && isa<LanaiMCExpr>(BinaryExpr->getLHS()) &&510cast<LanaiMCExpr>(BinaryExpr->getLHS())->getKind() ==511LanaiMCExpr::VK_Lanai_ABS_HI);512#endif513Inst.addOperand(MCOperand::createExpr(getImm()));514} else515assert(false && "Operand type not supported.");516}517518void addHiImm16AndOperands(MCInst &Inst, unsigned N) const {519assert(N == 1 && "Invalid number of operands!");520if (const MCConstantExpr *ConstExpr = dyn_cast<MCConstantExpr>(getImm()))521Inst.addOperand(MCOperand::createImm(ConstExpr->getValue() >> 16));522else523assert(false && "Operand type not supported.");524}525526void addLoImm21Operands(MCInst &Inst, unsigned N) const {527assert(N == 1 && "Invalid number of operands!");528if (const MCConstantExpr *ConstExpr = dyn_cast<MCConstantExpr>(getImm()))529Inst.addOperand(MCOperand::createImm(ConstExpr->getValue() & 0x1fffff));530else if (isa<LanaiMCExpr>(getImm())) {531#ifndef NDEBUG532const LanaiMCExpr *SymbolRefExpr = dyn_cast<LanaiMCExpr>(getImm());533assert(SymbolRefExpr &&534SymbolRefExpr->getKind() == LanaiMCExpr::VK_Lanai_None);535#endif536Inst.addOperand(MCOperand::createExpr(getImm()));537} else if (isa<MCSymbolRefExpr>(getImm())) {538#ifndef NDEBUG539const MCSymbolRefExpr *SymbolRefExpr =540dyn_cast<MCSymbolRefExpr>(getImm());541assert(SymbolRefExpr &&542SymbolRefExpr->getKind() == MCSymbolRefExpr::VK_None);543#endif544Inst.addOperand(MCOperand::createExpr(getImm()));545} else if (isa<MCBinaryExpr>(getImm())) {546#ifndef NDEBUG547const MCBinaryExpr *BinaryExpr = dyn_cast<MCBinaryExpr>(getImm());548assert(BinaryExpr && isa<LanaiMCExpr>(BinaryExpr->getLHS()) &&549cast<LanaiMCExpr>(BinaryExpr->getLHS())->getKind() ==550LanaiMCExpr::VK_Lanai_None);551#endif552Inst.addOperand(MCOperand::createExpr(getImm()));553} else554assert(false && "Operand type not supported.");555}556557void print(raw_ostream &OS) const override {558switch (Kind) {559case IMMEDIATE:560OS << "Imm: " << getImm() << "\n";561break;562case TOKEN:563OS << "Token: " << getToken() << "\n";564break;565case REGISTER:566OS << "Reg: %r" << getReg() << "\n";567break;568case MEMORY_IMM:569OS << "MemImm: " << *getMemOffset() << "\n";570break;571case MEMORY_REG_IMM:572OS << "MemRegImm: " << getMemBaseReg() << "+" << *getMemOffset() << "\n";573break;574case MEMORY_REG_REG:575assert(getMemOffset() == nullptr);576OS << "MemRegReg: " << getMemBaseReg() << "+"577<< "%r" << getMemOffsetReg() << "\n";578break;579}580}581582static std::unique_ptr<LanaiOperand> CreateToken(StringRef Str, SMLoc Start) {583auto Op = std::make_unique<LanaiOperand>(TOKEN);584Op->Tok.Data = Str.data();585Op->Tok.Length = Str.size();586Op->StartLoc = Start;587Op->EndLoc = Start;588return Op;589}590591static std::unique_ptr<LanaiOperand> createReg(unsigned RegNum, SMLoc Start,592SMLoc End) {593auto Op = std::make_unique<LanaiOperand>(REGISTER);594Op->Reg.RegNum = RegNum;595Op->StartLoc = Start;596Op->EndLoc = End;597return Op;598}599600static std::unique_ptr<LanaiOperand> createImm(const MCExpr *Value,601SMLoc Start, SMLoc End) {602auto Op = std::make_unique<LanaiOperand>(IMMEDIATE);603Op->Imm.Value = Value;604Op->StartLoc = Start;605Op->EndLoc = End;606return Op;607}608609static std::unique_ptr<LanaiOperand>610MorphToMemImm(std::unique_ptr<LanaiOperand> Op) {611const MCExpr *Imm = Op->getImm();612Op->Kind = MEMORY_IMM;613Op->Mem.BaseReg = 0;614Op->Mem.AluOp = LPAC::ADD;615Op->Mem.OffsetReg = 0;616Op->Mem.Offset = Imm;617return Op;618}619620static std::unique_ptr<LanaiOperand>621MorphToMemRegReg(unsigned BaseReg, std::unique_ptr<LanaiOperand> Op,622unsigned AluOp) {623unsigned OffsetReg = Op->getReg();624Op->Kind = MEMORY_REG_REG;625Op->Mem.BaseReg = BaseReg;626Op->Mem.AluOp = AluOp;627Op->Mem.OffsetReg = OffsetReg;628Op->Mem.Offset = nullptr;629return Op;630}631632static std::unique_ptr<LanaiOperand>633MorphToMemRegImm(unsigned BaseReg, std::unique_ptr<LanaiOperand> Op,634unsigned AluOp) {635const MCExpr *Imm = Op->getImm();636Op->Kind = MEMORY_REG_IMM;637Op->Mem.BaseReg = BaseReg;638Op->Mem.AluOp = AluOp;639Op->Mem.OffsetReg = 0;640Op->Mem.Offset = Imm;641return Op;642}643};644645} // end anonymous namespace646647bool LanaiAsmParser::MatchAndEmitInstruction(SMLoc IdLoc, unsigned &Opcode,648OperandVector &Operands,649MCStreamer &Out,650uint64_t &ErrorInfo,651bool MatchingInlineAsm) {652MCInst Inst;653SMLoc ErrorLoc;654655switch (MatchInstructionImpl(Operands, Inst, ErrorInfo, MatchingInlineAsm)) {656case Match_Success:657Out.emitInstruction(Inst, SubtargetInfo);658Opcode = Inst.getOpcode();659return false;660case Match_MissingFeature:661return Error(IdLoc, "Instruction use requires option to be enabled");662case Match_MnemonicFail:663return Error(IdLoc, "Unrecognized instruction mnemonic");664case Match_InvalidOperand: {665ErrorLoc = IdLoc;666if (ErrorInfo != ~0U) {667if (ErrorInfo >= Operands.size())668return Error(IdLoc, "Too few operands for instruction");669670ErrorLoc = ((LanaiOperand &)*Operands[ErrorInfo]).getStartLoc();671if (ErrorLoc == SMLoc())672ErrorLoc = IdLoc;673}674return Error(ErrorLoc, "Invalid operand for instruction");675}676default:677break;678}679680llvm_unreachable("Unknown match type detected!");681}682683// Both '%rN' and 'rN' are parsed as valid registers. This was done to remain684// backwards compatible with GCC and the different ways inline assembly is685// handled.686// TODO: see if there isn't a better way to do this.687std::unique_ptr<LanaiOperand>688LanaiAsmParser::parseRegister(bool RestoreOnFailure) {689SMLoc Start = Parser.getTok().getLoc();690SMLoc End = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);691std::optional<AsmToken> PercentTok;692693unsigned RegNum;694// Eat the '%'.695if (Lexer.getKind() == AsmToken::Percent) {696PercentTok = Parser.getTok();697Parser.Lex();698}699if (Lexer.getKind() == AsmToken::Identifier) {700RegNum = MatchRegisterName(Lexer.getTok().getIdentifier());701if (RegNum == 0) {702if (PercentTok && RestoreOnFailure)703Lexer.UnLex(*PercentTok);704return nullptr;705}706Parser.Lex(); // Eat identifier token707return LanaiOperand::createReg(RegNum, Start, End);708}709if (PercentTok && RestoreOnFailure)710Lexer.UnLex(*PercentTok);711return nullptr;712}713714bool LanaiAsmParser::parseRegister(MCRegister &RegNum, SMLoc &StartLoc,715SMLoc &EndLoc) {716const AsmToken &Tok = getParser().getTok();717StartLoc = Tok.getLoc();718EndLoc = Tok.getEndLoc();719std::unique_ptr<LanaiOperand> Op = parseRegister(/*RestoreOnFailure=*/false);720if (Op != nullptr)721RegNum = Op->getReg();722return (Op == nullptr);723}724725ParseStatus LanaiAsmParser::tryParseRegister(MCRegister &Reg, SMLoc &StartLoc,726SMLoc &EndLoc) {727const AsmToken &Tok = getParser().getTok();728StartLoc = Tok.getLoc();729EndLoc = Tok.getEndLoc();730std::unique_ptr<LanaiOperand> Op = parseRegister(/*RestoreOnFailure=*/true);731if (Op == nullptr)732return ParseStatus::NoMatch;733Reg = Op->getReg();734return ParseStatus::Success;735}736737std::unique_ptr<LanaiOperand> LanaiAsmParser::parseIdentifier() {738SMLoc Start = Parser.getTok().getLoc();739SMLoc End = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);740const MCExpr *Res, *RHS = nullptr;741LanaiMCExpr::VariantKind Kind = LanaiMCExpr::VK_Lanai_None;742743if (Lexer.getKind() != AsmToken::Identifier)744return nullptr;745746StringRef Identifier;747if (Parser.parseIdentifier(Identifier))748return nullptr;749750// Check if identifier has a modifier751if (Identifier.equals_insensitive("hi"))752Kind = LanaiMCExpr::VK_Lanai_ABS_HI;753else if (Identifier.equals_insensitive("lo"))754Kind = LanaiMCExpr::VK_Lanai_ABS_LO;755756// If the identifier corresponds to a variant then extract the real757// identifier.758if (Kind != LanaiMCExpr::VK_Lanai_None) {759if (Lexer.getKind() != AsmToken::LParen) {760Error(Lexer.getLoc(), "Expected '('");761return nullptr;762}763Lexer.Lex(); // lex '('764765// Parse identifier766if (Parser.parseIdentifier(Identifier))767return nullptr;768}769770// If addition parse the RHS.771if (Lexer.getKind() == AsmToken::Plus && Parser.parseExpression(RHS))772return nullptr;773774// For variants parse the final ')'775if (Kind != LanaiMCExpr::VK_Lanai_None) {776if (Lexer.getKind() != AsmToken::RParen) {777Error(Lexer.getLoc(), "Expected ')'");778return nullptr;779}780Lexer.Lex(); // lex ')'781}782783End = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);784MCSymbol *Sym = getContext().getOrCreateSymbol(Identifier);785const MCExpr *Expr = MCSymbolRefExpr::create(Sym, getContext());786Res = LanaiMCExpr::create(Kind, Expr, getContext());787788// Nest if this was an addition789if (RHS)790Res = MCBinaryExpr::createAdd(Res, RHS, getContext());791792return LanaiOperand::createImm(Res, Start, End);793}794795std::unique_ptr<LanaiOperand> LanaiAsmParser::parseImmediate() {796SMLoc Start = Parser.getTok().getLoc();797SMLoc End = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);798799const MCExpr *ExprVal;800switch (Lexer.getKind()) {801case AsmToken::Identifier:802return parseIdentifier();803case AsmToken::Plus:804case AsmToken::Minus:805case AsmToken::Integer:806case AsmToken::Dot:807if (!Parser.parseExpression(ExprVal))808return LanaiOperand::createImm(ExprVal, Start, End);809[[fallthrough]];810default:811return nullptr;812}813}814815static unsigned AluWithPrePost(unsigned AluCode, bool PreOp, bool PostOp) {816if (PreOp)817return LPAC::makePreOp(AluCode);818if (PostOp)819return LPAC::makePostOp(AluCode);820return AluCode;821}822823unsigned LanaiAsmParser::parseAluOperator(bool PreOp, bool PostOp) {824StringRef IdString;825Parser.parseIdentifier(IdString);826unsigned AluCode = LPAC::stringToLanaiAluCode(IdString);827if (AluCode == LPAC::UNKNOWN) {828Error(Parser.getTok().getLoc(), "Can't parse ALU operator");829return 0;830}831return AluCode;832}833834static int SizeForSuffix(StringRef T) {835return StringSwitch<int>(T).EndsWith(".h", 2).EndsWith(".b", 1).Default(4);836}837838bool LanaiAsmParser::parsePrePost(StringRef Type, int *OffsetValue) {839bool PreOrPost = false;840if (Lexer.getKind() == Lexer.peekTok(true).getKind()) {841PreOrPost = true;842if (Lexer.is(AsmToken::Minus))843*OffsetValue = -SizeForSuffix(Type);844else if (Lexer.is(AsmToken::Plus))845*OffsetValue = SizeForSuffix(Type);846else847return false;848849// Eat the '-' '-' or '+' '+'850Parser.Lex();851Parser.Lex();852} else if (Lexer.is(AsmToken::Star)) {853Parser.Lex(); // Eat the '*'854PreOrPost = true;855}856857return PreOrPost;858}859860bool shouldBeSls(const LanaiOperand &Op) {861// The instruction should be encoded as an SLS if the constant is word862// aligned and will fit in 21 bits863if (const MCConstantExpr *ConstExpr = dyn_cast<MCConstantExpr>(Op.getImm())) {864int64_t Value = ConstExpr->getValue();865return (Value % 4 == 0) && (Value >= 0) && (Value <= 0x1fffff);866}867// The instruction should be encoded as an SLS if the operand is a symbolic868// reference with no variant.869if (const LanaiMCExpr *SymbolRefExpr = dyn_cast<LanaiMCExpr>(Op.getImm()))870return SymbolRefExpr->getKind() == LanaiMCExpr::VK_Lanai_None;871// The instruction should be encoded as an SLS if the operand is a binary872// expression with the left-hand side being a symbolic reference with no873// variant.874if (const MCBinaryExpr *BinaryExpr = dyn_cast<MCBinaryExpr>(Op.getImm())) {875const LanaiMCExpr *LHSSymbolRefExpr =876dyn_cast<LanaiMCExpr>(BinaryExpr->getLHS());877return (LHSSymbolRefExpr &&878LHSSymbolRefExpr->getKind() == LanaiMCExpr::VK_Lanai_None);879}880return false;881}882883// Matches memory operand. Returns true if error encountered.884ParseStatus LanaiAsmParser::parseMemoryOperand(OperandVector &Operands) {885// Try to match a memory operand.886// The memory operands are of the form:887// (1) Register|Immediate|'' '[' '*'? Register '*'? ']' or888// ^889// (2) '[' '*'? Register '*'? AluOperator Register ']'890// ^891// (3) '[' '--'|'++' Register '--'|'++' ']'892//893// (4) '[' Immediate ']' (for SLS)894895// Store the type for use in parsing pre/post increment/decrement operators896StringRef Type;897if (Operands[0]->isToken())898Type = static_cast<LanaiOperand *>(Operands[0].get())->getToken();899900// Use 0 if no offset given901int OffsetValue = 0;902unsigned BaseReg = 0;903unsigned AluOp = LPAC::ADD;904bool PostOp = false, PreOp = false;905906// Try to parse the offset907std::unique_ptr<LanaiOperand> Op = parseRegister();908if (!Op)909Op = parseImmediate();910911// Only continue if next token is '['912if (Lexer.isNot(AsmToken::LBrac)) {913if (!Op)914return ParseStatus::NoMatch;915916// The start of this custom parsing overlaps with register/immediate so917// consider this as a successful match of an operand of that type as the918// token stream can't be rewound to allow them to match separately.919Operands.push_back(std::move(Op));920return ParseStatus::Success;921}922923Parser.Lex(); // Eat the '['.924std::unique_ptr<LanaiOperand> Offset = nullptr;925if (Op)926Offset.swap(Op);927928// Determine if a pre operation929PreOp = parsePrePost(Type, &OffsetValue);930931Op = parseRegister();932if (!Op) {933if (!Offset) {934if ((Op = parseImmediate()) && Lexer.is(AsmToken::RBrac)) {935Parser.Lex(); // Eat the ']'936937// Memory address operations aligned to word boundary are encoded as938// SLS, the rest as RM.939if (shouldBeSls(*Op)) {940Operands.push_back(LanaiOperand::MorphToMemImm(std::move(Op)));941} else {942if (!Op->isLoImm16Signed())943return Error(Parser.getTok().getLoc(),944"Memory address is not word aligned and larger than "945"class RM can handle");946Operands.push_back(LanaiOperand::MorphToMemRegImm(947Lanai::R0, std::move(Op), LPAC::ADD));948}949return ParseStatus::Success;950}951}952953return Error(Parser.getTok().getLoc(),954"Unknown operand, expected register or immediate");955}956BaseReg = Op->getReg();957958// Determine if a post operation959if (!PreOp)960PostOp = parsePrePost(Type, &OffsetValue);961962// If ] match form (1) else match form (2)963if (Lexer.is(AsmToken::RBrac)) {964Parser.Lex(); // Eat the ']'.965if (!Offset) {966SMLoc Start = Parser.getTok().getLoc();967SMLoc End =968SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);969const MCConstantExpr *OffsetConstExpr =970MCConstantExpr::create(OffsetValue, getContext());971Offset = LanaiOperand::createImm(OffsetConstExpr, Start, End);972}973} else {974if (Offset || OffsetValue != 0)975return Error(Parser.getTok().getLoc(), "Expected ']'");976977// Parse operator978AluOp = parseAluOperator(PreOp, PostOp);979980// Second form requires offset register981Offset = parseRegister();982if (!BaseReg || Lexer.isNot(AsmToken::RBrac))983return Error(Parser.getTok().getLoc(), "Expected ']'");984Parser.Lex(); // Eat the ']'.985}986987// First form has addition as operator. Add pre- or post-op indicator as988// needed.989AluOp = AluWithPrePost(AluOp, PreOp, PostOp);990991// Ensure immediate offset is not too large992if (Offset->isImm() && !Offset->isLoImm16Signed())993return Error(Parser.getTok().getLoc(),994"Memory address is not word aligned and larger than class RM "995"can handle");996997Operands.push_back(998Offset->isImm()999? LanaiOperand::MorphToMemRegImm(BaseReg, std::move(Offset), AluOp)1000: LanaiOperand::MorphToMemRegReg(BaseReg, std::move(Offset), AluOp));10011002return ParseStatus::Success;1003}10041005// Looks at a token type and creates the relevant operand from this1006// information, adding to operands.1007// If operand was parsed, returns false, else true.1008ParseStatus LanaiAsmParser::parseOperand(OperandVector *Operands,1009StringRef Mnemonic) {1010// Check if the current operand has a custom associated parser, if so, try to1011// custom parse the operand, or fallback to the general approach.1012ParseStatus Result = MatchOperandParserImpl(*Operands, Mnemonic);10131014if (Result.isSuccess())1015return Result;1016if (Result.isFailure()) {1017Parser.eatToEndOfStatement();1018return Result;1019}10201021// Attempt to parse token as register1022std::unique_ptr<LanaiOperand> Op = parseRegister();10231024// Attempt to parse token as immediate1025if (!Op)1026Op = parseImmediate();10271028// If the token could not be parsed then fail1029if (!Op) {1030Error(Parser.getTok().getLoc(), "Unknown operand");1031Parser.eatToEndOfStatement();1032return ParseStatus::Failure;1033}10341035// Push back parsed operand into list of operands1036Operands->push_back(std::move(Op));10371038return ParseStatus::Success;1039}10401041// Split the mnemonic into ASM operand, conditional code and instruction1042// qualifier (half-word, byte).1043StringRef LanaiAsmParser::splitMnemonic(StringRef Name, SMLoc NameLoc,1044OperandVector *Operands) {1045size_t Next = Name.find('.');10461047StringRef Mnemonic = Name;10481049bool IsBRR = Mnemonic.consume_back(".r");10501051// Match b?? and s?? (BR, BRR, and SCC instruction classes).1052if (Mnemonic[0] == 'b' ||1053(Mnemonic[0] == 's' && !Mnemonic.starts_with("sel") &&1054!Mnemonic.starts_with("st"))) {1055// Parse instructions with a conditional code. For example, 'bne' is1056// converted into two operands 'b' and 'ne'.1057LPCC::CondCode CondCode =1058LPCC::suffixToLanaiCondCode(Mnemonic.substr(1, Next));1059if (CondCode != LPCC::UNKNOWN) {1060Mnemonic = Mnemonic.slice(0, 1);1061Operands->push_back(LanaiOperand::CreateToken(Mnemonic, NameLoc));1062Operands->push_back(LanaiOperand::createImm(1063MCConstantExpr::create(CondCode, getContext()), NameLoc, NameLoc));1064if (IsBRR) {1065Operands->push_back(LanaiOperand::CreateToken(".r", NameLoc));1066}1067return Mnemonic;1068}1069}10701071// Parse other instructions with condition codes (RR instructions).1072// We ignore .f here and assume they are flag-setting operations, not1073// conditional codes (except for select instructions where flag-setting1074// variants are not yet implemented).1075if (Mnemonic.starts_with("sel") ||1076(!Mnemonic.ends_with(".f") && !Mnemonic.starts_with("st"))) {1077LPCC::CondCode CondCode = LPCC::suffixToLanaiCondCode(Mnemonic);1078if (CondCode != LPCC::UNKNOWN) {1079size_t Next = Mnemonic.rfind('.', Name.size());1080// 'sel' doesn't use a predicate operand whose printer adds the period,1081// but instead has the period as part of the identifier (i.e., 'sel.' is1082// expected by the generated matcher). If the mnemonic starts with 'sel'1083// then include the period as part of the mnemonic, else don't include it1084// as part of the mnemonic.1085if (Mnemonic.starts_with("sel")) {1086Mnemonic = Mnemonic.substr(0, Next + 1);1087} else {1088Mnemonic = Mnemonic.substr(0, Next);1089}1090Operands->push_back(LanaiOperand::CreateToken(Mnemonic, NameLoc));1091Operands->push_back(LanaiOperand::createImm(1092MCConstantExpr::create(CondCode, getContext()), NameLoc, NameLoc));1093return Mnemonic;1094}1095}10961097Operands->push_back(LanaiOperand::CreateToken(Mnemonic, NameLoc));1098if (IsBRR) {1099Operands->push_back(LanaiOperand::CreateToken(".r", NameLoc));1100}11011102return Mnemonic;1103}11041105static bool IsMemoryAssignmentError(const OperandVector &Operands) {1106// Detects if a memory operation has an erroneous base register modification.1107// Memory operations are detected by matching the types of operands.1108//1109// TODO: This test is focussed on one specific instance (ld/st).1110// Extend it to handle more cases or be more robust.1111bool Modifies = false;11121113int Offset = 0;11141115if (Operands.size() < 5)1116return false;1117else if (Operands[0]->isToken() && Operands[1]->isReg() &&1118Operands[2]->isImm() && Operands[3]->isImm() && Operands[4]->isReg())1119Offset = 0;1120else if (Operands[0]->isToken() && Operands[1]->isToken() &&1121Operands[2]->isReg() && Operands[3]->isImm() &&1122Operands[4]->isImm() && Operands[5]->isReg())1123Offset = 1;1124else1125return false;11261127int PossibleAluOpIdx = Offset + 3;1128int PossibleBaseIdx = Offset + 1;1129int PossibleDestIdx = Offset + 4;1130if (LanaiOperand *PossibleAluOp =1131static_cast<LanaiOperand *>(Operands[PossibleAluOpIdx].get()))1132if (PossibleAluOp->isImm())1133if (const MCConstantExpr *ConstExpr =1134dyn_cast<MCConstantExpr>(PossibleAluOp->getImm()))1135Modifies = LPAC::modifiesOp(ConstExpr->getValue());1136return Modifies && Operands[PossibleBaseIdx]->isReg() &&1137Operands[PossibleDestIdx]->isReg() &&1138Operands[PossibleBaseIdx]->getReg() ==1139Operands[PossibleDestIdx]->getReg();1140}11411142static bool IsRegister(const MCParsedAsmOperand &op) {1143return static_cast<const LanaiOperand &>(op).isReg();1144}11451146static bool MaybePredicatedInst(const OperandVector &Operands) {1147if (Operands.size() < 4 || !IsRegister(*Operands[1]) ||1148!IsRegister(*Operands[2]))1149return false;1150return StringSwitch<bool>(1151static_cast<const LanaiOperand &>(*Operands[0]).getToken())1152.StartsWith("addc", true)1153.StartsWith("add", true)1154.StartsWith("and", true)1155.StartsWith("sh", true)1156.StartsWith("subb", true)1157.StartsWith("sub", true)1158.StartsWith("or", true)1159.StartsWith("xor", true)1160.Default(false);1161}11621163bool LanaiAsmParser::ParseInstruction(ParseInstructionInfo & /*Info*/,1164StringRef Name, SMLoc NameLoc,1165OperandVector &Operands) {1166// First operand is token for instruction1167StringRef Mnemonic = splitMnemonic(Name, NameLoc, &Operands);11681169// If there are no more operands, then finish1170if (Lexer.is(AsmToken::EndOfStatement))1171return false;11721173// Parse first operand1174if (!parseOperand(&Operands, Mnemonic).isSuccess())1175return true;11761177// If it is a st instruction with one 1 operand then it is a "store true".1178// Transform <"st"> to <"s">, <LPCC:ICC_T>1179if (Lexer.is(AsmToken::EndOfStatement) && Name == "st" &&1180Operands.size() == 2) {1181Operands.erase(Operands.begin(), Operands.begin() + 1);1182Operands.insert(Operands.begin(), LanaiOperand::CreateToken("s", NameLoc));1183Operands.insert(Operands.begin() + 1,1184LanaiOperand::createImm(1185MCConstantExpr::create(LPCC::ICC_T, getContext()),1186NameLoc, NameLoc));1187}11881189// If the instruction is a bt instruction with 1 operand (in assembly) then it1190// is an unconditional branch instruction and the first two elements of1191// operands need to be merged.1192if (Lexer.is(AsmToken::EndOfStatement) && Name.starts_with("bt") &&1193Operands.size() == 3) {1194Operands.erase(Operands.begin(), Operands.begin() + 2);1195Operands.insert(Operands.begin(), LanaiOperand::CreateToken("bt", NameLoc));1196}11971198// Parse until end of statement, consuming commas between operands1199while (Lexer.isNot(AsmToken::EndOfStatement) && Lexer.is(AsmToken::Comma)) {1200// Consume comma token1201Lex();12021203// Parse next operand1204if (!parseOperand(&Operands, Mnemonic).isSuccess())1205return true;1206}12071208if (IsMemoryAssignmentError(Operands)) {1209Error(Parser.getTok().getLoc(),1210"the destination register can't equal the base register in an "1211"instruction that modifies the base register.");1212return true;1213}12141215// Insert always true operand for instruction that may be predicated but1216// are not. Currently the autogenerated parser always expects a predicate.1217if (MaybePredicatedInst(Operands)) {1218Operands.insert(Operands.begin() + 1,1219LanaiOperand::createImm(1220MCConstantExpr::create(LPCC::ICC_T, getContext()),1221NameLoc, NameLoc));1222}12231224return false;1225}12261227#define GET_REGISTER_MATCHER1228#define GET_MATCHER_IMPLEMENTATION1229#include "LanaiGenAsmMatcher.inc"12301231extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeLanaiAsmParser() {1232RegisterMCAsmParser<LanaiAsmParser> x(getTheLanaiTarget());1233}123412351236