xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/MSP430/MSP430AsmPrinter.cpp (revision 753f127f3ace09432b2baeffd71a308760641a62)
10b57cec5SDimitry Andric //===-- MSP430AsmPrinter.cpp - MSP430 LLVM assembly writer ----------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file contains a printer that converts from our internal representation
100b57cec5SDimitry Andric // of machine-dependent LLVM code to the MSP430 assembly language.
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric 
140b57cec5SDimitry Andric #include "MCTargetDesc/MSP430InstPrinter.h"
150b57cec5SDimitry Andric #include "MSP430.h"
160b57cec5SDimitry Andric #include "MSP430InstrInfo.h"
170b57cec5SDimitry Andric #include "MSP430MCInstLower.h"
180b57cec5SDimitry Andric #include "MSP430TargetMachine.h"
190b57cec5SDimitry Andric #include "TargetInfo/MSP430TargetInfo.h"
200b57cec5SDimitry Andric #include "llvm/BinaryFormat/ELF.h"
210b57cec5SDimitry Andric #include "llvm/CodeGen/AsmPrinter.h"
220b57cec5SDimitry Andric #include "llvm/CodeGen/MachineConstantPool.h"
230b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h"
240b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstr.h"
250b57cec5SDimitry Andric #include "llvm/CodeGen/MachineModuleInfo.h"
260b57cec5SDimitry Andric #include "llvm/IR/Constants.h"
270b57cec5SDimitry Andric #include "llvm/IR/DerivedTypes.h"
280b57cec5SDimitry Andric #include "llvm/IR/Mangler.h"
290b57cec5SDimitry Andric #include "llvm/IR/Module.h"
300b57cec5SDimitry Andric #include "llvm/MC/MCAsmInfo.h"
310b57cec5SDimitry Andric #include "llvm/MC/MCInst.h"
320b57cec5SDimitry Andric #include "llvm/MC/MCSectionELF.h"
330b57cec5SDimitry Andric #include "llvm/MC/MCStreamer.h"
340b57cec5SDimitry Andric #include "llvm/MC/MCSymbol.h"
35349cc55cSDimitry Andric #include "llvm/MC/TargetRegistry.h"
360b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
370b57cec5SDimitry Andric using namespace llvm;
380b57cec5SDimitry Andric 
390b57cec5SDimitry Andric #define DEBUG_TYPE "asm-printer"
400b57cec5SDimitry Andric 
410b57cec5SDimitry Andric namespace {
420b57cec5SDimitry Andric   class MSP430AsmPrinter : public AsmPrinter {
430b57cec5SDimitry Andric   public:
MSP430AsmPrinter(TargetMachine & TM,std::unique_ptr<MCStreamer> Streamer)440b57cec5SDimitry Andric     MSP430AsmPrinter(TargetMachine &TM, std::unique_ptr<MCStreamer> Streamer)
450b57cec5SDimitry Andric         : AsmPrinter(TM, std::move(Streamer)) {}
460b57cec5SDimitry Andric 
getPassName() const470b57cec5SDimitry Andric     StringRef getPassName() const override { return "MSP430 Assembly Printer"; }
480b57cec5SDimitry Andric 
490b57cec5SDimitry Andric     bool runOnMachineFunction(MachineFunction &MF) override;
500b57cec5SDimitry Andric 
510b57cec5SDimitry Andric     void PrintSymbolOperand(const MachineOperand &MO, raw_ostream &O) override;
520b57cec5SDimitry Andric     void printOperand(const MachineInstr *MI, int OpNum,
530b57cec5SDimitry Andric                       raw_ostream &O, const char* Modifier = nullptr);
540b57cec5SDimitry Andric     void printSrcMemOperand(const MachineInstr *MI, int OpNum,
550b57cec5SDimitry Andric                             raw_ostream &O);
560b57cec5SDimitry Andric     bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
570b57cec5SDimitry Andric                          const char *ExtraCode, raw_ostream &O) override;
580b57cec5SDimitry Andric     bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
590b57cec5SDimitry Andric                                const char *ExtraCode, raw_ostream &O) override;
605ffd83dbSDimitry Andric     void emitInstruction(const MachineInstr *MI) override;
610b57cec5SDimitry Andric 
620b57cec5SDimitry Andric     void EmitInterruptVectorSection(MachineFunction &ISR);
630b57cec5SDimitry Andric   };
640b57cec5SDimitry Andric } // end of anonymous namespace
650b57cec5SDimitry Andric 
PrintSymbolOperand(const MachineOperand & MO,raw_ostream & O)660b57cec5SDimitry Andric void MSP430AsmPrinter::PrintSymbolOperand(const MachineOperand &MO,
670b57cec5SDimitry Andric                                           raw_ostream &O) {
680b57cec5SDimitry Andric   uint64_t Offset = MO.getOffset();
690b57cec5SDimitry Andric   if (Offset)
700b57cec5SDimitry Andric     O << '(' << Offset << '+';
710b57cec5SDimitry Andric 
720b57cec5SDimitry Andric   getSymbol(MO.getGlobal())->print(O, MAI);
730b57cec5SDimitry Andric 
740b57cec5SDimitry Andric   if (Offset)
750b57cec5SDimitry Andric     O << ')';
760b57cec5SDimitry Andric }
770b57cec5SDimitry Andric 
printOperand(const MachineInstr * MI,int OpNum,raw_ostream & O,const char * Modifier)780b57cec5SDimitry Andric void MSP430AsmPrinter::printOperand(const MachineInstr *MI, int OpNum,
790b57cec5SDimitry Andric                                     raw_ostream &O, const char *Modifier) {
800b57cec5SDimitry Andric   const MachineOperand &MO = MI->getOperand(OpNum);
810b57cec5SDimitry Andric   switch (MO.getType()) {
820b57cec5SDimitry Andric   default: llvm_unreachable("Not implemented yet!");
830b57cec5SDimitry Andric   case MachineOperand::MO_Register:
840b57cec5SDimitry Andric     O << MSP430InstPrinter::getRegisterName(MO.getReg());
850b57cec5SDimitry Andric     return;
860b57cec5SDimitry Andric   case MachineOperand::MO_Immediate:
870b57cec5SDimitry Andric     if (!Modifier || strcmp(Modifier, "nohash"))
880b57cec5SDimitry Andric       O << '#';
890b57cec5SDimitry Andric     O << MO.getImm();
900b57cec5SDimitry Andric     return;
910b57cec5SDimitry Andric   case MachineOperand::MO_MachineBasicBlock:
920b57cec5SDimitry Andric     MO.getMBB()->getSymbol()->print(O, MAI);
930b57cec5SDimitry Andric     return;
940b57cec5SDimitry Andric   case MachineOperand::MO_GlobalAddress: {
950b57cec5SDimitry Andric     // If the global address expression is a part of displacement field with a
960b57cec5SDimitry Andric     // register base, we should not emit any prefix symbol here, e.g.
970b57cec5SDimitry Andric     //   mov.w glb(r1), r2
980b57cec5SDimitry Andric     // Otherwise (!) msp430-as will silently miscompile the output :(
990b57cec5SDimitry Andric     if (!Modifier || strcmp(Modifier, "nohash"))
1000b57cec5SDimitry Andric       O << '#';
1010b57cec5SDimitry Andric     PrintSymbolOperand(MO, O);
1020b57cec5SDimitry Andric     return;
1030b57cec5SDimitry Andric   }
1040b57cec5SDimitry Andric   }
1050b57cec5SDimitry Andric }
1060b57cec5SDimitry Andric 
printSrcMemOperand(const MachineInstr * MI,int OpNum,raw_ostream & O)1070b57cec5SDimitry Andric void MSP430AsmPrinter::printSrcMemOperand(const MachineInstr *MI, int OpNum,
1080b57cec5SDimitry Andric                                           raw_ostream &O) {
1090b57cec5SDimitry Andric   const MachineOperand &Base = MI->getOperand(OpNum);
1100b57cec5SDimitry Andric   const MachineOperand &Disp = MI->getOperand(OpNum+1);
1110b57cec5SDimitry Andric 
1120b57cec5SDimitry Andric   // Print displacement first
1130b57cec5SDimitry Andric 
1140b57cec5SDimitry Andric   // Imm here is in fact global address - print extra modifier.
1150b57cec5SDimitry Andric   if (Disp.isImm() && Base.getReg() == MSP430::SR)
1160b57cec5SDimitry Andric     O << '&';
1170b57cec5SDimitry Andric   printOperand(MI, OpNum+1, O, "nohash");
1180b57cec5SDimitry Andric 
1190b57cec5SDimitry Andric   // Print register base field
1200b57cec5SDimitry Andric   if (Base.getReg() != MSP430::SR && Base.getReg() != MSP430::PC) {
1210b57cec5SDimitry Andric     O << '(';
1220b57cec5SDimitry Andric     printOperand(MI, OpNum, O);
1230b57cec5SDimitry Andric     O << ')';
1240b57cec5SDimitry Andric   }
1250b57cec5SDimitry Andric }
1260b57cec5SDimitry Andric 
1270b57cec5SDimitry Andric /// PrintAsmOperand - Print out an operand for an inline asm expression.
1280b57cec5SDimitry Andric ///
PrintAsmOperand(const MachineInstr * MI,unsigned OpNo,const char * ExtraCode,raw_ostream & O)1290b57cec5SDimitry Andric bool MSP430AsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
1300b57cec5SDimitry Andric                                        const char *ExtraCode, raw_ostream &O) {
1310b57cec5SDimitry Andric   // Does this asm operand have a single letter operand modifier?
1320b57cec5SDimitry Andric   if (ExtraCode && ExtraCode[0])
1330b57cec5SDimitry Andric     return AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, O);
1340b57cec5SDimitry Andric 
1350b57cec5SDimitry Andric   printOperand(MI, OpNo, O);
1360b57cec5SDimitry Andric   return false;
1370b57cec5SDimitry Andric }
1380b57cec5SDimitry Andric 
PrintAsmMemoryOperand(const MachineInstr * MI,unsigned OpNo,const char * ExtraCode,raw_ostream & O)1390b57cec5SDimitry Andric bool MSP430AsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
1400b57cec5SDimitry Andric                                              unsigned OpNo,
1410b57cec5SDimitry Andric                                              const char *ExtraCode,
1420b57cec5SDimitry Andric                                              raw_ostream &O) {
1430b57cec5SDimitry Andric   if (ExtraCode && ExtraCode[0]) {
1440b57cec5SDimitry Andric     return true; // Unknown modifier.
1450b57cec5SDimitry Andric   }
1460b57cec5SDimitry Andric   printSrcMemOperand(MI, OpNo, O);
1470b57cec5SDimitry Andric   return false;
1480b57cec5SDimitry Andric }
1490b57cec5SDimitry Andric 
1500b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
emitInstruction(const MachineInstr * MI)1515ffd83dbSDimitry Andric void MSP430AsmPrinter::emitInstruction(const MachineInstr *MI) {
152*753f127fSDimitry Andric   MSP430_MC::verifyInstructionPredicates(MI->getOpcode(),
153*753f127fSDimitry Andric                                          getSubtargetInfo().getFeatureBits());
154*753f127fSDimitry Andric 
1550b57cec5SDimitry Andric   MSP430MCInstLower MCInstLowering(OutContext, *this);
1560b57cec5SDimitry Andric 
1570b57cec5SDimitry Andric   MCInst TmpInst;
1580b57cec5SDimitry Andric   MCInstLowering.Lower(MI, TmpInst);
1590b57cec5SDimitry Andric   EmitToStreamer(*OutStreamer, TmpInst);
1600b57cec5SDimitry Andric }
1610b57cec5SDimitry Andric 
EmitInterruptVectorSection(MachineFunction & ISR)1620b57cec5SDimitry Andric void MSP430AsmPrinter::EmitInterruptVectorSection(MachineFunction &ISR) {
1630b57cec5SDimitry Andric   MCSection *Cur = OutStreamer->getCurrentSectionOnly();
1640b57cec5SDimitry Andric   const auto *F = &ISR.getFunction();
1658bcb0991SDimitry Andric   if (F->getCallingConv() != CallingConv::MSP430_INTR) {
1668bcb0991SDimitry Andric     report_fatal_error("Functions with 'interrupt' attribute must have msp430_intrcc CC");
1678bcb0991SDimitry Andric   }
1680b57cec5SDimitry Andric   StringRef IVIdx = F->getFnAttribute("interrupt").getValueAsString();
1690b57cec5SDimitry Andric   MCSection *IV = OutStreamer->getContext().getELFSection(
1700b57cec5SDimitry Andric     "__interrupt_vector_" + IVIdx,
1710b57cec5SDimitry Andric     ELF::SHT_PROGBITS, ELF::SHF_ALLOC | ELF::SHF_EXECINSTR);
17281ad6265SDimitry Andric   OutStreamer->switchSection(IV);
1730b57cec5SDimitry Andric 
1740b57cec5SDimitry Andric   const MCSymbol *FunctionSymbol = getSymbol(F);
1755ffd83dbSDimitry Andric   OutStreamer->emitSymbolValue(FunctionSymbol, TM.getProgramPointerSize());
17681ad6265SDimitry Andric   OutStreamer->switchSection(Cur);
1770b57cec5SDimitry Andric }
1780b57cec5SDimitry Andric 
runOnMachineFunction(MachineFunction & MF)1790b57cec5SDimitry Andric bool MSP430AsmPrinter::runOnMachineFunction(MachineFunction &MF) {
1800b57cec5SDimitry Andric   // Emit separate section for an interrupt vector if ISR
1818bcb0991SDimitry Andric   if (MF.getFunction().hasFnAttribute("interrupt")) {
1820b57cec5SDimitry Andric     EmitInterruptVectorSection(MF);
1838bcb0991SDimitry Andric   }
1840b57cec5SDimitry Andric 
1850b57cec5SDimitry Andric   SetupMachineFunction(MF);
1865ffd83dbSDimitry Andric   emitFunctionBody();
1870b57cec5SDimitry Andric   return false;
1880b57cec5SDimitry Andric }
1890b57cec5SDimitry Andric 
1900b57cec5SDimitry Andric // Force static initialization.
LLVMInitializeMSP430AsmPrinter()191480093f4SDimitry Andric extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeMSP430AsmPrinter() {
1920b57cec5SDimitry Andric   RegisterAsmPrinter<MSP430AsmPrinter> X(getTheMSP430Target());
1930b57cec5SDimitry Andric }
194