//===- MSP430AsmParser.cpp - Parse MSP430 assembly to MCInst instructions -===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "MSP430.h" #include "MSP430RegisterInfo.h" #include "MCTargetDesc/MSP430MCTargetDesc.h" #include "TargetInfo/MSP430TargetInfo.h" #include "llvm/ADT/APInt.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCInst.h" #include "llvm/MC/MCInstBuilder.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/MC/MCValue.h" #include "llvm/Support/Debug.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/TargetRegistry.h" #define DEBUG_TYPE "msp430-asm-parser" using namespace llvm; namespace { /// Parses MSP430 assembly from a stream. class MSP430AsmParser : public MCTargetAsmParser { const MCSubtargetInfo &STI; MCAsmParser &Parser; const MCRegisterInfo *MRI; bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, OperandVector &Operands, MCStreamer &Out, uint64_t &ErrorInfo, bool MatchingInlineAsm) override; bool ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc) override; OperandMatchResultTy tryParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc) override; bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name, SMLoc NameLoc, OperandVector &Operands) override; bool ParseDirective(AsmToken DirectiveID) override; bool ParseDirectiveRefSym(AsmToken DirectiveID); unsigned validateTargetOperandClass(MCParsedAsmOperand &Op, unsigned Kind) override; bool parseJccInstruction(ParseInstructionInfo &Info, StringRef Name, SMLoc NameLoc, OperandVector &Operands); bool ParseOperand(OperandVector &Operands); bool ParseLiteralValues(unsigned Size, SMLoc L); MCAsmParser &getParser() const { return Parser; } MCAsmLexer &getLexer() const { return Parser.getLexer(); } /// @name Auto-generated Matcher Functions /// { #define GET_ASSEMBLER_HEADER #include "MSP430GenAsmMatcher.inc" /// } public: MSP430AsmParser(const MCSubtargetInfo &STI, MCAsmParser &Parser, const MCInstrInfo &MII, const MCTargetOptions &Options) : MCTargetAsmParser(Options, STI, MII), STI(STI), Parser(Parser) { MCAsmParserExtension::Initialize(Parser); MRI = getContext().getRegisterInfo(); setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits())); } }; /// A parsed MSP430 assembly operand. class MSP430Operand : public MCParsedAsmOperand { typedef MCParsedAsmOperand Base; enum KindTy { k_Imm, k_Reg, k_Tok, k_Mem, k_IndReg, k_PostIndReg } Kind; struct Memory { unsigned Reg; const MCExpr *Offset; }; union { const MCExpr *Imm; unsigned Reg; StringRef Tok; Memory Mem; }; SMLoc Start, End; public: MSP430Operand(StringRef Tok, SMLoc const &S) : Base(), Kind(k_Tok), Tok(Tok), Start(S), End(S) {} MSP430Operand(KindTy Kind, unsigned Reg, SMLoc const &S, SMLoc const &E) : Base(), Kind(Kind), Reg(Reg), Start(S), End(E) {} MSP430Operand(MCExpr const *Imm, SMLoc const &S, SMLoc const &E) : Base(), Kind(k_Imm), Imm(Imm), Start(S), End(E) {} MSP430Operand(unsigned Reg, MCExpr const *Expr, SMLoc const &S, SMLoc const &E) : Base(), Kind(k_Mem), Mem({Reg, Expr}), Start(S), End(E) {} void addRegOperands(MCInst &Inst, unsigned N) const { assert((Kind == k_Reg || Kind == k_IndReg || Kind == k_PostIndReg) && "Unexpected operand kind"); assert(N == 1 && "Invalid number of operands!"); Inst.addOperand(MCOperand::createReg(Reg)); } void addExprOperand(MCInst &Inst, const MCExpr *Expr) const { // Add as immediate when possible if (!Expr) Inst.addOperand(MCOperand::createImm(0)); else if (const MCConstantExpr *CE = dyn_cast(Expr)) Inst.addOperand(MCOperand::createImm(CE->getValue())); else Inst.addOperand(MCOperand::createExpr(Expr)); } void addImmOperands(MCInst &Inst, unsigned N) const { assert(Kind == k_Imm && "Unexpected operand kind"); assert(N == 1 && "Invalid number of operands!"); addExprOperand(Inst, Imm); } void addMemOperands(MCInst &Inst, unsigned N) const { assert(Kind == k_Mem && "Unexpected operand kind"); assert(N == 2 && "Invalid number of operands"); Inst.addOperand(MCOperand::createReg(Mem.Reg)); addExprOperand(Inst, Mem.Offset); } bool isReg() const override { return Kind == k_Reg; } bool isImm() const override { return Kind == k_Imm; } bool isToken() const override { return Kind == k_Tok; } bool isMem() const override { return Kind == k_Mem; } bool isIndReg() const { return Kind == k_IndReg; } bool isPostIndReg() const { return Kind == k_PostIndReg; } bool isCGImm() const { if (Kind != k_Imm) return false; int64_t Val; if (!Imm->evaluateAsAbsolute(Val)) return false; if (Val == 0 || Val == 1 || Val == 2 || Val == 4 || Val == 8 || Val == -1) return true; return false; } StringRef getToken() const { assert(Kind == k_Tok && "Invalid access!"); return Tok; } unsigned getReg() const override { assert(Kind == k_Reg && "Invalid access!"); return Reg; } void setReg(unsigned RegNo) { assert(Kind == k_Reg && "Invalid access!"); Reg = RegNo; } static std::unique_ptr CreateToken(StringRef Str, SMLoc S) { return std::make_unique(Str, S); } static std::unique_ptr CreateReg(unsigned RegNum, SMLoc S, SMLoc E) { return std::make_unique(k_Reg, RegNum, S, E); } static std::unique_ptr CreateImm(const MCExpr *Val, SMLoc S, SMLoc E) { return std::make_unique(Val, S, E); } static std::unique_ptr CreateMem(unsigned RegNum, const MCExpr *Val, SMLoc S, SMLoc E) { return std::make_unique(RegNum, Val, S, E); } static std::unique_ptr CreateIndReg(unsigned RegNum, SMLoc S, SMLoc E) { return std::make_unique(k_IndReg, RegNum, S, E); } static std::unique_ptr CreatePostIndReg(unsigned RegNum, SMLoc S, SMLoc E) { return std::make_unique(k_PostIndReg, RegNum, S, E); } SMLoc getStartLoc() const override { return Start; } SMLoc getEndLoc() const override { return End; } void print(raw_ostream &O) const override { switch (Kind) { case k_Tok: O << "Token " << Tok; break; case k_Reg: O << "Register " << Reg; break; case k_Imm: O << "Immediate " << *Imm; break; case k_Mem: O << "Memory "; O << *Mem.Offset << "(" << Reg << ")"; break; case k_IndReg: O << "RegInd " << Reg; break; case k_PostIndReg: O << "PostInc " << Reg; break; } } }; } // end anonymous namespace bool MSP430AsmParser::MatchAndEmitInstruction(SMLoc Loc, unsigned &Opcode, OperandVector &Operands, MCStreamer &Out, uint64_t &ErrorInfo, bool MatchingInlineAsm) { MCInst Inst; unsigned MatchResult = MatchInstructionImpl(Operands, Inst, ErrorInfo, MatchingInlineAsm); switch (MatchResult) { case Match_Success: Inst.setLoc(Loc); Out.emitInstruction(Inst, STI); return false; case Match_MnemonicFail: return Error(Loc, "invalid instruction mnemonic"); case Match_InvalidOperand: { SMLoc ErrorLoc = Loc; if (ErrorInfo != ~0U) { if (ErrorInfo >= Operands.size()) return Error(ErrorLoc, "too few operands for instruction"); ErrorLoc = ((MSP430Operand &)*Operands[ErrorInfo]).getStartLoc(); if (ErrorLoc == SMLoc()) ErrorLoc = Loc; } return Error(ErrorLoc, "invalid operand for instruction"); } default: return true; } } // Auto-generated by TableGen static unsigned MatchRegisterName(StringRef Name); static unsigned MatchRegisterAltName(StringRef Name); bool MSP430AsmParser::ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc) { switch (tryParseRegister(RegNo, StartLoc, EndLoc)) { case MatchOperand_ParseFail: return Error(StartLoc, "invalid register name"); case MatchOperand_Success: return false; case MatchOperand_NoMatch: return true; } llvm_unreachable("unknown match result type"); } OperandMatchResultTy MSP430AsmParser::tryParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc) { if (getLexer().getKind() == AsmToken::Identifier) { auto Name = getLexer().getTok().getIdentifier().lower(); RegNo = MatchRegisterName(Name); if (RegNo == MSP430::NoRegister) { RegNo = MatchRegisterAltName(Name); if (RegNo == MSP430::NoRegister) return MatchOperand_NoMatch; } AsmToken const &T = getParser().getTok(); StartLoc = T.getLoc(); EndLoc = T.getEndLoc(); getLexer().Lex(); // eat register token return MatchOperand_Success; } return MatchOperand_ParseFail; } bool MSP430AsmParser::parseJccInstruction(ParseInstructionInfo &Info, StringRef Name, SMLoc NameLoc, OperandVector &Operands) { if (!Name.startswith_lower("j")) return true; auto CC = Name.drop_front().lower(); unsigned CondCode; if (CC == "ne" || CC == "nz") CondCode = MSP430CC::COND_NE; else if (CC == "eq" || CC == "z") CondCode = MSP430CC::COND_E; else if (CC == "lo" || CC == "nc") CondCode = MSP430CC::COND_LO; else if (CC == "hs" || CC == "c") CondCode = MSP430CC::COND_HS; else if (CC == "n") CondCode = MSP430CC::COND_N; else if (CC == "ge") CondCode = MSP430CC::COND_GE; else if (CC == "l") CondCode = MSP430CC::COND_L; else if (CC == "mp") CondCode = MSP430CC::COND_NONE; else return Error(NameLoc, "unknown instruction"); if (CondCode == (unsigned)MSP430CC::COND_NONE) Operands.push_back(MSP430Operand::CreateToken("jmp", NameLoc)); else { Operands.push_back(MSP430Operand::CreateToken("j", NameLoc)); const MCExpr *CCode = MCConstantExpr::create(CondCode, getContext()); Operands.push_back(MSP430Operand::CreateImm(CCode, SMLoc(), SMLoc())); } // Skip optional '$' sign. if (getLexer().getKind() == AsmToken::Dollar) getLexer().Lex(); // Eat '$' const MCExpr *Val; SMLoc ExprLoc = getLexer().getLoc(); if (getParser().parseExpression(Val)) return Error(ExprLoc, "expected expression operand"); int64_t Res; if (Val->evaluateAsAbsolute(Res)) if (Res < -512 || Res > 511) return Error(ExprLoc, "invalid jump offset"); Operands.push_back(MSP430Operand::CreateImm(Val, ExprLoc, getLexer().getLoc())); if (getLexer().isNot(AsmToken::EndOfStatement)) { SMLoc Loc = getLexer().getLoc(); getParser().eatToEndOfStatement(); return Error(Loc, "unexpected token"); } getParser().Lex(); // Consume the EndOfStatement. return false; } bool MSP430AsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name, SMLoc NameLoc, OperandVector &Operands) { // Drop .w suffix if (Name.endswith_lower(".w")) Name = Name.drop_back(2); if (!parseJccInstruction(Info, Name, NameLoc, Operands)) return false; // First operand is instruction mnemonic Operands.push_back(MSP430Operand::CreateToken(Name, NameLoc)); // If there are no more operands, then finish if (getLexer().is(AsmToken::EndOfStatement)) return false; // Parse first operand if (ParseOperand(Operands)) return true; // Parse second operand if any if (getLexer().is(AsmToken::Comma)) { getLexer().Lex(); // Eat ',' if (ParseOperand(Operands)) return true; } if (getLexer().isNot(AsmToken::EndOfStatement)) { SMLoc Loc = getLexer().getLoc(); getParser().eatToEndOfStatement(); return Error(Loc, "unexpected token"); } getParser().Lex(); // Consume the EndOfStatement. return false; } bool MSP430AsmParser::ParseDirectiveRefSym(AsmToken DirectiveID) { StringRef Name; if (getParser().parseIdentifier(Name)) return TokError("expected identifier in directive"); MCSymbol *Sym = getContext().getOrCreateSymbol(Name); getStreamer().emitSymbolAttribute(Sym, MCSA_Global); return false; } bool MSP430AsmParser::ParseDirective(AsmToken DirectiveID) { StringRef IDVal = DirectiveID.getIdentifier(); if (IDVal.lower() == ".long") { ParseLiteralValues(4, DirectiveID.getLoc()); } else if (IDVal.lower() == ".word" || IDVal.lower() == ".short") { ParseLiteralValues(2, DirectiveID.getLoc()); } else if (IDVal.lower() == ".byte") { ParseLiteralValues(1, DirectiveID.getLoc()); } else if (IDVal.lower() == ".refsym") { return ParseDirectiveRefSym(DirectiveID); } return true; } bool MSP430AsmParser::ParseOperand(OperandVector &Operands) { switch (getLexer().getKind()) { default: return true; case AsmToken::Identifier: { // try rN unsigned RegNo; SMLoc StartLoc, EndLoc; if (!ParseRegister(RegNo, StartLoc, EndLoc)) { Operands.push_back(MSP430Operand::CreateReg(RegNo, StartLoc, EndLoc)); return false; } LLVM_FALLTHROUGH; } case AsmToken::Integer: case AsmToken::Plus: case AsmToken::Minus: { SMLoc StartLoc = getParser().getTok().getLoc(); const MCExpr *Val; // Try constexpr[(rN)] if (!getParser().parseExpression(Val)) { unsigned RegNo = MSP430::PC; SMLoc EndLoc = getParser().getTok().getLoc(); // Try (rN) if (getLexer().getKind() == AsmToken::LParen) { getLexer().Lex(); // Eat '(' SMLoc RegStartLoc; if (ParseRegister(RegNo, RegStartLoc, EndLoc)) return true; if (getLexer().getKind() != AsmToken::RParen) return true; EndLoc = getParser().getTok().getEndLoc(); getLexer().Lex(); // Eat ')' } Operands.push_back(MSP430Operand::CreateMem(RegNo, Val, StartLoc, EndLoc)); return false; } return true; } case AsmToken::Amp: { // Try &constexpr SMLoc StartLoc = getParser().getTok().getLoc(); getLexer().Lex(); // Eat '&' const MCExpr *Val; if (!getParser().parseExpression(Val)) { SMLoc EndLoc = getParser().getTok().getLoc(); Operands.push_back(MSP430Operand::CreateMem(MSP430::SR, Val, StartLoc, EndLoc)); return false; } return true; } case AsmToken::At: { // Try @rN[+] SMLoc StartLoc = getParser().getTok().getLoc(); getLexer().Lex(); // Eat '@' unsigned RegNo; SMLoc RegStartLoc, EndLoc; if (ParseRegister(RegNo, RegStartLoc, EndLoc)) return true; if (getLexer().getKind() == AsmToken::Plus) { Operands.push_back(MSP430Operand::CreatePostIndReg(RegNo, StartLoc, EndLoc)); getLexer().Lex(); // Eat '+' return false; } if (Operands.size() > 1) // Emulate @rd in destination position as 0(rd) Operands.push_back(MSP430Operand::CreateMem(RegNo, MCConstantExpr::create(0, getContext()), StartLoc, EndLoc)); else Operands.push_back(MSP430Operand::CreateIndReg(RegNo, StartLoc, EndLoc)); return false; } case AsmToken::Hash: // Try #constexpr SMLoc StartLoc = getParser().getTok().getLoc(); getLexer().Lex(); // Eat '#' const MCExpr *Val; if (!getParser().parseExpression(Val)) { SMLoc EndLoc = getParser().getTok().getLoc(); Operands.push_back(MSP430Operand::CreateImm(Val, StartLoc, EndLoc)); return false; } return true; } } bool MSP430AsmParser::ParseLiteralValues(unsigned Size, SMLoc L) { auto parseOne = [&]() -> bool { const MCExpr *Value; if (getParser().parseExpression(Value)) return true; getParser().getStreamer().emitValue(Value, Size, L); return false; }; return (parseMany(parseOne)); } extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeMSP430AsmParser() { RegisterMCAsmParser X(getTheMSP430Target()); } #define GET_REGISTER_MATCHER #define GET_MATCHER_IMPLEMENTATION #include "MSP430GenAsmMatcher.inc" static unsigned convertGR16ToGR8(unsigned Reg) { switch (Reg) { default: llvm_unreachable("Unknown GR16 register"); case MSP430::PC: return MSP430::PCB; case MSP430::SP: return MSP430::SPB; case MSP430::SR: return MSP430::SRB; case MSP430::CG: return MSP430::CGB; case MSP430::R4: return MSP430::R4B; case MSP430::R5: return MSP430::R5B; case MSP430::R6: return MSP430::R6B; case MSP430::R7: return MSP430::R7B; case MSP430::R8: return MSP430::R8B; case MSP430::R9: return MSP430::R9B; case MSP430::R10: return MSP430::R10B; case MSP430::R11: return MSP430::R11B; case MSP430::R12: return MSP430::R12B; case MSP430::R13: return MSP430::R13B; case MSP430::R14: return MSP430::R14B; case MSP430::R15: return MSP430::R15B; } } unsigned MSP430AsmParser::validateTargetOperandClass(MCParsedAsmOperand &AsmOp, unsigned Kind) { MSP430Operand &Op = static_cast(AsmOp); if (!Op.isReg()) return Match_InvalidOperand; unsigned Reg = Op.getReg(); bool isGR16 = MSP430MCRegisterClasses[MSP430::GR16RegClassID].contains(Reg); if (isGR16 && (Kind == MCK_GR8)) { Op.setReg(convertGR16ToGR8(Reg)); return Match_Success; } return Match_InvalidOperand; }