LLVM 20.0.0git
M68kAsmParser.cpp
Go to the documentation of this file.
1//===-- M68kAsmParser.cpp - Parse M68k 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 "M68kInstrInfo.h"
10#include "M68kRegisterInfo.h"
12
13#include "llvm/MC/MCContext.h"
17#include "llvm/MC/MCStreamer.h"
19
20#include <sstream>
21
22#define DEBUG_TYPE "m68k-asm-parser"
23
24using namespace llvm;
25
27 "m68k-register-prefix-optional", cl::Hidden,
28 cl::desc("Enable specifying registers without the % prefix"),
29 cl::init(false));
30
31namespace {
32/// Parses M68k assembly from a stream.
33class M68kAsmParser : public MCTargetAsmParser {
34 const MCSubtargetInfo &STI;
35 MCAsmParser &Parser;
36 const MCRegisterInfo *MRI;
37
38#define GET_ASSEMBLER_HEADER
39#include "M68kGenAsmMatcher.inc"
40
41 // Helpers for Match&Emit.
42 bool invalidOperand(const SMLoc &Loc, const OperandVector &Operands,
43 const uint64_t &ErrorInfo);
44 bool missingFeature(const SMLoc &Loc, const uint64_t &ErrorInfo);
45 bool emit(MCInst &Inst, SMLoc const &Loc, MCStreamer &Out) const;
46 bool parseRegisterName(MCRegister &RegNo, SMLoc Loc, StringRef RegisterName);
48
49 // Parser functions.
50 void eatComma();
51
52 bool isExpr();
55 ParseStatus parseRegOrMoveMask(OperandVector &Operands);
56
57public:
58 M68kAsmParser(const MCSubtargetInfo &STI, MCAsmParser &Parser,
59 const MCInstrInfo &MII, const MCTargetOptions &Options)
60 : MCTargetAsmParser(Options, STI, MII), STI(STI), Parser(Parser) {
63
64 setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits()));
65 }
66
68 unsigned Kind) override;
69 bool parseRegister(MCRegister &Reg, SMLoc &StartLoc, SMLoc &EndLoc) override;
71 SMLoc &EndLoc) override;
73 SMLoc NameLoc, OperandVector &Operands) override;
74 bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
77 bool MatchingInlineAsm) override;
78};
79
80struct M68kMemOp {
81 enum class Kind {
82 Addr,
83 RegMask,
84 Reg,
85 RegIndirect,
86 RegPostIncrement,
87 RegPreDecrement,
88 RegIndirectDisplacement,
89 RegIndirectDisplacementIndex,
90 };
91
92 // These variables are used for the following forms:
93 // Addr: (OuterDisp)
94 // RegMask: RegMask (as register mask)
95 // Reg: %OuterReg
96 // RegIndirect: (%OuterReg)
97 // RegPostIncrement: (%OuterReg)+
98 // RegPreDecrement: -(%OuterReg)
99 // RegIndirectDisplacement: OuterDisp(%OuterReg)
100 // RegIndirectDisplacementIndex:
101 // OuterDisp(%OuterReg, %InnerReg.Size * Scale, InnerDisp)
102
103 Kind Op;
104 MCRegister OuterReg;
105 MCRegister InnerReg;
106 const MCExpr *OuterDisp;
107 const MCExpr *InnerDisp;
108 uint8_t Size : 4;
109 uint8_t Scale : 4;
110 const MCExpr *Expr;
111 uint16_t RegMask;
112
113 M68kMemOp() {}
114 M68kMemOp(Kind Op) : Op(Op) {}
115
116 void print(raw_ostream &OS) const;
117};
118
119/// An parsed M68k assembly operand.
120class M68kOperand : public MCParsedAsmOperand {
121 typedef MCParsedAsmOperand Base;
122
123 enum class KindTy {
124 Invalid,
125 Token,
126 Imm,
127 MemOp,
128 };
129
130 KindTy Kind;
131 SMLoc Start, End;
132 union {
133 StringRef Token;
134 const MCExpr *Expr;
135 M68kMemOp MemOp;
136 };
137
138 template <unsigned N> bool isAddrN() const;
139
140public:
141 M68kOperand(KindTy Kind, SMLoc Start, SMLoc End)
142 : Base(), Kind(Kind), Start(Start), End(End) {}
143
144 SMLoc getStartLoc() const override { return Start; }
145 SMLoc getEndLoc() const override { return End; }
146
147 void print(raw_ostream &OS) const override;
148
149 bool isMem() const override { return false; }
150 bool isMemOp() const { return Kind == KindTy::MemOp; }
151
152 static void addExpr(MCInst &Inst, const MCExpr *Expr);
153
154 // Reg
155 bool isReg() const override;
156 bool isAReg() const;
157 bool isDReg() const;
158 bool isFPDReg() const;
159 bool isFPCReg() const;
160 MCRegister getReg() const override;
161 void addRegOperands(MCInst &Inst, unsigned N) const;
162
163 static std::unique_ptr<M68kOperand> createMemOp(M68kMemOp MemOp, SMLoc Start,
164 SMLoc End);
165
166 // Token
167 bool isToken() const override;
168 StringRef getToken() const;
169 static std::unique_ptr<M68kOperand> createToken(StringRef Token, SMLoc Start,
170 SMLoc End);
171
172 // Imm
173 bool isImm() const override;
174 void addImmOperands(MCInst &Inst, unsigned N) const;
175
176 static std::unique_ptr<M68kOperand> createImm(const MCExpr *Expr, SMLoc Start,
177 SMLoc End);
178
179 // Imm for TRAP instruction
180 bool isTrapImm() const;
181 // Imm for BKPT instruction
182 bool isBkptImm() const;
183
184 // MoveMask
185 bool isMoveMask() const;
186 void addMoveMaskOperands(MCInst &Inst, unsigned N) const;
187
188 // Addr
189 bool isAddr() const;
190 bool isAddr8() const { return isAddrN<8>(); }
191 bool isAddr16() const { return isAddrN<16>(); }
192 bool isAddr32() const { return isAddrN<32>(); }
193 void addAddrOperands(MCInst &Inst, unsigned N) const;
194
195 // ARI
196 bool isARI() const;
197 void addARIOperands(MCInst &Inst, unsigned N) const;
198
199 // ARID
200 bool isARID() const;
201 void addARIDOperands(MCInst &Inst, unsigned N) const;
202
203 // ARII
204 bool isARII() const;
205 void addARIIOperands(MCInst &Inst, unsigned N) const;
206
207 // ARIPD
208 bool isARIPD() const;
209 void addARIPDOperands(MCInst &Inst, unsigned N) const;
210
211 // ARIPI
212 bool isARIPI() const;
213 void addARIPIOperands(MCInst &Inst, unsigned N) const;
214
215 // PCD
216 bool isPCD() const;
217 void addPCDOperands(MCInst &Inst, unsigned N) const;
218
219 // PCI
220 bool isPCI() const;
221 void addPCIOperands(MCInst &Inst, unsigned N) const;
222};
223
224} // end anonymous namespace.
225
228}
229
230#define GET_REGISTER_MATCHER
231#define GET_MATCHER_IMPLEMENTATION
232#include "M68kGenAsmMatcher.inc"
233
234static inline unsigned getRegisterByIndex(unsigned RegisterIndex) {
235 static unsigned RegistersByIndex[] = {
236 M68k::D0, M68k::D1, M68k::D2, M68k::D3, M68k::D4, M68k::D5,
237 M68k::D6, M68k::D7, M68k::A0, M68k::A1, M68k::A2, M68k::A3,
238 M68k::A4, M68k::A5, M68k::A6, M68k::SP, M68k::FP0, M68k::FP1,
239 M68k::FP2, M68k::FP3, M68k::FP4, M68k::FP5, M68k::FP6, M68k::FP7};
240 assert(RegisterIndex <=
241 sizeof(RegistersByIndex) / sizeof(RegistersByIndex[0]));
242 return RegistersByIndex[RegisterIndex];
243}
244
245static inline unsigned getRegisterIndex(unsigned Register) {
246 if (Register >= M68k::D0 && Register <= M68k::D7)
247 return Register - M68k::D0;
248 if (Register >= M68k::A0 && Register <= M68k::A6)
249 return Register - M68k::A0 + 8;
250 if (Register >= M68k::FP0 && Register <= M68k::FP7)
251 return Register - M68k::FP0 + 16;
252
253 switch (Register) {
254 case M68k::SP:
255 // SP is sadly not contiguous with the rest of the An registers
256 return 15;
257
258 // We don't care about the indices of these registers.
259 case M68k::PC:
260 case M68k::CCR:
261 case M68k::FPC:
262 case M68k::FPS:
263 case M68k::FPIAR:
264 return UINT_MAX;
265
266 default:
267 llvm_unreachable("unexpected register number");
268 }
269}
270
271void M68kMemOp::print(raw_ostream &OS) const {
272 switch (Op) {
273 case Kind::Addr:
274 OS << OuterDisp;
275 break;
276 case Kind::RegMask:
277 OS << "RegMask(" << format("%04x", RegMask) << ")";
278 break;
279 case Kind::Reg:
280 OS << '%' << OuterReg;
281 break;
282 case Kind::RegIndirect:
283 OS << "(%" << OuterReg << ')';
284 break;
285 case Kind::RegPostIncrement:
286 OS << "(%" << OuterReg << ")+";
287 break;
288 case Kind::RegPreDecrement:
289 OS << "-(%" << OuterReg << ")";
290 break;
291 case Kind::RegIndirectDisplacement:
292 OS << OuterDisp << "(%" << OuterReg << ")";
293 break;
294 case Kind::RegIndirectDisplacementIndex:
295 OS << OuterDisp << "(%" << OuterReg << ", " << InnerReg << "." << Size
296 << ", " << InnerDisp << ")";
297 break;
298 }
299}
300
301void M68kOperand::addExpr(MCInst &Inst, const MCExpr *Expr) {
302 if (auto Const = dyn_cast<MCConstantExpr>(Expr)) {
303 Inst.addOperand(MCOperand::createImm(Const->getValue()));
304 return;
305 }
306
308}
309
310// Reg
311bool M68kOperand::isReg() const {
312 return Kind == KindTy::MemOp && MemOp.Op == M68kMemOp::Kind::Reg;
313}
314
315MCRegister M68kOperand::getReg() const {
316 assert(isReg());
317 return MemOp.OuterReg;
318}
319
320void M68kOperand::addRegOperands(MCInst &Inst, unsigned N) const {
321 assert(isReg() && "wrong operand kind");
322 assert((N == 1) && "can only handle one register operand");
323
325}
326
327std::unique_ptr<M68kOperand> M68kOperand::createMemOp(M68kMemOp MemOp,
328 SMLoc Start, SMLoc End) {
329 auto Op = std::make_unique<M68kOperand>(KindTy::MemOp, Start, End);
330 Op->MemOp = MemOp;
331 return Op;
332}
333
334// Token
335bool M68kOperand::isToken() const { return Kind == KindTy::Token; }
336StringRef M68kOperand::getToken() const {
337 assert(isToken());
338 return Token;
339}
340
341std::unique_ptr<M68kOperand> M68kOperand::createToken(StringRef Token,
342 SMLoc Start, SMLoc End) {
343 auto Op = std::make_unique<M68kOperand>(KindTy::Token, Start, End);
344 Op->Token = Token;
345 return Op;
346}
347
348// Imm
349bool M68kOperand::isImm() const { return Kind == KindTy::Imm; }
350void M68kOperand::addImmOperands(MCInst &Inst, unsigned N) const {
351 assert(isImm() && "wrong operand kind");
352 assert((N == 1) && "can only handle one register operand");
353
354 M68kOperand::addExpr(Inst, Expr);
355}
356
357std::unique_ptr<M68kOperand> M68kOperand::createImm(const MCExpr *Expr,
358 SMLoc Start, SMLoc End) {
359 auto Op = std::make_unique<M68kOperand>(KindTy::Imm, Start, End);
360 Op->Expr = Expr;
361 return Op;
362}
363
364bool M68kOperand::isTrapImm() const {
365 int64_t Value;
366 if (!isImm() || !Expr->evaluateAsAbsolute(Value))
367 return false;
368
369 return isUInt<4>(Value);
370}
371
372bool M68kOperand::isBkptImm() const {
373 int64_t Value;
374 if (!isImm() || !Expr->evaluateAsAbsolute(Value))
375 return false;
376
377 return isUInt<3>(Value);
378}
379
380// MoveMask
381bool M68kOperand::isMoveMask() const {
382 if (!isMemOp())
383 return false;
384
385 if (MemOp.Op == M68kMemOp::Kind::RegMask)
386 return true;
387
388 if (MemOp.Op != M68kMemOp::Kind::Reg)
389 return false;
390
391 // Only regular address / data registers are allowed to be used
392 // in register masks.
393 return getRegisterIndex(MemOp.OuterReg) < 16;
394}
395
396void M68kOperand::addMoveMaskOperands(MCInst &Inst, unsigned N) const {
397 assert(isMoveMask() && "wrong operand kind");
398 assert((N == 1) && "can only handle one immediate operand");
399
400 uint16_t MoveMask = MemOp.RegMask;
401 if (MemOp.Op == M68kMemOp::Kind::Reg)
402 MoveMask = 1 << getRegisterIndex(MemOp.OuterReg);
403
404 Inst.addOperand(MCOperand::createImm(MoveMask));
405}
406
407// Addr
408bool M68kOperand::isAddr() const {
409 return isMemOp() && MemOp.Op == M68kMemOp::Kind::Addr;
410}
411// TODO: Maybe we can also store the size of OuterDisp
412// in Size?
413template <unsigned N> bool M68kOperand::isAddrN() const {
414 if (isAddr()) {
415 int64_t Res;
416 if (MemOp.OuterDisp->evaluateAsAbsolute(Res))
417 return isInt<N>(Res);
418 return true;
419 }
420 return false;
421}
422void M68kOperand::addAddrOperands(MCInst &Inst, unsigned N) const {
423 M68kOperand::addExpr(Inst, MemOp.OuterDisp);
424}
425
426// ARI
427bool M68kOperand::isARI() const {
428 return isMemOp() && MemOp.Op == M68kMemOp::Kind::RegIndirect &&
429 M68k::AR32RegClass.contains(MemOp.OuterReg);
430}
431void M68kOperand::addARIOperands(MCInst &Inst, unsigned N) const {
432 Inst.addOperand(MCOperand::createReg(MemOp.OuterReg));
433}
434
435// ARID
436bool M68kOperand::isARID() const {
437 return isMemOp() && MemOp.Op == M68kMemOp::Kind::RegIndirectDisplacement &&
438 M68k::AR32RegClass.contains(MemOp.OuterReg);
439}
440void M68kOperand::addARIDOperands(MCInst &Inst, unsigned N) const {
441 M68kOperand::addExpr(Inst, MemOp.OuterDisp);
442 Inst.addOperand(MCOperand::createReg(MemOp.OuterReg));
443}
444
445// ARII
446bool M68kOperand::isARII() const {
447 return isMemOp() &&
448 MemOp.Op == M68kMemOp::Kind::RegIndirectDisplacementIndex &&
449 M68k::AR32RegClass.contains(MemOp.OuterReg);
450}
451void M68kOperand::addARIIOperands(MCInst &Inst, unsigned N) const {
452 M68kOperand::addExpr(Inst, MemOp.OuterDisp);
453 Inst.addOperand(MCOperand::createReg(MemOp.OuterReg));
454 Inst.addOperand(MCOperand::createReg(MemOp.InnerReg));
455}
456
457// ARIPD
458bool M68kOperand::isARIPD() const {
459 return isMemOp() && MemOp.Op == M68kMemOp::Kind::RegPreDecrement &&
460 M68k::AR32RegClass.contains(MemOp.OuterReg);
461}
462void M68kOperand::addARIPDOperands(MCInst &Inst, unsigned N) const {
463 Inst.addOperand(MCOperand::createReg(MemOp.OuterReg));
464}
465
466// ARIPI
467bool M68kOperand::isARIPI() const {
468 return isMemOp() && MemOp.Op == M68kMemOp::Kind::RegPostIncrement &&
469 M68k::AR32RegClass.contains(MemOp.OuterReg);
470}
471void M68kOperand::addARIPIOperands(MCInst &Inst, unsigned N) const {
472 Inst.addOperand(MCOperand::createReg(MemOp.OuterReg));
473}
474
475// PCD
476bool M68kOperand::isPCD() const {
477 return isMemOp() && MemOp.Op == M68kMemOp::Kind::RegIndirectDisplacement &&
478 MemOp.OuterReg == M68k::PC;
479}
480void M68kOperand::addPCDOperands(MCInst &Inst, unsigned N) const {
481 M68kOperand::addExpr(Inst, MemOp.OuterDisp);
482}
483
484// PCI
485bool M68kOperand::isPCI() const {
486 return isMemOp() &&
487 MemOp.Op == M68kMemOp::Kind::RegIndirectDisplacementIndex &&
488 MemOp.OuterReg == M68k::PC;
489}
490void M68kOperand::addPCIOperands(MCInst &Inst, unsigned N) const {
491 M68kOperand::addExpr(Inst, MemOp.OuterDisp);
492 Inst.addOperand(MCOperand::createReg(MemOp.InnerReg));
493}
494
495static inline bool checkRegisterClass(unsigned RegNo, bool Data, bool Address,
496 bool SP, bool FPDR = false,
497 bool FPCR = false) {
498 switch (RegNo) {
499 case M68k::A0:
500 case M68k::A1:
501 case M68k::A2:
502 case M68k::A3:
503 case M68k::A4:
504 case M68k::A5:
505 case M68k::A6:
506 return Address;
507
508 case M68k::SP:
509 return SP;
510
511 case M68k::D0:
512 case M68k::D1:
513 case M68k::D2:
514 case M68k::D3:
515 case M68k::D4:
516 case M68k::D5:
517 case M68k::D6:
518 case M68k::D7:
519 return Data;
520
521 case M68k::SR:
522 case M68k::CCR:
523 return false;
524
525 case M68k::FP0:
526 case M68k::FP1:
527 case M68k::FP2:
528 case M68k::FP3:
529 case M68k::FP4:
530 case M68k::FP5:
531 case M68k::FP6:
532 case M68k::FP7:
533 return FPDR;
534
535 case M68k::FPC:
536 case M68k::FPS:
537 case M68k::FPIAR:
538 return FPCR;
539
540 default:
541 llvm_unreachable("unexpected register type");
542 return false;
543 }
544}
545
546bool M68kOperand::isAReg() const {
547 return isReg() && checkRegisterClass(getReg(),
548 /*Data=*/false,
549 /*Address=*/true, /*SP=*/true);
550}
551
552bool M68kOperand::isDReg() const {
553 return isReg() && checkRegisterClass(getReg(),
554 /*Data=*/true,
555 /*Address=*/false, /*SP=*/false);
556}
557
558bool M68kOperand::isFPDReg() const {
559 return isReg() && checkRegisterClass(getReg(),
560 /*Data=*/false,
561 /*Address=*/false, /*SP=*/false,
562 /*FPDR=*/true);
563}
564
565bool M68kOperand::isFPCReg() const {
566 return isReg() && checkRegisterClass(getReg(),
567 /*Data=*/false,
568 /*Address=*/false, /*SP=*/false,
569 /*FPDR=*/false, /*FPCR=*/true);
570}
571
572unsigned M68kAsmParser::validateTargetOperandClass(MCParsedAsmOperand &Op,
573 unsigned Kind) {
574 M68kOperand &Operand = (M68kOperand &)Op;
575
576 switch (Kind) {
577 case MCK_XR16:
578 case MCK_SPILL:
579 if (Operand.isReg() &&
580 checkRegisterClass(Operand.getReg(), true, true, true)) {
581 return Match_Success;
582 }
583 break;
584
585 case MCK_AR16:
586 case MCK_AR32:
587 if (Operand.isReg() &&
588 checkRegisterClass(Operand.getReg(), false, true, true)) {
589 return Match_Success;
590 }
591 break;
592
593 case MCK_AR32_NOSP:
594 if (Operand.isReg() &&
595 checkRegisterClass(Operand.getReg(), false, true, false)) {
596 return Match_Success;
597 }
598 break;
599
600 case MCK_DR8:
601 case MCK_DR16:
602 case MCK_DR32:
603 if (Operand.isReg() &&
604 checkRegisterClass(Operand.getReg(), true, false, false)) {
605 return Match_Success;
606 }
607 break;
608
609 case MCK_AR16_TC:
610 if (Operand.isReg() &&
611 ((Operand.getReg() == M68k::A0) || (Operand.getReg() == M68k::A1))) {
612 return Match_Success;
613 }
614 break;
615
616 case MCK_DR16_TC:
617 if (Operand.isReg() &&
618 ((Operand.getReg() == M68k::D0) || (Operand.getReg() == M68k::D1))) {
619 return Match_Success;
620 }
621 break;
622
623 case MCK_XR16_TC:
624 if (Operand.isReg() &&
625 ((Operand.getReg() == M68k::D0) || (Operand.getReg() == M68k::D1) ||
626 (Operand.getReg() == M68k::A0) || (Operand.getReg() == M68k::A1))) {
627 return Match_Success;
628 }
629 break;
630 }
631
632 return Match_InvalidOperand;
633}
634
635bool M68kAsmParser::parseRegisterName(MCRegister &RegNo, SMLoc Loc,
636 StringRef RegisterName) {
637 auto RegisterNameLower = RegisterName.lower();
638
639 // CCR register
640 if (RegisterNameLower == "ccr") {
641 RegNo = M68k::CCR;
642 return true;
643 }
644
645 // Parse simple general-purpose registers.
646 if (RegisterNameLower.size() == 2) {
647
648 switch (RegisterNameLower[0]) {
649 case 'd':
650 case 'a': {
651 if (isdigit(RegisterNameLower[1])) {
652 unsigned IndexOffset = (RegisterNameLower[0] == 'a') ? 8 : 0;
653 unsigned RegIndex = (unsigned)(RegisterNameLower[1] - '0');
654 if (RegIndex < 8) {
655 RegNo = getRegisterByIndex(IndexOffset + RegIndex);
656 return true;
657 }
658 }
659 break;
660 }
661
662 case 's':
663 if (RegisterNameLower[1] == 'p') {
664 RegNo = M68k::SP;
665 return true;
666 } else if (RegisterNameLower[1] == 'r') {
667 RegNo = M68k::SR;
668 return true;
669 }
670 break;
671
672 case 'p':
673 if (RegisterNameLower[1] == 'c') {
674 RegNo = M68k::PC;
675 return true;
676 }
677 break;
678 }
679 } else if (StringRef(RegisterNameLower).starts_with("fp") &&
680 RegisterNameLower.size() > 2) {
681 auto RegIndex = unsigned(RegisterNameLower[2] - '0');
682 if (RegIndex < 8 && RegisterNameLower.size() == 3) {
683 // Floating point data register.
684 RegNo = getRegisterByIndex(16 + RegIndex);
685 return true;
686 } else {
687 // Floating point control register.
688 RegNo = StringSwitch<unsigned>(RegisterNameLower)
689 .Cases("fpc", "fpcr", M68k::FPC)
690 .Cases("fps", "fpsr", M68k::FPS)
691 .Cases("fpi", "fpiar", M68k::FPIAR)
692 .Default(M68k::NoRegister);
693 assert(RegNo != M68k::NoRegister &&
694 "Unrecognized FP control register name");
695 return true;
696 }
697 }
698
699 return false;
700}
701
702ParseStatus M68kAsmParser::parseRegister(MCRegister &RegNo) {
703 bool HasPercent = false;
704 AsmToken PercentToken;
705
706 LLVM_DEBUG(dbgs() << "parseRegister "; getTok().dump(dbgs()); dbgs() << "\n");
707
708 if (getTok().is(AsmToken::Percent)) {
709 HasPercent = true;
710 PercentToken = Lex();
711 } else if (!RegisterPrefixOptional.getValue()) {
713 }
714
715 if (!Parser.getTok().is(AsmToken::Identifier)) {
716 if (HasPercent) {
717 getLexer().UnLex(PercentToken);
718 }
720 }
721
722 auto RegisterName = Parser.getTok().getString();
723 if (!parseRegisterName(RegNo, Parser.getLexer().getLoc(), RegisterName)) {
724 if (HasPercent) {
725 getLexer().UnLex(PercentToken);
726 }
728 }
729
730 Parser.Lex();
732}
733
734bool M68kAsmParser::parseRegister(MCRegister &Reg, SMLoc &StartLoc,
735 SMLoc &EndLoc) {
736 ParseStatus Result = tryParseRegister(Reg, StartLoc, EndLoc);
737 if (!Result.isSuccess())
738 return Error(StartLoc, "expected register");
739
740 return false;
741}
742
743ParseStatus M68kAsmParser::tryParseRegister(MCRegister &Reg, SMLoc &StartLoc,
744 SMLoc &EndLoc) {
745 StartLoc = getLexer().getLoc();
746 ParseStatus Result = parseRegister(Reg);
747 EndLoc = getLexer().getLoc();
748 return Result;
749}
750
751bool M68kAsmParser::isExpr() {
752 switch (Parser.getTok().getKind()) {
755 return true;
756 case AsmToken::Minus:
757 return getLexer().peekTok().getKind() == AsmToken::Integer;
758
759 default:
760 return false;
761 }
762}
763
764ParseStatus M68kAsmParser::parseImm(OperandVector &Operands) {
765 if (getLexer().isNot(AsmToken::Hash))
767 SMLoc Start = getLexer().getLoc();
768 Parser.Lex();
769
770 SMLoc End;
771 const MCExpr *Expr;
772
773 if (getParser().parseExpression(Expr, End))
775
776 Operands.push_back(M68kOperand::createImm(Expr, Start, End));
778}
779
780ParseStatus M68kAsmParser::parseMemOp(OperandVector &Operands) {
781 SMLoc Start = getLexer().getLoc();
782 bool IsPD = false;
783 M68kMemOp MemOp;
784
785 // Check for a plain register or register mask.
786 ParseStatus Result = parseRegOrMoveMask(Operands);
787 if (!Result.isNoMatch())
788 return Result;
789
790 // Check for pre-decrement & outer displacement.
791 bool HasDisplacement = false;
792 if (getLexer().is(AsmToken::Minus)) {
793 IsPD = true;
794 Parser.Lex();
795 } else if (isExpr()) {
796 if (Parser.parseExpression(MemOp.OuterDisp))
798 HasDisplacement = true;
799 }
800
801 if (getLexer().isNot(AsmToken::LParen)) {
802 if (HasDisplacement) {
803 MemOp.Op = M68kMemOp::Kind::Addr;
804 Operands.push_back(
805 M68kOperand::createMemOp(MemOp, Start, getLexer().getLoc()));
807 }
808 if (IsPD)
809 return Error(getLexer().getLoc(), "expected (");
810
812 }
813 Parser.Lex();
814
815 // Check for constant dereference & MIT-style displacement
816 if (!HasDisplacement && isExpr()) {
817 if (Parser.parseExpression(MemOp.OuterDisp))
819 HasDisplacement = true;
820
821 // If we're not followed by a comma, we're a constant dereference.
822 if (getLexer().isNot(AsmToken::Comma)) {
823 MemOp.Op = M68kMemOp::Kind::Addr;
824 Operands.push_back(
825 M68kOperand::createMemOp(MemOp, Start, getLexer().getLoc()));
827 }
828
829 Parser.Lex();
830 }
831
832 Result = parseRegister(MemOp.OuterReg);
833 if (Result.isFailure())
835
836 if (!Result.isSuccess())
837 return Error(getLexer().getLoc(), "expected register");
838
839 // Check for Index.
840 bool HasIndex = false;
841 if (Parser.getTok().is(AsmToken::Comma)) {
842 Parser.Lex();
843
844 Result = parseRegister(MemOp.InnerReg);
845 if (Result.isFailure())
846 return Result;
847
848 if (Result.isNoMatch())
849 return Error(getLexer().getLoc(), "expected register");
850
851 // TODO: parse size, scale and inner displacement.
852 MemOp.Size = 4;
853 MemOp.Scale = 1;
854 MemOp.InnerDisp = MCConstantExpr::create(0, Parser.getContext(), true, 4);
855 HasIndex = true;
856 }
857
858 if (Parser.getTok().isNot(AsmToken::RParen))
859 return Error(getLexer().getLoc(), "expected )");
860 Parser.Lex();
861
862 bool IsPI = false;
863 if (!IsPD && Parser.getTok().is(AsmToken::Plus)) {
864 Parser.Lex();
865 IsPI = true;
866 }
867
868 SMLoc End = getLexer().getLoc();
869
870 unsigned OpCount = IsPD + IsPI + (HasIndex || HasDisplacement);
871 if (OpCount > 1)
872 return Error(Start, "only one of post-increment, pre-decrement or "
873 "displacement can be used");
874
875 if (IsPD) {
876 MemOp.Op = M68kMemOp::Kind::RegPreDecrement;
877 } else if (IsPI) {
878 MemOp.Op = M68kMemOp::Kind::RegPostIncrement;
879 } else if (HasIndex) {
880 MemOp.Op = M68kMemOp::Kind::RegIndirectDisplacementIndex;
881 } else if (HasDisplacement) {
882 MemOp.Op = M68kMemOp::Kind::RegIndirectDisplacement;
883 } else {
884 MemOp.Op = M68kMemOp::Kind::RegIndirect;
885 }
886
887 Operands.push_back(M68kOperand::createMemOp(MemOp, Start, End));
889}
890
891ParseStatus M68kAsmParser::parseRegOrMoveMask(OperandVector &Operands) {
892 SMLoc Start = getLexer().getLoc();
893 M68kMemOp MemOp(M68kMemOp::Kind::RegMask);
894 MemOp.RegMask = 0;
895
896 for (;;) {
897 bool IsFirstRegister =
898 (MemOp.Op == M68kMemOp::Kind::RegMask) && (MemOp.RegMask == 0);
899
900 MCRegister FirstRegister;
901 ParseStatus Result = parseRegister(FirstRegister);
902 if (IsFirstRegister && Result.isNoMatch())
904 if (!Result.isSuccess())
905 return Error(getLexer().getLoc(), "expected start register");
906
907 MCRegister LastRegister = FirstRegister;
908 if (parseOptionalToken(AsmToken::Minus)) {
909 Result = parseRegister(LastRegister);
910 if (!Result.isSuccess())
911 return Error(getLexer().getLoc(), "expected end register");
912 }
913
914 unsigned FirstRegisterIndex = getRegisterIndex(FirstRegister);
915 unsigned LastRegisterIndex = getRegisterIndex(LastRegister);
916
917 uint16_t NumNewBits = LastRegisterIndex - FirstRegisterIndex + 1;
918 uint16_t NewMaskBits = ((1 << NumNewBits) - 1) << FirstRegisterIndex;
919
920 if (IsFirstRegister && (FirstRegister == LastRegister)) {
921 // First register range is a single register, simplify to just Reg
922 // so that it matches more operands.
923 MemOp.Op = M68kMemOp::Kind::Reg;
924 MemOp.OuterReg = FirstRegister;
925 } else {
926 if (MemOp.Op == M68kMemOp::Kind::Reg) {
927 // This is the second register being specified - expand the Reg operand
928 // into a mask first.
929 MemOp.Op = M68kMemOp::Kind::RegMask;
930 MemOp.RegMask = 1 << getRegisterIndex(MemOp.OuterReg);
931
932 if (MemOp.RegMask == 0)
933 return Error(getLexer().getLoc(),
934 "special registers cannot be used in register masks");
935 }
936
937 if ((FirstRegisterIndex >= 16) || (LastRegisterIndex >= 16))
938 return Error(getLexer().getLoc(),
939 "special registers cannot be used in register masks");
940
941 if (NewMaskBits & MemOp.RegMask)
942 return Error(getLexer().getLoc(), "conflicting masked registers");
943
944 MemOp.RegMask |= NewMaskBits;
945 }
946
947 if (!parseOptionalToken(AsmToken::Slash))
948 break;
949 }
950
951 Operands.push_back(
952 M68kOperand::createMemOp(MemOp, Start, getLexer().getLoc()));
954}
955
956void M68kAsmParser::eatComma() {
957 if (Parser.getTok().is(AsmToken::Comma)) {
958 Parser.Lex();
959 }
960}
961
962bool M68kAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
963 SMLoc NameLoc, OperandVector &Operands) {
964 SMLoc Start = getLexer().getLoc();
965 Operands.push_back(M68kOperand::createToken(Name, Start, Start));
966
967 bool First = true;
968 while (Parser.getTok().isNot(AsmToken::EndOfStatement)) {
969 if (!First) {
970 eatComma();
971 } else {
972 First = false;
973 }
974
975 ParseStatus MatchResult = MatchOperandParserImpl(Operands, Name);
976 if (MatchResult.isSuccess())
977 continue;
978
979 // Add custom operand formats here...
980 SMLoc Loc = getLexer().getLoc();
981 Parser.eatToEndOfStatement();
982 return Error(Loc, "unexpected token parsing operands");
983 }
984
985 // Eat EndOfStatement.
986 Parser.Lex();
987 return false;
988}
989
990bool M68kAsmParser::invalidOperand(SMLoc const &Loc,
991 OperandVector const &Operands,
992 uint64_t const &ErrorInfo) {
993 SMLoc ErrorLoc = Loc;
994 char const *Diag = 0;
995
996 if (ErrorInfo != ~0U) {
997 if (ErrorInfo >= Operands.size()) {
998 Diag = "too few operands for instruction.";
999 } else {
1000 auto const &Op = (M68kOperand const &)*Operands[ErrorInfo];
1001 if (Op.getStartLoc() != SMLoc()) {
1002 ErrorLoc = Op.getStartLoc();
1003 }
1004 }
1005 }
1006
1007 if (!Diag) {
1008 Diag = "invalid operand for instruction";
1009 }
1010
1011 return Error(ErrorLoc, Diag);
1012}
1013
1014bool M68kAsmParser::missingFeature(llvm::SMLoc const &Loc,
1015 uint64_t const &ErrorInfo) {
1016 return Error(Loc, "instruction requires a CPU feature not currently enabled");
1017}
1018
1019bool M68kAsmParser::emit(MCInst &Inst, SMLoc const &Loc,
1020 MCStreamer &Out) const {
1021 Inst.setLoc(Loc);
1022 Out.emitInstruction(Inst, STI);
1023
1024 return false;
1025}
1026
1027bool M68kAsmParser::MatchAndEmitInstruction(SMLoc Loc, unsigned &Opcode,
1029 MCStreamer &Out,
1031 bool MatchingInlineAsm) {
1032 MCInst Inst;
1033 unsigned MatchResult =
1034 MatchInstructionImpl(Operands, Inst, ErrorInfo, MatchingInlineAsm);
1035
1036 switch (MatchResult) {
1037 case Match_Success:
1038 return emit(Inst, Loc, Out);
1039 case Match_MissingFeature:
1040 return missingFeature(Loc, ErrorInfo);
1041 case Match_InvalidOperand:
1042 return invalidOperand(Loc, Operands, ErrorInfo);
1043 case Match_MnemonicFail:
1044 return Error(Loc, "invalid instruction");
1045 default:
1046 return true;
1047 }
1048}
1049
1050void M68kOperand::print(raw_ostream &OS) const {
1051 switch (Kind) {
1052 case KindTy::Invalid:
1053 OS << "invalid";
1054 break;
1055
1056 case KindTy::Token:
1057 OS << "token '" << Token << "'";
1058 break;
1059
1060 case KindTy::Imm: {
1061 int64_t Value;
1062 Expr->evaluateAsAbsolute(Value);
1063 OS << "immediate " << Value;
1064 break;
1065 }
1066
1067 case KindTy::MemOp:
1068 MemOp.print(OS);
1069 break;
1070 }
1071}
unsigned const MachineRegisterInfo * MRI
static bool isNot(const MachineRegisterInfo &MRI, const MachineInstr &MI)
static void print(raw_ostream &Out, object::Archive::Kind Kind, T Val)
#define LLVM_EXTERNAL_VISIBILITY
Definition: Compiler.h:131
#define LLVM_DEBUG(X)
Definition: Debug.h:101
uint64_t Addr
std::string Name
uint64_t Size
bool End
Definition: ELF_riscv.cpp:480
static GCMetadataPrinterRegistry::Add< ErlangGCPrinter > X("erlang", "erlang-compatible garbage collector")
static LVOptions Options
Definition: LVOptions.cpp:25
static bool checkRegisterClass(unsigned RegNo, bool Data, bool Address, bool SP, bool FPDR=false, bool FPCR=false)
static cl::opt< bool > RegisterPrefixOptional("m68k-register-prefix-optional", cl::Hidden, cl::desc("Enable specifying registers without the % prefix"), cl::init(false))
LLVM_EXTERNAL_VISIBILITY void LLVMInitializeM68kAsmParser()
static unsigned getRegisterByIndex(unsigned RegisterIndex)
static unsigned getRegisterIndex(unsigned Register)
This file contains the M68k implementation of the TargetInstrInfo class.
This file contains the M68k implementation of the TargetRegisterInfo class.
mir Rename Register Operands
static unsigned getReg(const MCDisassembler *D, unsigned RC, unsigned RegNo)
static bool isReg(const MCInst &MI, unsigned OpNo)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
static bool isImm(const MachineOperand &MO, MachineRegisterInfo *MRI)
raw_pwrite_stream & OS
DEMANGLE_NAMESPACE_BEGIN bool starts_with(std::string_view self, char C) noexcept
Target independent representation for an assembler token.
Definition: MCAsmMacro.h:21
bool isNot(TokenKind K) const
Definition: MCAsmMacro.h:83
StringRef getString() const
Get the string for the current token, this includes all characters (for example, the quotes on string...
Definition: MCAsmMacro.h:110
bool is(TokenKind K) const
Definition: MCAsmMacro.h:82
TokenKind getKind() const
Definition: MCAsmMacro.h:81
This class represents an Operation in the Expression.
Base class for user error types.
Definition: Error.h:355
Lightweight error class with error context and mandatory checking.
Definition: Error.h:160
SMLoc getLoc() const
Get the current source location.
Definition: MCAsmLexer.cpp:22
virtual void Initialize(MCAsmParser &Parser)
Initialize the extension for parsing using the given Parser.
Generic assembler parser interface, for use by target specific assembly parsers.
Definition: MCAsmParser.h:123
virtual void eatToEndOfStatement()=0
Skip to the end of the current statement, for error recovery.
virtual bool parseExpression(const MCExpr *&Res, SMLoc &EndLoc)=0
Parse an arbitrary expression.
const AsmToken & getTok() const
Get the current AsmToken from the stream.
Definition: MCAsmParser.cpp:40
virtual const AsmToken & Lex()=0
Get the next AsmToken in the stream, possibly handling file inclusion first.
virtual MCAsmLexer & getLexer()=0
virtual MCContext & getContext()=0
static const MCConstantExpr * create(int64_t Value, MCContext &Ctx, bool PrintInHex=false, unsigned SizeInBytes=0)
Definition: MCExpr.cpp:193
const MCRegisterInfo * getRegisterInfo() const
Definition: MCContext.h:414
Base class for the full range of assembler expressions which are needed for parsing.
Definition: MCExpr.h:34
Instances of this class represent a single low-level machine instruction.
Definition: MCInst.h:184
void setLoc(SMLoc loc)
Definition: MCInst.h:203
void addOperand(const MCOperand Op)
Definition: MCInst.h:210
Interface to description of machine instruction set.
Definition: MCInstrInfo.h:26
static MCOperand createReg(unsigned Reg)
Definition: MCInst.h:134
static MCOperand createExpr(const MCExpr *Val)
Definition: MCInst.h:162
static MCOperand createImm(int64_t Val)
Definition: MCInst.h:141
MCParsedAsmOperand - This abstract class represents a source-level assembly instruction operand.
virtual SMLoc getStartLoc() const =0
getStartLoc - Get the location of the first token of this operand.
virtual bool isReg() const =0
isReg - Is this a register operand?
virtual bool isMem() const =0
isMem - Is this a memory operand?
virtual MCRegister getReg() const =0
virtual void print(raw_ostream &OS) const =0
print - Print a debug representation of the operand to the given stream.
virtual bool isToken() const =0
isToken - Is this a token operand?
virtual bool isImm() const =0
isImm - Is this an immediate operand?
virtual SMLoc getEndLoc() const =0
getEndLoc - Get the location of the last token of this operand.
MCRegisterInfo base class - We assume that the target defines a static array of MCRegisterDesc object...
Wrapper class representing physical registers. Should be passed by value.
Definition: MCRegister.h:33
Streaming machine code generation interface.
Definition: MCStreamer.h:213
virtual void emitInstruction(const MCInst &Inst, const MCSubtargetInfo &STI)
Emit the given Instruction into the current section.
Generic base class for all target subtargets.
const FeatureBitset & getFeatureBits() const
MCTargetAsmParser - Generic interface to target specific assembly parsers.
virtual bool parseRegister(MCRegister &Reg, SMLoc &StartLoc, SMLoc &EndLoc)=0
virtual ParseStatus tryParseRegister(MCRegister &Reg, SMLoc &StartLoc, SMLoc &EndLoc)=0
tryParseRegister - parse one register if possible
void setAvailableFeatures(const FeatureBitset &Value)
virtual unsigned validateTargetOperandClass(MCParsedAsmOperand &Op, unsigned Kind)
Allow a target to add special case operand matching for things that tblgen doesn't/can't handle effec...
virtual bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name, SMLoc NameLoc, OperandVector &Operands)=0
ParseInstruction - Parse one assembly instruction.
virtual bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, OperandVector &Operands, MCStreamer &Out, uint64_t &ErrorInfo, bool MatchingInlineAsm)=0
MatchAndEmitInstruction - Recognize a series of operands of a parsed instruction as an actual MCInst ...
const MCSubtargetInfo * STI
Current STI.
Ternary parse status returned by various parse* methods.
static constexpr StatusTy Failure
constexpr bool isSuccess() const
static constexpr StatusTy Success
static constexpr StatusTy NoMatch
Wrapper class representing virtual and physical registers.
Definition: Register.h:19
Represents a location in source code.
Definition: SMLoc.h:23
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
Definition: SmallVector.h:586
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:50
std::string lower() const
Definition: StringRef.cpp:111
A switch()-like statement whose cases are string literals.
Definition: StringSwitch.h:44
R Default(T Value)
Definition: StringSwitch.h:182
StringSwitch & Cases(StringLiteral S0, StringLiteral S1, T Value)
Definition: StringSwitch.h:90
LLVM Value Representation.
Definition: Value.h:74
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition: raw_ostream.h:52
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
Reg
All possible values of the reg field in the ModR/M byte.
initializer< Ty > init(const Ty &Val)
Definition: CommandLine.h:443
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:163
format_object< Ts... > format(const char *Fmt, const Ts &... Vals)
These are helper functions used to produce formatted output.
Definition: Format.h:125
@ First
Helpers to iterate all locations in the MemoryEffectsBase class.
DWARFExpression::Operation Op
Target & getTheM68kTarget()
#define N
RegisterMCAsmParser - Helper template for registering a target specific assembly parser,...