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 M68kMCRegisterClasses[M68k::XR32RegClassID].contains(MemOp.InnerReg));
517}
518bool M68kOperand::isPCIBD16() const {
519 return isPCIBD() &&
520 M68kMCRegisterClasses[M68k::XR16RegClassID].contains(MemOp.InnerReg);
521}
522void M68kOperand::addPCIBDOperands(MCInst &Inst, unsigned N) const {
523 M68kOperand::addExpr(Inst, MemOp.OuterDisp);
524 Inst.addOperand(MCOperand::createReg(MemOp.InnerReg));
525 Inst.addOperand(MCOperand::createImm(MemOp.Scale));
526}
527
528static inline bool checkRegisterClass(unsigned RegNo, bool Data, bool Address,
529 bool SP, bool FPDR = false,
530 bool FPCR = false) {
531 switch (RegNo) {
532 case M68k::A0:
533 case M68k::A1:
534 case M68k::A2:
535 case M68k::A3:
536 case M68k::A4:
537 case M68k::A5:
538 case M68k::A6:
539 return Address;
540
541 case M68k::SP:
542 return SP;
543
544 case M68k::D0:
545 case M68k::D1:
546 case M68k::D2:
547 case M68k::D3:
548 case M68k::D4:
549 case M68k::D5:
550 case M68k::D6:
551 case M68k::D7:
552 return Data;
553
554 case M68k::SR:
555 case M68k::CCR:
556 return false;
557
558 case M68k::FP0:
559 case M68k::FP1:
560 case M68k::FP2:
561 case M68k::FP3:
562 case M68k::FP4:
563 case M68k::FP5:
564 case M68k::FP6:
565 case M68k::FP7:
566 return FPDR;
567
568 case M68k::FPC:
569 case M68k::FPS:
570 case M68k::FPIAR:
571 return FPCR;
572
573 default:
574 llvm_unreachable("unexpected register type");
575 return false;
576 }
577}
578
579bool M68kOperand::isAReg() const {
580 return isReg() && checkRegisterClass(getReg(),
581 /*Data=*/false,
582 /*Address=*/true, /*SP=*/true);
583}
584
585bool M68kOperand::isDReg() const {
586 return isReg() && checkRegisterClass(getReg(),
587 /*Data=*/true,
588 /*Address=*/false, /*SP=*/false);
589}
590
591bool M68kOperand::isFPDReg() const {
592 return isReg() && checkRegisterClass(getReg(),
593 /*Data=*/false,
594 /*Address=*/false, /*SP=*/false,
595 /*FPDR=*/true);
596}
597
598bool M68kOperand::isFPCReg() const {
599 return isReg() && checkRegisterClass(getReg(),
600 /*Data=*/false,
601 /*Address=*/false, /*SP=*/false,
602 /*FPDR=*/false, /*FPCR=*/true);
603}
604
605unsigned M68kAsmParser::validateTargetOperandClass(MCParsedAsmOperand &Op,
606 unsigned Kind) {
607 M68kOperand &Operand = (M68kOperand &)Op;
608
609 switch (Kind) {
610 case MCK_XR16:
611 case MCK_SPILL:
612 if (Operand.isReg() &&
613 checkRegisterClass(Operand.getReg(), true, true, true)) {
614 return Match_Success;
615 }
616 break;
617
618 case MCK_AR16:
619 case MCK_AR32:
620 if (Operand.isReg() &&
621 checkRegisterClass(Operand.getReg(), false, true, true)) {
622 return Match_Success;
623 }
624 break;
625
626 case MCK_AR32_NOSP:
627 if (Operand.isReg() &&
628 checkRegisterClass(Operand.getReg(), false, true, false)) {
629 return Match_Success;
630 }
631 break;
632
633 case MCK_DR8:
634 case MCK_DR16:
635 case MCK_DR32:
636 if (Operand.isReg() &&
637 checkRegisterClass(Operand.getReg(), true, false, false)) {
638 return Match_Success;
639 }
640 break;
641
642 case MCK_AR16_TC:
643 if (Operand.isReg() &&
644 ((Operand.getReg() == M68k::A0) || (Operand.getReg() == M68k::A1))) {
645 return Match_Success;
646 }
647 break;
648
649 case MCK_DR16_TC:
650 if (Operand.isReg() &&
651 ((Operand.getReg() == M68k::D0) || (Operand.getReg() == M68k::D1))) {
652 return Match_Success;
653 }
654 break;
655
656 case MCK_XR16_TC:
657 if (Operand.isReg() &&
658 ((Operand.getReg() == M68k::D0) || (Operand.getReg() == M68k::D1) ||
659 (Operand.getReg() == M68k::A0) || (Operand.getReg() == M68k::A1))) {
660 return Match_Success;
661 }
662 break;
663 }
664
665 return Match_InvalidOperand;
666}
667
668bool M68kAsmParser::parseRegisterName(MCRegister &RegNo, SMLoc Loc,
669 StringRef RegisterName) {
670 auto RegisterNameLower = RegisterName.lower();
671
672 // CCR and SR register
673 if (RegisterNameLower == "ccr") {
674 RegNo = M68k::CCR;
675 return true;
676 } else if (RegisterNameLower == "sr") {
677 RegNo = M68k::SR;
678 return true;
679 }
680
681 // Parse simple general-purpose registers.
682 if (RegisterNameLower.size() == 2) {
683
684 switch (RegisterNameLower[0]) {
685 case 'd':
686 case 'a': {
687 if (isdigit(RegisterNameLower[1])) {
688 unsigned IndexOffset = (RegisterNameLower[0] == 'a') ? 8 : 0;
689 unsigned RegIndex = (unsigned)(RegisterNameLower[1] - '0');
690 if (RegIndex < 8) {
691 RegNo = getRegisterByIndex(IndexOffset + RegIndex);
692 return true;
693 }
694 }
695 break;
696 }
697
698 case 's':
699 if (RegisterNameLower[1] == 'p') {
700 RegNo = M68k::SP;
701 return true;
702 } else if (RegisterNameLower[1] == 'r') {
703 RegNo = M68k::SR;
704 return true;
705 }
706 break;
707
708 case 'p':
709 if (RegisterNameLower[1] == 'c') {
710 RegNo = M68k::PC;
711 return true;
712 }
713 break;
714 }
715 } else if (StringRef(RegisterNameLower).starts_with("fp") &&
716 RegisterNameLower.size() > 2) {
717 auto RegIndex = unsigned(RegisterNameLower[2] - '0');
718 if (RegIndex < 8 && RegisterNameLower.size() == 3) {
719 // Floating point data register.
720 RegNo = getRegisterByIndex(16 + RegIndex);
721 return true;
722 } else {
723 // Floating point control register.
724 RegNo = StringSwitch<unsigned>(RegisterNameLower)
725 .Cases({"fpc", "fpcr"}, M68k::FPC)
726 .Cases({"fps", "fpsr"}, M68k::FPS)
727 .Cases({"fpi", "fpiar"}, M68k::FPIAR)
728 .Default(M68k::NoRegister);
729 assert(RegNo != M68k::NoRegister &&
730 "Unrecognized FP control register name");
731 return true;
732 }
733 }
734
735 return false;
736}
737
738ParseStatus M68kAsmParser::parseRegister(MCRegister &RegNo,
739 bool WithSizeSuffix) {
740 bool HasPercent = false;
741 AsmToken PercentToken;
742
743 LLVM_DEBUG(dbgs() << "parseRegister "; getTok().dump(dbgs()); dbgs() << "\n");
744
745 if (getTok().is(AsmToken::Percent)) {
746 HasPercent = true;
747 PercentToken = Lex();
748 } else if (!RegisterPrefixOptional.getValue()) {
750 }
751
752 if (!Parser.getTok().is(AsmToken::Identifier)) {
753 if (HasPercent) {
754 getLexer().UnLex(PercentToken);
755 }
757 }
758
759 auto RegisterName = Parser.getTok().getString();
760 unsigned RegSize = 4;
761 if (WithSizeSuffix && (RegisterName.ends_with_insensitive(".w") ||
762 RegisterName.ends_with_insensitive(".l"))) {
763 if (RegisterName.ends_with_insensitive(".w"))
764 RegSize = 2;
765 RegisterName = RegisterName.drop_back(2);
766 }
767
768 if (!parseRegisterName(RegNo, Parser.getLexer().getLoc(), RegisterName)) {
769 if (HasPercent) {
770 getLexer().UnLex(PercentToken);
771 }
773 }
774 if (RegSize == 2)
775 RegNo = MRI->getSubReg(RegNo, M68k::MxSubRegIndex16Lo);
776
777 Parser.Lex();
779}
780
781bool M68kAsmParser::parseRegister(MCRegister &Reg, SMLoc &StartLoc,
782 SMLoc &EndLoc) {
783 ParseStatus Result = tryParseRegister(Reg, StartLoc, EndLoc);
784 if (!Result.isSuccess())
785 return Error(StartLoc, "expected register");
786
787 return false;
788}
789
790ParseStatus M68kAsmParser::tryParseRegister(MCRegister &Reg, SMLoc &StartLoc,
791 SMLoc &EndLoc) {
792 StartLoc = getLexer().getLoc();
793 ParseStatus Result = parseRegister(Reg);
794 EndLoc = getLexer().getLoc();
795 return Result;
796}
797
798bool M68kAsmParser::isExpr() {
799 switch (Parser.getTok().getKind()) {
802 return true;
803 case AsmToken::Minus:
804 return getLexer().peekTok().getKind() == AsmToken::Integer;
805
806 default:
807 return false;
808 }
809}
810
811ParseStatus M68kAsmParser::parseImm(OperandVector &Operands) {
812 if (getLexer().isNot(AsmToken::Hash))
814 SMLoc Start = getLexer().getLoc();
815 Parser.Lex();
816
817 SMLoc End;
818 const MCExpr *Expr;
819
820 if (getParser().parseExpression(Expr, End))
822
823 Operands.push_back(M68kOperand::createImm(Expr, Start, End));
825}
826
827ParseStatus M68kAsmParser::parseMemOp(OperandVector &Operands) {
828 SMLoc Start = getLexer().getLoc();
829 bool IsPD = false;
830 M68kMemOp MemOp;
831
832 MemOp.AtLeast68020 = STI->hasFeature(M68k::FeatureISA20);
833 MemOp.Scale = 1;
834
835 // Check for a plain register or register mask.
836 ParseStatus Result = parseRegOrMoveMask(Operands);
837 if (!Result.isNoMatch())
838 return Result;
839
840 // Check for pre-decrement & outer displacement.
841 bool HasDisplacement = false;
842 if (getLexer().is(AsmToken::Minus)) {
843 IsPD = true;
844 Parser.Lex();
845 } else if (isExpr()) {
846 if (Parser.parseExpression(MemOp.OuterDisp))
848 HasDisplacement = true;
849 }
850
851 if (getLexer().isNot(AsmToken::LParen)) {
852 if (HasDisplacement) {
853 MemOp.Op = M68kMemOp::Kind::Addr;
854 Operands.push_back(
855 M68kOperand::createMemOp(MemOp, Start, getLexer().getLoc()));
857 }
858 if (IsPD)
859 return Error(getLexer().getLoc(), "expected (");
860
862 }
863 Parser.Lex();
864
865 // Check for constant dereference & MIT-style displacement
866 if (!HasDisplacement && isExpr()) {
867 if (Parser.parseExpression(MemOp.OuterDisp))
869 HasDisplacement = true;
870
871 // If we're not followed by a comma, we're a constant dereference.
872 if (getLexer().isNot(AsmToken::Comma)) {
873 MemOp.Op = M68kMemOp::Kind::Addr;
874 Operands.push_back(
875 M68kOperand::createMemOp(MemOp, Start, getLexer().getLoc()));
877 }
878
879 Parser.Lex();
880 }
881
882 Result = parseRegister(MemOp.OuterReg);
883 if (Result.isFailure())
885
886 if (!Result.isSuccess())
887 return Error(getLexer().getLoc(), "expected register");
888
889 bool HasIndex = false;
890 // Check for Index.
891 if (Parser.getTok().is(AsmToken::Comma)) {
892 Parser.Lex();
893
894 Result = parseRegister(MemOp.InnerReg, /*WithSizeSuffix=*/true);
895 if (Result.isFailure())
896 return Result;
897
898 if (Result.isNoMatch())
899 return Error(getLexer().getLoc(), "expected register");
900 HasIndex = true;
901
902 // Parse the scale
903 if (Parser.getTok().is(AsmToken::Star)) {
904 const auto &ScaleTok = Parser.Lex();
905 if (ScaleTok.isNot(AsmToken::Integer))
906 return Error(getLexer().getLoc(), "expected scale");
907 int64_t ScaleVal = ScaleTok.getIntVal();
908 if (ScaleVal < 1 || ScaleVal > 8 || !isPowerOf2_32(ScaleVal))
909 return Error(ScaleTok.getLoc(), "expected scale to be 1, 2, 4, or 8");
910 MemOp.Scale = static_cast<uint8_t>(ScaleVal);
911 Parser.Lex();
912 }
913
914 // TODO: parse the inner displacement.
915 MemOp.InnerDisp = MCConstantExpr::create(0, Parser.getContext(), true, 4);
916 }
917
918 if (Parser.getTok().isNot(AsmToken::RParen))
919 return Error(getLexer().getLoc(), "expected )");
920 Parser.Lex();
921
922 bool IsPI = false;
923 if (!IsPD && Parser.getTok().is(AsmToken::Plus)) {
924 Parser.Lex();
925 IsPI = true;
926 }
927
928 SMLoc End = getLexer().getLoc();
929
930 unsigned OpCount = IsPD + IsPI + (HasIndex || HasDisplacement);
931 if (OpCount > 1)
932 return Error(Start, "only one of post-increment, pre-decrement or "
933 "displacement can be used");
934
935 if (IsPD) {
936 MemOp.Op = M68kMemOp::Kind::RegPreDecrement;
937 } else if (IsPI) {
938 MemOp.Op = M68kMemOp::Kind::RegPostIncrement;
939 } else if (HasIndex) {
940 MemOp.Op = M68kMemOp::Kind::RegIndirectDisplacementIndex;
941 } else if (HasDisplacement) {
942 MemOp.Op = M68kMemOp::Kind::RegIndirectDisplacement;
943 } else {
944 MemOp.Op = M68kMemOp::Kind::RegIndirect;
945 }
946
947 Operands.push_back(M68kOperand::createMemOp(MemOp, Start, End));
949}
950
951ParseStatus M68kAsmParser::parseRegOrMoveMask(OperandVector &Operands) {
952 SMLoc Start = getLexer().getLoc();
953 M68kMemOp MemOp(M68kMemOp::Kind::RegMask);
954 MemOp.RegMask = 0;
955
956 for (;;) {
957 bool IsFirstRegister =
958 (MemOp.Op == M68kMemOp::Kind::RegMask) && (MemOp.RegMask == 0);
959
960 MCRegister FirstRegister;
961 ParseStatus Result = parseRegister(FirstRegister);
962 if (IsFirstRegister && Result.isNoMatch())
964 if (!Result.isSuccess())
965 return Error(getLexer().getLoc(), "expected start register");
966
967 MCRegister LastRegister = FirstRegister;
968 if (parseOptionalToken(AsmToken::Minus)) {
969 Result = parseRegister(LastRegister);
970 if (!Result.isSuccess())
971 return Error(getLexer().getLoc(), "expected end register");
972 }
973
974 unsigned FirstRegisterIndex = getRegisterIndex(FirstRegister);
975 unsigned LastRegisterIndex = getRegisterIndex(LastRegister);
976
977 uint16_t NumNewBits = LastRegisterIndex - FirstRegisterIndex + 1;
978 uint16_t NewMaskBits = ((1 << NumNewBits) - 1) << FirstRegisterIndex;
979
980 if (IsFirstRegister && (FirstRegister == LastRegister)) {
981 // First register range is a single register, simplify to just Reg
982 // so that it matches more operands.
983 MemOp.Op = M68kMemOp::Kind::Reg;
984 MemOp.OuterReg = FirstRegister;
985 } else {
986 if (MemOp.Op == M68kMemOp::Kind::Reg) {
987 // This is the second register being specified - expand the Reg operand
988 // into a mask first.
989 MemOp.Op = M68kMemOp::Kind::RegMask;
990 MemOp.RegMask = 1 << getRegisterIndex(MemOp.OuterReg);
991
992 if (MemOp.RegMask == 0)
993 return Error(getLexer().getLoc(),
994 "special registers cannot be used in register masks");
995 }
996
997 if ((FirstRegisterIndex >= 16) || (LastRegisterIndex >= 16))
998 return Error(getLexer().getLoc(),
999 "special registers cannot be used in register masks");
1000
1001 if (NewMaskBits & MemOp.RegMask)
1002 return Error(getLexer().getLoc(), "conflicting masked registers");
1003
1004 MemOp.RegMask |= NewMaskBits;
1005 }
1006
1007 if (!parseOptionalToken(AsmToken::Slash))
1008 break;
1009 }
1010
1011 Operands.push_back(
1012 M68kOperand::createMemOp(MemOp, Start, getLexer().getLoc()));
1013 return ParseStatus::Success;
1014}
1015
1016void M68kAsmParser::eatComma() {
1017 if (Parser.getTok().is(AsmToken::Comma)) {
1018 Parser.Lex();
1019 }
1020}
1021
1022bool M68kAsmParser::parseInstruction(ParseInstructionInfo &Info, StringRef Name,
1023 SMLoc NameLoc, OperandVector &Operands) {
1024 SMLoc Start = getLexer().getLoc();
1025 Operands.push_back(M68kOperand::createToken(Name, Start, Start));
1026
1027 bool First = true;
1028 while (Parser.getTok().isNot(AsmToken::EndOfStatement)) {
1029 if (!First) {
1030 eatComma();
1031 } else {
1032 First = false;
1033 }
1034
1035 ParseStatus MatchResult = MatchOperandParserImpl(Operands, Name);
1036 if (MatchResult.isSuccess())
1037 continue;
1038
1039 // Add custom operand formats here...
1040 SMLoc Loc = getLexer().getLoc();
1041 Parser.eatToEndOfStatement();
1042 return Error(Loc, "unexpected token parsing operands");
1043 }
1044
1045 // Eat EndOfStatement.
1046 Parser.Lex();
1047 return false;
1048}
1049
1050bool M68kAsmParser::invalidOperand(SMLoc Loc, OperandVector const &Operands,
1051 uint64_t const &ErrorInfo) {
1052 SMLoc ErrorLoc = Loc;
1053 char const *Diag = 0;
1054
1055 if (ErrorInfo != ~0U) {
1056 if (ErrorInfo >= Operands.size()) {
1057 Diag = "too few operands for instruction.";
1058 } else {
1059 auto const &Op = (M68kOperand const &)*Operands[ErrorInfo];
1060 if (Op.getStartLoc() != SMLoc()) {
1061 ErrorLoc = Op.getStartLoc();
1062 }
1063 }
1064 }
1065
1066 if (!Diag) {
1067 Diag = "invalid operand for instruction";
1068 }
1069
1070 return Error(ErrorLoc, Diag);
1071}
1072
1073bool M68kAsmParser::missingFeature(SMLoc Loc, uint64_t const &ErrorInfo) {
1074 return Error(Loc, "instruction requires a CPU feature not currently enabled");
1075}
1076
1077bool M68kAsmParser::emit(MCInst &Inst, SMLoc Loc, MCStreamer &Out) const {
1078 Inst.setLoc(Loc);
1079 Out.emitInstruction(Inst, *STI);
1080
1081 return false;
1082}
1083
1084bool M68kAsmParser::matchAndEmitInstruction(SMLoc Loc, unsigned &Opcode,
1085 OperandVector &Operands,
1086 MCStreamer &Out,
1087 uint64_t &ErrorInfo,
1088 bool MatchingInlineAsm) {
1089 MCInst Inst;
1090 unsigned MatchResult =
1091 MatchInstructionImpl(Operands, Inst, ErrorInfo, MatchingInlineAsm);
1092
1093 switch (MatchResult) {
1094 case Match_Success:
1095 return emit(Inst, Loc, Out);
1096 case Match_MissingFeature:
1097 return missingFeature(Loc, ErrorInfo);
1098 case Match_InvalidOperand:
1099 return invalidOperand(Loc, Operands, ErrorInfo);
1100 case Match_MnemonicFail:
1101 return Error(Loc, "invalid instruction");
1102 default:
1103 return true;
1104 }
1105}
1106
1107void M68kOperand::print(raw_ostream &OS, const MCAsmInfo &MAI) const {
1108 switch (Kind) {
1109 case KindTy::Invalid:
1110 OS << "invalid";
1111 break;
1112
1113 case KindTy::Token:
1114 OS << "token '" << Token << "'";
1115 break;
1116
1117 case KindTy::Imm: {
1118 int64_t Value;
1119 Expr->evaluateAsAbsolute(Value);
1120 OS << "immediate " << Value;
1121 break;
1122 }
1123
1124 case KindTy::MemOp:
1125 MemOp.print(OS);
1126 break;
1127 }
1128}
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:853
#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:483
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:636
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.
FunctionAddr VTableAddr Value
Definition InstrProf.h:137
Printable print(const GCNRegPressure &RP, const GCNSubtarget *ST=nullptr, unsigned DynamicVGPRBlockSize=0)
constexpr bool isInt(int64_t x)
Checks if an integer fits into the given bit width.
Definition MathExtras.h: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
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:129
@ First
Helpers to iterate all locations in the MemoryEffectsBase class.
Definition ModRef.h:74
FunctionAddr VTableAddr uintptr_t uintptr_t Data
Definition InstrProf.h:221
DWARFExpression::Operation Op
Target & getTheM68kTarget()
#define N
RegisterMCAsmParser - Helper template for registering a target specific assembly parser,...