Change MCStreamer EmitInstruction interface to take subtarget info
[oota-llvm.git] / lib / Target / MSP430 / MSP430AsmPrinter.cpp
1 //===-- MSP430AsmPrinter.cpp - MSP430 LLVM assembly writer ----------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file contains a printer that converts from our internal representation
11 // of machine-dependent LLVM code to the MSP430 assembly language.
12 //
13 //===----------------------------------------------------------------------===//
14
15 #define DEBUG_TYPE "asm-printer"
16 #include "MSP430.h"
17 #include "InstPrinter/MSP430InstPrinter.h"
18 #include "MSP430InstrInfo.h"
19 #include "MSP430MCInstLower.h"
20 #include "MSP430TargetMachine.h"
21 #include "llvm/CodeGen/AsmPrinter.h"
22 #include "llvm/CodeGen/MachineConstantPool.h"
23 #include "llvm/CodeGen/MachineFunctionPass.h"
24 #include "llvm/CodeGen/MachineInstr.h"
25 #include "llvm/CodeGen/MachineModuleInfo.h"
26 #include "llvm/IR/Constants.h"
27 #include "llvm/IR/DerivedTypes.h"
28 #include "llvm/IR/Mangler.h"
29 #include "llvm/IR/Module.h"
30 #include "llvm/MC/MCAsmInfo.h"
31 #include "llvm/MC/MCInst.h"
32 #include "llvm/MC/MCStreamer.h"
33 #include "llvm/MC/MCSymbol.h"
34 #include "llvm/Support/TargetRegistry.h"
35 #include "llvm/Support/raw_ostream.h"
36 using namespace llvm;
37
38 namespace {
39   class MSP430AsmPrinter : public AsmPrinter {
40   public:
41     MSP430AsmPrinter(TargetMachine &TM, MCStreamer &Streamer)
42       : AsmPrinter(TM, Streamer) {}
43
44     virtual const char *getPassName() const {
45       return "MSP430 Assembly Printer";
46     }
47
48     void printOperand(const MachineInstr *MI, int OpNum,
49                       raw_ostream &O, const char* Modifier = 0);
50     void printSrcMemOperand(const MachineInstr *MI, int OpNum,
51                             raw_ostream &O);
52     bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
53                          unsigned AsmVariant, const char *ExtraCode,
54                          raw_ostream &O);
55     bool PrintAsmMemoryOperand(const MachineInstr *MI,
56                                unsigned OpNo, unsigned AsmVariant,
57                                const char *ExtraCode, raw_ostream &O);
58     void EmitInstruction(const MachineInstr *MI);
59   };
60 } // end of anonymous namespace
61
62
63 void MSP430AsmPrinter::printOperand(const MachineInstr *MI, int OpNum,
64                                     raw_ostream &O, const char *Modifier) {
65   const MachineOperand &MO = MI->getOperand(OpNum);
66   switch (MO.getType()) {
67   default: llvm_unreachable("Not implemented yet!");
68   case MachineOperand::MO_Register:
69     O << MSP430InstPrinter::getRegisterName(MO.getReg());
70     return;
71   case MachineOperand::MO_Immediate:
72     if (!Modifier || strcmp(Modifier, "nohash"))
73       O << '#';
74     O << MO.getImm();
75     return;
76   case MachineOperand::MO_MachineBasicBlock:
77     O << *MO.getMBB()->getSymbol();
78     return;
79   case MachineOperand::MO_GlobalAddress: {
80     bool isMemOp  = Modifier && !strcmp(Modifier, "mem");
81     uint64_t Offset = MO.getOffset();
82
83     // If the global address expression is a part of displacement field with a
84     // register base, we should not emit any prefix symbol here, e.g.
85     //   mov.w &foo, r1
86     // vs
87     //   mov.w glb(r1), r2
88     // Otherwise (!) msp430-as will silently miscompile the output :(
89     if (!Modifier || strcmp(Modifier, "nohash"))
90       O << (isMemOp ? '&' : '#');
91     if (Offset)
92       O << '(' << Offset << '+';
93
94     O << *getSymbol(MO.getGlobal());
95
96     if (Offset)
97       O << ')';
98
99     return;
100   }
101   }
102 }
103
104 void MSP430AsmPrinter::printSrcMemOperand(const MachineInstr *MI, int OpNum,
105                                           raw_ostream &O) {
106   const MachineOperand &Base = MI->getOperand(OpNum);
107   const MachineOperand &Disp = MI->getOperand(OpNum+1);
108
109   // Print displacement first
110
111   // Imm here is in fact global address - print extra modifier.
112   if (Disp.isImm() && !Base.getReg())
113     O << '&';
114   printOperand(MI, OpNum+1, O, "nohash");
115
116   // Print register base field
117   if (Base.getReg()) {
118     O << '(';
119     printOperand(MI, OpNum, O);
120     O << ')';
121   }
122 }
123
124 /// PrintAsmOperand - Print out an operand for an inline asm expression.
125 ///
126 bool MSP430AsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
127                                        unsigned AsmVariant,
128                                        const char *ExtraCode, raw_ostream &O) {
129   // Does this asm operand have a single letter operand modifier?
130   if (ExtraCode && ExtraCode[0])
131     return true; // Unknown modifier.
132
133   printOperand(MI, OpNo, O);
134   return false;
135 }
136
137 bool MSP430AsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
138                                              unsigned OpNo, unsigned AsmVariant,
139                                              const char *ExtraCode,
140                                              raw_ostream &O) {
141   if (ExtraCode && ExtraCode[0]) {
142     return true; // Unknown modifier.
143   }
144   printSrcMemOperand(MI, OpNo, O);
145   return false;
146 }
147
148 //===----------------------------------------------------------------------===//
149 void MSP430AsmPrinter::EmitInstruction(const MachineInstr *MI) {
150   MSP430MCInstLower MCInstLowering(OutContext, *this);
151
152   MCInst TmpInst;
153   MCInstLowering.Lower(MI, TmpInst);
154   EmitToStreamer(OutStreamer, TmpInst);
155 }
156
157 // Force static initialization.
158 extern "C" void LLVMInitializeMSP430AsmPrinter() {
159   RegisterAsmPrinter<MSP430AsmPrinter> X(TheMSP430Target);
160 }