LLVM 23.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 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(SMLoc Loc, const OperandVector &Operands,
43 const uint64_t &ErrorInfo);
44 bool missingFeature(SMLoc Loc, const uint64_t &ErrorInfo);
45 bool emit(MCInst &Inst, SMLoc Loc, MCStreamer &Out) const;
46 bool parseRegisterName(MCRegister &RegNo, SMLoc Loc, StringRef RegisterName);
47 ParseStatus parseRegister(MCRegister &RegNo, bool WithSizeSuffix = false);
48
49 // Parser functions.
50 void eatComma();
51
52 bool isExpr();
53 ParseStatus parseImm(OperandVector &Operands);
54 ParseStatus parseMemOp(OperandVector &Operands);
55 ParseStatus parseRegOrMoveMask(OperandVector &Operands);
56
57public:
58 M68kAsmParser(const MCSubtargetInfo &STI, MCAsmParser &Parser,
59 const MCInstrInfo &MII)
60 : MCTargetAsmParser(STI, MII), Parser(Parser) {
62 MRI = getContext().getRegisterInfo();
63
64 setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits()));
65 }
66
67 unsigned validateTargetOperandClass(MCParsedAsmOperand &Op,
68 unsigned Kind) override;
69 bool parseRegister(MCRegister &Reg, SMLoc &StartLoc, SMLoc &EndLoc) override;
70 ParseStatus tryParseRegister(MCRegister &Reg, SMLoc &StartLoc,
71 SMLoc &EndLoc) override;
72 bool parseInstruction(ParseInstructionInfo &Info, StringRef Name,
73 SMLoc NameLoc, OperandVector &Operands) override;
74 bool matchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
75 OperandVector &Operands, MCStreamer &Out,
76 uint64_t &ErrorInfo,
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 * Scale, InnerDisp)
102
103 Kind Op;
104 MCRegister OuterReg;
105 MCRegister InnerReg;
106 const MCExpr *OuterDisp;
107 const MCExpr *InnerDisp;
108 uint8_t Scale : 4;
109 const MCExpr *Expr;
110 uint16_t RegMask;
111 uint8_t AtLeast68020 : 1;
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 MCAsmInfo &MAI) 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 // PCIBD
224 bool isPCIBD() const;
225 bool isPCIBD32() const;
226 bool isPCIBD16() const;
227 void addPCIBDOperands(MCInst &Inst, unsigned N) const;
228};
229
230} // end anonymous namespace.
231
235
236#define GET_REGISTER_MATCHER
237#define GET_MATCHER_IMPLEMENTATION
238#include "M68kGenAsmMatcher.inc"
239
240static inline unsigned getRegisterByIndex(unsigned RegisterIndex) {
241 static unsigned RegistersByIndex[] = {
242 M68k::D0, M68k::D1, M68k::D2, M68k::D3, M68k::D4, M68k::D5,
243 M68k::D6, M68k::D7, M68k::A0, M68k::A1, M68k::A2, M68k::A3,
244 M68k::A4, M68k::A5, M68k::A6, M68k::SP, M68k::FP0, M68k::FP1,
245 M68k::FP2, M68k::FP3, M68k::FP4, M68k::FP5, M68k::FP6, M68k::FP7};
246 assert(RegisterIndex <=
247 sizeof(RegistersByIndex) / sizeof(RegistersByIndex[0]));
248 return RegistersByIndex[RegisterIndex];
249}
250
251static inline unsigned getRegisterIndex(unsigned Register) {
252 if (Register >= M68k::D0 && Register <= M68k::D7)
253 return Register - M68k::D0;
254 if (Register >= M68k::A0 && Register <= M68k::A6)
255 return Register - M68k::A0 + 8;
256 if (Register >= M68k::FP0 && Register <= M68k::FP7)
257 return Register - M68k::FP0 + 16;
258
259 switch (Register) {
260 case M68k::SP:
261 // SP is sadly not contiguous with the rest of the An registers
262 return 15;
263
264 // We don't care about the indices of these registers.
265 case M68k::PC:
266 case M68k::CCR:
267 case M68k::SR:
268 case M68k::FPC:
269 case M68k::FPS:
270 case M68k::FPIAR:
271 return UINT_MAX;
272
273 default:
274 llvm_unreachable("unexpected register number");
275 }
276}
277
278void M68kMemOp::print(raw_ostream &OS) const {
279 switch (Op) {
280 case Kind::Addr:
281 OS << OuterDisp;
282 break;
283 case Kind::RegMask:
284 OS << "RegMask(" << format("%04x", RegMask) << ")";
285 break;
286 case Kind::Reg:
287 OS << '%' << OuterReg;
288 break;
289 case Kind::RegIndirect:
290 OS << "(%" << OuterReg << ')';
291 break;
292 case Kind::RegPostIncrement:
293 OS << "(%" << OuterReg << ")+";
294 break;
295 case Kind::RegPreDecrement:
296 OS << "-(%" << OuterReg << ")";
297 break;
298 case Kind::RegIndirectDisplacement:
299 OS << OuterDisp << "(%" << OuterReg << ")";
300 break;
301 case Kind::RegIndirectDisplacementIndex:
302 OS << OuterDisp << "(%" << OuterReg << ", " << InnerReg << ", " << InnerDisp
303 << ")";
304 break;
305 }
306}
307
308void M68kOperand::addExpr(MCInst &Inst, const MCExpr *Expr) {
309 if (auto Const = dyn_cast<MCConstantExpr>(Expr)) {
310 Inst.addOperand(MCOperand::createImm(Const->getValue()));
311 return;
312 }
313
315}
316
317// Reg
318bool M68kOperand::isReg() const {
319 return Kind == KindTy::MemOp && MemOp.Op == M68kMemOp::Kind::Reg;
320}
321
322MCRegister M68kOperand::getReg() const {
323 assert(isReg());
324 return MemOp.OuterReg;
325}
326
327void M68kOperand::addRegOperands(MCInst &Inst, unsigned N) const {
328 assert(isReg() && "wrong operand kind");
329 assert((N == 1) && "can only handle one register operand");
330
332}
333
334std::unique_ptr<M68kOperand> M68kOperand::createMemOp(M68kMemOp MemOp,
335 SMLoc Start, SMLoc End) {
336 auto Op = std::make_unique<M68kOperand>(KindTy::MemOp, Start, End);
337 Op->MemOp = MemOp;
338 return Op;
339}
340
341// Token
342bool M68kOperand::isToken() const { return Kind == KindTy::Token; }
343StringRef M68kOperand::getToken() const {
344 assert(isToken());
345 return Token;
346}
347
348std::unique_ptr<M68kOperand> M68kOperand::createToken(StringRef Token,
349 SMLoc Start, SMLoc End) {
350 auto Op = std::make_unique<M68kOperand>(KindTy::Token, Start, End);
351 Op->Token = Token;
352 return Op;
353}
354
355// Imm
356bool M68kOperand::isImm() const { return Kind == KindTy::Imm; }
357void M68kOperand::addImmOperands(MCInst &Inst, unsigned N) const {
358 assert(isImm() && "wrong operand kind");
359 assert((N == 1) && "can only handle one register operand");
360
361 M68kOperand::addExpr(Inst, Expr);
362}
363
364std::unique_ptr<M68kOperand> M68kOperand::createImm(const MCExpr *Expr,
365 SMLoc Start, SMLoc End) {
366 auto Op = std::make_unique<M68kOperand>(KindTy::Imm, Start, End);
367 Op->Expr = Expr;
368 return Op;
369}
370
371bool M68kOperand::isTrapImm() const {
372 int64_t Value;
373 if (!isImm() || !Expr->evaluateAsAbsolute(Value))
374 return false;
375
376 return isUInt<4>(Value);
377}
378
379bool M68kOperand::isBkptImm() const {
380 int64_t Value;
381 if (!isImm() || !Expr->evaluateAsAbsolute(Value))
382 return false;
383
384 return isUInt<3>(Value);
385}
386
387// MoveMask
388bool M68kOperand::isMoveMask() const {
389 if (!isMemOp())
390 return false;
391
392 if (MemOp.Op == M68kMemOp::Kind::RegMask)
393 return true;
394
395 if (MemOp.Op != M68kMemOp::Kind::Reg)
396 return false;
397
398 // Only regular address / data registers are allowed to be used
399 // in register masks.
400 return getRegisterIndex(MemOp.OuterReg) < 16;
401}
402
403void M68kOperand::addMoveMaskOperands(MCInst &Inst, unsigned N) const {
404 assert(isMoveMask() && "wrong operand kind");
405 assert((N == 1) && "can only handle one immediate operand");
406
407 uint16_t MoveMask = MemOp.RegMask;
408 if (MemOp.Op == M68kMemOp::Kind::Reg)
409 MoveMask = 1 << getRegisterIndex(MemOp.OuterReg);
410
411 Inst.addOperand(MCOperand::createImm(MoveMask));
412}
413
414// Addr
415bool M68kOperand::isAddr() const {
416 return isMemOp() && MemOp.Op == M68kMemOp::Kind::Addr;
417}
418// TODO: Maybe we can also store the size of OuterDisp
419// in Size?
420template <unsigned N> bool M68kOperand::isAddrN() const {
421 if (isAddr()) {
422 int64_t Res;
423 if (MemOp.OuterDisp->evaluateAsAbsolute(Res))
424 return isInt<N>(Res);
425 return true;
426 }
427 return false;
428}
429void M68kOperand::addAddrOperands(MCInst &Inst, unsigned N) const {
430 M68kOperand::addExpr(Inst, MemOp.OuterDisp);
431}
432
433// ARI
434bool M68kOperand::isARI() const {
435 return isMemOp() && MemOp.Op == M68kMemOp::Kind::RegIndirect &&
436 M68k::AR32RegClass.contains(MemOp.OuterReg);
437}
438void M68kOperand::addARIOperands(MCInst &Inst, unsigned N) const {
439 Inst.addOperand(MCOperand::createReg(MemOp.OuterReg));
440}
441
442// ARID
443bool M68kOperand::isARID() const {
444 return isMemOp() && MemOp.Op == M68kMemOp::Kind::RegIndirectDisplacement &&
445 M68k::AR32RegClass.contains(MemOp.OuterReg);
446}
447void M68kOperand::addARIDOperands(MCInst &Inst, unsigned N) const {
448 M68kOperand::addExpr(Inst, MemOp.OuterDisp);
449 Inst.addOperand(MCOperand::createReg(MemOp.OuterReg));
450}
451
452// ARII
453bool M68kOperand::isARII() const {
454 return isMemOp() &&
455 MemOp.Op == M68kMemOp::Kind::RegIndirectDisplacementIndex &&
456 M68k::AR32RegClass.contains(MemOp.OuterReg);
457}
458void M68kOperand::addARIIOperands(MCInst &Inst, unsigned N) const {
459 M68kOperand::addExpr(Inst, MemOp.OuterDisp);
460 Inst.addOperand(MCOperand::createReg(MemOp.OuterReg));
461 Inst.addOperand(MCOperand::createReg(MemOp.InnerReg));
462}
463
464// ARIPD
465bool M68kOperand::isARIPD() const {
466 return isMemOp() && MemOp.Op == M68kMemOp::Kind::RegPreDecrement &&
467 M68k::AR32RegClass.contains(MemOp.OuterReg);
468}
469void M68kOperand::addARIPDOperands(MCInst &Inst, unsigned N) const {
470 Inst.addOperand(MCOperand::createReg(MemOp.OuterReg));
471}
472
473// ARIPI
474bool M68kOperand::isARIPI() const {
475 return isMemOp() && MemOp.Op == M68kMemOp::Kind::RegPostIncrement &&
476 M68k::AR32RegClass.contains(MemOp.OuterReg);
477}
478void M68kOperand::addARIPIOperands(MCInst &Inst, unsigned N) const {
479 Inst.addOperand(MCOperand::createReg(MemOp.OuterReg));
480}
481
482// PCD
483bool M68kOperand::isPCD() const {
484 return isMemOp() && MemOp.Op == M68kMemOp::Kind::RegIndirectDisplacement &&
485 MemOp.OuterReg == M68k::PC && !MemOp.AtLeast68020;
486}
487void M68kOperand::addPCDOperands(MCInst &Inst, unsigned N) const {
488 M68kOperand::addExpr(Inst, MemOp.OuterDisp);
489}
490
491// PCI
492bool M68kOperand::isPCI() const {
493 return isMemOp() &&
494 MemOp.Op == M68kMemOp::Kind::RegIndirectDisplacementIndex &&
495 MemOp.OuterReg == M68k::PC && MemOp.Scale == 1 && !MemOp.AtLeast68020;
496}
497void M68kOperand::addPCIOperands(MCInst &Inst, unsigned N) const {
498 M68kOperand::addExpr(Inst, MemOp.OuterDisp);
499 Inst.addOperand(MCOperand::createReg(MemOp.InnerReg));
500}
501
502// PCIBD
503// We use this to capture all PCI and PCD addressing modes on M68020+.
504// In order to leverage the large displacement size.
505bool M68kOperand::isPCIBD() const {
506 return isMemOp() && MemOp.AtLeast68020 &&
507 (MemOp.Op == M68kMemOp::Kind::RegIndirectDisplacementIndex ||
508 MemOp.Op == M68kMemOp::Kind::RegIndirectDisplacement) &&
509 MemOp.OuterReg == M68k::PC;
510}
511bool M68kOperand::isPCIBD32() const {
512 return isPCIBD() &&
513 // If InnerReg is NoReg, this is essentially a PCD with larger
514 // displacement.
515 (!MemOp.InnerReg.isValid() ||
516 getM68kMCRegisterClass(M68k::XR32RegClassID)
517 .contains(MemOp.InnerReg));
518}
519bool M68kOperand::isPCIBD16() const {
520 return isPCIBD() &&
521 getM68kMCRegisterClass(M68k::XR16RegClassID).contains(MemOp.InnerReg);
522}
523void M68kOperand::addPCIBDOperands(MCInst &Inst, unsigned N) const {
524 M68kOperand::addExpr(Inst, MemOp.OuterDisp);
525 Inst.addOperand(MCOperand::createReg(MemOp.InnerReg));
526 Inst.addOperand(MCOperand::createImm(MemOp.Scale));
527}
528
529static inline bool checkRegisterClass(unsigned RegNo, bool Data, bool Address,
530 bool SP, bool FPDR = false,
531 bool FPCR = false) {
532 switch (RegNo) {
533 case M68k::A0:
534 case M68k::A1:
535 case M68k::A2:
536 case M68k::A3:
537 case M68k::A4:
538 case M68k::A5:
539 case M68k::A6:
540 return Address;
541
542 case M68k::SP:
543 return SP;
544
545 case M68k::D0:
546 case M68k::D1:
547 case M68k::D2:
548 case M68k::D3:
549 case M68k::D4:
550 case M68k::D5:
551 case M68k::D6:
552 case M68k::D7:
553 return Data;
554
555 case M68k::SR:
556 case M68k::CCR:
557 return false;
558
559 case M68k::FP0:
560 case M68k::FP1:
561 case M68k::FP2:
562 case M68k::FP3:
563 case M68k::FP4:
564 case M68k::FP5:
565 case M68k::FP6:
566 case M68k::FP7:
567 return FPDR;
568
569 case M68k::FPC:
570 case M68k::FPS:
571 case M68k::FPIAR:
572 return FPCR;
573
574 default:
575 llvm_unreachable("unexpected register type");
576 return false;
577 }
578}
579
580bool M68kOperand::isAReg() const {
581 return isReg() && checkRegisterClass(getReg(),
582 /*Data=*/false,
583 /*Address=*/true, /*SP=*/true);
584}
585
586bool M68kOperand::isDReg() const {
587 return isReg() && checkRegisterClass(getReg(),
588 /*Data=*/true,
589 /*Address=*/false, /*SP=*/false);
590}
591
592bool M68kOperand::isFPDReg() const {
593 return isReg() && checkRegisterClass(getReg(),
594 /*Data=*/false,
595 /*Address=*/false, /*SP=*/false,
596 /*FPDR=*/true);
597}
598
599bool M68kOperand::isFPCReg() const {
600 return isReg() && checkRegisterClass(getReg(),
601 /*Data=*/false,
602 /*Address=*/false, /*SP=*/false,
603 /*FPDR=*/false, /*FPCR=*/true);
604}
605
606unsigned M68kAsmParser::validateTargetOperandClass(MCParsedAsmOperand &Op,
607 unsigned Kind) {
608 M68kOperand &Operand = (M68kOperand &)Op;
609
610 switch (Kind) {
611 case MCK_XR16:
612 case MCK_SPILL:
613 if (Operand.isReg() &&
614 checkRegisterClass(Operand.getReg(), true, true, true)) {
615 return Match_Success;
616 }
617 break;
618
619 case MCK_AR16:
620 case MCK_AR32:
621 if (Operand.isReg() &&
622 checkRegisterClass(Operand.getReg(), false, true, true)) {
623 return Match_Success;
624 }
625 break;
626
627 case MCK_AR32_NOSP:
628 if (Operand.isReg() &&
629 checkRegisterClass(Operand.getReg(), false, true, false)) {
630 return Match_Success;
631 }
632 break;
633
634 case MCK_DR8:
635 case MCK_DR16:
636 case MCK_DR32:
637 if (Operand.isReg() &&
638 checkRegisterClass(Operand.getReg(), true, false, false)) {
639 return Match_Success;
640 }
641 break;
642
643 case MCK_AR16_TC:
644 if (Operand.isReg() &&
645 ((Operand.getReg() == M68k::A0) || (Operand.getReg() == M68k::A1))) {
646 return Match_Success;
647 }
648 break;
649
650 case MCK_DR16_TC:
651 if (Operand.isReg() &&
652 ((Operand.getReg() == M68k::D0) || (Operand.getReg() == M68k::D1))) {
653 return Match_Success;
654 }
655 break;
656
657 case MCK_XR16_TC:
658 if (Operand.isReg() &&
659 ((Operand.getReg() == M68k::D0) || (Operand.getReg() == M68k::D1) ||
660 (Operand.getReg() == M68k::A0) || (Operand.getReg() == M68k::A1))) {
661 return Match_Success;
662 }
663 break;
664 }
665
666 return Match_InvalidOperand;
667}
668
669bool M68kAsmParser::parseRegisterName(MCRegister &RegNo, SMLoc Loc,
670 StringRef RegisterName) {
671 auto RegisterNameLower = RegisterName.lower();
672
673 // CCR and SR register
674 if (RegisterNameLower == "ccr") {
675 RegNo = M68k::CCR;
676 return true;
677 } else if (RegisterNameLower == "sr") {
678 RegNo = M68k::SR;
679 return true;
680 }
681
682 // Parse simple general-purpose registers.
683 if (RegisterNameLower.size() == 2) {
684
685 switch (RegisterNameLower[0]) {
686 case 'd':
687 case 'a': {
688 if (isdigit(RegisterNameLower[1])) {
689 unsigned IndexOffset = (RegisterNameLower[0] == 'a') ? 8 : 0;
690 unsigned RegIndex = (unsigned)(RegisterNameLower[1] - '0');
691 if (RegIndex < 8) {
692 RegNo = getRegisterByIndex(IndexOffset + RegIndex);
693 return true;
694 }
695 }
696 break;
697 }
698
699 case 's':
700 if (RegisterNameLower[1] == 'p') {
701 RegNo = M68k::SP;
702 return true;
703 } else if (RegisterNameLower[1] == 'r') {
704 RegNo = M68k::SR;
705 return true;
706 }
707 break;
708
709 case 'p':
710 if (RegisterNameLower[1] == 'c') {
711 RegNo = M68k::PC;
712 return true;
713 }
714 break;
715 }
716 } else if (StringRef(RegisterNameLower).starts_with("fp") &&
717 RegisterNameLower.size() > 2) {
718 auto RegIndex = unsigned(RegisterNameLower[2] - '0');
719 if (RegIndex < 8 && RegisterNameLower.size() == 3) {
720 // Floating point data register.
721 RegNo = getRegisterByIndex(16 + RegIndex);
722 return true;
723 } else {
724 // Floating point control register.
725 RegNo = StringSwitch<unsigned>(RegisterNameLower)
726 .Cases({"fpc", "fpcr"}, M68k::FPC)
727 .Cases({"fps", "fpsr"}, M68k::FPS)
728 .Cases({"fpi", "fpiar"}, M68k::FPIAR)
729 .Default(M68k::NoRegister);
730 assert(RegNo != M68k::NoRegister &&
731 "Unrecognized FP control register name");
732 return true;
733 }
734 }
735
736 return false;
737}
738
739ParseStatus M68kAsmParser::parseRegister(MCRegister &RegNo,
740 bool WithSizeSuffix) {
741 bool HasPercent = false;
742 AsmToken PercentToken;
743
744 LLVM_DEBUG(dbgs() << "parseRegister "; getTok().dump(dbgs()); dbgs() << "\n");
745
746 if (getTok().is(AsmToken::Percent)) {
747 HasPercent = true;
748 PercentToken = Lex();
749 } else if (!RegisterPrefixOptional.getValue()) {
751 }
752
753 if (!Parser.getTok().is(AsmToken::Identifier)) {
754 if (HasPercent) {
755 getLexer().UnLex(PercentToken);
756 }
758 }
759
760 auto RegisterName = Parser.getTok().getString();
761 unsigned RegSize = 4;
762 if (WithSizeSuffix && (RegisterName.ends_with_insensitive(".w") ||
763 RegisterName.ends_with_insensitive(".l"))) {
764 if (RegisterName.ends_with_insensitive(".w"))
765 RegSize = 2;
766 RegisterName = RegisterName.drop_back(2);
767 }
768
769 if (!parseRegisterName(RegNo, Parser.getLexer().getLoc(), RegisterName)) {
770 if (HasPercent) {
771 getLexer().UnLex(PercentToken);
772 }
774 }
775 if (RegSize == 2)
776 RegNo = MRI->getSubReg(RegNo, M68k::MxSubRegIndex16Lo);
777
778 Parser.Lex();
780}
781
782bool M68kAsmParser::parseRegister(MCRegister &Reg, SMLoc &StartLoc,
783 SMLoc &EndLoc) {
784 ParseStatus Result = tryParseRegister(Reg, StartLoc, EndLoc);
785 if (!Result.isSuccess())
786 return Error(StartLoc, "expected register");
787
788 return false;
789}
790
791ParseStatus M68kAsmParser::tryParseRegister(MCRegister &Reg, SMLoc &StartLoc,
792 SMLoc &EndLoc) {
793 StartLoc = getLexer().getLoc();
794 ParseStatus Result = parseRegister(Reg);
795 EndLoc = getLexer().getLoc();
796 return Result;
797}
798
799bool M68kAsmParser::isExpr() {
800 switch (Parser.getTok().getKind()) {
803 return true;
804 case AsmToken::Minus:
805 return getLexer().peekTok().getKind() == AsmToken::Integer;
806
807 default:
808 return false;
809 }
810}
811
812ParseStatus M68kAsmParser::parseImm(OperandVector &Operands) {
813 if (getLexer().isNot(AsmToken::Hash))
815 SMLoc Start = getLexer().getLoc();
816 Parser.Lex();
817
818 SMLoc End;
819 const MCExpr *Expr;
820
821 if (getParser().parseExpression(Expr, End))
823
824 Operands.push_back(M68kOperand::createImm(Expr, Start, End));
826}
827
828ParseStatus M68kAsmParser::parseMemOp(OperandVector &Operands) {
829 SMLoc Start = getLexer().getLoc();
830 bool IsPD = false;
831 M68kMemOp MemOp;
832
833 MemOp.AtLeast68020 = STI->hasFeature(M68k::FeatureISA20);
834 MemOp.Scale = 1;
835
836 // Check for a plain register or register mask.
837 ParseStatus Result = parseRegOrMoveMask(Operands);
838 if (!Result.isNoMatch())
839 return Result;
840
841 // Check for pre-decrement & outer displacement.
842 bool HasDisplacement = false;
843 if (getLexer().is(AsmToken::Minus)) {
844 IsPD = true;
845 Parser.Lex();
846 } else if (isExpr()) {
847 if (Parser.parseExpression(MemOp.OuterDisp))
849 HasDisplacement = true;
850 }
851
852 if (getLexer().isNot(AsmToken::LParen)) {
853 if (HasDisplacement) {
854 MemOp.Op = M68kMemOp::Kind::Addr;
855 Operands.push_back(
856 M68kOperand::createMemOp(MemOp, Start, getLexer().getLoc()));
858 }
859 if (IsPD)
860 return Error(getLexer().getLoc(), "expected (");
861
863 }
864 Parser.Lex();
865
866 // Check for constant dereference & MIT-style displacement
867 if (!HasDisplacement && isExpr()) {
868 if (Parser.parseExpression(MemOp.OuterDisp))
870 HasDisplacement = true;
871
872 // If we're not followed by a comma, we're a constant dereference.
873 if (getLexer().isNot(AsmToken::Comma)) {
874 MemOp.Op = M68kMemOp::Kind::Addr;
875 Operands.push_back(
876 M68kOperand::createMemOp(MemOp, Start, getLexer().getLoc()));
878 }
879
880 Parser.Lex();
881 }
882
883 Result = parseRegister(MemOp.OuterReg);
884 if (Result.isFailure())
886
887 if (!Result.isSuccess())
888 return Error(getLexer().getLoc(), "expected register");
889
890 bool HasIndex = false;
891 // Check for Index.
892 if (Parser.getTok().is(AsmToken::Comma)) {
893 Parser.Lex();
894
895 Result = parseRegister(MemOp.InnerReg, /*WithSizeSuffix=*/true);
896 if (Result.isFailure())
897 return Result;
898
899 if (Result.isNoMatch())
900 return Error(getLexer().getLoc(), "expected register");
901 HasIndex = true;
902
903 // Parse the scale
904 if (Parser.getTok().is(AsmToken::Star)) {
905 const auto &ScaleTok = Parser.Lex();
906 if (ScaleTok.isNot(AsmToken::Integer))
907 return Error(getLexer().getLoc(), "expected scale");
908 int64_t ScaleVal = ScaleTok.getIntVal();
909 if (ScaleVal < 1 || ScaleVal > 8 || !isPowerOf2_32(ScaleVal))
910 return Error(ScaleTok.getLoc(), "expected scale to be 1, 2, 4, or 8");
911 MemOp.Scale = static_cast<uint8_t>(ScaleVal);
912 Parser.Lex();
913 }
914
915 // TODO: parse the inner displacement.
916 MemOp.InnerDisp = MCConstantExpr::create(0, Parser.getContext(), true, 4);
917 }
918
919 if (Parser.getTok().isNot(AsmToken::RParen))
920 return Error(getLexer().getLoc(), "expected )");
921 Parser.Lex();
922
923 bool IsPI = false;
924 if (!IsPD && Parser.getTok().is(AsmToken::Plus)) {
925 Parser.Lex();
926 IsPI = true;
927 }
928
929 SMLoc End = getLexer().getLoc();
930
931 unsigned OpCount = IsPD + IsPI + (HasIndex || HasDisplacement);
932 if (OpCount > 1)
933 return Error(Start, "only one of post-increment, pre-decrement or "
934 "displacement can be used");
935
936 if (IsPD) {
937 MemOp.Op = M68kMemOp::Kind::RegPreDecrement;
938 } else if (IsPI) {
939 MemOp.Op = M68kMemOp::Kind::RegPostIncrement;
940 } else if (HasIndex) {
941 MemOp.Op = M68kMemOp::Kind::RegIndirectDisplacementIndex;
942 } else if (HasDisplacement) {
943 MemOp.Op = M68kMemOp::Kind::RegIndirectDisplacement;
944 } else {
945 MemOp.Op = M68kMemOp::Kind::RegIndirect;
946 }
947
948 Operands.push_back(M68kOperand::createMemOp(MemOp, Start, End));
950}
951
952ParseStatus M68kAsmParser::parseRegOrMoveMask(OperandVector &Operands) {
953 SMLoc Start = getLexer().getLoc();
954 M68kMemOp MemOp(M68kMemOp::Kind::RegMask);
955 MemOp.RegMask = 0;
956
957 for (;;) {
958 bool IsFirstRegister =
959 (MemOp.Op == M68kMemOp::Kind::RegMask) && (MemOp.RegMask == 0);
960
961 MCRegister FirstRegister;
962 ParseStatus Result = parseRegister(FirstRegister);
963 if (IsFirstRegister && Result.isNoMatch())
965 if (!Result.isSuccess())
966 return Error(getLexer().getLoc(), "expected start register");
967
968 MCRegister LastRegister = FirstRegister;
969 if (parseOptionalToken(AsmToken::Minus)) {
970 Result = parseRegister(LastRegister);
971 if (!Result.isSuccess())
972 return Error(getLexer().getLoc(), "expected end register");
973 }
974
975 unsigned FirstRegisterIndex = getRegisterIndex(FirstRegister);
976 unsigned LastRegisterIndex = getRegisterIndex(LastRegister);
977
978 uint16_t NumNewBits = LastRegisterIndex - FirstRegisterIndex + 1;
979 uint16_t NewMaskBits = ((1 << NumNewBits) - 1) << FirstRegisterIndex;
980
981 if (IsFirstRegister && (FirstRegister == LastRegister)) {
982 // First register range is a single register, simplify to just Reg
983 // so that it matches more operands.
984 MemOp.Op = M68kMemOp::Kind::Reg;
985 MemOp.OuterReg = FirstRegister;
986 } else {
987 if (MemOp.Op == M68kMemOp::Kind::Reg) {
988 // This is the second register being specified - expand the Reg operand
989 // into a mask first.
990 MemOp.Op = M68kMemOp::Kind::RegMask;
991 MemOp.RegMask = 1 << getRegisterIndex(MemOp.OuterReg);
992
993 if (MemOp.RegMask == 0)
994 return Error(getLexer().getLoc(),
995 "special registers cannot be used in register masks");
996 }
997
998 if ((FirstRegisterIndex >= 16) || (LastRegisterIndex >= 16))
999 return Error(getLexer().getLoc(),
1000 "special registers cannot be used in register masks");
1001
1002 if (NewMaskBits & MemOp.RegMask)
1003 return Error(getLexer().getLoc(), "conflicting masked registers");
1004
1005 MemOp.RegMask |= NewMaskBits;
1006 }
1007
1008 if (!parseOptionalToken(AsmToken::Slash))
1009 break;
1010 }
1011
1012 Operands.push_back(
1013 M68kOperand::createMemOp(MemOp, Start, getLexer().getLoc()));
1014 return ParseStatus::Success;
1015}
1016
1017void M68kAsmParser::eatComma() {
1018 if (Parser.getTok().is(AsmToken::Comma)) {
1019 Parser.Lex();
1020 }
1021}
1022
1023bool M68kAsmParser::parseInstruction(ParseInstructionInfo &Info, StringRef Name,
1024 SMLoc NameLoc, OperandVector &Operands) {
1025 SMLoc Start = getLexer().getLoc();
1026 Operands.push_back(M68kOperand::createToken(Name, Start, Start));
1027
1028 bool First = true;
1029 while (Parser.getTok().isNot(AsmToken::EndOfStatement)) {
1030 if (!First) {
1031 eatComma();
1032 } else {
1033 First = false;
1034 }
1035
1036 ParseStatus MatchResult = MatchOperandParserImpl(Operands, Name);
1037 if (MatchResult.isSuccess())
1038 continue;
1039
1040 // Add custom operand formats here...
1041 SMLoc Loc = getLexer().getLoc();
1042 Parser.eatToEndOfStatement();
1043 return Error(Loc, "unexpected token parsing operands");
1044 }
1045
1046 // Eat EndOfStatement.
1047 Parser.Lex();
1048 return false;
1049}
1050
1051bool M68kAsmParser::invalidOperand(SMLoc Loc, OperandVector const &Operands,
1052 uint64_t const &ErrorInfo) {
1053 SMLoc ErrorLoc = Loc;
1054 char const *Diag = 0;
1055
1056 if (ErrorInfo != ~0U) {
1057 if (ErrorInfo >= Operands.size()) {
1058 Diag = "too few operands for instruction.";
1059 } else {
1060 auto const &Op = (M68kOperand const &)*Operands[ErrorInfo];
1061 if (Op.getStartLoc() != SMLoc()) {
1062 ErrorLoc = Op.getStartLoc();
1063 }
1064 }
1065 }
1066
1067 if (!Diag) {
1068 Diag = "invalid operand for instruction";
1069 }
1070
1071 return Error(ErrorLoc, Diag);
1072}
1073
1074bool M68kAsmParser::missingFeature(SMLoc Loc, uint64_t const &ErrorInfo) {
1075 return Error(Loc, "instruction requires a CPU feature not currently enabled");
1076}
1077
1078bool M68kAsmParser::emit(MCInst &Inst, SMLoc Loc, MCStreamer &Out) const {
1079 Inst.setLoc(Loc);
1080 Out.emitInstruction(Inst, *STI);
1081
1082 return false;
1083}
1084
1085bool M68kAsmParser::matchAndEmitInstruction(SMLoc Loc, unsigned &Opcode,
1086 OperandVector &Operands,
1087 MCStreamer &Out,
1088 uint64_t &ErrorInfo,
1089 bool MatchingInlineAsm) {
1090 MCInst Inst;
1091 unsigned MatchResult =
1092 MatchInstructionImpl(Operands, Inst, ErrorInfo, MatchingInlineAsm);
1093
1094 switch (MatchResult) {
1095 case Match_Success:
1096 return emit(Inst, Loc, Out);
1097 case Match_MissingFeature:
1098 return missingFeature(Loc, ErrorInfo);
1099 case Match_InvalidOperand:
1100 return invalidOperand(Loc, Operands, ErrorInfo);
1101 case Match_MnemonicFail:
1102 return Error(Loc, "invalid instruction");
1103 default:
1104 return true;
1105 }
1106}
1107
1108void M68kOperand::print(raw_ostream &OS, const MCAsmInfo &MAI) const {
1109 switch (Kind) {
1110 case KindTy::Invalid:
1111 OS << "invalid";
1112 break;
1113
1114 case KindTy::Token:
1115 OS << "token '" << Token << "'";
1116 break;
1117
1118 case KindTy::Imm: {
1119 int64_t Value;
1120 Expr->evaluateAsAbsolute(Value);
1121 OS << "immediate " << Value;
1122 break;
1123 }
1124
1125 case KindTy::MemOp:
1126 MemOp.print(OS);
1127 break;
1128 }
1129}
unsigned RegSize
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static bool isNot(const MachineRegisterInfo &MRI, const MachineInstr &MI)
#define X(NUM, ENUM, NAME)
Definition ELF.h:856
#define LLVM_EXTERNAL_VISIBILITY
Definition Compiler.h:132
@ Default
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.
Register Reg
static MCRegister getReg(const MCDisassembler *D, unsigned RC, unsigned RegNo)
static bool isReg(const MCInst &MI, unsigned OpNo)
static bool contains(SmallPtrSetImpl< ConstantExpr * > &Cache, ConstantExpr *Expr, Constant *C)
Definition Value.cpp:484
DEMANGLE_NAMESPACE_BEGIN bool starts_with(std::string_view self, char C) noexcept
#define LLVM_DEBUG(...)
Definition Debug.h:119
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...
MCRegister getSubReg(MCRegister Reg, unsigned Idx) const
Returns the physical register number of sub-register "Index" for physical register RegNo.
Wrapper class representing physical registers. Should be passed by value.
Definition MCRegister.h:41
Streaming machine code generation interface.
Definition MCStreamer.h:222
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:20
Represents a location in source code.
Definition SMLoc.h:22
void push_back(const T &Elt)
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
LLVM_ABI std::string lower() const
StringRef drop_back(size_t N=1) const
Return a StringRef equal to 'this' but with the last N elements dropped.
Definition StringRef.h:642
LLVM_ABI bool ends_with_insensitive(StringRef Suffix) const
Check if this string ends with the given Suffix, ignoring case.
Definition StringRef.cpp:46
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.
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:165
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:643
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
Definition InstrProf.h:143
SmallVectorImpl< std::unique_ptr< MCParsedAsmOperand > > OperandVector
constexpr bool isPowerOf2_32(uint32_t Value)
Return true if the argument is a power of two > 0.
Definition MathExtras.h:279
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
constexpr bool isUInt(uint64_t x)
Checks if an unsigned integer fits into the given bit width.
Definition MathExtras.h:189
format_object< Ts... > format(const char *Fmt, const Ts &... Vals)
These are helper functions used to produce formatted output.
Definition Format.h:94
@ First
Helpers to iterate all locations in the MemoryEffectsBase class.
Definition ModRef.h:74
DWARFExpression::Operation Op
Target & getTheM68kTarget()
#define N
RegisterMCAsmParser - Helper template for registering a target specific assembly parser,...