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::SR:
262 case M68k::FPC:
263 case M68k::FPS:
264 case M68k::FPIAR:
265 return UINT_MAX;
266
267 default:
268 llvm_unreachable("unexpected register number");
269 }
270}
271
272void M68kMemOp::print(raw_ostream &OS) const {
273 switch (Op) {
274 case Kind::Addr:
275 OS << OuterDisp;
276 break;
277 case Kind::RegMask:
278 OS << "RegMask(" << format("%04x", RegMask) << ")";
279 break;
280 case Kind::Reg:
281 OS << '%' << OuterReg;
282 break;
283 case Kind::RegIndirect:
284 OS << "(%" << OuterReg << ')';
285 break;
286 case Kind::RegPostIncrement:
287 OS << "(%" << OuterReg << ")+";
288 break;
289 case Kind::RegPreDecrement:
290 OS << "-(%" << OuterReg << ")";
291 break;
292 case Kind::RegIndirectDisplacement:
293 OS << OuterDisp << "(%" << OuterReg << ")";
294 break;
295 case Kind::RegIndirectDisplacementIndex:
296 OS << OuterDisp << "(%" << OuterReg << ", " << InnerReg << "." << Size
297 << ", " << InnerDisp << ")";
298 break;
299 }
300}
301
302void M68kOperand::addExpr(MCInst &Inst, const MCExpr *Expr) {
303 if (auto Const = dyn_cast<MCConstantExpr>(Expr)) {
304 Inst.addOperand(MCOperand::createImm(Const->getValue()));
305 return;
306 }
307
309}
310
311// Reg
312bool M68kOperand::isReg() const {
313 return Kind == KindTy::MemOp && MemOp.Op == M68kMemOp::Kind::Reg;
314}
315
316MCRegister M68kOperand::getReg() const {
317 assert(isReg());
318 return MemOp.OuterReg;
319}
320
321void M68kOperand::addRegOperands(MCInst &Inst, unsigned N) const {
322 assert(isReg() && "wrong operand kind");
323 assert((N == 1) && "can only handle one register operand");
324
326}
327
328std::unique_ptr<M68kOperand> M68kOperand::createMemOp(M68kMemOp MemOp,
329 SMLoc Start, SMLoc End) {
330 auto Op = std::make_unique<M68kOperand>(KindTy::MemOp, Start, End);
331 Op->MemOp = MemOp;
332 return Op;
333}
334
335// Token
336bool M68kOperand::isToken() const { return Kind == KindTy::Token; }
337StringRef M68kOperand::getToken() const {
338 assert(isToken());
339 return Token;
340}
341
342std::unique_ptr<M68kOperand> M68kOperand::createToken(StringRef Token,
343 SMLoc Start, SMLoc End) {
344 auto Op = std::make_unique<M68kOperand>(KindTy::Token, Start, End);
345 Op->Token = Token;
346 return Op;
347}
348
349// Imm
350bool M68kOperand::isImm() const { return Kind == KindTy::Imm; }
351void M68kOperand::addImmOperands(MCInst &Inst, unsigned N) const {
352 assert(isImm() && "wrong operand kind");
353 assert((N == 1) && "can only handle one register operand");
354
355 M68kOperand::addExpr(Inst, Expr);
356}
357
358std::unique_ptr<M68kOperand> M68kOperand::createImm(const MCExpr *Expr,
359 SMLoc Start, SMLoc End) {
360 auto Op = std::make_unique<M68kOperand>(KindTy::Imm, Start, End);
361 Op->Expr = Expr;
362 return Op;
363}
364
365bool M68kOperand::isTrapImm() const {
366 int64_t Value;
367 if (!isImm() || !Expr->evaluateAsAbsolute(Value))
368 return false;
369
370 return isUInt<4>(Value);
371}
372
373bool M68kOperand::isBkptImm() const {
374 int64_t Value;
375 if (!isImm() || !Expr->evaluateAsAbsolute(Value))
376 return false;
377
378 return isUInt<3>(Value);
379}
380
381// MoveMask
382bool M68kOperand::isMoveMask() const {
383 if (!isMemOp())
384 return false;
385
386 if (MemOp.Op == M68kMemOp::Kind::RegMask)
387 return true;
388
389 if (MemOp.Op != M68kMemOp::Kind::Reg)
390 return false;
391
392 // Only regular address / data registers are allowed to be used
393 // in register masks.
394 return getRegisterIndex(MemOp.OuterReg) < 16;
395}
396
397void M68kOperand::addMoveMaskOperands(MCInst &Inst, unsigned N) const {
398 assert(isMoveMask() && "wrong operand kind");
399 assert((N == 1) && "can only handle one immediate operand");
400
401 uint16_t MoveMask = MemOp.RegMask;
402 if (MemOp.Op == M68kMemOp::Kind::Reg)
403 MoveMask = 1 << getRegisterIndex(MemOp.OuterReg);
404
405 Inst.addOperand(MCOperand::createImm(MoveMask));
406}
407
408// Addr
409bool M68kOperand::isAddr() const {
410 return isMemOp() && MemOp.Op == M68kMemOp::Kind::Addr;
411}
412// TODO: Maybe we can also store the size of OuterDisp
413// in Size?
414template <unsigned N> bool M68kOperand::isAddrN() const {
415 if (isAddr()) {
416 int64_t Res;
417 if (MemOp.OuterDisp->evaluateAsAbsolute(Res))
418 return isInt<N>(Res);
419 return true;
420 }
421 return false;
422}
423void M68kOperand::addAddrOperands(MCInst &Inst, unsigned N) const {
424 M68kOperand::addExpr(Inst, MemOp.OuterDisp);
425}
426
427// ARI
428bool M68kOperand::isARI() const {
429 return isMemOp() && MemOp.Op == M68kMemOp::Kind::RegIndirect &&
430 M68k::AR32RegClass.contains(MemOp.OuterReg);
431}
432void M68kOperand::addARIOperands(MCInst &Inst, unsigned N) const {
433 Inst.addOperand(MCOperand::createReg(MemOp.OuterReg));
434}
435
436// ARID
437bool M68kOperand::isARID() const {
438 return isMemOp() && MemOp.Op == M68kMemOp::Kind::RegIndirectDisplacement &&
439 M68k::AR32RegClass.contains(MemOp.OuterReg);
440}
441void M68kOperand::addARIDOperands(MCInst &Inst, unsigned N) const {
442 M68kOperand::addExpr(Inst, MemOp.OuterDisp);
443 Inst.addOperand(MCOperand::createReg(MemOp.OuterReg));
444}
445
446// ARII
447bool M68kOperand::isARII() const {
448 return isMemOp() &&
449 MemOp.Op == M68kMemOp::Kind::RegIndirectDisplacementIndex &&
450 M68k::AR32RegClass.contains(MemOp.OuterReg);
451}
452void M68kOperand::addARIIOperands(MCInst &Inst, unsigned N) const {
453 M68kOperand::addExpr(Inst, MemOp.OuterDisp);
454 Inst.addOperand(MCOperand::createReg(MemOp.OuterReg));
455 Inst.addOperand(MCOperand::createReg(MemOp.InnerReg));
456}
457
458// ARIPD
459bool M68kOperand::isARIPD() const {
460 return isMemOp() && MemOp.Op == M68kMemOp::Kind::RegPreDecrement &&
461 M68k::AR32RegClass.contains(MemOp.OuterReg);
462}
463void M68kOperand::addARIPDOperands(MCInst &Inst, unsigned N) const {
464 Inst.addOperand(MCOperand::createReg(MemOp.OuterReg));
465}
466
467// ARIPI
468bool M68kOperand::isARIPI() const {
469 return isMemOp() && MemOp.Op == M68kMemOp::Kind::RegPostIncrement &&
470 M68k::AR32RegClass.contains(MemOp.OuterReg);
471}
472void M68kOperand::addARIPIOperands(MCInst &Inst, unsigned N) const {
473 Inst.addOperand(MCOperand::createReg(MemOp.OuterReg));
474}
475
476// PCD
477bool M68kOperand::isPCD() const {
478 return isMemOp() && MemOp.Op == M68kMemOp::Kind::RegIndirectDisplacement &&
479 MemOp.OuterReg == M68k::PC;
480}
481void M68kOperand::addPCDOperands(MCInst &Inst, unsigned N) const {
482 M68kOperand::addExpr(Inst, MemOp.OuterDisp);
483}
484
485// PCI
486bool M68kOperand::isPCI() const {
487 return isMemOp() &&
488 MemOp.Op == M68kMemOp::Kind::RegIndirectDisplacementIndex &&
489 MemOp.OuterReg == M68k::PC;
490}
491void M68kOperand::addPCIOperands(MCInst &Inst, unsigned N) const {
492 M68kOperand::addExpr(Inst, MemOp.OuterDisp);
493 Inst.addOperand(MCOperand::createReg(MemOp.InnerReg));
494}
495
496static inline bool checkRegisterClass(unsigned RegNo, bool Data, bool Address,
497 bool SP, bool FPDR = false,
498 bool FPCR = false) {
499 switch (RegNo) {
500 case M68k::A0:
501 case M68k::A1:
502 case M68k::A2:
503 case M68k::A3:
504 case M68k::A4:
505 case M68k::A5:
506 case M68k::A6:
507 return Address;
508
509 case M68k::SP:
510 return SP;
511
512 case M68k::D0:
513 case M68k::D1:
514 case M68k::D2:
515 case M68k::D3:
516 case M68k::D4:
517 case M68k::D5:
518 case M68k::D6:
519 case M68k::D7:
520 return Data;
521
522 case M68k::SR:
523 case M68k::CCR:
524 return false;
525
526 case M68k::FP0:
527 case M68k::FP1:
528 case M68k::FP2:
529 case M68k::FP3:
530 case M68k::FP4:
531 case M68k::FP5:
532 case M68k::FP6:
533 case M68k::FP7:
534 return FPDR;
535
536 case M68k::FPC:
537 case M68k::FPS:
538 case M68k::FPIAR:
539 return FPCR;
540
541 default:
542 llvm_unreachable("unexpected register type");
543 return false;
544 }
545}
546
547bool M68kOperand::isAReg() const {
548 return isReg() && checkRegisterClass(getReg(),
549 /*Data=*/false,
550 /*Address=*/true, /*SP=*/true);
551}
552
553bool M68kOperand::isDReg() const {
554 return isReg() && checkRegisterClass(getReg(),
555 /*Data=*/true,
556 /*Address=*/false, /*SP=*/false);
557}
558
559bool M68kOperand::isFPDReg() const {
560 return isReg() && checkRegisterClass(getReg(),
561 /*Data=*/false,
562 /*Address=*/false, /*SP=*/false,
563 /*FPDR=*/true);
564}
565
566bool M68kOperand::isFPCReg() const {
567 return isReg() && checkRegisterClass(getReg(),
568 /*Data=*/false,
569 /*Address=*/false, /*SP=*/false,
570 /*FPDR=*/false, /*FPCR=*/true);
571}
572
573unsigned M68kAsmParser::validateTargetOperandClass(MCParsedAsmOperand &Op,
574 unsigned Kind) {
575 M68kOperand &Operand = (M68kOperand &)Op;
576
577 switch (Kind) {
578 case MCK_XR16:
579 case MCK_SPILL:
580 if (Operand.isReg() &&
581 checkRegisterClass(Operand.getReg(), true, true, true)) {
582 return Match_Success;
583 }
584 break;
585
586 case MCK_AR16:
587 case MCK_AR32:
588 if (Operand.isReg() &&
589 checkRegisterClass(Operand.getReg(), false, true, true)) {
590 return Match_Success;
591 }
592 break;
593
594 case MCK_AR32_NOSP:
595 if (Operand.isReg() &&
596 checkRegisterClass(Operand.getReg(), false, true, false)) {
597 return Match_Success;
598 }
599 break;
600
601 case MCK_DR8:
602 case MCK_DR16:
603 case MCK_DR32:
604 if (Operand.isReg() &&
605 checkRegisterClass(Operand.getReg(), true, false, false)) {
606 return Match_Success;
607 }
608 break;
609
610 case MCK_AR16_TC:
611 if (Operand.isReg() &&
612 ((Operand.getReg() == M68k::A0) || (Operand.getReg() == M68k::A1))) {
613 return Match_Success;
614 }
615 break;
616
617 case MCK_DR16_TC:
618 if (Operand.isReg() &&
619 ((Operand.getReg() == M68k::D0) || (Operand.getReg() == M68k::D1))) {
620 return Match_Success;
621 }
622 break;
623
624 case MCK_XR16_TC:
625 if (Operand.isReg() &&
626 ((Operand.getReg() == M68k::D0) || (Operand.getReg() == M68k::D1) ||
627 (Operand.getReg() == M68k::A0) || (Operand.getReg() == M68k::A1))) {
628 return Match_Success;
629 }
630 break;
631 }
632
633 return Match_InvalidOperand;
634}
635
636bool M68kAsmParser::parseRegisterName(MCRegister &RegNo, SMLoc Loc,
637 StringRef RegisterName) {
638 auto RegisterNameLower = RegisterName.lower();
639
640 // CCR and SR register
641 if (RegisterNameLower == "ccr") {
642 RegNo = M68k::CCR;
643 return true;
644 } else if (RegisterNameLower == "sr") {
645 RegNo = M68k::SR;
646 return true;
647 }
648
649 // Parse simple general-purpose registers.
650 if (RegisterNameLower.size() == 2) {
651
652 switch (RegisterNameLower[0]) {
653 case 'd':
654 case 'a': {
655 if (isdigit(RegisterNameLower[1])) {
656 unsigned IndexOffset = (RegisterNameLower[0] == 'a') ? 8 : 0;
657 unsigned RegIndex = (unsigned)(RegisterNameLower[1] - '0');
658 if (RegIndex < 8) {
659 RegNo = getRegisterByIndex(IndexOffset + RegIndex);
660 return true;
661 }
662 }
663 break;
664 }
665
666 case 's':
667 if (RegisterNameLower[1] == 'p') {
668 RegNo = M68k::SP;
669 return true;
670 } else if (RegisterNameLower[1] == 'r') {
671 RegNo = M68k::SR;
672 return true;
673 }
674 break;
675
676 case 'p':
677 if (RegisterNameLower[1] == 'c') {
678 RegNo = M68k::PC;
679 return true;
680 }
681 break;
682 }
683 } else if (StringRef(RegisterNameLower).starts_with("fp") &&
684 RegisterNameLower.size() > 2) {
685 auto RegIndex = unsigned(RegisterNameLower[2] - '0');
686 if (RegIndex < 8 && RegisterNameLower.size() == 3) {
687 // Floating point data register.
688 RegNo = getRegisterByIndex(16 + RegIndex);
689 return true;
690 } else {
691 // Floating point control register.
692 RegNo = StringSwitch<unsigned>(RegisterNameLower)
693 .Cases("fpc", "fpcr", M68k::FPC)
694 .Cases("fps", "fpsr", M68k::FPS)
695 .Cases("fpi", "fpiar", M68k::FPIAR)
696 .Default(M68k::NoRegister);
697 assert(RegNo != M68k::NoRegister &&
698 "Unrecognized FP control register name");
699 return true;
700 }
701 }
702
703 return false;
704}
705
706ParseStatus M68kAsmParser::parseRegister(MCRegister &RegNo) {
707 bool HasPercent = false;
708 AsmToken PercentToken;
709
710 LLVM_DEBUG(dbgs() << "parseRegister "; getTok().dump(dbgs()); dbgs() << "\n");
711
712 if (getTok().is(AsmToken::Percent)) {
713 HasPercent = true;
714 PercentToken = Lex();
715 } else if (!RegisterPrefixOptional.getValue()) {
717 }
718
719 if (!Parser.getTok().is(AsmToken::Identifier)) {
720 if (HasPercent) {
721 getLexer().UnLex(PercentToken);
722 }
724 }
725
726 auto RegisterName = Parser.getTok().getString();
727 if (!parseRegisterName(RegNo, Parser.getLexer().getLoc(), RegisterName)) {
728 if (HasPercent) {
729 getLexer().UnLex(PercentToken);
730 }
732 }
733
734 Parser.Lex();
736}
737
738bool M68kAsmParser::parseRegister(MCRegister &Reg, SMLoc &StartLoc,
739 SMLoc &EndLoc) {
740 ParseStatus Result = tryParseRegister(Reg, StartLoc, EndLoc);
741 if (!Result.isSuccess())
742 return Error(StartLoc, "expected register");
743
744 return false;
745}
746
747ParseStatus M68kAsmParser::tryParseRegister(MCRegister &Reg, SMLoc &StartLoc,
748 SMLoc &EndLoc) {
749 StartLoc = getLexer().getLoc();
750 ParseStatus Result = parseRegister(Reg);
751 EndLoc = getLexer().getLoc();
752 return Result;
753}
754
755bool M68kAsmParser::isExpr() {
756 switch (Parser.getTok().getKind()) {
759 return true;
760 case AsmToken::Minus:
761 return getLexer().peekTok().getKind() == AsmToken::Integer;
762
763 default:
764 return false;
765 }
766}
767
768ParseStatus M68kAsmParser::parseImm(OperandVector &Operands) {
769 if (getLexer().isNot(AsmToken::Hash))
771 SMLoc Start = getLexer().getLoc();
772 Parser.Lex();
773
774 SMLoc End;
775 const MCExpr *Expr;
776
777 if (getParser().parseExpression(Expr, End))
779
780 Operands.push_back(M68kOperand::createImm(Expr, Start, End));
782}
783
784ParseStatus M68kAsmParser::parseMemOp(OperandVector &Operands) {
785 SMLoc Start = getLexer().getLoc();
786 bool IsPD = false;
787 M68kMemOp MemOp;
788
789 // Check for a plain register or register mask.
790 ParseStatus Result = parseRegOrMoveMask(Operands);
791 if (!Result.isNoMatch())
792 return Result;
793
794 // Check for pre-decrement & outer displacement.
795 bool HasDisplacement = false;
796 if (getLexer().is(AsmToken::Minus)) {
797 IsPD = true;
798 Parser.Lex();
799 } else if (isExpr()) {
800 if (Parser.parseExpression(MemOp.OuterDisp))
802 HasDisplacement = true;
803 }
804
805 if (getLexer().isNot(AsmToken::LParen)) {
806 if (HasDisplacement) {
807 MemOp.Op = M68kMemOp::Kind::Addr;
808 Operands.push_back(
809 M68kOperand::createMemOp(MemOp, Start, getLexer().getLoc()));
811 }
812 if (IsPD)
813 return Error(getLexer().getLoc(), "expected (");
814
816 }
817 Parser.Lex();
818
819 // Check for constant dereference & MIT-style displacement
820 if (!HasDisplacement && isExpr()) {
821 if (Parser.parseExpression(MemOp.OuterDisp))
823 HasDisplacement = true;
824
825 // If we're not followed by a comma, we're a constant dereference.
826 if (getLexer().isNot(AsmToken::Comma)) {
827 MemOp.Op = M68kMemOp::Kind::Addr;
828 Operands.push_back(
829 M68kOperand::createMemOp(MemOp, Start, getLexer().getLoc()));
831 }
832
833 Parser.Lex();
834 }
835
836 Result = parseRegister(MemOp.OuterReg);
837 if (Result.isFailure())
839
840 if (!Result.isSuccess())
841 return Error(getLexer().getLoc(), "expected register");
842
843 // Check for Index.
844 bool HasIndex = false;
845 if (Parser.getTok().is(AsmToken::Comma)) {
846 Parser.Lex();
847
848 Result = parseRegister(MemOp.InnerReg);
849 if (Result.isFailure())
850 return Result;
851
852 if (Result.isNoMatch())
853 return Error(getLexer().getLoc(), "expected register");
854
855 // TODO: parse size, scale and inner displacement.
856 MemOp.Size = 4;
857 MemOp.Scale = 1;
858 MemOp.InnerDisp = MCConstantExpr::create(0, Parser.getContext(), true, 4);
859 HasIndex = true;
860 }
861
862 if (Parser.getTok().isNot(AsmToken::RParen))
863 return Error(getLexer().getLoc(), "expected )");
864 Parser.Lex();
865
866 bool IsPI = false;
867 if (!IsPD && Parser.getTok().is(AsmToken::Plus)) {
868 Parser.Lex();
869 IsPI = true;
870 }
871
872 SMLoc End = getLexer().getLoc();
873
874 unsigned OpCount = IsPD + IsPI + (HasIndex || HasDisplacement);
875 if (OpCount > 1)
876 return Error(Start, "only one of post-increment, pre-decrement or "
877 "displacement can be used");
878
879 if (IsPD) {
880 MemOp.Op = M68kMemOp::Kind::RegPreDecrement;
881 } else if (IsPI) {
882 MemOp.Op = M68kMemOp::Kind::RegPostIncrement;
883 } else if (HasIndex) {
884 MemOp.Op = M68kMemOp::Kind::RegIndirectDisplacementIndex;
885 } else if (HasDisplacement) {
886 MemOp.Op = M68kMemOp::Kind::RegIndirectDisplacement;
887 } else {
888 MemOp.Op = M68kMemOp::Kind::RegIndirect;
889 }
890
891 Operands.push_back(M68kOperand::createMemOp(MemOp, Start, End));
893}
894
895ParseStatus M68kAsmParser::parseRegOrMoveMask(OperandVector &Operands) {
896 SMLoc Start = getLexer().getLoc();
897 M68kMemOp MemOp(M68kMemOp::Kind::RegMask);
898 MemOp.RegMask = 0;
899
900 for (;;) {
901 bool IsFirstRegister =
902 (MemOp.Op == M68kMemOp::Kind::RegMask) && (MemOp.RegMask == 0);
903
904 MCRegister FirstRegister;
905 ParseStatus Result = parseRegister(FirstRegister);
906 if (IsFirstRegister && Result.isNoMatch())
908 if (!Result.isSuccess())
909 return Error(getLexer().getLoc(), "expected start register");
910
911 MCRegister LastRegister = FirstRegister;
912 if (parseOptionalToken(AsmToken::Minus)) {
913 Result = parseRegister(LastRegister);
914 if (!Result.isSuccess())
915 return Error(getLexer().getLoc(), "expected end register");
916 }
917
918 unsigned FirstRegisterIndex = getRegisterIndex(FirstRegister);
919 unsigned LastRegisterIndex = getRegisterIndex(LastRegister);
920
921 uint16_t NumNewBits = LastRegisterIndex - FirstRegisterIndex + 1;
922 uint16_t NewMaskBits = ((1 << NumNewBits) - 1) << FirstRegisterIndex;
923
924 if (IsFirstRegister && (FirstRegister == LastRegister)) {
925 // First register range is a single register, simplify to just Reg
926 // so that it matches more operands.
927 MemOp.Op = M68kMemOp::Kind::Reg;
928 MemOp.OuterReg = FirstRegister;
929 } else {
930 if (MemOp.Op == M68kMemOp::Kind::Reg) {
931 // This is the second register being specified - expand the Reg operand
932 // into a mask first.
933 MemOp.Op = M68kMemOp::Kind::RegMask;
934 MemOp.RegMask = 1 << getRegisterIndex(MemOp.OuterReg);
935
936 if (MemOp.RegMask == 0)
937 return Error(getLexer().getLoc(),
938 "special registers cannot be used in register masks");
939 }
940
941 if ((FirstRegisterIndex >= 16) || (LastRegisterIndex >= 16))
942 return Error(getLexer().getLoc(),
943 "special registers cannot be used in register masks");
944
945 if (NewMaskBits & MemOp.RegMask)
946 return Error(getLexer().getLoc(), "conflicting masked registers");
947
948 MemOp.RegMask |= NewMaskBits;
949 }
950
951 if (!parseOptionalToken(AsmToken::Slash))
952 break;
953 }
954
955 Operands.push_back(
956 M68kOperand::createMemOp(MemOp, Start, getLexer().getLoc()));
958}
959
960void M68kAsmParser::eatComma() {
961 if (Parser.getTok().is(AsmToken::Comma)) {
962 Parser.Lex();
963 }
964}
965
966bool M68kAsmParser::parseInstruction(ParseInstructionInfo &Info, StringRef Name,
967 SMLoc NameLoc, OperandVector &Operands) {
968 SMLoc Start = getLexer().getLoc();
969 Operands.push_back(M68kOperand::createToken(Name, Start, Start));
970
971 bool First = true;
972 while (Parser.getTok().isNot(AsmToken::EndOfStatement)) {
973 if (!First) {
974 eatComma();
975 } else {
976 First = false;
977 }
978
979 ParseStatus MatchResult = MatchOperandParserImpl(Operands, Name);
980 if (MatchResult.isSuccess())
981 continue;
982
983 // Add custom operand formats here...
984 SMLoc Loc = getLexer().getLoc();
985 Parser.eatToEndOfStatement();
986 return Error(Loc, "unexpected token parsing operands");
987 }
988
989 // Eat EndOfStatement.
990 Parser.Lex();
991 return false;
992}
993
994bool M68kAsmParser::invalidOperand(SMLoc const &Loc,
995 OperandVector const &Operands,
996 uint64_t const &ErrorInfo) {
997 SMLoc ErrorLoc = Loc;
998 char const *Diag = 0;
999
1000 if (ErrorInfo != ~0U) {
1001 if (ErrorInfo >= Operands.size()) {
1002 Diag = "too few operands for instruction.";
1003 } else {
1004 auto const &Op = (M68kOperand const &)*Operands[ErrorInfo];
1005 if (Op.getStartLoc() != SMLoc()) {
1006 ErrorLoc = Op.getStartLoc();
1007 }
1008 }
1009 }
1010
1011 if (!Diag) {
1012 Diag = "invalid operand for instruction";
1013 }
1014
1015 return Error(ErrorLoc, Diag);
1016}
1017
1018bool M68kAsmParser::missingFeature(llvm::SMLoc const &Loc,
1019 uint64_t const &ErrorInfo) {
1020 return Error(Loc, "instruction requires a CPU feature not currently enabled");
1021}
1022
1023bool M68kAsmParser::emit(MCInst &Inst, SMLoc const &Loc,
1024 MCStreamer &Out) const {
1025 Inst.setLoc(Loc);
1026 Out.emitInstruction(Inst, STI);
1027
1028 return false;
1029}
1030
1031bool M68kAsmParser::matchAndEmitInstruction(SMLoc Loc, unsigned &Opcode,
1033 MCStreamer &Out,
1035 bool MatchingInlineAsm) {
1036 MCInst Inst;
1037 unsigned MatchResult =
1038 MatchInstructionImpl(Operands, Inst, ErrorInfo, MatchingInlineAsm);
1039
1040 switch (MatchResult) {
1041 case Match_Success:
1042 return emit(Inst, Loc, Out);
1043 case Match_MissingFeature:
1044 return missingFeature(Loc, ErrorInfo);
1045 case Match_InvalidOperand:
1046 return invalidOperand(Loc, Operands, ErrorInfo);
1047 case Match_MnemonicFail:
1048 return Error(Loc, "invalid instruction");
1049 default:
1050 return true;
1051 }
1052}
1053
1054void M68kOperand::print(raw_ostream &OS) const {
1055 switch (Kind) {
1056 case KindTy::Invalid:
1057 OS << "invalid";
1058 break;
1059
1060 case KindTy::Token:
1061 OS << "token '" << Token << "'";
1062 break;
1063
1064 case KindTy::Imm: {
1065 int64_t Value;
1066 Expr->evaluateAsAbsolute(Value);
1067 OS << "immediate " << Value;
1068 break;
1069 }
1070
1071 case KindTy::MemOp:
1072 MemOp.print(OS);
1073 break;
1074 }
1075}
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:128
#define LLVM_DEBUG(...)
Definition: Debug.h:106
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:222
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:185
void setLoc(SMLoc loc)
Definition: MCInst.h:204
void addOperand(const MCOperand Op)
Definition: MCInst.h:211
Interface to description of machine instruction set.
Definition: MCInstrInfo.h:26
static MCOperand createExpr(const MCExpr *Val)
Definition: MCInst.h:163
static MCOperand createReg(MCRegister Reg)
Definition: MCInst.h:135
static MCOperand createImm(int64_t Val)
Definition: MCInst.h:142
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 parseInstruction(ParseInstructionInfo &Info, StringRef Name, SMLoc NameLoc, OperandVector &Operands)=0
Parse one assembly instruction.
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
virtual bool matchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, OperandVector &Operands, MCStreamer &Out, uint64_t &ErrorInfo, bool MatchingInlineAsm)=0
Recognize a series of operands of a parsed instruction as an actual MCInst and emit it to the specifi...
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...
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:573
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:51
std::string lower() const
Definition: StringRef.cpp:113
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
DataType & getValue()
Definition: CommandLine.h:1352
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,...