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