fd96694b32fe7b9f8f7e42241810402859403b93
[oota-llvm.git] / lib / Target / CellSPU / SPUAsmPrinter.cpp
1 //===-- SPUAsmPrinter.cpp - Print machine instrs to Cell SPU assembly -------=//
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 Cell SPU assembly language. This printer
12 // is the output mechanism used by `llc'.
13 //
14 //===----------------------------------------------------------------------===//
15
16 #define DEBUG_TYPE "asmprinter"
17 #include "SPU.h"
18 #include "SPUTargetMachine.h"
19 #include "llvm/Constants.h"
20 #include "llvm/DerivedTypes.h"
21 #include "llvm/Module.h"
22 #include "llvm/CodeGen/AsmPrinter.h"
23 #include "llvm/CodeGen/MachineModuleInfo.h"
24 #include "llvm/MC/MCStreamer.h"
25 #include "llvm/MC/MCAsmInfo.h"
26 #include "llvm/MC/MCSymbol.h"
27 #include "llvm/Target/Mangler.h"
28 #include "llvm/Target/TargetLoweringObjectFile.h"
29 #include "llvm/Target/TargetInstrInfo.h"
30 #include "llvm/Target/TargetOptions.h"
31 #include "llvm/Target/TargetRegisterInfo.h"
32 #include "llvm/Target/TargetRegistry.h"
33 #include "llvm/ADT/SmallString.h"
34 #include "llvm/ADT/StringExtras.h"
35 #include "llvm/Support/ErrorHandling.h"
36 #include "llvm/Support/raw_ostream.h"
37 using namespace llvm;
38
39 namespace {
40   class SPUAsmPrinter : public AsmPrinter {
41   public:
42     explicit SPUAsmPrinter(TargetMachine &TM, MCStreamer &Streamer) :
43       AsmPrinter(TM, Streamer) {}
44
45     virtual const char *getPassName() const {
46       return "STI CBEA SPU Assembly Printer";
47     }
48
49     /// printInstruction - This method is automatically generated by tablegen
50     /// from the instruction set description.
51     void printInstruction(const MachineInstr *MI, raw_ostream &OS);
52     static const char *getRegisterName(unsigned RegNo);
53
54
55     void EmitInstruction(const MachineInstr *MI) {
56       SmallString<128> Str;
57       raw_svector_ostream OS(Str);
58       printInstruction(MI, OS);
59       OutStreamer.EmitRawText(OS.str());
60     }
61     void printOp(const MachineOperand &MO, raw_ostream &OS);
62
63     void printOperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O) {
64       const MachineOperand &MO = MI->getOperand(OpNo);
65       if (MO.isReg()) {
66         O << getRegisterName(MO.getReg());
67       } else if (MO.isImm()) {
68         O << MO.getImm();
69       } else {
70         printOp(MO, O);
71       }
72     }
73
74     bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
75                          unsigned AsmVariant, const char *ExtraCode,
76                          raw_ostream &O);
77     bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
78                                unsigned AsmVariant, const char *ExtraCode,
79                                raw_ostream &O);
80
81
82     void
83     printU7ImmOperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O)
84     {
85       unsigned int value = MI->getOperand(OpNo).getImm();
86       assert(value < (1 << 8) && "Invalid u7 argument");
87       O << value;
88     }
89
90     void
91     printShufAddr(const MachineInstr *MI, unsigned OpNo, raw_ostream &O)
92     {
93       char value = MI->getOperand(OpNo).getImm();
94       O << (int) value;
95       O << "(";
96       printOperand(MI, OpNo+1, O);
97       O << ")";
98     }
99
100     void
101     printS16ImmOperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O)
102     {
103       O << (short) MI->getOperand(OpNo).getImm();
104     }
105
106     void
107     printU16ImmOperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O)
108     {
109       O << (unsigned short)MI->getOperand(OpNo).getImm();
110     }
111
112     void
113     printMemRegReg(const MachineInstr *MI, unsigned OpNo, raw_ostream &O) {
114       // When used as the base register, r0 reads constant zero rather than
115       // the value contained in the register.  For this reason, the darwin
116       // assembler requires that we print r0 as 0 (no r) when used as the base.
117       const MachineOperand &MO = MI->getOperand(OpNo);
118       O << getRegisterName(MO.getReg()) << ", ";
119       printOperand(MI, OpNo+1, O);
120     }
121
122     void
123     printU18ImmOperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O)
124     {
125       unsigned int value = MI->getOperand(OpNo).getImm();
126       assert(value <= (1 << 19) - 1 && "Invalid u18 argument");
127       O << value;
128     }
129
130     void
131     printS10ImmOperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O)
132     {
133       short value = (short) (((int) MI->getOperand(OpNo).getImm() << 16)
134                              >> 16);
135       assert((value >= -(1 << 9) && value <= (1 << 9) - 1)
136              && "Invalid s10 argument");
137       O << value;
138     }
139
140     void
141     printU10ImmOperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O)
142     {
143       short value = (short) (((int) MI->getOperand(OpNo).getImm() << 16)
144                              >> 16);
145       assert((value <= (1 << 10) - 1) && "Invalid u10 argument");
146       O << value;
147     }
148
149     void
150     printDFormAddr(const MachineInstr *MI, unsigned OpNo, raw_ostream &O)
151     {
152       assert(MI->getOperand(OpNo).isImm() &&
153              "printDFormAddr first operand is not immediate");
154       int64_t value = int64_t(MI->getOperand(OpNo).getImm());
155       int16_t value16 = int16_t(value);
156       assert((value16 >= -(1 << (9+4)) && value16 <= (1 << (9+4)) - 1)
157              && "Invalid dform s10 offset argument");
158       O << (value16 & ~0xf) << "(";
159       printOperand(MI, OpNo+1, O);
160       O << ")";
161     }
162
163     void
164     printAddr256K(const MachineInstr *MI, unsigned OpNo, raw_ostream &O)
165     {
166       /* Note: operand 1 is an offset or symbol name. */
167       if (MI->getOperand(OpNo).isImm()) {
168         printS16ImmOperand(MI, OpNo, O);
169       } else {
170         printOp(MI->getOperand(OpNo), O);
171         if (MI->getOperand(OpNo+1).isImm()) {
172           int displ = int(MI->getOperand(OpNo+1).getImm());
173           if (displ > 0)
174             O << "+" << displ;
175           else if (displ < 0)
176             O << displ;
177         }
178       }
179     }
180
181     void printCallOperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O) {
182       printOp(MI->getOperand(OpNo), O);
183     }
184
185     void printHBROperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O) {
186       printOp(MI->getOperand(OpNo), O);
187     }
188
189     void printPCRelativeOperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O) {
190       // Used to generate a ".-<target>", but it turns out that the assembler
191       // really wants the target.
192       //
193       // N.B.: This operand is used for call targets. Branch hints are another
194       // animal entirely.
195       printOp(MI->getOperand(OpNo), O);
196     }
197
198     void printSymbolHi(const MachineInstr *MI, unsigned OpNo, raw_ostream &O) {
199       if (MI->getOperand(OpNo).isImm()) {
200         printS16ImmOperand(MI, OpNo, O);
201       } else {
202         printOp(MI->getOperand(OpNo), O);
203         O << "@h";
204       }
205     }
206
207     void printSymbolLo(const MachineInstr *MI, unsigned OpNo, raw_ostream &O) {
208       if (MI->getOperand(OpNo).isImm()) {
209         printS16ImmOperand(MI, OpNo, O);
210       } else {
211         printOp(MI->getOperand(OpNo), O);
212         O << "@l";
213       }
214     }
215
216     /// Print local store address
217     void printSymbolLSA(const MachineInstr *MI, unsigned OpNo, raw_ostream &O) {
218       printOp(MI->getOperand(OpNo), O);
219     }
220
221     void printROTHNeg7Imm(const MachineInstr *MI, unsigned OpNo,
222                           raw_ostream &O) {
223       if (MI->getOperand(OpNo).isImm()) {
224         int value = (int) MI->getOperand(OpNo).getImm();
225         assert((value >= 0 && value < 16)
226                && "Invalid negated immediate rotate 7-bit argument");
227         O << -value;
228       } else {
229         llvm_unreachable("Invalid/non-immediate rotate amount in printRotateNeg7Imm");
230       }
231     }
232
233     void printROTNeg7Imm(const MachineInstr *MI, unsigned OpNo, raw_ostream &O){
234       assert(MI->getOperand(OpNo).isImm() &&
235              "Invalid/non-immediate rotate amount in printRotateNeg7Imm");
236       int value = (int) MI->getOperand(OpNo).getImm();
237       assert((value >= 0 && value <= 32)
238              && "Invalid negated immediate rotate 7-bit argument");
239       O << -value;
240     }
241   };
242 } // end of anonymous namespace
243
244 // Include the auto-generated portion of the assembly writer
245 #include "SPUGenAsmWriter.inc"
246
247 void SPUAsmPrinter::printOp(const MachineOperand &MO, raw_ostream &O) {
248   switch (MO.getType()) {
249   case MachineOperand::MO_Immediate:
250     report_fatal_error("printOp() does not handle immediate values");
251     return;
252
253   case MachineOperand::MO_MachineBasicBlock:
254     O << *MO.getMBB()->getSymbol();
255     return;
256   case MachineOperand::MO_JumpTableIndex:
257     O << MAI->getPrivateGlobalPrefix() << "JTI" << getFunctionNumber()
258       << '_' << MO.getIndex();
259     return;
260   case MachineOperand::MO_ConstantPoolIndex:
261     O << MAI->getPrivateGlobalPrefix() << "CPI" << getFunctionNumber()
262       << '_' << MO.getIndex();
263     return;
264   case MachineOperand::MO_ExternalSymbol:
265     // Computing the address of an external symbol, not calling it.
266     if (TM.getRelocationModel() != Reloc::Static) {
267       O << "L" << MAI->getGlobalPrefix() << MO.getSymbolName()
268         << "$non_lazy_ptr";
269       return;
270     }
271     O << *GetExternalSymbolSymbol(MO.getSymbolName());
272     return;
273   case MachineOperand::MO_GlobalAddress:
274     // External or weakly linked global variables need non-lazily-resolved
275     // stubs
276     if (TM.getRelocationModel() != Reloc::Static) {
277       const GlobalValue *GV = MO.getGlobal();
278       if (((GV->isDeclaration() || GV->hasWeakLinkage() ||
279             GV->hasLinkOnceLinkage() || GV->hasCommonLinkage()))) {
280         O << *GetSymbolWithGlobalValueBase(GV, "$non_lazy_ptr");
281         return;
282       }
283     }
284     O << *Mang->getSymbol(MO.getGlobal());
285     return;
286   case MachineOperand::MO_MCSymbol:
287     O << *(MO.getMCSymbol());
288     return;
289   default:
290     O << "<unknown operand type: " << MO.getType() << ">";
291     return;
292   }
293 }
294
295 /// PrintAsmOperand - Print out an operand for an inline asm expression.
296 ///
297 bool SPUAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
298                                     unsigned AsmVariant,
299                                     const char *ExtraCode, raw_ostream &O) {
300   // Does this asm operand have a single letter operand modifier?
301   if (ExtraCode && ExtraCode[0]) {
302     if (ExtraCode[1] != 0) return true; // Unknown modifier.
303
304     switch (ExtraCode[0]) {
305     default: return true;  // Unknown modifier.
306     case 'L': // Write second word of DImode reference.
307       // Verify that this operand has two consecutive registers.
308       if (!MI->getOperand(OpNo).isReg() ||
309           OpNo+1 == MI->getNumOperands() ||
310           !MI->getOperand(OpNo+1).isReg())
311         return true;
312       ++OpNo;   // Return the high-part.
313       break;
314     }
315   }
316
317   printOperand(MI, OpNo, O);
318   return false;
319 }
320
321 bool SPUAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
322                                           unsigned OpNo, unsigned AsmVariant,
323                                           const char *ExtraCode,
324                                           raw_ostream &O) {
325   if (ExtraCode && ExtraCode[0])
326     return true; // Unknown modifier.
327   printMemRegReg(MI, OpNo, O);
328   return false;
329 }
330
331 // Force static initialization.
332 extern "C" void LLVMInitializeCellSPUAsmPrinter() { 
333   RegisterAsmPrinter<SPUAsmPrinter> X(TheCellSPUTarget);
334 }