589 lines · cpp
1//===- MSP430AsmParser.cpp - Parse MSP430 assembly to MCInst instructions -===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "MCTargetDesc/MSP430MCAsmInfo.h"10#include "MCTargetDesc/MSP430MCTargetDesc.h"11#include "MSP430.h"12#include "MSP430RegisterInfo.h"13#include "TargetInfo/MSP430TargetInfo.h"14 15#include "llvm/ADT/APInt.h"16#include "llvm/MC/MCContext.h"17#include "llvm/MC/MCExpr.h"18#include "llvm/MC/MCInst.h"19#include "llvm/MC/MCInstrInfo.h"20#include "llvm/MC/MCParser/AsmLexer.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/MCValue.h"27#include "llvm/MC/TargetRegistry.h"28#include "llvm/Support/Compiler.h"29#include "llvm/Support/Debug.h"30 31#define DEBUG_TYPE "msp430-asm-parser"32 33using namespace llvm;34 35namespace {36 37/// Parses MSP430 assembly from a stream.38class MSP430AsmParser : public MCTargetAsmParser {39 MCAsmParser &Parser;40 const MCRegisterInfo *MRI;41 42 bool matchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,43 OperandVector &Operands, MCStreamer &Out,44 uint64_t &ErrorInfo,45 bool MatchingInlineAsm) override;46 47 bool parseRegister(MCRegister &Reg, SMLoc &StartLoc, SMLoc &EndLoc) override;48 ParseStatus tryParseRegister(MCRegister &Reg, SMLoc &StartLoc,49 SMLoc &EndLoc) override;50 51 bool parseInstruction(ParseInstructionInfo &Info, StringRef Name,52 SMLoc NameLoc, OperandVector &Operands) override;53 54 ParseStatus parseDirective(AsmToken DirectiveID) override;55 bool ParseDirectiveRefSym(AsmToken DirectiveID);56 57 unsigned validateTargetOperandClass(MCParsedAsmOperand &Op,58 unsigned Kind) override;59 60 bool parseJccInstruction(ParseInstructionInfo &Info, StringRef Name,61 SMLoc NameLoc, OperandVector &Operands);62 63 bool ParseOperand(OperandVector &Operands);64 65 bool ParseLiteralValues(unsigned Size, SMLoc L);66 67 MCAsmParser &getParser() const { return Parser; }68 AsmLexer &getLexer() const { return Parser.getLexer(); }69 70 /// @name Auto-generated Matcher Functions71 /// {72 73#define GET_ASSEMBLER_HEADER74#include "MSP430GenAsmMatcher.inc"75 76 /// }77 78public:79 MSP430AsmParser(const MCSubtargetInfo &STI, MCAsmParser &Parser,80 const MCInstrInfo &MII, const MCTargetOptions &Options)81 : MCTargetAsmParser(Options, STI, MII), Parser(Parser) {82 MCAsmParserExtension::Initialize(Parser);83 MRI = getContext().getRegisterInfo();84 85 setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits()));86 }87};88 89/// A parsed MSP430 assembly operand.90class MSP430Operand : public MCParsedAsmOperand {91 typedef MCParsedAsmOperand Base;92 93 enum KindTy {94 k_Imm,95 k_Reg,96 k_Tok,97 k_Mem,98 k_IndReg,99 k_PostIndReg100 } Kind;101 102 struct Memory {103 MCRegister Reg;104 const MCExpr *Offset;105 };106 union {107 const MCExpr *Imm;108 MCRegister Reg;109 StringRef Tok;110 Memory Mem;111 };112 113 SMLoc Start, End;114 115public:116 MSP430Operand(StringRef Tok, SMLoc const &S)117 : Kind(k_Tok), Tok(Tok), Start(S), End(S) {}118 MSP430Operand(KindTy Kind, MCRegister Reg, SMLoc const &S, SMLoc const &E)119 : Kind(Kind), Reg(Reg), Start(S), End(E) {}120 MSP430Operand(MCExpr const *Imm, SMLoc const &S, SMLoc const &E)121 : Kind(k_Imm), Imm(Imm), Start(S), End(E) {}122 MSP430Operand(MCRegister Reg, MCExpr const *Expr, SMLoc const &S,123 SMLoc const &E)124 : Kind(k_Mem), Mem({Reg, Expr}), Start(S), End(E) {}125 126 void addRegOperands(MCInst &Inst, unsigned N) const {127 assert((Kind == k_Reg || Kind == k_IndReg || Kind == k_PostIndReg) &&128 "Unexpected operand kind");129 assert(N == 1 && "Invalid number of operands!");130 131 Inst.addOperand(MCOperand::createReg(Reg));132 }133 134 void addExprOperand(MCInst &Inst, const MCExpr *Expr) const {135 // Add as immediate when possible136 if (!Expr)137 Inst.addOperand(MCOperand::createImm(0));138 else if (const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Expr))139 Inst.addOperand(MCOperand::createImm(CE->getValue()));140 else141 Inst.addOperand(MCOperand::createExpr(Expr));142 }143 144 void addImmOperands(MCInst &Inst, unsigned N) const {145 assert(Kind == k_Imm && "Unexpected operand kind");146 assert(N == 1 && "Invalid number of operands!");147 148 addExprOperand(Inst, Imm);149 }150 151 void addMemOperands(MCInst &Inst, unsigned N) const {152 assert(Kind == k_Mem && "Unexpected operand kind");153 assert(N == 2 && "Invalid number of operands");154 155 Inst.addOperand(MCOperand::createReg(Mem.Reg));156 addExprOperand(Inst, Mem.Offset);157 }158 159 bool isReg() const override { return Kind == k_Reg; }160 bool isImm() const override { return Kind == k_Imm; }161 bool isToken() const override { return Kind == k_Tok; }162 bool isMem() const override { return Kind == k_Mem; }163 bool isIndReg() const { return Kind == k_IndReg; }164 bool isPostIndReg() const { return Kind == k_PostIndReg; }165 166 bool isCGImm() const {167 if (Kind != k_Imm)168 return false;169 170 int64_t Val;171 if (!Imm->evaluateAsAbsolute(Val))172 return false;173 174 if (Val == 0 || Val == 1 || Val == 2 || Val == 4 || Val == 8 || Val == -1)175 return true;176 177 return false;178 }179 180 StringRef getToken() const {181 assert(Kind == k_Tok && "Invalid access!");182 return Tok;183 }184 185 MCRegister getReg() const override {186 assert(Kind == k_Reg && "Invalid access!");187 return Reg;188 }189 190 void setReg(MCRegister RegNo) {191 assert(Kind == k_Reg && "Invalid access!");192 Reg = RegNo;193 }194 195 static std::unique_ptr<MSP430Operand> CreateToken(StringRef Str, SMLoc S) {196 return std::make_unique<MSP430Operand>(Str, S);197 }198 199 static std::unique_ptr<MSP430Operand> CreateReg(MCRegister Reg, SMLoc S,200 SMLoc E) {201 return std::make_unique<MSP430Operand>(k_Reg, Reg, S, E);202 }203 204 static std::unique_ptr<MSP430Operand> CreateImm(const MCExpr *Val, SMLoc S,205 SMLoc E) {206 return std::make_unique<MSP430Operand>(Val, S, E);207 }208 209 static std::unique_ptr<MSP430Operand>210 CreateMem(MCRegister Reg, const MCExpr *Val, SMLoc S, SMLoc E) {211 return std::make_unique<MSP430Operand>(Reg, Val, S, E);212 }213 214 static std::unique_ptr<MSP430Operand> CreateIndReg(MCRegister Reg, SMLoc S,215 SMLoc E) {216 return std::make_unique<MSP430Operand>(k_IndReg, Reg, S, E);217 }218 219 static std::unique_ptr<MSP430Operand> CreatePostIndReg(MCRegister Reg,220 SMLoc S, SMLoc E) {221 return std::make_unique<MSP430Operand>(k_PostIndReg, Reg, S, E);222 }223 224 SMLoc getStartLoc() const override { return Start; }225 SMLoc getEndLoc() const override { return End; }226 227 void print(raw_ostream &O, const MCAsmInfo &MAI) const override {228 switch (Kind) {229 case k_Tok:230 O << "Token " << Tok;231 break;232 case k_Reg:233 O << "Register " << Reg.id();234 break;235 case k_Imm:236 O << "Immediate ";237 MAI.printExpr(O, *Imm);238 break;239 case k_Mem:240 O << "Memory ";241 MAI.printExpr(O, *Mem.Offset);242 break;243 case k_IndReg:244 O << "RegInd " << Reg.id();245 break;246 case k_PostIndReg:247 O << "PostInc " << Reg.id();248 break;249 }250 }251};252} // end anonymous namespace253 254bool MSP430AsmParser::matchAndEmitInstruction(SMLoc Loc, unsigned &Opcode,255 OperandVector &Operands,256 MCStreamer &Out,257 uint64_t &ErrorInfo,258 bool MatchingInlineAsm) {259 MCInst Inst;260 unsigned MatchResult =261 MatchInstructionImpl(Operands, Inst, ErrorInfo, MatchingInlineAsm);262 263 switch (MatchResult) {264 case Match_Success:265 Inst.setLoc(Loc);266 Out.emitInstruction(Inst, *STI);267 return false;268 case Match_MnemonicFail:269 return Error(Loc, "invalid instruction mnemonic");270 case Match_InvalidOperand: {271 SMLoc ErrorLoc = Loc;272 if (ErrorInfo != ~0U) {273 if (ErrorInfo >= Operands.size())274 return Error(ErrorLoc, "too few operands for instruction");275 276 ErrorLoc = ((MSP430Operand &)*Operands[ErrorInfo]).getStartLoc();277 if (ErrorLoc == SMLoc())278 ErrorLoc = Loc;279 }280 return Error(ErrorLoc, "invalid operand for instruction");281 }282 default:283 return true;284 }285}286 287// Auto-generated by TableGen288static MCRegister MatchRegisterName(StringRef Name);289static MCRegister MatchRegisterAltName(StringRef Name);290 291bool MSP430AsmParser::parseRegister(MCRegister &Reg, SMLoc &StartLoc,292 SMLoc &EndLoc) {293 ParseStatus Res = tryParseRegister(Reg, StartLoc, EndLoc);294 if (Res.isFailure())295 return Error(StartLoc, "invalid register name");296 if (Res.isSuccess())297 return false;298 if (Res.isNoMatch())299 return true;300 301 llvm_unreachable("unknown parse status");302}303 304ParseStatus MSP430AsmParser::tryParseRegister(MCRegister &Reg, SMLoc &StartLoc,305 SMLoc &EndLoc) {306 if (getLexer().getKind() == AsmToken::Identifier) {307 auto Name = getLexer().getTok().getIdentifier().lower();308 Reg = MatchRegisterName(Name);309 if (Reg == MSP430::NoRegister) {310 Reg = MatchRegisterAltName(Name);311 if (Reg == MSP430::NoRegister)312 return ParseStatus::NoMatch;313 }314 315 AsmToken const &T = getParser().getTok();316 StartLoc = T.getLoc();317 EndLoc = T.getEndLoc();318 getLexer().Lex(); // eat register token319 320 return ParseStatus::Success;321 }322 323 return ParseStatus::Failure;324}325 326bool MSP430AsmParser::parseJccInstruction(ParseInstructionInfo &Info,327 StringRef Name, SMLoc NameLoc,328 OperandVector &Operands) {329 if (!Name.starts_with_insensitive("j"))330 return true;331 332 auto CC = Name.drop_front().lower();333 unsigned CondCode;334 if (CC == "ne" || CC == "nz")335 CondCode = MSP430CC::COND_NE;336 else if (CC == "eq" || CC == "z")337 CondCode = MSP430CC::COND_E;338 else if (CC == "lo" || CC == "nc")339 CondCode = MSP430CC::COND_LO;340 else if (CC == "hs" || CC == "c")341 CondCode = MSP430CC::COND_HS;342 else if (CC == "n")343 CondCode = MSP430CC::COND_N;344 else if (CC == "ge")345 CondCode = MSP430CC::COND_GE;346 else if (CC == "l")347 CondCode = MSP430CC::COND_L;348 else if (CC == "mp")349 CondCode = MSP430CC::COND_NONE;350 else351 return Error(NameLoc, "unknown instruction");352 353 if (CondCode == (unsigned)MSP430CC::COND_NONE)354 Operands.push_back(MSP430Operand::CreateToken("jmp", NameLoc));355 else {356 Operands.push_back(MSP430Operand::CreateToken("j", NameLoc));357 const MCExpr *CCode = MCConstantExpr::create(CondCode, getContext());358 Operands.push_back(MSP430Operand::CreateImm(CCode, SMLoc(), SMLoc()));359 }360 361 // Skip optional '$' sign.362 (void)parseOptionalToken(AsmToken::Dollar);363 364 const MCExpr *Val;365 SMLoc ExprLoc = getLexer().getLoc();366 if (getParser().parseExpression(Val))367 return Error(ExprLoc, "expected expression operand");368 369 int64_t Res;370 if (Val->evaluateAsAbsolute(Res))371 if (Res < -512 || Res > 511)372 return Error(ExprLoc, "invalid jump offset");373 374 Operands.push_back(MSP430Operand::CreateImm(Val, ExprLoc,375 getLexer().getLoc()));376 377 if (getLexer().isNot(AsmToken::EndOfStatement)) {378 SMLoc Loc = getLexer().getLoc();379 getParser().eatToEndOfStatement();380 return Error(Loc, "unexpected token");381 }382 383 getParser().Lex(); // Consume the EndOfStatement.384 return false;385}386 387bool MSP430AsmParser::parseInstruction(ParseInstructionInfo &Info,388 StringRef Name, SMLoc NameLoc,389 OperandVector &Operands) {390 // Drop .w suffix391 if (Name.ends_with_insensitive(".w"))392 Name = Name.drop_back(2);393 394 if (!parseJccInstruction(Info, Name, NameLoc, Operands))395 return false;396 397 // First operand is instruction mnemonic398 Operands.push_back(MSP430Operand::CreateToken(Name, NameLoc));399 400 // If there are no more operands, then finish401 if (getLexer().is(AsmToken::EndOfStatement))402 return false;403 404 // Parse first operand405 if (ParseOperand(Operands))406 return true;407 408 // Parse second operand if any409 if (parseOptionalToken(AsmToken::Comma) && ParseOperand(Operands))410 return true;411 412 if (getLexer().isNot(AsmToken::EndOfStatement)) {413 SMLoc Loc = getLexer().getLoc();414 getParser().eatToEndOfStatement();415 return Error(Loc, "unexpected token");416 }417 418 getParser().Lex(); // Consume the EndOfStatement.419 return false;420}421 422bool MSP430AsmParser::ParseDirectiveRefSym(AsmToken DirectiveID) {423 StringRef Name;424 if (getParser().parseIdentifier(Name))425 return TokError("expected identifier in directive");426 427 MCSymbol *Sym = getContext().getOrCreateSymbol(Name);428 getStreamer().emitSymbolAttribute(Sym, MCSA_Global);429 return parseEOL();430}431 432ParseStatus MSP430AsmParser::parseDirective(AsmToken DirectiveID) {433 StringRef IDVal = DirectiveID.getIdentifier();434 if (IDVal.lower() == ".long")435 return ParseLiteralValues(4, DirectiveID.getLoc());436 if (IDVal.lower() == ".word" || IDVal.lower() == ".short")437 return ParseLiteralValues(2, DirectiveID.getLoc());438 if (IDVal.lower() == ".byte")439 return ParseLiteralValues(1, DirectiveID.getLoc());440 if (IDVal.lower() == ".refsym")441 return ParseDirectiveRefSym(DirectiveID);442 return ParseStatus::NoMatch;443}444 445bool MSP430AsmParser::ParseOperand(OperandVector &Operands) {446 switch (getLexer().getKind()) {447 default: return true;448 case AsmToken::Identifier: {449 // try rN450 MCRegister RegNo;451 SMLoc StartLoc, EndLoc;452 if (!parseRegister(RegNo, StartLoc, EndLoc)) {453 Operands.push_back(MSP430Operand::CreateReg(RegNo, StartLoc, EndLoc));454 return false;455 }456 [[fallthrough]];457 }458 case AsmToken::Integer:459 case AsmToken::Plus:460 case AsmToken::Minus: {461 SMLoc StartLoc = getParser().getTok().getLoc();462 const MCExpr *Val;463 // Try constexpr[(rN)]464 if (!getParser().parseExpression(Val)) {465 MCRegister RegNo = MSP430::PC;466 SMLoc EndLoc = getParser().getTok().getLoc();467 // Try (rN)468 if (parseOptionalToken(AsmToken::LParen)) {469 SMLoc RegStartLoc;470 if (parseRegister(RegNo, RegStartLoc, EndLoc))471 return true;472 EndLoc = getParser().getTok().getEndLoc();473 if (!parseOptionalToken(AsmToken::RParen))474 return true;475 }476 Operands.push_back(MSP430Operand::CreateMem(RegNo, Val, StartLoc,477 EndLoc));478 return false;479 }480 return true;481 }482 case AsmToken::Amp: {483 // Try &constexpr484 SMLoc StartLoc = getParser().getTok().getLoc();485 getLexer().Lex(); // Eat '&'486 const MCExpr *Val;487 if (!getParser().parseExpression(Val)) {488 SMLoc EndLoc = getParser().getTok().getLoc();489 Operands.push_back(MSP430Operand::CreateMem(MSP430::SR, Val, StartLoc,490 EndLoc));491 return false;492 }493 return true;494 }495 case AsmToken::At: {496 // Try @rN[+]497 SMLoc StartLoc = getParser().getTok().getLoc();498 getLexer().Lex(); // Eat '@'499 MCRegister RegNo;500 SMLoc RegStartLoc, EndLoc;501 if (parseRegister(RegNo, RegStartLoc, EndLoc))502 return true;503 if (parseOptionalToken(AsmToken::Plus)) {504 Operands.push_back(MSP430Operand::CreatePostIndReg(RegNo, StartLoc, EndLoc));505 return false;506 }507 if (Operands.size() > 1) // Emulate @rd in destination position as 0(rd)508 Operands.push_back(MSP430Operand::CreateMem(RegNo,509 MCConstantExpr::create(0, getContext()), StartLoc, EndLoc));510 else511 Operands.push_back(MSP430Operand::CreateIndReg(RegNo, StartLoc, EndLoc));512 return false;513 }514 case AsmToken::Hash:515 // Try #constexpr516 SMLoc StartLoc = getParser().getTok().getLoc();517 getLexer().Lex(); // Eat '#'518 const MCExpr *Val;519 if (!getParser().parseExpression(Val)) {520 SMLoc EndLoc = getParser().getTok().getLoc();521 Operands.push_back(MSP430Operand::CreateImm(Val, StartLoc, EndLoc));522 return false;523 }524 return true;525 }526}527 528bool MSP430AsmParser::ParseLiteralValues(unsigned Size, SMLoc L) {529 auto parseOne = [&]() -> bool {530 const MCExpr *Value;531 if (getParser().parseExpression(Value))532 return true;533 getParser().getStreamer().emitValue(Value, Size, L);534 return false;535 };536 return (parseMany(parseOne));537}538 539extern "C" LLVM_ABI LLVM_EXTERNAL_VISIBILITY void540LLVMInitializeMSP430AsmParser() {541 RegisterMCAsmParser<MSP430AsmParser> X(getTheMSP430Target());542}543 544#define GET_REGISTER_MATCHER545#define GET_MATCHER_IMPLEMENTATION546#include "MSP430GenAsmMatcher.inc"547 548static MCRegister convertGR16ToGR8(MCRegister Reg) {549 switch (Reg.id()) {550 default:551 llvm_unreachable("Unknown GR16 register");552 case MSP430::PC: return MSP430::PCB;553 case MSP430::SP: return MSP430::SPB;554 case MSP430::SR: return MSP430::SRB;555 case MSP430::CG: return MSP430::CGB;556 case MSP430::R4: return MSP430::R4B;557 case MSP430::R5: return MSP430::R5B;558 case MSP430::R6: return MSP430::R6B;559 case MSP430::R7: return MSP430::R7B;560 case MSP430::R8: return MSP430::R8B;561 case MSP430::R9: return MSP430::R9B;562 case MSP430::R10: return MSP430::R10B;563 case MSP430::R11: return MSP430::R11B;564 case MSP430::R12: return MSP430::R12B;565 case MSP430::R13: return MSP430::R13B;566 case MSP430::R14: return MSP430::R14B;567 case MSP430::R15: return MSP430::R15B;568 }569}570 571unsigned MSP430AsmParser::validateTargetOperandClass(MCParsedAsmOperand &AsmOp,572 unsigned Kind) {573 MSP430Operand &Op = static_cast<MSP430Operand &>(AsmOp);574 575 if (!Op.isReg())576 return Match_InvalidOperand;577 578 MCRegister Reg = Op.getReg();579 bool isGR16 =580 MSP430MCRegisterClasses[MSP430::GR16RegClassID].contains(Reg);581 582 if (isGR16 && (Kind == MCK_GR8)) {583 Op.setReg(convertGR16ToGR8(Reg));584 return Match_Success;585 }586 587 return Match_InvalidOperand;588}589