1*82d56013Sjoerg //===-- M68kInstPrinter.cpp - Convert M68k MCInst to asm ----*- C++ -*-===//
2*82d56013Sjoerg //
3*82d56013Sjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*82d56013Sjoerg // See https://llvm.org/LICENSE.txt for license information.
5*82d56013Sjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*82d56013Sjoerg //
7*82d56013Sjoerg //===----------------------------------------------------------------------===//
8*82d56013Sjoerg ///
9*82d56013Sjoerg /// \file
10*82d56013Sjoerg /// This file contains definitions for an M68k MCInst printer.
11*82d56013Sjoerg ///
12*82d56013Sjoerg //===----------------------------------------------------------------------===//
13*82d56013Sjoerg
14*82d56013Sjoerg // TODO Conform with all supported Motorola ASM syntax
15*82d56013Sjoerg // Motorola's assembly has several syntax variants, especially on
16*82d56013Sjoerg // addressing modes.
17*82d56013Sjoerg // For example, you can write pc indirect w/ displacement as
18*82d56013Sjoerg // `x(%pc)`, where `x` is the displacement imm, or `(x,%pc)`.
19*82d56013Sjoerg // Currently we're picking the variant that is different from
20*82d56013Sjoerg // GCC, albeit being recognizable by GNU AS.
21*82d56013Sjoerg // Not sure what is the impact now (e.g. some syntax might
22*82d56013Sjoerg // not be recognized by some old consoles' toolchains, in which
23*82d56013Sjoerg // case we can not use our integrated assembler), but either way,
24*82d56013Sjoerg // it will be great to support all of the variants in the future.
25*82d56013Sjoerg
26*82d56013Sjoerg #include "M68kInstPrinter.h"
27*82d56013Sjoerg #include "M68kBaseInfo.h"
28*82d56013Sjoerg
29*82d56013Sjoerg #include "llvm/ADT/StringExtras.h"
30*82d56013Sjoerg #include "llvm/MC/MCExpr.h"
31*82d56013Sjoerg #include "llvm/MC/MCInst.h"
32*82d56013Sjoerg #include "llvm/MC/MCInstrInfo.h"
33*82d56013Sjoerg #include "llvm/MC/MCSymbol.h"
34*82d56013Sjoerg #include "llvm/Support/ErrorHandling.h"
35*82d56013Sjoerg #include "llvm/Support/raw_ostream.h"
36*82d56013Sjoerg
37*82d56013Sjoerg using namespace llvm;
38*82d56013Sjoerg
39*82d56013Sjoerg #define DEBUG_TYPE "asm-printer"
40*82d56013Sjoerg
41*82d56013Sjoerg #define PRINT_ALIAS_INSTR
42*82d56013Sjoerg #include "M68kGenAsmWriter.inc"
43*82d56013Sjoerg
printRegName(raw_ostream & OS,unsigned RegNo) const44*82d56013Sjoerg void M68kInstPrinter::printRegName(raw_ostream &OS, unsigned RegNo) const {
45*82d56013Sjoerg OS << "%" << getRegisterName(RegNo);
46*82d56013Sjoerg }
47*82d56013Sjoerg
printInst(const MCInst * MI,uint64_t Address,StringRef Annot,const MCSubtargetInfo & STI,raw_ostream & O)48*82d56013Sjoerg void M68kInstPrinter::printInst(const MCInst *MI, uint64_t Address,
49*82d56013Sjoerg StringRef Annot, const MCSubtargetInfo &STI,
50*82d56013Sjoerg raw_ostream &O) {
51*82d56013Sjoerg if (!printAliasInstr(MI, Address, O))
52*82d56013Sjoerg printInstruction(MI, Address, O);
53*82d56013Sjoerg
54*82d56013Sjoerg printAnnotation(O, Annot);
55*82d56013Sjoerg }
56*82d56013Sjoerg
printOperand(const MCInst * MI,unsigned OpNo,raw_ostream & O)57*82d56013Sjoerg void M68kInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
58*82d56013Sjoerg raw_ostream &O) {
59*82d56013Sjoerg const MCOperand &MO = MI->getOperand(OpNo);
60*82d56013Sjoerg if (MO.isReg()) {
61*82d56013Sjoerg printRegName(O, MO.getReg());
62*82d56013Sjoerg return;
63*82d56013Sjoerg }
64*82d56013Sjoerg
65*82d56013Sjoerg if (MO.isImm()) {
66*82d56013Sjoerg printImmediate(MI, OpNo, O);
67*82d56013Sjoerg return;
68*82d56013Sjoerg }
69*82d56013Sjoerg
70*82d56013Sjoerg assert(MO.isExpr() && "Unknown operand kind in printOperand");
71*82d56013Sjoerg MO.getExpr()->print(O, &MAI);
72*82d56013Sjoerg }
73*82d56013Sjoerg
printImmediate(const MCInst * MI,unsigned opNum,raw_ostream & O)74*82d56013Sjoerg void M68kInstPrinter::printImmediate(const MCInst *MI, unsigned opNum,
75*82d56013Sjoerg raw_ostream &O) {
76*82d56013Sjoerg const MCOperand &MO = MI->getOperand(opNum);
77*82d56013Sjoerg if (MO.isImm())
78*82d56013Sjoerg O << '#' << MO.getImm();
79*82d56013Sjoerg else if (MO.isExpr()) {
80*82d56013Sjoerg O << '#';
81*82d56013Sjoerg MO.getExpr()->print(O, &MAI);
82*82d56013Sjoerg } else
83*82d56013Sjoerg llvm_unreachable("Unknown immediate kind");
84*82d56013Sjoerg }
85*82d56013Sjoerg
printMoveMask(const MCInst * MI,unsigned opNum,raw_ostream & O)86*82d56013Sjoerg void M68kInstPrinter::printMoveMask(const MCInst *MI, unsigned opNum,
87*82d56013Sjoerg raw_ostream &O) {
88*82d56013Sjoerg unsigned Mask = MI->getOperand(opNum).getImm();
89*82d56013Sjoerg assert((Mask & 0xFFFF) == Mask && "Mask is always 16 bits");
90*82d56013Sjoerg
91*82d56013Sjoerg // A move mask is splitted into two parts:
92*82d56013Sjoerg // bits 0 ~ 7 correspond to D0 ~ D7 regs
93*82d56013Sjoerg // bits 8 ~ 15 correspond to A0 ~ A7 regs
94*82d56013Sjoerg //
95*82d56013Sjoerg // In the assembly syntax, we want to use a dash to replace
96*82d56013Sjoerg // a continuous range of registers. For example, if the bit
97*82d56013Sjoerg // mask is 0b101110, we want to print "D1-D3,D5" instead of
98*82d56013Sjoerg // "D1,D2,D3,D4,D5".
99*82d56013Sjoerg //
100*82d56013Sjoerg // However, we don't want a dash to cross between data registers
101*82d56013Sjoerg // and address registers (i.e. there shouldn't be a dash crossing
102*82d56013Sjoerg // bit 7 and 8) since that is not really intuitive. So we simply
103*82d56013Sjoerg // print the data register part (bit 0~7) and address register part
104*82d56013Sjoerg // separately.
105*82d56013Sjoerg uint8_t HalfMask;
106*82d56013Sjoerg unsigned Reg;
107*82d56013Sjoerg for (int s = 0; s < 16; s += 8) {
108*82d56013Sjoerg HalfMask = (Mask >> s) & 0xFF;
109*82d56013Sjoerg // Print separation comma only if
110*82d56013Sjoerg // both data & register parts have bit(s) set
111*82d56013Sjoerg if (s != 0 && (Mask & 0xFF) && HalfMask)
112*82d56013Sjoerg O << ',';
113*82d56013Sjoerg
114*82d56013Sjoerg for (int i = 0; HalfMask; ++i) {
115*82d56013Sjoerg if ((HalfMask >> i) & 0b1) {
116*82d56013Sjoerg HalfMask ^= 0b1 << i;
117*82d56013Sjoerg Reg = M68kII::getMaskedSpillRegister(i + s);
118*82d56013Sjoerg printRegName(O, Reg);
119*82d56013Sjoerg
120*82d56013Sjoerg int j = i;
121*82d56013Sjoerg while ((HalfMask >> (j + 1)) & 0b1)
122*82d56013Sjoerg HalfMask ^= 0b1 << ++j;
123*82d56013Sjoerg
124*82d56013Sjoerg if (j != i) {
125*82d56013Sjoerg O << '-';
126*82d56013Sjoerg Reg = M68kII::getMaskedSpillRegister(j + s);
127*82d56013Sjoerg printRegName(O, Reg);
128*82d56013Sjoerg }
129*82d56013Sjoerg
130*82d56013Sjoerg i = j;
131*82d56013Sjoerg
132*82d56013Sjoerg if (HalfMask)
133*82d56013Sjoerg O << ',';
134*82d56013Sjoerg }
135*82d56013Sjoerg }
136*82d56013Sjoerg }
137*82d56013Sjoerg }
138*82d56013Sjoerg
printDisp(const MCInst * MI,unsigned opNum,raw_ostream & O)139*82d56013Sjoerg void M68kInstPrinter::printDisp(const MCInst *MI, unsigned opNum,
140*82d56013Sjoerg raw_ostream &O) {
141*82d56013Sjoerg const MCOperand &Op = MI->getOperand(opNum);
142*82d56013Sjoerg if (Op.isImm()) {
143*82d56013Sjoerg O << Op.getImm();
144*82d56013Sjoerg return;
145*82d56013Sjoerg }
146*82d56013Sjoerg assert(Op.isExpr() && "Unknown operand kind in printOperand");
147*82d56013Sjoerg Op.getExpr()->print(O, &MAI);
148*82d56013Sjoerg }
149*82d56013Sjoerg
printARIMem(const MCInst * MI,unsigned opNum,raw_ostream & O)150*82d56013Sjoerg void M68kInstPrinter::printARIMem(const MCInst *MI, unsigned opNum,
151*82d56013Sjoerg raw_ostream &O) {
152*82d56013Sjoerg O << '(';
153*82d56013Sjoerg printOperand(MI, opNum, O);
154*82d56013Sjoerg O << ')';
155*82d56013Sjoerg }
156*82d56013Sjoerg
printARIPIMem(const MCInst * MI,unsigned opNum,raw_ostream & O)157*82d56013Sjoerg void M68kInstPrinter::printARIPIMem(const MCInst *MI, unsigned opNum,
158*82d56013Sjoerg raw_ostream &O) {
159*82d56013Sjoerg O << "(";
160*82d56013Sjoerg printOperand(MI, opNum, O);
161*82d56013Sjoerg O << ")+";
162*82d56013Sjoerg }
163*82d56013Sjoerg
printARIPDMem(const MCInst * MI,unsigned opNum,raw_ostream & O)164*82d56013Sjoerg void M68kInstPrinter::printARIPDMem(const MCInst *MI, unsigned opNum,
165*82d56013Sjoerg raw_ostream &O) {
166*82d56013Sjoerg O << "-(";
167*82d56013Sjoerg printOperand(MI, opNum, O);
168*82d56013Sjoerg O << ")";
169*82d56013Sjoerg }
170*82d56013Sjoerg
printARIDMem(const MCInst * MI,unsigned opNum,raw_ostream & O)171*82d56013Sjoerg void M68kInstPrinter::printARIDMem(const MCInst *MI, unsigned opNum,
172*82d56013Sjoerg raw_ostream &O) {
173*82d56013Sjoerg O << '(';
174*82d56013Sjoerg printDisp(MI, opNum + M68k::MemDisp, O);
175*82d56013Sjoerg O << ',';
176*82d56013Sjoerg printOperand(MI, opNum + M68k::MemBase, O);
177*82d56013Sjoerg O << ')';
178*82d56013Sjoerg }
179*82d56013Sjoerg
printARIIMem(const MCInst * MI,unsigned opNum,raw_ostream & O)180*82d56013Sjoerg void M68kInstPrinter::printARIIMem(const MCInst *MI, unsigned opNum,
181*82d56013Sjoerg raw_ostream &O) {
182*82d56013Sjoerg O << '(';
183*82d56013Sjoerg printDisp(MI, opNum + M68k::MemDisp, O);
184*82d56013Sjoerg O << ',';
185*82d56013Sjoerg printOperand(MI, opNum + M68k::MemBase, O);
186*82d56013Sjoerg O << ',';
187*82d56013Sjoerg printOperand(MI, opNum + M68k::MemIndex, O);
188*82d56013Sjoerg O << ')';
189*82d56013Sjoerg }
190*82d56013Sjoerg
191*82d56013Sjoerg // NOTE forcing (W,L) size available since M68020 only
printAbsMem(const MCInst * MI,unsigned opNum,raw_ostream & O)192*82d56013Sjoerg void M68kInstPrinter::printAbsMem(const MCInst *MI, unsigned opNum,
193*82d56013Sjoerg raw_ostream &O) {
194*82d56013Sjoerg const MCOperand &MO = MI->getOperand(opNum);
195*82d56013Sjoerg
196*82d56013Sjoerg if (MO.isExpr()) {
197*82d56013Sjoerg MO.getExpr()->print(O, &MAI);
198*82d56013Sjoerg return;
199*82d56013Sjoerg }
200*82d56013Sjoerg
201*82d56013Sjoerg assert(MO.isImm() && "absolute memory addressing needs an immediate");
202*82d56013Sjoerg O << format("$%0" PRIx64, (uint64_t)MO.getImm());
203*82d56013Sjoerg }
204*82d56013Sjoerg
printPCDMem(const MCInst * MI,uint64_t Address,unsigned opNum,raw_ostream & O)205*82d56013Sjoerg void M68kInstPrinter::printPCDMem(const MCInst *MI, uint64_t Address,
206*82d56013Sjoerg unsigned opNum, raw_ostream &O) {
207*82d56013Sjoerg O << '(';
208*82d56013Sjoerg printDisp(MI, opNum + M68k::PCRelDisp, O);
209*82d56013Sjoerg O << ",%pc)";
210*82d56013Sjoerg }
211*82d56013Sjoerg
printPCIMem(const MCInst * MI,uint64_t Address,unsigned opNum,raw_ostream & O)212*82d56013Sjoerg void M68kInstPrinter::printPCIMem(const MCInst *MI, uint64_t Address,
213*82d56013Sjoerg unsigned opNum, raw_ostream &O) {
214*82d56013Sjoerg O << '(';
215*82d56013Sjoerg printDisp(MI, opNum + M68k::PCRelDisp, O);
216*82d56013Sjoerg O << ",%pc,";
217*82d56013Sjoerg printOperand(MI, opNum + M68k::PCRelIndex, O);
218*82d56013Sjoerg O << ')';
219*82d56013Sjoerg }
220