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