1 //===-- M68kInstPrinter.cpp - Convert M68k MCInst to asm --------*- C++ -*-===//
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 /// \file
10 /// This file contains definitions for an M68k MCInst printer.
11 ///
12 //===----------------------------------------------------------------------===//
13 
14 // TODO Conform with all supported Motorola ASM syntax
15 // Motorola's assembly has several syntax variants, especially on
16 // addressing modes.
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.
25 
26 #include "M68kInstPrinter.h"
27 #include "M68kBaseInfo.h"
28 
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"
36 
37 using namespace llvm;
38 
39 #define DEBUG_TYPE "asm-printer"
40 
41 #define PRINT_ALIAS_INSTR
42 #include "M68kGenAsmWriter.inc"
43 
44 void M68kInstPrinter::printRegName(raw_ostream &OS, MCRegister Reg) const {
45   OS << "%" << getRegisterName(Reg);
46 }
47 
48 void M68kInstPrinter::printInst(const MCInst *MI, uint64_t Address,
49                                 StringRef Annot, const MCSubtargetInfo &STI,
50                                 raw_ostream &O) {
51   if (!printAliasInstr(MI, Address, O))
52     printInstruction(MI, Address, O);
53 
54   printAnnotation(O, Annot);
55 }
56 
57 void M68kInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
58                                    raw_ostream &O) {
59   const MCOperand &MO = MI->getOperand(OpNo);
60   if (MO.isReg()) {
61     printRegName(O, MO.getReg());
62     return;
63   }
64 
65   if (MO.isImm()) {
66     printImmediate(MI, OpNo, O);
67     return;
68   }
69 
70   assert(MO.isExpr() && "Unknown operand kind in printOperand");
71   MO.getExpr()->print(O, &MAI);
72 }
73 
74 void M68kInstPrinter::printImmediate(const MCInst *MI, unsigned opNum,
75                                      raw_ostream &O) {
76   const MCOperand &MO = MI->getOperand(opNum);
77   if (MO.isImm())
78     O << '#' << MO.getImm();
79   else if (MO.isExpr()) {
80     O << '#';
81     MO.getExpr()->print(O, &MAI);
82   } else
83     llvm_unreachable("Unknown immediate kind");
84 }
85 
86 void M68kInstPrinter::printMoveMask(const MCInst *MI, unsigned opNum,
87                                     raw_ostream &O) {
88   unsigned Mask = MI->getOperand(opNum).getImm();
89   assert((Mask & 0xFFFF) == Mask && "Mask is always 16 bits");
90 
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
94   //
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
98   // "D1,D2,D3,D4,D5".
99   //
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
104   // separately.
105   uint8_t HalfMask;
106   unsigned Reg;
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)
112       O << '/';
113 
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);
119 
120         int j = i;
121         while ((HalfMask >> (j + 1)) & 0b1)
122           HalfMask ^= 0b1 << ++j;
123 
124         if (j != i) {
125           O << '-';
126           Reg = M68kII::getMaskedSpillRegister(j + s);
127           printRegName(O, Reg);
128         }
129 
130         i = j;
131 
132         if (HalfMask)
133           O << '/';
134       }
135     }
136   }
137 }
138 
139 void M68kInstPrinter::printDisp(const MCInst *MI, unsigned opNum,
140                                 raw_ostream &O) {
141   const MCOperand &Op = MI->getOperand(opNum);
142   if (Op.isImm()) {
143     O << Op.getImm();
144     return;
145   }
146   assert(Op.isExpr() && "Unknown operand kind in printOperand");
147   Op.getExpr()->print(O, &MAI);
148 }
149 
150 // NOTE forcing (W,L) size available since M68020 only
151 void M68kInstPrinter::printAbsMem(const MCInst *MI, unsigned opNum,
152                                   raw_ostream &O) {
153   const MCOperand &MO = MI->getOperand(opNum);
154 
155   if (MO.isExpr()) {
156     MO.getExpr()->print(O, &MAI);
157     return;
158   }
159 
160   assert(MO.isImm() && "absolute memory addressing needs an immediate");
161   O << format("$%0" PRIx64, (uint64_t)MO.getImm());
162 }
163