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, unsigned RegNo) const { 45 OS << "%" << getRegisterName(RegNo); 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 void M68kInstPrinter::printARIMem(const MCInst *MI, unsigned opNum, 151 raw_ostream &O) { 152 O << '('; 153 printOperand(MI, opNum, O); 154 O << ')'; 155 } 156 157 void M68kInstPrinter::printARIPIMem(const MCInst *MI, unsigned opNum, 158 raw_ostream &O) { 159 O << "("; 160 printOperand(MI, opNum, O); 161 O << ")+"; 162 } 163 164 void M68kInstPrinter::printARIPDMem(const MCInst *MI, unsigned opNum, 165 raw_ostream &O) { 166 O << "-("; 167 printOperand(MI, opNum, O); 168 O << ")"; 169 } 170 171 void M68kInstPrinter::printARIDMem(const MCInst *MI, unsigned opNum, 172 raw_ostream &O) { 173 O << '('; 174 printDisp(MI, opNum + M68k::MemDisp, O); 175 O << ','; 176 printOperand(MI, opNum + M68k::MemBase, O); 177 O << ')'; 178 } 179 180 void M68kInstPrinter::printARIIMem(const MCInst *MI, unsigned opNum, 181 raw_ostream &O) { 182 O << '('; 183 printDisp(MI, opNum + M68k::MemDisp, O); 184 O << ','; 185 printOperand(MI, opNum + M68k::MemBase, O); 186 O << ','; 187 printOperand(MI, opNum + M68k::MemIndex, O); 188 O << ')'; 189 } 190 191 // NOTE forcing (W,L) size available since M68020 only 192 void M68kInstPrinter::printAbsMem(const MCInst *MI, unsigned opNum, 193 raw_ostream &O) { 194 const MCOperand &MO = MI->getOperand(opNum); 195 196 if (MO.isExpr()) { 197 MO.getExpr()->print(O, &MAI); 198 return; 199 } 200 201 assert(MO.isImm() && "absolute memory addressing needs an immediate"); 202 O << format("$%0" PRIx64, (uint64_t)MO.getImm()); 203 } 204 205 void M68kInstPrinter::printPCDMem(const MCInst *MI, uint64_t Address, 206 unsigned opNum, raw_ostream &O) { 207 O << '('; 208 printDisp(MI, opNum + M68k::PCRelDisp, O); 209 O << ",%pc)"; 210 } 211 212 void M68kInstPrinter::printPCIMem(const MCInst *MI, uint64_t Address, 213 unsigned opNum, raw_ostream &O) { 214 O << '('; 215 printDisp(MI, opNum + M68k::PCRelDisp, O); 216 O << ",%pc,"; 217 printOperand(MI, opNum + M68k::PCRelIndex, O); 218 O << ')'; 219 } 220