1a85a4e21SJim Grosbach //===-- MSP430AsmPrinter.cpp - MSP430 LLVM assembly writer ----------------===//
2a85a4e21SJim Grosbach //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6a85a4e21SJim Grosbach //
7a85a4e21SJim Grosbach //===----------------------------------------------------------------------===//
8a85a4e21SJim Grosbach //
9a85a4e21SJim Grosbach // This file contains a printer that converts from our internal representation
10a85a4e21SJim Grosbach // of machine-dependent LLVM code to the MSP430 assembly language.
11a85a4e21SJim Grosbach //
12a85a4e21SJim Grosbach //===----------------------------------------------------------------------===//
13a85a4e21SJim Grosbach 
1461fb6700SRichard Trieu #include "MCTargetDesc/MSP430InstPrinter.h"
156bda14b3SChandler Carruth #include "MSP430.h"
16a85a4e21SJim Grosbach #include "MSP430InstrInfo.h"
17a85a4e21SJim Grosbach #include "MSP430MCInstLower.h"
18a85a4e21SJim Grosbach #include "MSP430TargetMachine.h"
19a57ce32eSRichard Trieu #include "TargetInfo/MSP430TargetInfo.h"
20cbdb4effSAnton Korobeynikov #include "llvm/BinaryFormat/ELF.h"
21a85a4e21SJim Grosbach #include "llvm/CodeGen/AsmPrinter.h"
22a85a4e21SJim Grosbach #include "llvm/CodeGen/MachineConstantPool.h"
23ed0881b2SChandler Carruth #include "llvm/CodeGen/MachineFunctionPass.h"
24a85a4e21SJim Grosbach #include "llvm/CodeGen/MachineInstr.h"
25ed0881b2SChandler Carruth #include "llvm/CodeGen/MachineModuleInfo.h"
269fb823bbSChandler Carruth #include "llvm/IR/Constants.h"
279fb823bbSChandler Carruth #include "llvm/IR/DerivedTypes.h"
28894843cbSRafael Espindola #include "llvm/IR/Mangler.h"
299fb823bbSChandler Carruth #include "llvm/IR/Module.h"
301705ab00SEvan Cheng #include "llvm/MC/MCAsmInfo.h"
31a85a4e21SJim Grosbach #include "llvm/MC/MCInst.h"
32cbdb4effSAnton Korobeynikov #include "llvm/MC/MCSectionELF.h"
33a85a4e21SJim Grosbach #include "llvm/MC/MCStreamer.h"
34a85a4e21SJim Grosbach #include "llvm/MC/MCSymbol.h"
3589b57061SReid Kleckner #include "llvm/MC/TargetRegistry.h"
36a85a4e21SJim Grosbach #include "llvm/Support/raw_ostream.h"
37a85a4e21SJim Grosbach using namespace llvm;
38a85a4e21SJim Grosbach 
3984e68b29SChandler Carruth #define DEBUG_TYPE "asm-printer"
4084e68b29SChandler Carruth 
41a85a4e21SJim Grosbach namespace {
42a85a4e21SJim Grosbach   class MSP430AsmPrinter : public AsmPrinter {
43a85a4e21SJim Grosbach   public:
MSP430AsmPrinter(TargetMachine & TM,std::unique_ptr<MCStreamer> Streamer)449459832eSDavid Blaikie     MSP430AsmPrinter(TargetMachine &TM, std::unique_ptr<MCStreamer> Streamer)
459459832eSDavid Blaikie         : AsmPrinter(TM, std::move(Streamer)) {}
46a85a4e21SJim Grosbach 
getPassName() const47117296c0SMehdi Amini     StringRef getPassName() const override { return "MSP430 Assembly Printer"; }
48a85a4e21SJim Grosbach 
49cbdb4effSAnton Korobeynikov     bool runOnMachineFunction(MachineFunction &MF) override;
50cbdb4effSAnton Korobeynikov 
517ab164c4SNick Desaulniers     void PrintSymbolOperand(const MachineOperand &MO, raw_ostream &O) override;
52a85a4e21SJim Grosbach     void printOperand(const MachineInstr *MI, int OpNum,
53062a2baeSCraig Topper                       raw_ostream &O, const char* Modifier = nullptr);
54a85a4e21SJim Grosbach     void printSrcMemOperand(const MachineInstr *MI, int OpNum,
55a85a4e21SJim Grosbach                             raw_ostream &O);
56a85a4e21SJim Grosbach     bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
575277b3ffSNick Desaulniers                          const char *ExtraCode, raw_ostream &O) override;
585277b3ffSNick Desaulniers     bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
596f9e59eaSCraig Topper                                const char *ExtraCode, raw_ostream &O) override;
60bcd24b2dSFangrui Song     void emitInstruction(const MachineInstr *MI) override;
61cbdb4effSAnton Korobeynikov 
62cbdb4effSAnton Korobeynikov     void EmitInterruptVectorSection(MachineFunction &ISR);
63a85a4e21SJim Grosbach   };
64a85a4e21SJim Grosbach } // end of anonymous namespace
65a85a4e21SJim Grosbach 
PrintSymbolOperand(const MachineOperand & MO,raw_ostream & O)667ab164c4SNick Desaulniers void MSP430AsmPrinter::PrintSymbolOperand(const MachineOperand &MO,
677ab164c4SNick Desaulniers                                           raw_ostream &O) {
687ab164c4SNick Desaulniers   uint64_t Offset = MO.getOffset();
697ab164c4SNick Desaulniers   if (Offset)
707ab164c4SNick Desaulniers     O << '(' << Offset << '+';
717ab164c4SNick Desaulniers 
727ab164c4SNick Desaulniers   getSymbol(MO.getGlobal())->print(O, MAI);
737ab164c4SNick Desaulniers 
747ab164c4SNick Desaulniers   if (Offset)
757ab164c4SNick Desaulniers     O << ')';
767ab164c4SNick Desaulniers }
77a85a4e21SJim Grosbach 
printOperand(const MachineInstr * MI,int OpNum,raw_ostream & O,const char * Modifier)78a85a4e21SJim Grosbach void MSP430AsmPrinter::printOperand(const MachineInstr *MI, int OpNum,
79a85a4e21SJim Grosbach                                     raw_ostream &O, const char *Modifier) {
80a85a4e21SJim Grosbach   const MachineOperand &MO = MI->getOperand(OpNum);
81a85a4e21SJim Grosbach   switch (MO.getType()) {
82e55c556aSCraig Topper   default: llvm_unreachable("Not implemented yet!");
83a85a4e21SJim Grosbach   case MachineOperand::MO_Register:
84a85a4e21SJim Grosbach     O << MSP430InstPrinter::getRegisterName(MO.getReg());
85a85a4e21SJim Grosbach     return;
86a85a4e21SJim Grosbach   case MachineOperand::MO_Immediate:
87a85a4e21SJim Grosbach     if (!Modifier || strcmp(Modifier, "nohash"))
88a85a4e21SJim Grosbach       O << '#';
89a85a4e21SJim Grosbach     O << MO.getImm();
90a85a4e21SJim Grosbach     return;
91a85a4e21SJim Grosbach   case MachineOperand::MO_MachineBasicBlock:
928b643559SMatt Arsenault     MO.getMBB()->getSymbol()->print(O, MAI);
93a85a4e21SJim Grosbach     return;
94a85a4e21SJim Grosbach   case MachineOperand::MO_GlobalAddress: {
95a85a4e21SJim Grosbach     // If the global address expression is a part of displacement field with a
96a85a4e21SJim Grosbach     // register base, we should not emit any prefix symbol here, e.g.
97a85a4e21SJim Grosbach     //   mov.w glb(r1), r2
98a85a4e21SJim Grosbach     // Otherwise (!) msp430-as will silently miscompile the output :(
99a85a4e21SJim Grosbach     if (!Modifier || strcmp(Modifier, "nohash"))
1007ab164c4SNick Desaulniers       O << '#';
1017ab164c4SNick Desaulniers     PrintSymbolOperand(MO, O);
102a85a4e21SJim Grosbach     return;
103a85a4e21SJim Grosbach   }
104a85a4e21SJim Grosbach   }
105a85a4e21SJim Grosbach }
106a85a4e21SJim Grosbach 
printSrcMemOperand(const MachineInstr * MI,int OpNum,raw_ostream & O)107a85a4e21SJim Grosbach void MSP430AsmPrinter::printSrcMemOperand(const MachineInstr *MI, int OpNum,
108a85a4e21SJim Grosbach                                           raw_ostream &O) {
109a85a4e21SJim Grosbach   const MachineOperand &Base = MI->getOperand(OpNum);
110a85a4e21SJim Grosbach   const MachineOperand &Disp = MI->getOperand(OpNum+1);
111a85a4e21SJim Grosbach 
112a85a4e21SJim Grosbach   // Print displacement first
113a85a4e21SJim Grosbach 
114a85a4e21SJim Grosbach   // Imm here is in fact global address - print extra modifier.
115509d5c4aSAnton Korobeynikov   if (Disp.isImm() && Base.getReg() == MSP430::SR)
116a85a4e21SJim Grosbach     O << '&';
117a85a4e21SJim Grosbach   printOperand(MI, OpNum+1, O, "nohash");
118a85a4e21SJim Grosbach 
119a85a4e21SJim Grosbach   // Print register base field
120509d5c4aSAnton Korobeynikov   if (Base.getReg() != MSP430::SR && Base.getReg() != MSP430::PC) {
121a85a4e21SJim Grosbach     O << '(';
122a85a4e21SJim Grosbach     printOperand(MI, OpNum, O);
123a85a4e21SJim Grosbach     O << ')';
124a85a4e21SJim Grosbach   }
125a85a4e21SJim Grosbach }
126a85a4e21SJim Grosbach 
127a85a4e21SJim Grosbach /// PrintAsmOperand - Print out an operand for an inline asm expression.
128a85a4e21SJim Grosbach ///
PrintAsmOperand(const MachineInstr * MI,unsigned OpNo,const char * ExtraCode,raw_ostream & O)129a85a4e21SJim Grosbach bool MSP430AsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
130a85a4e21SJim Grosbach                                        const char *ExtraCode, raw_ostream &O) {
131a85a4e21SJim Grosbach   // Does this asm operand have a single letter operand modifier?
132a85a4e21SJim Grosbach   if (ExtraCode && ExtraCode[0])
1337ab164c4SNick Desaulniers     return AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, O);
134a85a4e21SJim Grosbach 
135a85a4e21SJim Grosbach   printOperand(MI, OpNo, O);
136a85a4e21SJim Grosbach   return false;
137a85a4e21SJim Grosbach }
138a85a4e21SJim Grosbach 
PrintAsmMemoryOperand(const MachineInstr * MI,unsigned OpNo,const char * ExtraCode,raw_ostream & O)139a85a4e21SJim Grosbach bool MSP430AsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
1405277b3ffSNick Desaulniers                                              unsigned OpNo,
141a85a4e21SJim Grosbach                                              const char *ExtraCode,
142a85a4e21SJim Grosbach                                              raw_ostream &O) {
143a85a4e21SJim Grosbach   if (ExtraCode && ExtraCode[0]) {
144a85a4e21SJim Grosbach     return true; // Unknown modifier.
145a85a4e21SJim Grosbach   }
146a85a4e21SJim Grosbach   printSrcMemOperand(MI, OpNo, O);
147a85a4e21SJim Grosbach   return false;
148a85a4e21SJim Grosbach }
149a85a4e21SJim Grosbach 
150a85a4e21SJim Grosbach //===----------------------------------------------------------------------===//
emitInstruction(const MachineInstr * MI)151bcd24b2dSFangrui Song void MSP430AsmPrinter::emitInstruction(const MachineInstr *MI) {
152*3e0bf1c7SDavid Green   MSP430_MC::verifyInstructionPredicates(MI->getOpcode(),
153*3e0bf1c7SDavid Green                                          getSubtargetInfo().getFeatureBits());
154*3e0bf1c7SDavid Green 
155628a39faSBenjamin Kramer   MSP430MCInstLower MCInstLowering(OutContext, *this);
156a85a4e21SJim Grosbach 
157a85a4e21SJim Grosbach   MCInst TmpInst;
158a85a4e21SJim Grosbach   MCInstLowering.Lower(MI, TmpInst);
1599ff69c8fSLang Hames   EmitToStreamer(*OutStreamer, TmpInst);
160a85a4e21SJim Grosbach }
161a85a4e21SJim Grosbach 
EmitInterruptVectorSection(MachineFunction & ISR)162cbdb4effSAnton Korobeynikov void MSP430AsmPrinter::EmitInterruptVectorSection(MachineFunction &ISR) {
163cbdb4effSAnton Korobeynikov   MCSection *Cur = OutStreamer->getCurrentSectionOnly();
164cbdb4effSAnton Korobeynikov   const auto *F = &ISR.getFunction();
165efcad774SVadzim Dambrouski   if (F->getCallingConv() != CallingConv::MSP430_INTR) {
166efcad774SVadzim Dambrouski     report_fatal_error("Functions with 'interrupt' attribute must have msp430_intrcc CC");
167efcad774SVadzim Dambrouski   }
168cbdb4effSAnton Korobeynikov   StringRef IVIdx = F->getFnAttribute("interrupt").getValueAsString();
169cbdb4effSAnton Korobeynikov   MCSection *IV = OutStreamer->getContext().getELFSection(
170cbdb4effSAnton Korobeynikov     "__interrupt_vector_" + IVIdx,
171cbdb4effSAnton Korobeynikov     ELF::SHT_PROGBITS, ELF::SHF_ALLOC | ELF::SHF_EXECINSTR);
172adf4142fSFangrui Song   OutStreamer->switchSection(IV);
173cbdb4effSAnton Korobeynikov 
174cbdb4effSAnton Korobeynikov   const MCSymbol *FunctionSymbol = getSymbol(F);
1756d2d589bSFangrui Song   OutStreamer->emitSymbolValue(FunctionSymbol, TM.getProgramPointerSize());
176adf4142fSFangrui Song   OutStreamer->switchSection(Cur);
177cbdb4effSAnton Korobeynikov }
178cbdb4effSAnton Korobeynikov 
runOnMachineFunction(MachineFunction & MF)179cbdb4effSAnton Korobeynikov bool MSP430AsmPrinter::runOnMachineFunction(MachineFunction &MF) {
180cbdb4effSAnton Korobeynikov   // Emit separate section for an interrupt vector if ISR
181efcad774SVadzim Dambrouski   if (MF.getFunction().hasFnAttribute("interrupt")) {
182cbdb4effSAnton Korobeynikov     EmitInterruptVectorSection(MF);
183efcad774SVadzim Dambrouski   }
184cbdb4effSAnton Korobeynikov 
185cbdb4effSAnton Korobeynikov   SetupMachineFunction(MF);
1860dce409cSFangrui Song   emitFunctionBody();
187cbdb4effSAnton Korobeynikov   return false;
188cbdb4effSAnton Korobeynikov }
189cbdb4effSAnton Korobeynikov 
190a85a4e21SJim Grosbach // Force static initialization.
LLVMInitializeMSP430AsmPrinter()1910dbcb363STom Stellard extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeMSP430AsmPrinter() {
192f42454b9SMehdi Amini   RegisterAsmPrinter<MSP430AsmPrinter> X(getTheMSP430Target());
193a85a4e21SJim Grosbach }
194