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