104eeddc0SDimitry Andric //===-- M68kAsmPrinter.cpp - M68k LLVM Assembly Printer ---------*- 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 a printer that converts from our internal representation
11fe6060f1SDimitry Andric /// of machine-dependent LLVM code to GAS-format M68k assembly language.
12fe6060f1SDimitry Andric ///
13fe6060f1SDimitry Andric //===----------------------------------------------------------------------===//
14fe6060f1SDimitry Andric
15fe6060f1SDimitry Andric // TODO Conform to Motorola ASM syntax
16fe6060f1SDimitry Andric
17fe6060f1SDimitry Andric #include "M68kAsmPrinter.h"
18fe6060f1SDimitry Andric
19fe6060f1SDimitry Andric #include "M68k.h"
20fe6060f1SDimitry Andric #include "M68kMachineFunction.h"
21fe6060f1SDimitry Andric #include "MCTargetDesc/M68kInstPrinter.h"
22fe6060f1SDimitry Andric #include "TargetInfo/M68kTargetInfo.h"
23fe6060f1SDimitry Andric
24349cc55cSDimitry Andric #include "llvm/MC/TargetRegistry.h"
25fe6060f1SDimitry Andric
26fe6060f1SDimitry Andric using namespace llvm;
27fe6060f1SDimitry Andric
28fe6060f1SDimitry Andric #define DEBUG_TYPE "m68k-asm-printer"
29fe6060f1SDimitry Andric
runOnMachineFunction(MachineFunction & MF)30fe6060f1SDimitry Andric bool M68kAsmPrinter::runOnMachineFunction(MachineFunction &MF) {
31fe6060f1SDimitry Andric MMFI = MF.getInfo<M68kMachineFunctionInfo>();
32fe6060f1SDimitry Andric MCInstLowering = std::make_unique<M68kMCInstLower>(MF, *this);
33fe6060f1SDimitry Andric AsmPrinter::runOnMachineFunction(MF);
34fe6060f1SDimitry Andric return true;
35fe6060f1SDimitry Andric }
36fe6060f1SDimitry Andric
printOperand(const MachineInstr * MI,int OpNum,raw_ostream & OS)37fe6060f1SDimitry Andric void M68kAsmPrinter::printOperand(const MachineInstr *MI, int OpNum,
38fe6060f1SDimitry Andric raw_ostream &OS) {
39fe6060f1SDimitry Andric const MachineOperand &MO = MI->getOperand(OpNum);
40fe6060f1SDimitry Andric switch (MO.getType()) {
41fe6060f1SDimitry Andric case MachineOperand::MO_Register:
42fe6060f1SDimitry Andric OS << "%" << M68kInstPrinter::getRegisterName(MO.getReg());
43fe6060f1SDimitry Andric break;
44fe6060f1SDimitry Andric case MachineOperand::MO_Immediate:
45fe6060f1SDimitry Andric OS << '#' << MO.getImm();
46fe6060f1SDimitry Andric break;
47fe6060f1SDimitry Andric case MachineOperand::MO_MachineBasicBlock:
48fe6060f1SDimitry Andric MO.getMBB()->getSymbol()->print(OS, MAI);
49fe6060f1SDimitry Andric break;
50fe6060f1SDimitry Andric case MachineOperand::MO_GlobalAddress:
51fe6060f1SDimitry Andric PrintSymbolOperand(MO, OS);
52fe6060f1SDimitry Andric break;
53fe6060f1SDimitry Andric case MachineOperand::MO_BlockAddress:
54fe6060f1SDimitry Andric GetBlockAddressSymbol(MO.getBlockAddress())->print(OS, MAI);
55fe6060f1SDimitry Andric break;
56fe6060f1SDimitry Andric case MachineOperand::MO_ConstantPoolIndex: {
57fe6060f1SDimitry Andric const DataLayout &DL = getDataLayout();
58fe6060f1SDimitry Andric OS << DL.getPrivateGlobalPrefix() << "CPI" << getFunctionNumber() << '_'
59fe6060f1SDimitry Andric << MO.getIndex();
60fe6060f1SDimitry Andric break;
61fe6060f1SDimitry Andric }
62fe6060f1SDimitry Andric default:
63fe6060f1SDimitry Andric llvm_unreachable("not implemented");
64fe6060f1SDimitry Andric }
65fe6060f1SDimitry Andric }
66fe6060f1SDimitry Andric
PrintAsmOperand(const MachineInstr * MI,unsigned OpNo,const char * ExtraCode,raw_ostream & OS)67fe6060f1SDimitry Andric bool M68kAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
68fe6060f1SDimitry Andric const char *ExtraCode, raw_ostream &OS) {
69fe6060f1SDimitry Andric // Print the operand if there is no operand modifier.
70fe6060f1SDimitry Andric if (!ExtraCode || !ExtraCode[0]) {
71fe6060f1SDimitry Andric printOperand(MI, OpNo, OS);
72fe6060f1SDimitry Andric return false;
73fe6060f1SDimitry Andric }
74fe6060f1SDimitry Andric
75fe6060f1SDimitry Andric // Fallback to the default implementation.
76fe6060f1SDimitry Andric return AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, OS);
77fe6060f1SDimitry Andric }
78fe6060f1SDimitry Andric
printDisp(const MachineInstr * MI,unsigned opNum,raw_ostream & O)79*06c3fb27SDimitry Andric void M68kAsmPrinter::printDisp(const MachineInstr *MI, unsigned opNum,
80*06c3fb27SDimitry Andric raw_ostream &O) {
81*06c3fb27SDimitry Andric // Print immediate displacement without the '#' predix
82*06c3fb27SDimitry Andric const MachineOperand &Op = MI->getOperand(opNum);
83*06c3fb27SDimitry Andric if (Op.isImm()) {
84*06c3fb27SDimitry Andric O << Op.getImm();
85*06c3fb27SDimitry Andric return;
86*06c3fb27SDimitry Andric }
87*06c3fb27SDimitry Andric // Displacement is relocatable, so we're pretty permissive about what
88*06c3fb27SDimitry Andric // can be put here.
89*06c3fb27SDimitry Andric printOperand(MI, opNum, O);
90*06c3fb27SDimitry Andric }
91*06c3fb27SDimitry Andric
printAbsMem(const MachineInstr * MI,unsigned OpNum,raw_ostream & O)92*06c3fb27SDimitry Andric void M68kAsmPrinter::printAbsMem(const MachineInstr *MI, unsigned OpNum,
93*06c3fb27SDimitry Andric raw_ostream &O) {
94*06c3fb27SDimitry Andric const MachineOperand &MO = MI->getOperand(OpNum);
95*06c3fb27SDimitry Andric if (MO.isImm())
96*06c3fb27SDimitry Andric O << format("$%0" PRIx64, (uint64_t)MO.getImm());
97*06c3fb27SDimitry Andric else
98*06c3fb27SDimitry Andric PrintAsmMemoryOperand(MI, OpNum, nullptr, O);
99*06c3fb27SDimitry Andric }
100*06c3fb27SDimitry Andric
PrintAsmMemoryOperand(const MachineInstr * MI,unsigned OpNo,const char * ExtraCode,raw_ostream & OS)101*06c3fb27SDimitry Andric bool M68kAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
102*06c3fb27SDimitry Andric unsigned OpNo, const char *ExtraCode,
103*06c3fb27SDimitry Andric raw_ostream &OS) {
104*06c3fb27SDimitry Andric const MachineOperand &MO = MI->getOperand(OpNo);
105*06c3fb27SDimitry Andric switch (MO.getType()) {
106*06c3fb27SDimitry Andric case MachineOperand::MO_Immediate:
107*06c3fb27SDimitry Andric // Immediate value that goes here is the addressing mode kind we set
108*06c3fb27SDimitry Andric // in M68kDAGToDAGISel::SelectInlineAsmMemoryOperand.
109*06c3fb27SDimitry Andric using namespace M68k;
110*06c3fb27SDimitry Andric // Skip the addressing mode kind operand.
111*06c3fb27SDimitry Andric ++OpNo;
112*06c3fb27SDimitry Andric // Decode MemAddrModeKind.
113*06c3fb27SDimitry Andric switch (static_cast<MemAddrModeKind>(MO.getImm())) {
114*06c3fb27SDimitry Andric case MemAddrModeKind::j:
115*06c3fb27SDimitry Andric printARIMem(MI, OpNo, OS);
116*06c3fb27SDimitry Andric break;
117*06c3fb27SDimitry Andric case MemAddrModeKind::o:
118*06c3fb27SDimitry Andric printARIPIMem(MI, OpNo, OS);
119*06c3fb27SDimitry Andric break;
120*06c3fb27SDimitry Andric case MemAddrModeKind::e:
121*06c3fb27SDimitry Andric printARIPDMem(MI, OpNo, OS);
122*06c3fb27SDimitry Andric break;
123*06c3fb27SDimitry Andric case MemAddrModeKind::p:
124*06c3fb27SDimitry Andric printARIDMem(MI, OpNo, OS);
125*06c3fb27SDimitry Andric break;
126*06c3fb27SDimitry Andric case MemAddrModeKind::f:
127*06c3fb27SDimitry Andric case MemAddrModeKind::F:
128*06c3fb27SDimitry Andric printARIIMem(MI, OpNo, OS);
129*06c3fb27SDimitry Andric break;
130*06c3fb27SDimitry Andric case MemAddrModeKind::k:
131*06c3fb27SDimitry Andric printPCIMem(MI, 0, OpNo, OS);
132*06c3fb27SDimitry Andric break;
133*06c3fb27SDimitry Andric case MemAddrModeKind::q:
134*06c3fb27SDimitry Andric printPCDMem(MI, 0, OpNo, OS);
135*06c3fb27SDimitry Andric break;
136*06c3fb27SDimitry Andric case MemAddrModeKind::b:
137*06c3fb27SDimitry Andric printAbsMem(MI, OpNo, OS);
138*06c3fb27SDimitry Andric break;
139*06c3fb27SDimitry Andric default:
140*06c3fb27SDimitry Andric llvm_unreachable("Unrecognized memory addressing mode");
141*06c3fb27SDimitry Andric }
142*06c3fb27SDimitry Andric return false;
143*06c3fb27SDimitry Andric case MachineOperand::MO_GlobalAddress:
144*06c3fb27SDimitry Andric PrintSymbolOperand(MO, OS);
145*06c3fb27SDimitry Andric return false;
146*06c3fb27SDimitry Andric case MachineOperand::MO_BlockAddress:
147*06c3fb27SDimitry Andric GetBlockAddressSymbol(MO.getBlockAddress())->print(OS, MAI);
148*06c3fb27SDimitry Andric return false;
149*06c3fb27SDimitry Andric case MachineOperand::MO_Register:
150*06c3fb27SDimitry Andric // This is a special case where it is treated as a memory reference, with
151*06c3fb27SDimitry Andric // the register holding the address value. Thus, we print it as ARI here.
152*06c3fb27SDimitry Andric if (M68kII::isAddressRegister(MO.getReg())) {
153*06c3fb27SDimitry Andric printARIMem(MI, OpNo, OS);
154*06c3fb27SDimitry Andric return false;
155*06c3fb27SDimitry Andric }
156*06c3fb27SDimitry Andric break;
157*06c3fb27SDimitry Andric default:
158*06c3fb27SDimitry Andric break;
159*06c3fb27SDimitry Andric }
160*06c3fb27SDimitry Andric return AsmPrinter::PrintAsmMemoryOperand(MI, OpNo, ExtraCode, OS);
161*06c3fb27SDimitry Andric }
162*06c3fb27SDimitry Andric
emitInstruction(const MachineInstr * MI)163fe6060f1SDimitry Andric void M68kAsmPrinter::emitInstruction(const MachineInstr *MI) {
164753f127fSDimitry Andric M68k_MC::verifyInstructionPredicates(MI->getOpcode(),
165753f127fSDimitry Andric getSubtargetInfo().getFeatureBits());
166753f127fSDimitry Andric
167fe6060f1SDimitry Andric switch (MI->getOpcode()) {
168fe6060f1SDimitry Andric default: {
169fe6060f1SDimitry Andric if (MI->isPseudo()) {
170fe6060f1SDimitry Andric LLVM_DEBUG(dbgs() << "Pseudo opcode(" << MI->getOpcode()
171fe6060f1SDimitry Andric << ") found in EmitInstruction()\n");
172fe6060f1SDimitry Andric llvm_unreachable("Cannot proceed");
173fe6060f1SDimitry Andric }
174fe6060f1SDimitry Andric break;
175fe6060f1SDimitry Andric }
176fe6060f1SDimitry Andric case M68k::TAILJMPj:
177fe6060f1SDimitry Andric case M68k::TAILJMPq:
178fe6060f1SDimitry Andric // Lower these as normal, but add some comments.
179fe6060f1SDimitry Andric OutStreamer->AddComment("TAILCALL");
180fe6060f1SDimitry Andric break;
181fe6060f1SDimitry Andric }
182fe6060f1SDimitry Andric
183fe6060f1SDimitry Andric MCInst TmpInst0;
184fe6060f1SDimitry Andric MCInstLowering->Lower(MI, TmpInst0);
185fe6060f1SDimitry Andric OutStreamer->emitInstruction(TmpInst0, getSubtargetInfo());
186fe6060f1SDimitry Andric }
187fe6060f1SDimitry Andric
emitFunctionBodyStart()188fe6060f1SDimitry Andric void M68kAsmPrinter::emitFunctionBodyStart() {}
189fe6060f1SDimitry Andric
emitFunctionBodyEnd()190fe6060f1SDimitry Andric void M68kAsmPrinter::emitFunctionBodyEnd() {}
191fe6060f1SDimitry Andric
emitStartOfAsmFile(Module & M)192fe6060f1SDimitry Andric void M68kAsmPrinter::emitStartOfAsmFile(Module &M) {
193fe6060f1SDimitry Andric OutStreamer->emitSyntaxDirective();
194fe6060f1SDimitry Andric }
195fe6060f1SDimitry Andric
emitEndOfAsmFile(Module & M)196fe6060f1SDimitry Andric void M68kAsmPrinter::emitEndOfAsmFile(Module &M) {}
197fe6060f1SDimitry Andric
LLVMInitializeM68kAsmPrinter()198fe6060f1SDimitry Andric extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeM68kAsmPrinter() {
199fe6060f1SDimitry Andric RegisterAsmPrinter<M68kAsmPrinter> X(getTheM68kTarget());
200fe6060f1SDimitry Andric }
201