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