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