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