1 //===-- M68kInstPrinter.cpp - Convert M68k MCInst to asm ----*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
10 /// This file contains definitions for an M68k MCInst printer.
12 //===----------------------------------------------------------------------===//
14 // TODO Conform with all supported Motorola ASM syntax
15 // Motorola's assembly has several syntax variants, especially on
17 // For example, you can write pc indirect w/ displacement as
18 // `x(%pc)`, where `x` is the displacement imm, or `(x,%pc)`.
19 // Currently we're picking the variant that is different from
20 // GCC, albeit being recognizable by GNU AS.
21 // Not sure what is the impact now (e.g. some syntax might
22 // not be recognized by some old consoles' toolchains, in which
23 // case we can not use our integrated assembler), but either way,
24 // it will be great to support all of the variants in the future.
26 #include "M68kInstPrinter.h"
27 #include "M68kBaseInfo.h"
29 #include "llvm/ADT/StringExtras.h"
30 #include "llvm/MC/MCExpr.h"
31 #include "llvm/MC/MCInst.h"
32 #include "llvm/MC/MCInstrInfo.h"
33 #include "llvm/MC/MCSymbol.h"
34 #include "llvm/Support/ErrorHandling.h"
35 #include "llvm/Support/raw_ostream.h"
39 #define DEBUG_TYPE "asm-printer"
41 #define PRINT_ALIAS_INSTR
42 #include "M68kGenAsmWriter.inc"
44 void M68kInstPrinter::printRegName(raw_ostream
&OS
, unsigned RegNo
) const {
45 OS
<< "%" << getRegisterName(RegNo
);
48 void M68kInstPrinter::printInst(const MCInst
*MI
, uint64_t Address
,
49 StringRef Annot
, const MCSubtargetInfo
&STI
,
51 if (!printAliasInstr(MI
, Address
, O
))
52 printInstruction(MI
, Address
, O
);
54 printAnnotation(O
, Annot
);
57 void M68kInstPrinter::printOperand(const MCInst
*MI
, unsigned OpNo
,
59 const MCOperand
&MO
= MI
->getOperand(OpNo
);
61 printRegName(O
, MO
.getReg());
66 printImmediate(MI
, OpNo
, O
);
70 assert(MO
.isExpr() && "Unknown operand kind in printOperand");
71 MO
.getExpr()->print(O
, &MAI
);
74 void M68kInstPrinter::printImmediate(const MCInst
*MI
, unsigned opNum
,
76 const MCOperand
&MO
= MI
->getOperand(opNum
);
78 O
<< '#' << MO
.getImm();
79 else if (MO
.isExpr()) {
81 MO
.getExpr()->print(O
, &MAI
);
83 llvm_unreachable("Unknown immediate kind");
86 void M68kInstPrinter::printMoveMask(const MCInst
*MI
, unsigned opNum
,
88 unsigned Mask
= MI
->getOperand(opNum
).getImm();
89 assert((Mask
& 0xFFFF) == Mask
&& "Mask is always 16 bits");
91 // A move mask is splitted into two parts:
92 // bits 0 ~ 7 correspond to D0 ~ D7 regs
93 // bits 8 ~ 15 correspond to A0 ~ A7 regs
95 // In the assembly syntax, we want to use a dash to replace
96 // a continuous range of registers. For example, if the bit
97 // mask is 0b101110, we want to print "D1-D3,D5" instead of
100 // However, we don't want a dash to cross between data registers
101 // and address registers (i.e. there shouldn't be a dash crossing
102 // bit 7 and 8) since that is not really intuitive. So we simply
103 // print the data register part (bit 0~7) and address register part
107 for (int s
= 0; s
< 16; s
+= 8) {
108 HalfMask
= (Mask
>> s
) & 0xFF;
109 // Print separation comma only if
110 // both data & register parts have bit(s) set
111 if (s
!= 0 && (Mask
& 0xFF) && HalfMask
)
114 for (int i
= 0; HalfMask
; ++i
) {
115 if ((HalfMask
>> i
) & 0b1) {
116 HalfMask
^= 0b1 << i
;
117 Reg
= M68kII::getMaskedSpillRegister(i
+ s
);
118 printRegName(O
, Reg
);
121 while ((HalfMask
>> (j
+ 1)) & 0b1)
122 HalfMask
^= 0b1 << ++j
;
126 Reg
= M68kII::getMaskedSpillRegister(j
+ s
);
127 printRegName(O
, Reg
);
139 void M68kInstPrinter::printDisp(const MCInst
*MI
, unsigned opNum
,
141 const MCOperand
&Op
= MI
->getOperand(opNum
);
146 assert(Op
.isExpr() && "Unknown operand kind in printOperand");
147 Op
.getExpr()->print(O
, &MAI
);
150 void M68kInstPrinter::printARIMem(const MCInst
*MI
, unsigned opNum
,
153 printOperand(MI
, opNum
, O
);
157 void M68kInstPrinter::printARIPIMem(const MCInst
*MI
, unsigned opNum
,
160 printOperand(MI
, opNum
, O
);
164 void M68kInstPrinter::printARIPDMem(const MCInst
*MI
, unsigned opNum
,
167 printOperand(MI
, opNum
, O
);
171 void M68kInstPrinter::printARIDMem(const MCInst
*MI
, unsigned opNum
,
174 printDisp(MI
, opNum
+ M68k::MemDisp
, O
);
176 printOperand(MI
, opNum
+ M68k::MemBase
, O
);
180 void M68kInstPrinter::printARIIMem(const MCInst
*MI
, unsigned opNum
,
183 printDisp(MI
, opNum
+ M68k::MemDisp
, O
);
185 printOperand(MI
, opNum
+ M68k::MemBase
, O
);
187 printOperand(MI
, opNum
+ M68k::MemIndex
, O
);
191 // NOTE forcing (W,L) size available since M68020 only
192 void M68kInstPrinter::printAbsMem(const MCInst
*MI
, unsigned opNum
,
194 const MCOperand
&MO
= MI
->getOperand(opNum
);
197 MO
.getExpr()->print(O
, &MAI
);
201 assert(MO
.isImm() && "absolute memory addressing needs an immediate");
202 O
<< format("$%0" PRIx64
, (uint64_t)MO
.getImm());
205 void M68kInstPrinter::printPCDMem(const MCInst
*MI
, uint64_t Address
,
206 unsigned opNum
, raw_ostream
&O
) {
208 printDisp(MI
, opNum
+ M68k::PCRelDisp
, O
);
212 void M68kInstPrinter::printPCIMem(const MCInst
*MI
, uint64_t Address
,
213 unsigned opNum
, raw_ostream
&O
) {
215 printDisp(MI
, opNum
+ M68k::PCRelDisp
, O
);
217 printOperand(MI
, opNum
+ M68k::PCRelIndex
, O
);