Path: blob/main/contrib/llvm-project/llvm/lib/Target/M68k/AsmParser/M68kAsmParser.cpp
35294 views
//===-- M68kAsmParser.cpp - Parse M68k 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 "M68kInstrInfo.h"9#include "M68kRegisterInfo.h"10#include "TargetInfo/M68kTargetInfo.h"1112#include "llvm/MC/MCContext.h"13#include "llvm/MC/MCParser/MCAsmLexer.h"14#include "llvm/MC/MCParser/MCParsedAsmOperand.h"15#include "llvm/MC/MCParser/MCTargetAsmParser.h"16#include "llvm/MC/MCStreamer.h"17#include "llvm/MC/TargetRegistry.h"1819#include <sstream>2021#define DEBUG_TYPE "m68k-asm-parser"2223using namespace llvm;2425static cl::opt<bool> RegisterPrefixOptional(26"m68k-register-prefix-optional", cl::Hidden,27cl::desc("Enable specifying registers without the % prefix"),28cl::init(false));2930namespace {31/// Parses M68k assembly from a stream.32class M68kAsmParser : public MCTargetAsmParser {33const MCSubtargetInfo &STI;34MCAsmParser &Parser;35const MCRegisterInfo *MRI;3637#define GET_ASSEMBLER_HEADER38#include "M68kGenAsmMatcher.inc"3940// Helpers for Match&Emit.41bool invalidOperand(const SMLoc &Loc, const OperandVector &Operands,42const uint64_t &ErrorInfo);43bool missingFeature(const SMLoc &Loc, const uint64_t &ErrorInfo);44bool emit(MCInst &Inst, SMLoc const &Loc, MCStreamer &Out) const;45bool parseRegisterName(MCRegister &RegNo, SMLoc Loc, StringRef RegisterName);46ParseStatus parseRegister(MCRegister &RegNo);4748// Parser functions.49void eatComma();5051bool isExpr();52ParseStatus parseImm(OperandVector &Operands);53ParseStatus parseMemOp(OperandVector &Operands);54ParseStatus parseRegOrMoveMask(OperandVector &Operands);5556public:57M68kAsmParser(const MCSubtargetInfo &STI, MCAsmParser &Parser,58const MCInstrInfo &MII, const MCTargetOptions &Options)59: MCTargetAsmParser(Options, STI, MII), STI(STI), Parser(Parser) {60MCAsmParserExtension::Initialize(Parser);61MRI = getContext().getRegisterInfo();6263setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits()));64}6566unsigned validateTargetOperandClass(MCParsedAsmOperand &Op,67unsigned Kind) override;68bool parseRegister(MCRegister &Reg, SMLoc &StartLoc, SMLoc &EndLoc) override;69ParseStatus tryParseRegister(MCRegister &Reg, SMLoc &StartLoc,70SMLoc &EndLoc) override;71bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name,72SMLoc NameLoc, OperandVector &Operands) override;73bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,74OperandVector &Operands, MCStreamer &Out,75uint64_t &ErrorInfo,76bool MatchingInlineAsm) override;77};7879struct M68kMemOp {80enum class Kind {81Addr,82RegMask,83Reg,84RegIndirect,85RegPostIncrement,86RegPreDecrement,87RegIndirectDisplacement,88RegIndirectDisplacementIndex,89};9091// These variables are used for the following forms:92// Addr: (OuterDisp)93// RegMask: RegMask (as register mask)94// Reg: %OuterReg95// RegIndirect: (%OuterReg)96// RegPostIncrement: (%OuterReg)+97// RegPreDecrement: -(%OuterReg)98// RegIndirectDisplacement: OuterDisp(%OuterReg)99// RegIndirectDisplacementIndex:100// OuterDisp(%OuterReg, %InnerReg.Size * Scale, InnerDisp)101102Kind Op;103MCRegister OuterReg;104MCRegister InnerReg;105const MCExpr *OuterDisp;106const MCExpr *InnerDisp;107uint8_t Size : 4;108uint8_t Scale : 4;109const MCExpr *Expr;110uint16_t RegMask;111112M68kMemOp() {}113M68kMemOp(Kind Op) : Op(Op) {}114115void print(raw_ostream &OS) const;116};117118/// An parsed M68k assembly operand.119class M68kOperand : public MCParsedAsmOperand {120typedef MCParsedAsmOperand Base;121122enum class KindTy {123Invalid,124Token,125Imm,126MemOp,127};128129KindTy Kind;130SMLoc Start, End;131union {132StringRef Token;133const MCExpr *Expr;134M68kMemOp MemOp;135};136137template <unsigned N> bool isAddrN() const;138139public:140M68kOperand(KindTy Kind, SMLoc Start, SMLoc End)141: Base(), Kind(Kind), Start(Start), End(End) {}142143SMLoc getStartLoc() const override { return Start; }144SMLoc getEndLoc() const override { return End; }145146void print(raw_ostream &OS) const override;147148bool isMem() const override { return false; }149bool isMemOp() const { return Kind == KindTy::MemOp; }150151static void addExpr(MCInst &Inst, const MCExpr *Expr);152153// Reg154bool isReg() const override;155bool isAReg() const;156bool isDReg() const;157bool isFPDReg() const;158bool isFPCReg() const;159MCRegister getReg() const override;160void addRegOperands(MCInst &Inst, unsigned N) const;161162static std::unique_ptr<M68kOperand> createMemOp(M68kMemOp MemOp, SMLoc Start,163SMLoc End);164165// Token166bool isToken() const override;167StringRef getToken() const;168static std::unique_ptr<M68kOperand> createToken(StringRef Token, SMLoc Start,169SMLoc End);170171// Imm172bool isImm() const override;173void addImmOperands(MCInst &Inst, unsigned N) const;174175static std::unique_ptr<M68kOperand> createImm(const MCExpr *Expr, SMLoc Start,176SMLoc End);177178// Imm for TRAP instruction179bool isTrapImm() const;180// Imm for BKPT instruction181bool isBkptImm() const;182183// MoveMask184bool isMoveMask() const;185void addMoveMaskOperands(MCInst &Inst, unsigned N) const;186187// Addr188bool isAddr() const;189bool isAddr8() const { return isAddrN<8>(); }190bool isAddr16() const { return isAddrN<16>(); }191bool isAddr32() const { return isAddrN<32>(); }192void addAddrOperands(MCInst &Inst, unsigned N) const;193194// ARI195bool isARI() const;196void addARIOperands(MCInst &Inst, unsigned N) const;197198// ARID199bool isARID() const;200void addARIDOperands(MCInst &Inst, unsigned N) const;201202// ARII203bool isARII() const;204void addARIIOperands(MCInst &Inst, unsigned N) const;205206// ARIPD207bool isARIPD() const;208void addARIPDOperands(MCInst &Inst, unsigned N) const;209210// ARIPI211bool isARIPI() const;212void addARIPIOperands(MCInst &Inst, unsigned N) const;213214// PCD215bool isPCD() const;216void addPCDOperands(MCInst &Inst, unsigned N) const;217218// PCI219bool isPCI() const;220void addPCIOperands(MCInst &Inst, unsigned N) const;221};222223} // end anonymous namespace.224225extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeM68kAsmParser() {226RegisterMCAsmParser<M68kAsmParser> X(getTheM68kTarget());227}228229#define GET_REGISTER_MATCHER230#define GET_MATCHER_IMPLEMENTATION231#include "M68kGenAsmMatcher.inc"232233static inline unsigned getRegisterByIndex(unsigned RegisterIndex) {234static unsigned RegistersByIndex[] = {235M68k::D0, M68k::D1, M68k::D2, M68k::D3, M68k::D4, M68k::D5,236M68k::D6, M68k::D7, M68k::A0, M68k::A1, M68k::A2, M68k::A3,237M68k::A4, M68k::A5, M68k::A6, M68k::SP, M68k::FP0, M68k::FP1,238M68k::FP2, M68k::FP3, M68k::FP4, M68k::FP5, M68k::FP6, M68k::FP7};239assert(RegisterIndex <=240sizeof(RegistersByIndex) / sizeof(RegistersByIndex[0]));241return RegistersByIndex[RegisterIndex];242}243244static inline unsigned getRegisterIndex(unsigned Register) {245if (Register >= M68k::D0 && Register <= M68k::D7)246return Register - M68k::D0;247if (Register >= M68k::A0 && Register <= M68k::A6)248return Register - M68k::A0 + 8;249if (Register >= M68k::FP0 && Register <= M68k::FP7)250return Register - M68k::FP0 + 16;251252switch (Register) {253case M68k::SP:254// SP is sadly not contiguous with the rest of the An registers255return 15;256257// We don't care about the indices of these registers.258case M68k::PC:259case M68k::CCR:260case M68k::FPC:261case M68k::FPS:262case M68k::FPIAR:263return UINT_MAX;264265default:266llvm_unreachable("unexpected register number");267}268}269270void M68kMemOp::print(raw_ostream &OS) const {271switch (Op) {272case Kind::Addr:273OS << OuterDisp;274break;275case Kind::RegMask:276OS << "RegMask(" << format("%04x", RegMask) << ")";277break;278case Kind::Reg:279OS << '%' << OuterReg;280break;281case Kind::RegIndirect:282OS << "(%" << OuterReg << ')';283break;284case Kind::RegPostIncrement:285OS << "(%" << OuterReg << ")+";286break;287case Kind::RegPreDecrement:288OS << "-(%" << OuterReg << ")";289break;290case Kind::RegIndirectDisplacement:291OS << OuterDisp << "(%" << OuterReg << ")";292break;293case Kind::RegIndirectDisplacementIndex:294OS << OuterDisp << "(%" << OuterReg << ", " << InnerReg << "." << Size295<< ", " << InnerDisp << ")";296break;297}298}299300void M68kOperand::addExpr(MCInst &Inst, const MCExpr *Expr) {301if (auto Const = dyn_cast<MCConstantExpr>(Expr)) {302Inst.addOperand(MCOperand::createImm(Const->getValue()));303return;304}305306Inst.addOperand(MCOperand::createExpr(Expr));307}308309// Reg310bool M68kOperand::isReg() const {311return Kind == KindTy::MemOp && MemOp.Op == M68kMemOp::Kind::Reg;312}313314MCRegister M68kOperand::getReg() const {315assert(isReg());316return MemOp.OuterReg;317}318319void M68kOperand::addRegOperands(MCInst &Inst, unsigned N) const {320assert(isReg() && "wrong operand kind");321assert((N == 1) && "can only handle one register operand");322323Inst.addOperand(MCOperand::createReg(getReg()));324}325326std::unique_ptr<M68kOperand> M68kOperand::createMemOp(M68kMemOp MemOp,327SMLoc Start, SMLoc End) {328auto Op = std::make_unique<M68kOperand>(KindTy::MemOp, Start, End);329Op->MemOp = MemOp;330return Op;331}332333// Token334bool M68kOperand::isToken() const { return Kind == KindTy::Token; }335StringRef M68kOperand::getToken() const {336assert(isToken());337return Token;338}339340std::unique_ptr<M68kOperand> M68kOperand::createToken(StringRef Token,341SMLoc Start, SMLoc End) {342auto Op = std::make_unique<M68kOperand>(KindTy::Token, Start, End);343Op->Token = Token;344return Op;345}346347// Imm348bool M68kOperand::isImm() const { return Kind == KindTy::Imm; }349void M68kOperand::addImmOperands(MCInst &Inst, unsigned N) const {350assert(isImm() && "wrong operand kind");351assert((N == 1) && "can only handle one register operand");352353M68kOperand::addExpr(Inst, Expr);354}355356std::unique_ptr<M68kOperand> M68kOperand::createImm(const MCExpr *Expr,357SMLoc Start, SMLoc End) {358auto Op = std::make_unique<M68kOperand>(KindTy::Imm, Start, End);359Op->Expr = Expr;360return Op;361}362363bool M68kOperand::isTrapImm() const {364int64_t Value;365if (!isImm() || !Expr->evaluateAsAbsolute(Value))366return false;367368return isUInt<4>(Value);369}370371bool M68kOperand::isBkptImm() const {372int64_t Value;373if (!isImm() || !Expr->evaluateAsAbsolute(Value))374return false;375376return isUInt<3>(Value);377}378379// MoveMask380bool M68kOperand::isMoveMask() const {381if (!isMemOp())382return false;383384if (MemOp.Op == M68kMemOp::Kind::RegMask)385return true;386387if (MemOp.Op != M68kMemOp::Kind::Reg)388return false;389390// Only regular address / data registers are allowed to be used391// in register masks.392return getRegisterIndex(MemOp.OuterReg) < 16;393}394395void M68kOperand::addMoveMaskOperands(MCInst &Inst, unsigned N) const {396assert(isMoveMask() && "wrong operand kind");397assert((N == 1) && "can only handle one immediate operand");398399uint16_t MoveMask = MemOp.RegMask;400if (MemOp.Op == M68kMemOp::Kind::Reg)401MoveMask = 1 << getRegisterIndex(MemOp.OuterReg);402403Inst.addOperand(MCOperand::createImm(MoveMask));404}405406// Addr407bool M68kOperand::isAddr() const {408return isMemOp() && MemOp.Op == M68kMemOp::Kind::Addr;409}410// TODO: Maybe we can also store the size of OuterDisp411// in Size?412template <unsigned N> bool M68kOperand::isAddrN() const {413if (isAddr()) {414int64_t Res;415if (MemOp.OuterDisp->evaluateAsAbsolute(Res))416return isInt<N>(Res);417return true;418}419return false;420}421void M68kOperand::addAddrOperands(MCInst &Inst, unsigned N) const {422M68kOperand::addExpr(Inst, MemOp.OuterDisp);423}424425// ARI426bool M68kOperand::isARI() const {427return isMemOp() && MemOp.Op == M68kMemOp::Kind::RegIndirect &&428M68k::AR32RegClass.contains(MemOp.OuterReg);429}430void M68kOperand::addARIOperands(MCInst &Inst, unsigned N) const {431Inst.addOperand(MCOperand::createReg(MemOp.OuterReg));432}433434// ARID435bool M68kOperand::isARID() const {436return isMemOp() && MemOp.Op == M68kMemOp::Kind::RegIndirectDisplacement &&437M68k::AR32RegClass.contains(MemOp.OuterReg);438}439void M68kOperand::addARIDOperands(MCInst &Inst, unsigned N) const {440M68kOperand::addExpr(Inst, MemOp.OuterDisp);441Inst.addOperand(MCOperand::createReg(MemOp.OuterReg));442}443444// ARII445bool M68kOperand::isARII() const {446return isMemOp() &&447MemOp.Op == M68kMemOp::Kind::RegIndirectDisplacementIndex &&448M68k::AR32RegClass.contains(MemOp.OuterReg);449}450void M68kOperand::addARIIOperands(MCInst &Inst, unsigned N) const {451M68kOperand::addExpr(Inst, MemOp.OuterDisp);452Inst.addOperand(MCOperand::createReg(MemOp.OuterReg));453Inst.addOperand(MCOperand::createReg(MemOp.InnerReg));454}455456// ARIPD457bool M68kOperand::isARIPD() const {458return isMemOp() && MemOp.Op == M68kMemOp::Kind::RegPreDecrement &&459M68k::AR32RegClass.contains(MemOp.OuterReg);460}461void M68kOperand::addARIPDOperands(MCInst &Inst, unsigned N) const {462Inst.addOperand(MCOperand::createReg(MemOp.OuterReg));463}464465// ARIPI466bool M68kOperand::isARIPI() const {467return isMemOp() && MemOp.Op == M68kMemOp::Kind::RegPostIncrement &&468M68k::AR32RegClass.contains(MemOp.OuterReg);469}470void M68kOperand::addARIPIOperands(MCInst &Inst, unsigned N) const {471Inst.addOperand(MCOperand::createReg(MemOp.OuterReg));472}473474// PCD475bool M68kOperand::isPCD() const {476return isMemOp() && MemOp.Op == M68kMemOp::Kind::RegIndirectDisplacement &&477MemOp.OuterReg == M68k::PC;478}479void M68kOperand::addPCDOperands(MCInst &Inst, unsigned N) const {480M68kOperand::addExpr(Inst, MemOp.OuterDisp);481}482483// PCI484bool M68kOperand::isPCI() const {485return isMemOp() &&486MemOp.Op == M68kMemOp::Kind::RegIndirectDisplacementIndex &&487MemOp.OuterReg == M68k::PC;488}489void M68kOperand::addPCIOperands(MCInst &Inst, unsigned N) const {490M68kOperand::addExpr(Inst, MemOp.OuterDisp);491Inst.addOperand(MCOperand::createReg(MemOp.InnerReg));492}493494static inline bool checkRegisterClass(unsigned RegNo, bool Data, bool Address,495bool SP, bool FPDR = false,496bool FPCR = false) {497switch (RegNo) {498case M68k::A0:499case M68k::A1:500case M68k::A2:501case M68k::A3:502case M68k::A4:503case M68k::A5:504case M68k::A6:505return Address;506507case M68k::SP:508return SP;509510case M68k::D0:511case M68k::D1:512case M68k::D2:513case M68k::D3:514case M68k::D4:515case M68k::D5:516case M68k::D6:517case M68k::D7:518return Data;519520case M68k::SR:521case M68k::CCR:522return false;523524case M68k::FP0:525case M68k::FP1:526case M68k::FP2:527case M68k::FP3:528case M68k::FP4:529case M68k::FP5:530case M68k::FP6:531case M68k::FP7:532return FPDR;533534case M68k::FPC:535case M68k::FPS:536case M68k::FPIAR:537return FPCR;538539default:540llvm_unreachable("unexpected register type");541return false;542}543}544545bool M68kOperand::isAReg() const {546return isReg() && checkRegisterClass(getReg(),547/*Data=*/false,548/*Address=*/true, /*SP=*/true);549}550551bool M68kOperand::isDReg() const {552return isReg() && checkRegisterClass(getReg(),553/*Data=*/true,554/*Address=*/false, /*SP=*/false);555}556557bool M68kOperand::isFPDReg() const {558return isReg() && checkRegisterClass(getReg(),559/*Data=*/false,560/*Address=*/false, /*SP=*/false,561/*FPDR=*/true);562}563564bool M68kOperand::isFPCReg() const {565return isReg() && checkRegisterClass(getReg(),566/*Data=*/false,567/*Address=*/false, /*SP=*/false,568/*FPDR=*/false, /*FPCR=*/true);569}570571unsigned M68kAsmParser::validateTargetOperandClass(MCParsedAsmOperand &Op,572unsigned Kind) {573M68kOperand &Operand = (M68kOperand &)Op;574575switch (Kind) {576case MCK_XR16:577case MCK_SPILL:578if (Operand.isReg() &&579checkRegisterClass(Operand.getReg(), true, true, true)) {580return Match_Success;581}582break;583584case MCK_AR16:585case MCK_AR32:586if (Operand.isReg() &&587checkRegisterClass(Operand.getReg(), false, true, true)) {588return Match_Success;589}590break;591592case MCK_AR32_NOSP:593if (Operand.isReg() &&594checkRegisterClass(Operand.getReg(), false, true, false)) {595return Match_Success;596}597break;598599case MCK_DR8:600case MCK_DR16:601case MCK_DR32:602if (Operand.isReg() &&603checkRegisterClass(Operand.getReg(), true, false, false)) {604return Match_Success;605}606break;607608case MCK_AR16_TC:609if (Operand.isReg() &&610((Operand.getReg() == M68k::A0) || (Operand.getReg() == M68k::A1))) {611return Match_Success;612}613break;614615case MCK_DR16_TC:616if (Operand.isReg() &&617((Operand.getReg() == M68k::D0) || (Operand.getReg() == M68k::D1))) {618return Match_Success;619}620break;621622case MCK_XR16_TC:623if (Operand.isReg() &&624((Operand.getReg() == M68k::D0) || (Operand.getReg() == M68k::D1) ||625(Operand.getReg() == M68k::A0) || (Operand.getReg() == M68k::A1))) {626return Match_Success;627}628break;629}630631return Match_InvalidOperand;632}633634bool M68kAsmParser::parseRegisterName(MCRegister &RegNo, SMLoc Loc,635StringRef RegisterName) {636auto RegisterNameLower = RegisterName.lower();637638// CCR register639if (RegisterNameLower == "ccr") {640RegNo = M68k::CCR;641return true;642}643644// Parse simple general-purpose registers.645if (RegisterNameLower.size() == 2) {646647switch (RegisterNameLower[0]) {648case 'd':649case 'a': {650if (isdigit(RegisterNameLower[1])) {651unsigned IndexOffset = (RegisterNameLower[0] == 'a') ? 8 : 0;652unsigned RegIndex = (unsigned)(RegisterNameLower[1] - '0');653if (RegIndex < 8) {654RegNo = getRegisterByIndex(IndexOffset + RegIndex);655return true;656}657}658break;659}660661case 's':662if (RegisterNameLower[1] == 'p') {663RegNo = M68k::SP;664return true;665} else if (RegisterNameLower[1] == 'r') {666RegNo = M68k::SR;667return true;668}669break;670671case 'p':672if (RegisterNameLower[1] == 'c') {673RegNo = M68k::PC;674return true;675}676break;677}678} else if (StringRef(RegisterNameLower).starts_with("fp") &&679RegisterNameLower.size() > 2) {680auto RegIndex = unsigned(RegisterNameLower[2] - '0');681if (RegIndex < 8 && RegisterNameLower.size() == 3) {682// Floating point data register.683RegNo = getRegisterByIndex(16 + RegIndex);684return true;685} else {686// Floating point control register.687RegNo = StringSwitch<unsigned>(RegisterNameLower)688.Cases("fpc", "fpcr", M68k::FPC)689.Cases("fps", "fpsr", M68k::FPS)690.Cases("fpi", "fpiar", M68k::FPIAR)691.Default(M68k::NoRegister);692assert(RegNo != M68k::NoRegister &&693"Unrecognized FP control register name");694return true;695}696}697698return false;699}700701ParseStatus M68kAsmParser::parseRegister(MCRegister &RegNo) {702bool HasPercent = false;703AsmToken PercentToken;704705LLVM_DEBUG(dbgs() << "parseRegister "; getTok().dump(dbgs()); dbgs() << "\n");706707if (getTok().is(AsmToken::Percent)) {708HasPercent = true;709PercentToken = Lex();710} else if (!RegisterPrefixOptional.getValue()) {711return ParseStatus::NoMatch;712}713714if (!Parser.getTok().is(AsmToken::Identifier)) {715if (HasPercent) {716getLexer().UnLex(PercentToken);717}718return ParseStatus::NoMatch;719}720721auto RegisterName = Parser.getTok().getString();722if (!parseRegisterName(RegNo, Parser.getLexer().getLoc(), RegisterName)) {723if (HasPercent) {724getLexer().UnLex(PercentToken);725}726return ParseStatus::NoMatch;727}728729Parser.Lex();730return ParseStatus::Success;731}732733bool M68kAsmParser::parseRegister(MCRegister &Reg, SMLoc &StartLoc,734SMLoc &EndLoc) {735ParseStatus Result = tryParseRegister(Reg, StartLoc, EndLoc);736if (!Result.isSuccess())737return Error(StartLoc, "expected register");738739return false;740}741742ParseStatus M68kAsmParser::tryParseRegister(MCRegister &Reg, SMLoc &StartLoc,743SMLoc &EndLoc) {744StartLoc = getLexer().getLoc();745ParseStatus Result = parseRegister(Reg);746EndLoc = getLexer().getLoc();747return Result;748}749750bool M68kAsmParser::isExpr() {751switch (Parser.getTok().getKind()) {752case AsmToken::Identifier:753case AsmToken::Integer:754return true;755case AsmToken::Minus:756return getLexer().peekTok().getKind() == AsmToken::Integer;757758default:759return false;760}761}762763ParseStatus M68kAsmParser::parseImm(OperandVector &Operands) {764if (getLexer().isNot(AsmToken::Hash))765return ParseStatus::NoMatch;766SMLoc Start = getLexer().getLoc();767Parser.Lex();768769SMLoc End;770const MCExpr *Expr;771772if (getParser().parseExpression(Expr, End))773return ParseStatus::Failure;774775Operands.push_back(M68kOperand::createImm(Expr, Start, End));776return ParseStatus::Success;777}778779ParseStatus M68kAsmParser::parseMemOp(OperandVector &Operands) {780SMLoc Start = getLexer().getLoc();781bool IsPD = false;782M68kMemOp MemOp;783784// Check for a plain register or register mask.785ParseStatus Result = parseRegOrMoveMask(Operands);786if (!Result.isNoMatch())787return Result;788789// Check for pre-decrement & outer displacement.790bool HasDisplacement = false;791if (getLexer().is(AsmToken::Minus)) {792IsPD = true;793Parser.Lex();794} else if (isExpr()) {795if (Parser.parseExpression(MemOp.OuterDisp))796return ParseStatus::Failure;797HasDisplacement = true;798}799800if (getLexer().isNot(AsmToken::LParen)) {801if (HasDisplacement) {802MemOp.Op = M68kMemOp::Kind::Addr;803Operands.push_back(804M68kOperand::createMemOp(MemOp, Start, getLexer().getLoc()));805return ParseStatus::Success;806}807if (IsPD)808return Error(getLexer().getLoc(), "expected (");809810return ParseStatus::NoMatch;811}812Parser.Lex();813814// Check for constant dereference & MIT-style displacement815if (!HasDisplacement && isExpr()) {816if (Parser.parseExpression(MemOp.OuterDisp))817return ParseStatus::Failure;818HasDisplacement = true;819820// If we're not followed by a comma, we're a constant dereference.821if (getLexer().isNot(AsmToken::Comma)) {822MemOp.Op = M68kMemOp::Kind::Addr;823Operands.push_back(824M68kOperand::createMemOp(MemOp, Start, getLexer().getLoc()));825return ParseStatus::Success;826}827828Parser.Lex();829}830831Result = parseRegister(MemOp.OuterReg);832if (Result.isFailure())833return ParseStatus::Failure;834835if (!Result.isSuccess())836return Error(getLexer().getLoc(), "expected register");837838// Check for Index.839bool HasIndex = false;840if (Parser.getTok().is(AsmToken::Comma)) {841Parser.Lex();842843Result = parseRegister(MemOp.InnerReg);844if (Result.isFailure())845return Result;846847if (Result.isNoMatch())848return Error(getLexer().getLoc(), "expected register");849850// TODO: parse size, scale and inner displacement.851MemOp.Size = 4;852MemOp.Scale = 1;853MemOp.InnerDisp = MCConstantExpr::create(0, Parser.getContext(), true, 4);854HasIndex = true;855}856857if (Parser.getTok().isNot(AsmToken::RParen))858return Error(getLexer().getLoc(), "expected )");859Parser.Lex();860861bool IsPI = false;862if (!IsPD && Parser.getTok().is(AsmToken::Plus)) {863Parser.Lex();864IsPI = true;865}866867SMLoc End = getLexer().getLoc();868869unsigned OpCount = IsPD + IsPI + (HasIndex || HasDisplacement);870if (OpCount > 1)871return Error(Start, "only one of post-increment, pre-decrement or "872"displacement can be used");873874if (IsPD) {875MemOp.Op = M68kMemOp::Kind::RegPreDecrement;876} else if (IsPI) {877MemOp.Op = M68kMemOp::Kind::RegPostIncrement;878} else if (HasIndex) {879MemOp.Op = M68kMemOp::Kind::RegIndirectDisplacementIndex;880} else if (HasDisplacement) {881MemOp.Op = M68kMemOp::Kind::RegIndirectDisplacement;882} else {883MemOp.Op = M68kMemOp::Kind::RegIndirect;884}885886Operands.push_back(M68kOperand::createMemOp(MemOp, Start, End));887return ParseStatus::Success;888}889890ParseStatus M68kAsmParser::parseRegOrMoveMask(OperandVector &Operands) {891SMLoc Start = getLexer().getLoc();892M68kMemOp MemOp(M68kMemOp::Kind::RegMask);893MemOp.RegMask = 0;894895for (;;) {896bool IsFirstRegister =897(MemOp.Op == M68kMemOp::Kind::RegMask) && (MemOp.RegMask == 0);898899MCRegister FirstRegister;900ParseStatus Result = parseRegister(FirstRegister);901if (IsFirstRegister && Result.isNoMatch())902return ParseStatus::NoMatch;903if (!Result.isSuccess())904return Error(getLexer().getLoc(), "expected start register");905906MCRegister LastRegister = FirstRegister;907if (parseOptionalToken(AsmToken::Minus)) {908Result = parseRegister(LastRegister);909if (!Result.isSuccess())910return Error(getLexer().getLoc(), "expected end register");911}912913unsigned FirstRegisterIndex = getRegisterIndex(FirstRegister);914unsigned LastRegisterIndex = getRegisterIndex(LastRegister);915916uint16_t NumNewBits = LastRegisterIndex - FirstRegisterIndex + 1;917uint16_t NewMaskBits = ((1 << NumNewBits) - 1) << FirstRegisterIndex;918919if (IsFirstRegister && (FirstRegister == LastRegister)) {920// First register range is a single register, simplify to just Reg921// so that it matches more operands.922MemOp.Op = M68kMemOp::Kind::Reg;923MemOp.OuterReg = FirstRegister;924} else {925if (MemOp.Op == M68kMemOp::Kind::Reg) {926// This is the second register being specified - expand the Reg operand927// into a mask first.928MemOp.Op = M68kMemOp::Kind::RegMask;929MemOp.RegMask = 1 << getRegisterIndex(MemOp.OuterReg);930931if (MemOp.RegMask == 0)932return Error(getLexer().getLoc(),933"special registers cannot be used in register masks");934}935936if ((FirstRegisterIndex >= 16) || (LastRegisterIndex >= 16))937return Error(getLexer().getLoc(),938"special registers cannot be used in register masks");939940if (NewMaskBits & MemOp.RegMask)941return Error(getLexer().getLoc(), "conflicting masked registers");942943MemOp.RegMask |= NewMaskBits;944}945946if (!parseOptionalToken(AsmToken::Slash))947break;948}949950Operands.push_back(951M68kOperand::createMemOp(MemOp, Start, getLexer().getLoc()));952return ParseStatus::Success;953}954955void M68kAsmParser::eatComma() {956if (Parser.getTok().is(AsmToken::Comma)) {957Parser.Lex();958}959}960961bool M68kAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,962SMLoc NameLoc, OperandVector &Operands) {963SMLoc Start = getLexer().getLoc();964Operands.push_back(M68kOperand::createToken(Name, Start, Start));965966bool First = true;967while (Parser.getTok().isNot(AsmToken::EndOfStatement)) {968if (!First) {969eatComma();970} else {971First = false;972}973974ParseStatus MatchResult = MatchOperandParserImpl(Operands, Name);975if (MatchResult.isSuccess())976continue;977978// Add custom operand formats here...979SMLoc Loc = getLexer().getLoc();980Parser.eatToEndOfStatement();981return Error(Loc, "unexpected token parsing operands");982}983984// Eat EndOfStatement.985Parser.Lex();986return false;987}988989bool M68kAsmParser::invalidOperand(SMLoc const &Loc,990OperandVector const &Operands,991uint64_t const &ErrorInfo) {992SMLoc ErrorLoc = Loc;993char const *Diag = 0;994995if (ErrorInfo != ~0U) {996if (ErrorInfo >= Operands.size()) {997Diag = "too few operands for instruction.";998} else {999auto const &Op = (M68kOperand const &)*Operands[ErrorInfo];1000if (Op.getStartLoc() != SMLoc()) {1001ErrorLoc = Op.getStartLoc();1002}1003}1004}10051006if (!Diag) {1007Diag = "invalid operand for instruction";1008}10091010return Error(ErrorLoc, Diag);1011}10121013bool M68kAsmParser::missingFeature(llvm::SMLoc const &Loc,1014uint64_t const &ErrorInfo) {1015return Error(Loc, "instruction requires a CPU feature not currently enabled");1016}10171018bool M68kAsmParser::emit(MCInst &Inst, SMLoc const &Loc,1019MCStreamer &Out) const {1020Inst.setLoc(Loc);1021Out.emitInstruction(Inst, STI);10221023return false;1024}10251026bool M68kAsmParser::MatchAndEmitInstruction(SMLoc Loc, unsigned &Opcode,1027OperandVector &Operands,1028MCStreamer &Out,1029uint64_t &ErrorInfo,1030bool MatchingInlineAsm) {1031MCInst Inst;1032unsigned MatchResult =1033MatchInstructionImpl(Operands, Inst, ErrorInfo, MatchingInlineAsm);10341035switch (MatchResult) {1036case Match_Success:1037return emit(Inst, Loc, Out);1038case Match_MissingFeature:1039return missingFeature(Loc, ErrorInfo);1040case Match_InvalidOperand:1041return invalidOperand(Loc, Operands, ErrorInfo);1042case Match_MnemonicFail:1043return Error(Loc, "invalid instruction");1044default:1045return true;1046}1047}10481049void M68kOperand::print(raw_ostream &OS) const {1050switch (Kind) {1051case KindTy::Invalid:1052OS << "invalid";1053break;10541055case KindTy::Token:1056OS << "token '" << Token << "'";1057break;10581059case KindTy::Imm: {1060int64_t Value;1061Expr->evaluateAsAbsolute(Value);1062OS << "immediate " << Value;1063break;1064}10651066case KindTy::MemOp:1067MemOp.print(OS);1068break;1069}1070}107110721073