1//===-- MSP430AsmPrinter.cpp - MSP430 LLVM assembly writer ----------------===//
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// This file contains a printer that converts from our internal representation
10// of machine-dependent LLVM code to the MSP430 assembly language.
11//
12//===----------------------------------------------------------------------===//
13
14#include "MSP430AsmPrinter.h"
15#include "MCTargetDesc/MSP430InstPrinter.h"
16#include "MSP430MCInstLower.h"
17#include "MSP430TargetMachine.h"
18#include "TargetInfo/MSP430TargetInfo.h"
19#include "llvm/BinaryFormat/ELF.h"
20#include "llvm/CodeGen/AsmPrinter.h"
21#include "llvm/CodeGen/AsmPrinterAnalysis.h"
22#include "llvm/CodeGen/MachineConstantPool.h"
23#include "llvm/CodeGen/MachineFunctionAnalysisManager.h"
24#include "llvm/CodeGen/MachineInstr.h"
25#include "llvm/CodeGen/MachineModuleInfo.h"
26#include "llvm/CodeGen/MachinePassManager.h"
27#include "llvm/IR/Analysis.h"
28#include "llvm/IR/Mangler.h"
29#include "llvm/IR/PassManager.h"
30#include "llvm/MC/MCAsmInfo.h"
31#include "llvm/MC/MCInst.h"
32#include "llvm/MC/MCSectionELF.h"
33#include "llvm/MC/MCStreamer.h"
34#include "llvm/MC/MCSymbol.h"
35#include "llvm/MC/TargetRegistry.h"
36#include "llvm/Support/Compiler.h"
37#include "llvm/Support/raw_ostream.h"
38using namespace llvm;
39
40#define DEBUG_TYPE "asm-printer"
41
42namespace {
43 class MSP430AsmPrinter : public AsmPrinter {
44 public:
45 MSP430AsmPrinter(TargetMachine &TM, std::unique_ptr<MCStreamer> Streamer)
46 : AsmPrinter(TM, std::move(Streamer), ID) {}
47
48 StringRef getPassName() const override { return "MSP430 Assembly Printer"; }
49
50 bool runOnMachineFunction(MachineFunction &MF) override;
51
52 void PrintSymbolOperand(const MachineOperand &MO, raw_ostream &O) override;
53 void printOperand(const MachineInstr *MI, int OpNum, raw_ostream &O,
54 bool PrefixHash = true);
55 void printSrcMemOperand(const MachineInstr *MI, int OpNum,
56 raw_ostream &O);
57 bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
58 const char *ExtraCode, raw_ostream &O) override;
59 bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
60 const char *ExtraCode, raw_ostream &O) override;
61 void emitInstruction(const MachineInstr *MI) override;
62
63 void EmitInterruptVectorSection(MachineFunction &ISR);
64
65 static char ID;
66 };
67} // end of anonymous namespace
68
69void MSP430AsmPrinter::PrintSymbolOperand(const MachineOperand &MO,
70 raw_ostream &O) {
71 uint64_t Offset = MO.getOffset();
72 if (Offset)
73 O << '(' << Offset << '+';
74
75 getSymbol(GV: MO.getGlobal())->print(OS&: O, MAI);
76
77 if (Offset)
78 O << ')';
79}
80
81void MSP430AsmPrinter::printOperand(const MachineInstr *MI, int OpNum,
82 raw_ostream &O, bool PrefixHash) {
83 const MachineOperand &MO = MI->getOperand(i: OpNum);
84 switch (MO.getType()) {
85 default: llvm_unreachable("Not implemented yet!");
86 case MachineOperand::MO_Register:
87 O << MSP430InstPrinter::getRegisterName(Reg: MO.getReg());
88 return;
89 case MachineOperand::MO_Immediate:
90 if (PrefixHash)
91 O << '#';
92 O << MO.getImm();
93 return;
94 case MachineOperand::MO_MachineBasicBlock:
95 MO.getMBB()->getSymbol()->print(OS&: O, MAI);
96 return;
97 case MachineOperand::MO_GlobalAddress: {
98 // If the global address expression is a part of displacement field with a
99 // register base, we should not emit any prefix symbol here, e.g.
100 // mov.w glb(r1), r2
101 // Otherwise (!) msp430-as will silently miscompile the output :(
102 if (PrefixHash)
103 O << '#';
104 PrintSymbolOperand(MO, O);
105 return;
106 }
107 }
108}
109
110void MSP430AsmPrinter::printSrcMemOperand(const MachineInstr *MI, int OpNum,
111 raw_ostream &O) {
112 const MachineOperand &Base = MI->getOperand(i: OpNum);
113 const MachineOperand &Disp = MI->getOperand(i: OpNum+1);
114
115 // Print displacement first
116
117 // Imm here is in fact global address - print extra modifier.
118 if (Disp.isImm() && Base.getReg() == MSP430::SR)
119 O << '&';
120 printOperand(MI, OpNum: OpNum + 1, O, /*PrefixHash=*/false);
121
122 // Print register base field
123 if (Base.getReg() != MSP430::SR && Base.getReg() != MSP430::PC) {
124 O << '(';
125 printOperand(MI, OpNum, O);
126 O << ')';
127 }
128}
129
130/// PrintAsmOperand - Print out an operand for an inline asm expression.
131///
132bool MSP430AsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
133 const char *ExtraCode, raw_ostream &O) {
134 // Does this asm operand have a single letter operand modifier?
135 if (ExtraCode && ExtraCode[0])
136 return AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, OS&: O);
137
138 printOperand(MI, OpNum: OpNo, O);
139 return false;
140}
141
142bool MSP430AsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
143 unsigned OpNo,
144 const char *ExtraCode,
145 raw_ostream &O) {
146 if (ExtraCode && ExtraCode[0]) {
147 return true; // Unknown modifier.
148 }
149 printSrcMemOperand(MI, OpNum: OpNo, O);
150 return false;
151}
152
153//===----------------------------------------------------------------------===//
154void MSP430AsmPrinter::emitInstruction(const MachineInstr *MI) {
155 MSP430_MC::verifyInstructionPredicates(Opcode: MI->getOpcode(),
156 Features: getSubtargetInfo().getFeatureBits());
157
158 MSP430MCInstLower MCInstLowering(OutContext, *this);
159
160 MCInst TmpInst;
161 MCInstLowering.Lower(MI, OutMI&: TmpInst);
162 EmitToStreamer(S&: *OutStreamer, Inst: TmpInst);
163}
164
165void MSP430AsmPrinter::EmitInterruptVectorSection(MachineFunction &ISR) {
166 MCSection *Cur = OutStreamer->getCurrentSectionOnly();
167 const auto *F = &ISR.getFunction();
168 if (F->getCallingConv() != CallingConv::MSP430_INTR) {
169 report_fatal_error(reason: "Functions with 'interrupt' attribute must have msp430_intrcc CC");
170 }
171 StringRef IVIdx = F->getFnAttribute(Kind: "interrupt").getValueAsString();
172 MCSection *IV = OutStreamer->getContext().getELFSection(
173 Section: "__interrupt_vector_" + IVIdx,
174 Type: ELF::SHT_PROGBITS, Flags: ELF::SHF_ALLOC | ELF::SHF_EXECINSTR);
175 OutStreamer->switchSection(Section: IV);
176
177 const MCSymbol *FunctionSymbol = getSymbol(GV: F);
178 OutStreamer->emitSymbolValue(Sym: FunctionSymbol, Size: TM.getProgramPointerSize());
179 OutStreamer->switchSection(Section: Cur);
180}
181
182bool MSP430AsmPrinter::runOnMachineFunction(MachineFunction &MF) {
183 // Emit separate section for an interrupt vector if ISR
184 if (MF.getFunction().hasFnAttribute(Kind: "interrupt")) {
185 EmitInterruptVectorSection(ISR&: MF);
186 }
187
188 SetupMachineFunction(MF);
189 emitFunctionBody();
190 return false;
191}
192
193char MSP430AsmPrinter::ID = 0;
194
195INITIALIZE_PASS(MSP430AsmPrinter, "msp430-asm-printer",
196 "MSP430 Assembly Printer", false, false)
197
198// Force static initialization.
199extern "C" LLVM_ABI LLVM_EXTERNAL_VISIBILITY void
200LLVMInitializeMSP430AsmPrinter() {
201 RegisterAsmPrinter<MSP430AsmPrinter> X(getTheMSP430Target());
202}
203
204PreservedAnalyses MSP430AsmPrinterBeginPass::run(Module &M,
205 ModuleAnalysisManager &MAM) {
206 MSP430AsmPrinter &AsmPrinter = static_cast<MSP430AsmPrinter &>(
207 MAM.getResult<AsmPrinterAnalysis>(IR&: M).getPrinter());
208 setupModuleAsmPrinter(M, MAM, AsmPrinter);
209 AsmPrinter.doInitialization(M);
210 return PreservedAnalyses::all();
211}
212
213PreservedAnalyses
214MSP430AsmPrinterPass::run(MachineFunction &MF,
215 MachineFunctionAnalysisManager &MFAM) {
216 MSP430AsmPrinter &AsmPrinter = static_cast<MSP430AsmPrinter &>(
217 MFAM.getResult<ModuleAnalysisManagerMachineFunctionProxy>(IR&: MF)
218 .getCachedResult<AsmPrinterAnalysis>(IR&: *MF.getFunction().getParent())
219 ->getPrinter());
220 setupMachineFunctionAsmPrinter(MFAM, MF, AsmPrinter);
221 AsmPrinter.runOnMachineFunction(MF);
222 return PreservedAnalyses::all();
223}
224
225PreservedAnalyses MSP430AsmPrinterEndPass::run(Module &M,
226 ModuleAnalysisManager &MAM) {
227 MSP430AsmPrinter &AsmPrinter = static_cast<MSP430AsmPrinter &>(
228 MAM.getResult<AsmPrinterAnalysis>(IR&: M).getPrinter());
229 setupModuleAsmPrinter(M, MAM, AsmPrinter);
230 AsmPrinter.doFinalization(M);
231 return PreservedAnalyses::all();
232}
233