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