1218885Sdim//===-- MSP430AsmPrinter.cpp - MSP430 LLVM assembly writer ----------------===//
2218885Sdim//
3218885Sdim//                     The LLVM Compiler Infrastructure
4218885Sdim//
5218885Sdim// This file is distributed under the University of Illinois Open Source
6218885Sdim// License. See LICENSE.TXT for details.
7218885Sdim//
8218885Sdim//===----------------------------------------------------------------------===//
9218885Sdim//
10218885Sdim// This file contains a printer that converts from our internal representation
11218885Sdim// of machine-dependent LLVM code to the MSP430 assembly language.
12218885Sdim//
13218885Sdim//===----------------------------------------------------------------------===//
14218885Sdim
15218885Sdim#define DEBUG_TYPE "asm-printer"
16218885Sdim#include "MSP430.h"
17249423Sdim#include "InstPrinter/MSP430InstPrinter.h"
18218885Sdim#include "MSP430InstrInfo.h"
19218885Sdim#include "MSP430MCInstLower.h"
20218885Sdim#include "MSP430TargetMachine.h"
21218885Sdim#include "llvm/Assembly/Writer.h"
22218885Sdim#include "llvm/CodeGen/AsmPrinter.h"
23249423Sdim#include "llvm/CodeGen/MachineConstantPool.h"
24218885Sdim#include "llvm/CodeGen/MachineFunctionPass.h"
25218885Sdim#include "llvm/CodeGen/MachineInstr.h"
26249423Sdim#include "llvm/CodeGen/MachineModuleInfo.h"
27249423Sdim#include "llvm/IR/Constants.h"
28249423Sdim#include "llvm/IR/DerivedTypes.h"
29249423Sdim#include "llvm/IR/Module.h"
30224145Sdim#include "llvm/MC/MCAsmInfo.h"
31218885Sdim#include "llvm/MC/MCInst.h"
32218885Sdim#include "llvm/MC/MCStreamer.h"
33218885Sdim#include "llvm/MC/MCSymbol.h"
34226633Sdim#include "llvm/Support/TargetRegistry.h"
35218885Sdim#include "llvm/Support/raw_ostream.h"
36249423Sdim#include "llvm/Target/Mangler.h"
37218885Sdimusing namespace llvm;
38218885Sdim
39218885Sdimnamespace {
40218885Sdim  class MSP430AsmPrinter : public AsmPrinter {
41218885Sdim  public:
42218885Sdim    MSP430AsmPrinter(TargetMachine &TM, MCStreamer &Streamer)
43218885Sdim      : AsmPrinter(TM, Streamer) {}
44218885Sdim
45218885Sdim    virtual const char *getPassName() const {
46218885Sdim      return "MSP430 Assembly Printer";
47218885Sdim    }
48218885Sdim
49218885Sdim    void printOperand(const MachineInstr *MI, int OpNum,
50218885Sdim                      raw_ostream &O, const char* Modifier = 0);
51218885Sdim    void printSrcMemOperand(const MachineInstr *MI, int OpNum,
52218885Sdim                            raw_ostream &O);
53218885Sdim    bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
54218885Sdim                         unsigned AsmVariant, const char *ExtraCode,
55218885Sdim                         raw_ostream &O);
56218885Sdim    bool PrintAsmMemoryOperand(const MachineInstr *MI,
57218885Sdim                               unsigned OpNo, unsigned AsmVariant,
58218885Sdim                               const char *ExtraCode, raw_ostream &O);
59218885Sdim    void EmitInstruction(const MachineInstr *MI);
60218885Sdim  };
61218885Sdim} // end of anonymous namespace
62218885Sdim
63218885Sdim
64218885Sdimvoid MSP430AsmPrinter::printOperand(const MachineInstr *MI, int OpNum,
65218885Sdim                                    raw_ostream &O, const char *Modifier) {
66218885Sdim  const MachineOperand &MO = MI->getOperand(OpNum);
67218885Sdim  switch (MO.getType()) {
68234353Sdim  default: llvm_unreachable("Not implemented yet!");
69218885Sdim  case MachineOperand::MO_Register:
70218885Sdim    O << MSP430InstPrinter::getRegisterName(MO.getReg());
71218885Sdim    return;
72218885Sdim  case MachineOperand::MO_Immediate:
73218885Sdim    if (!Modifier || strcmp(Modifier, "nohash"))
74218885Sdim      O << '#';
75218885Sdim    O << MO.getImm();
76218885Sdim    return;
77218885Sdim  case MachineOperand::MO_MachineBasicBlock:
78218885Sdim    O << *MO.getMBB()->getSymbol();
79218885Sdim    return;
80218885Sdim  case MachineOperand::MO_GlobalAddress: {
81218885Sdim    bool isMemOp  = Modifier && !strcmp(Modifier, "mem");
82218885Sdim    uint64_t Offset = MO.getOffset();
83218885Sdim
84218885Sdim    // If the global address expression is a part of displacement field with a
85218885Sdim    // register base, we should not emit any prefix symbol here, e.g.
86218885Sdim    //   mov.w &foo, r1
87218885Sdim    // vs
88218885Sdim    //   mov.w glb(r1), r2
89218885Sdim    // Otherwise (!) msp430-as will silently miscompile the output :(
90218885Sdim    if (!Modifier || strcmp(Modifier, "nohash"))
91218885Sdim      O << (isMemOp ? '&' : '#');
92218885Sdim    if (Offset)
93218885Sdim      O << '(' << Offset << '+';
94218885Sdim
95263508Sdim    O << *getSymbol(MO.getGlobal());
96218885Sdim
97218885Sdim    if (Offset)
98218885Sdim      O << ')';
99218885Sdim
100218885Sdim    return;
101218885Sdim  }
102218885Sdim  case MachineOperand::MO_ExternalSymbol: {
103218885Sdim    bool isMemOp  = Modifier && !strcmp(Modifier, "mem");
104218885Sdim    O << (isMemOp ? '&' : '#');
105218885Sdim    O << MAI->getGlobalPrefix() << MO.getSymbolName();
106218885Sdim    return;
107218885Sdim  }
108218885Sdim  }
109218885Sdim}
110218885Sdim
111218885Sdimvoid MSP430AsmPrinter::printSrcMemOperand(const MachineInstr *MI, int OpNum,
112218885Sdim                                          raw_ostream &O) {
113218885Sdim  const MachineOperand &Base = MI->getOperand(OpNum);
114218885Sdim  const MachineOperand &Disp = MI->getOperand(OpNum+1);
115218885Sdim
116218885Sdim  // Print displacement first
117218885Sdim
118218885Sdim  // Imm here is in fact global address - print extra modifier.
119218885Sdim  if (Disp.isImm() && !Base.getReg())
120218885Sdim    O << '&';
121218885Sdim  printOperand(MI, OpNum+1, O, "nohash");
122218885Sdim
123218885Sdim  // Print register base field
124218885Sdim  if (Base.getReg()) {
125218885Sdim    O << '(';
126218885Sdim    printOperand(MI, OpNum, O);
127218885Sdim    O << ')';
128218885Sdim  }
129218885Sdim}
130218885Sdim
131218885Sdim/// PrintAsmOperand - Print out an operand for an inline asm expression.
132218885Sdim///
133218885Sdimbool MSP430AsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
134218885Sdim                                       unsigned AsmVariant,
135218885Sdim                                       const char *ExtraCode, raw_ostream &O) {
136218885Sdim  // Does this asm operand have a single letter operand modifier?
137218885Sdim  if (ExtraCode && ExtraCode[0])
138218885Sdim    return true; // Unknown modifier.
139218885Sdim
140218885Sdim  printOperand(MI, OpNo, O);
141218885Sdim  return false;
142218885Sdim}
143218885Sdim
144218885Sdimbool MSP430AsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
145218885Sdim                                             unsigned OpNo, unsigned AsmVariant,
146218885Sdim                                             const char *ExtraCode,
147218885Sdim                                             raw_ostream &O) {
148218885Sdim  if (ExtraCode && ExtraCode[0]) {
149218885Sdim    return true; // Unknown modifier.
150218885Sdim  }
151218885Sdim  printSrcMemOperand(MI, OpNo, O);
152218885Sdim  return false;
153218885Sdim}
154218885Sdim
155218885Sdim//===----------------------------------------------------------------------===//
156218885Sdimvoid MSP430AsmPrinter::EmitInstruction(const MachineInstr *MI) {
157239462Sdim  MSP430MCInstLower MCInstLowering(OutContext, *this);
158218885Sdim
159218885Sdim  MCInst TmpInst;
160218885Sdim  MCInstLowering.Lower(MI, TmpInst);
161218885Sdim  OutStreamer.EmitInstruction(TmpInst);
162218885Sdim}
163218885Sdim
164218885Sdim// Force static initialization.
165218885Sdimextern "C" void LLVMInitializeMSP430AsmPrinter() {
166218885Sdim  RegisterAsmPrinter<MSP430AsmPrinter> X(TheMSP430Target);
167218885Sdim}
168