f67235681b968fc4bd7b46b8b804d4d7809e48ff
[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/Assembly/Writer.h"
23 #include "llvm/CodeGen/AsmPrinter.h"
24 #include "llvm/CodeGen/DwarfWriter.h"
25 #include "llvm/CodeGen/MachineModuleInfo.h"
26 #include "llvm/CodeGen/MachineFunctionPass.h"
27 #include "llvm/CodeGen/MachineInstr.h"
28 #include "llvm/MC/MCStreamer.h"
29 #include "llvm/MC/MCAsmInfo.h"
30 #include "llvm/MC/MCSymbol.h"
31 #include "llvm/Target/TargetLoweringObjectFile.h"
32 #include "llvm/Target/TargetInstrInfo.h"
33 #include "llvm/Target/TargetOptions.h"
34 #include "llvm/Target/TargetRegisterInfo.h"
35 #include "llvm/Target/TargetRegistry.h"
36 #include "llvm/ADT/Statistic.h"
37 #include "llvm/ADT/StringExtras.h"
38 #include "llvm/Support/CommandLine.h"
39 #include "llvm/Support/Debug.h"
40 #include "llvm/Support/ErrorHandling.h"
41 #include "llvm/Support/FormattedStream.h"
42 #include "llvm/Support/MathExtras.h"
43 using namespace llvm;
44
45 namespace {
46   STATISTIC(EmittedInsts, "Number of machine instrs printed");
47
48   const std::string bss_section(".bss");
49
50   class SPUAsmPrinter : public AsmPrinter {
51   public:
52     explicit SPUAsmPrinter(formatted_raw_ostream &O, TargetMachine &TM,
53                            const MCAsmInfo *T, bool V) :
54       AsmPrinter(O, TM, T, V) {}
55
56     virtual const char *getPassName() const {
57       return "STI CBEA SPU Assembly Printer";
58     }
59
60     SPUTargetMachine &getTM() {
61       return static_cast<SPUTargetMachine&>(TM);
62     }
63
64     /// printInstruction - This method is automatically generated by tablegen
65     /// from the instruction set description.
66     void printInstruction(const MachineInstr *MI);
67     static const char *getRegisterName(unsigned RegNo);
68
69
70     void printMachineInstruction(const MachineInstr *MI);
71     void printOp(const MachineOperand &MO);
72
73     /// printRegister - Print register according to target requirements.
74     ///
75     void printRegister(const MachineOperand &MO, bool R0AsZero) {
76       unsigned RegNo = MO.getReg();
77       assert(TargetRegisterInfo::isPhysicalRegister(RegNo) &&
78              "Not physreg??");
79       O << getRegisterName(RegNo);
80     }
81
82     void printOperand(const MachineInstr *MI, unsigned OpNo) {
83       const MachineOperand &MO = MI->getOperand(OpNo);
84       if (MO.isReg()) {
85         O << getRegisterName(MO.getReg());
86       } else if (MO.isImm()) {
87         O << MO.getImm();
88       } else {
89         printOp(MO);
90       }
91     }
92
93     bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
94                          unsigned AsmVariant, const char *ExtraCode);
95     bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
96                                unsigned AsmVariant, const char *ExtraCode);
97
98
99     void
100     printS7ImmOperand(const MachineInstr *MI, unsigned OpNo)
101     {
102       int value = MI->getOperand(OpNo).getImm();
103       value = (value << (32 - 7)) >> (32 - 7);
104
105       assert((value >= -(1 << 8) && value <= (1 << 7) - 1)
106              && "Invalid s7 argument");
107       O << value;
108     }
109
110     void
111     printU7ImmOperand(const MachineInstr *MI, unsigned OpNo)
112     {
113       unsigned int value = MI->getOperand(OpNo).getImm();
114       assert(value < (1 << 8) && "Invalid u7 argument");
115       O << value;
116     }
117
118     void
119     printShufAddr(const MachineInstr *MI, unsigned OpNo)
120     {
121       char value = MI->getOperand(OpNo).getImm();
122       O << (int) value;
123       O << "(";
124       printOperand(MI, OpNo+1);
125       O << ")";
126     }
127
128     void
129     printS16ImmOperand(const MachineInstr *MI, unsigned OpNo)
130     {
131       O << (short) MI->getOperand(OpNo).getImm();
132     }
133
134     void
135     printU16ImmOperand(const MachineInstr *MI, unsigned OpNo)
136     {
137       O << (unsigned short)MI->getOperand(OpNo).getImm();
138     }
139
140     void
141     printU32ImmOperand(const MachineInstr *MI, unsigned OpNo)
142     {
143       O << (unsigned)MI->getOperand(OpNo).getImm();
144     }
145
146     void
147     printMemRegReg(const MachineInstr *MI, unsigned OpNo) {
148       // When used as the base register, r0 reads constant zero rather than
149       // the value contained in the register.  For this reason, the darwin
150       // assembler requires that we print r0 as 0 (no r) when used as the base.
151       const MachineOperand &MO = MI->getOperand(OpNo);
152       O << getRegisterName(MO.getReg()) << ", ";
153       printOperand(MI, OpNo+1);
154     }
155
156     void
157     printU18ImmOperand(const MachineInstr *MI, unsigned OpNo)
158     {
159       unsigned int value = MI->getOperand(OpNo).getImm();
160       assert(value <= (1 << 19) - 1 && "Invalid u18 argument");
161       O << value;
162     }
163
164     void
165     printS10ImmOperand(const MachineInstr *MI, unsigned OpNo)
166     {
167       short value = (short) (((int) MI->getOperand(OpNo).getImm() << 16)
168                              >> 16);
169       assert((value >= -(1 << 9) && value <= (1 << 9) - 1)
170              && "Invalid s10 argument");
171       O << value;
172     }
173
174     void
175     printU10ImmOperand(const MachineInstr *MI, unsigned OpNo)
176     {
177       short value = (short) (((int) MI->getOperand(OpNo).getImm() << 16)
178                              >> 16);
179       assert((value <= (1 << 10) - 1) && "Invalid u10 argument");
180       O << value;
181     }
182
183     void
184     printDFormAddr(const MachineInstr *MI, unsigned OpNo)
185     {
186       assert(MI->getOperand(OpNo).isImm() &&
187              "printDFormAddr first operand is not immediate");
188       int64_t value = int64_t(MI->getOperand(OpNo).getImm());
189       int16_t value16 = int16_t(value);
190       assert((value16 >= -(1 << (9+4)) && value16 <= (1 << (9+4)) - 1)
191              && "Invalid dform s10 offset argument");
192       O << (value16 & ~0xf) << "(";
193       printOperand(MI, OpNo+1);
194       O << ")";
195     }
196
197     void
198     printAddr256K(const MachineInstr *MI, unsigned OpNo)
199     {
200       /* Note: operand 1 is an offset or symbol name. */
201       if (MI->getOperand(OpNo).isImm()) {
202         printS16ImmOperand(MI, OpNo);
203       } else {
204         printOp(MI->getOperand(OpNo));
205         if (MI->getOperand(OpNo+1).isImm()) {
206           int displ = int(MI->getOperand(OpNo+1).getImm());
207           if (displ > 0)
208             O << "+" << displ;
209           else if (displ < 0)
210             O << displ;
211         }
212       }
213     }
214
215     void printCallOperand(const MachineInstr *MI, unsigned OpNo) {
216       printOp(MI->getOperand(OpNo));
217     }
218
219     void printPCRelativeOperand(const MachineInstr *MI, unsigned OpNo) {
220       // Used to generate a ".-<target>", but it turns out that the assembler
221       // really wants the target.
222       //
223       // N.B.: This operand is used for call targets. Branch hints are another
224       // animal entirely.
225       printOp(MI->getOperand(OpNo));
226     }
227
228     void printHBROperand(const MachineInstr *MI, unsigned OpNo) {
229       // HBR operands are generated in front of branches, hence, the
230       // program counter plus the target.
231       O << ".+";
232       printOp(MI->getOperand(OpNo));
233     }
234
235     void printSymbolHi(const MachineInstr *MI, unsigned OpNo) {
236       if (MI->getOperand(OpNo).isImm()) {
237         printS16ImmOperand(MI, OpNo);
238       } else {
239         printOp(MI->getOperand(OpNo));
240         O << "@h";
241       }
242     }
243
244     void printSymbolLo(const MachineInstr *MI, unsigned OpNo) {
245       if (MI->getOperand(OpNo).isImm()) {
246         printS16ImmOperand(MI, OpNo);
247       } else {
248         printOp(MI->getOperand(OpNo));
249         O << "@l";
250       }
251     }
252
253     /// Print local store address
254     void printSymbolLSA(const MachineInstr *MI, unsigned OpNo) {
255       printOp(MI->getOperand(OpNo));
256     }
257
258     void printROTHNeg7Imm(const MachineInstr *MI, unsigned OpNo) {
259       if (MI->getOperand(OpNo).isImm()) {
260         int value = (int) MI->getOperand(OpNo).getImm();
261         assert((value >= 0 && value < 16)
262                && "Invalid negated immediate rotate 7-bit argument");
263         O << -value;
264       } else {
265         llvm_unreachable("Invalid/non-immediate rotate amount in printRotateNeg7Imm");
266       }
267     }
268
269     void printROTNeg7Imm(const MachineInstr *MI, unsigned OpNo) {
270       if (MI->getOperand(OpNo).isImm()) {
271         int value = (int) MI->getOperand(OpNo).getImm();
272         assert((value >= 0 && value <= 32)
273                && "Invalid negated immediate rotate 7-bit argument");
274         O << -value;
275       } else {
276         llvm_unreachable("Invalid/non-immediate rotate amount in printRotateNeg7Imm");
277       }
278     }
279
280     virtual bool runOnMachineFunction(MachineFunction &F) = 0;
281   };
282
283   /// LinuxAsmPrinter - SPU assembly printer, customized for Linux
284   class LinuxAsmPrinter : public SPUAsmPrinter {
285   public:
286     explicit LinuxAsmPrinter(formatted_raw_ostream &O, TargetMachine &TM,
287                              const MCAsmInfo *T, bool V)
288       : SPUAsmPrinter(O, TM, T, V) {}
289
290     virtual const char *getPassName() const {
291       return "STI CBEA SPU Assembly Printer";
292     }
293
294     bool runOnMachineFunction(MachineFunction &F);
295
296     void getAnalysisUsage(AnalysisUsage &AU) const {
297       AU.setPreservesAll();
298       AU.addRequired<MachineModuleInfo>();
299       AU.addRequired<DwarfWriter>();
300       SPUAsmPrinter::getAnalysisUsage(AU);
301     }
302
303     //! Emit a global variable according to its section and type
304     void PrintGlobalVariable(const GlobalVariable* GVar);
305   };
306 } // end of anonymous namespace
307
308 // Include the auto-generated portion of the assembly writer
309 #include "SPUGenAsmWriter.inc"
310
311 void SPUAsmPrinter::printOp(const MachineOperand &MO) {
312   switch (MO.getType()) {
313   case MachineOperand::MO_Immediate:
314     llvm_report_error("printOp() does not handle immediate values");
315     return;
316
317   case MachineOperand::MO_MachineBasicBlock:
318     GetMBBSymbol(MO.getMBB()->getNumber())->print(O, MAI);
319     return;
320   case MachineOperand::MO_JumpTableIndex:
321     O << MAI->getPrivateGlobalPrefix() << "JTI" << getFunctionNumber()
322       << '_' << MO.getIndex();
323     return;
324   case MachineOperand::MO_ConstantPoolIndex:
325     O << MAI->getPrivateGlobalPrefix() << "CPI" << getFunctionNumber()
326       << '_' << MO.getIndex();
327     return;
328   case MachineOperand::MO_ExternalSymbol:
329     // Computing the address of an external symbol, not calling it.
330     if (TM.getRelocationModel() != Reloc::Static) {
331       O << "L" << MAI->getGlobalPrefix() << MO.getSymbolName()
332         << "$non_lazy_ptr";
333       return;
334     }
335     GetExternalSymbolSymbol(MO.getSymbolName())->print(O, MAI);
336     return;
337   case MachineOperand::MO_GlobalAddress:
338     // External or weakly linked global variables need non-lazily-resolved
339     // stubs
340     if (TM.getRelocationModel() != Reloc::Static) {
341       GlobalValue *GV = MO.getGlobal();
342       if (((GV->isDeclaration() || GV->hasWeakLinkage() ||
343             GV->hasLinkOnceLinkage() || GV->hasCommonLinkage()))) {
344         GetPrivateGlobalValueSymbolStub(GV, "$non_lazy_ptr")->print(O, MAI);
345         return;
346       }
347     }
348     GetGlobalValueSymbol(MO.getGlobal())->print(O, MAI);
349     return;
350   default:
351     O << "<unknown operand type: " << MO.getType() << ">";
352     return;
353   }
354 }
355
356 /// PrintAsmOperand - Print out an operand for an inline asm expression.
357 ///
358 bool SPUAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
359                                     unsigned AsmVariant,
360                                     const char *ExtraCode) {
361   // Does this asm operand have a single letter operand modifier?
362   if (ExtraCode && ExtraCode[0]) {
363     if (ExtraCode[1] != 0) return true; // Unknown modifier.
364
365     switch (ExtraCode[0]) {
366     default: return true;  // Unknown modifier.
367     case 'L': // Write second word of DImode reference.
368       // Verify that this operand has two consecutive registers.
369       if (!MI->getOperand(OpNo).isReg() ||
370           OpNo+1 == MI->getNumOperands() ||
371           !MI->getOperand(OpNo+1).isReg())
372         return true;
373       ++OpNo;   // Return the high-part.
374       break;
375     }
376   }
377
378   printOperand(MI, OpNo);
379   return false;
380 }
381
382 bool SPUAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
383                                           unsigned OpNo,
384                                           unsigned AsmVariant,
385                                           const char *ExtraCode) {
386   if (ExtraCode && ExtraCode[0])
387     return true; // Unknown modifier.
388   printMemRegReg(MI, OpNo);
389   return false;
390 }
391
392 /// printMachineInstruction -- Print out a single PowerPC MI in Darwin syntax
393 /// to the current output stream.
394 ///
395 void SPUAsmPrinter::printMachineInstruction(const MachineInstr *MI) {
396   ++EmittedInsts;
397   processDebugLoc(MI, true);
398   printInstruction(MI);
399   if (VerboseAsm)
400     EmitComments(*MI);
401   processDebugLoc(MI, false);
402   O << '\n';
403 }
404
405 /// runOnMachineFunction - This uses the printMachineInstruction()
406 /// method to print assembly for each instruction.
407 ///
408 bool LinuxAsmPrinter::runOnMachineFunction(MachineFunction &MF) {
409   this->MF = &MF;
410
411   SetupMachineFunction(MF);
412   O << "\n\n";
413
414   // Print out constants referenced by the function
415   EmitConstantPool(MF.getConstantPool());
416
417   // Print out labels for the function.
418   const Function *F = MF.getFunction();
419
420   OutStreamer.SwitchSection(getObjFileLowering().SectionForGlobal(F, Mang, TM));
421   EmitAlignment(MF.getAlignment(), F);
422
423   switch (F->getLinkage()) {
424   default: llvm_unreachable("Unknown linkage type!");
425   case Function::PrivateLinkage:
426   case Function::LinkerPrivateLinkage:
427   case Function::InternalLinkage:  // Symbols default to internal.
428     break;
429   case Function::ExternalLinkage:
430     O << "\t.global\t";
431     CurrentFnSym->print(O, MAI);
432     O << "\n" << "\t.type\t";
433     CurrentFnSym->print(O, MAI);
434     O << ", @function\n";
435     break;
436   case Function::WeakAnyLinkage:
437   case Function::WeakODRLinkage:
438   case Function::LinkOnceAnyLinkage:
439   case Function::LinkOnceODRLinkage:
440     O << "\t.global\t";
441     CurrentFnSym->print(O, MAI);
442     O << "\n";
443     O << "\t.weak_definition\t";
444     CurrentFnSym->print(O, MAI);
445     O << "\n";
446     break;
447   }
448   
449   CurrentFnSym->print(O, MAI);
450   O << ":\n";
451
452   // Emit pre-function debug information.
453   DW->BeginFunction(&MF);
454
455   // Print out code for the function.
456   for (MachineFunction::const_iterator I = MF.begin(), E = MF.end();
457        I != E; ++I) {
458     // Print a label for the basic block.
459     if (I != MF.begin()) {
460       EmitBasicBlockStart(I);
461     }
462     for (MachineBasicBlock::const_iterator II = I->begin(), E = I->end();
463          II != E; ++II) {
464       // Print the assembly for the instruction.
465       printMachineInstruction(II);
466     }
467   }
468
469   O << "\t.size\t";
470   CurrentFnSym->print(O, MAI);
471   O << ",.-";
472   CurrentFnSym->print(O, MAI);
473   O << "\n";
474
475   // Print out jump tables referenced by the function.
476   EmitJumpTableInfo(MF.getJumpTableInfo(), MF);
477
478   // Emit post-function debug information.
479   DW->EndFunction(&MF);
480
481   // We didn't modify anything.
482   return false;
483 }
484
485
486 /*!
487   Emit a global variable according to its section, alignment, etc.
488
489   \note This code was shamelessly copied from the PowerPC's assembly printer,
490   which sort of screams for some kind of refactorization of common code.
491  */
492 void LinuxAsmPrinter::PrintGlobalVariable(const GlobalVariable *GVar) {
493   const TargetData *TD = TM.getTargetData();
494
495   if (!GVar->hasInitializer())
496     return;
497
498   // Check to see if this is a special global used by LLVM, if so, emit it.
499   if (EmitSpecialLLVMGlobal(GVar))
500     return;
501
502   MCSymbol *GVarSym = GetGlobalValueSymbol(GVar);
503
504   printVisibility(GVarSym, GVar->getVisibility());
505
506   Constant *C = GVar->getInitializer();
507   const Type *Type = C->getType();
508   unsigned Size = TD->getTypeAllocSize(Type);
509   unsigned Align = TD->getPreferredAlignmentLog(GVar);
510
511   OutStreamer.SwitchSection(getObjFileLowering().SectionForGlobal(GVar, Mang,
512                                                                   TM));
513
514   if (C->isNullValue() && /* FIXME: Verify correct */
515       !GVar->hasSection() &&
516       (GVar->hasLocalLinkage() || GVar->hasExternalLinkage() ||
517        GVar->isWeakForLinker())) {
518       if (Size == 0) Size = 1;   // .comm Foo, 0 is undefined, avoid it.
519
520       if (GVar->hasExternalLinkage()) {
521         O << "\t.global ";
522         GVarSym->print(O, MAI);
523         O << '\n';
524         O << "\t.type ";
525         GVarSym->print(O, MAI);
526         O << ", @object\n";
527         GVarSym->print(O, MAI);
528         O << ":\n";
529         O << "\t.zero " << Size << '\n';
530       } else if (GVar->hasLocalLinkage()) {
531         O << MAI->getLCOMMDirective();
532         GVarSym->print(O, MAI);
533         O << ',' << Size;
534       } else {
535         O << ".comm ";
536         GVarSym->print(O, MAI);
537         O << ',' << Size;
538       }
539       O << "\t\t" << MAI->getCommentString() << " '";
540       WriteAsOperand(O, GVar, /*PrintType=*/false, GVar->getParent());
541       O << "'\n";
542       return;
543   }
544
545   switch (GVar->getLinkage()) {
546   // Should never be seen for the CellSPU platform...
547   case GlobalValue::LinkOnceAnyLinkage:
548   case GlobalValue::LinkOnceODRLinkage:
549   case GlobalValue::WeakAnyLinkage:
550   case GlobalValue::WeakODRLinkage:
551   case GlobalValue::CommonLinkage:
552     O << "\t.global ";
553     GVarSym->print(O, MAI);
554     O << "\n\t.type ";
555     GVarSym->print(O, MAI);
556     O << ", @object\n" << "\t.weak ";
557     GVarSym->print(O, MAI);
558     O << '\n';
559     break;
560   case GlobalValue::AppendingLinkage:
561     // FIXME: appending linkage variables should go into a section of
562     // their name or something.  For now, just emit them as external.
563   case GlobalValue::ExternalLinkage:
564     // If external or appending, declare as a global symbol
565     O << "\t.global ";
566     GVarSym->print(O, MAI);
567     O << "\n\t.type ";
568     GVarSym->print(O, MAI);
569     O << ", @object\n";
570     break;
571   case GlobalValue::PrivateLinkage:
572   case GlobalValue::LinkerPrivateLinkage:
573   case GlobalValue::InternalLinkage:
574     break;
575   default:
576     llvm_report_error("Unknown linkage type!");
577   }
578
579   EmitAlignment(Align, GVar);
580   GVarSym->print(O, MAI);
581   O << ":\t\t\t\t" << MAI->getCommentString() << " '";
582   WriteAsOperand(O, GVar, /*PrintType=*/false, GVar->getParent());
583   O << "'\n";
584
585   EmitGlobalConstant(C);
586   O << '\n';
587 }
588
589 // Force static initialization.
590 extern "C" void LLVMInitializeCellSPUAsmPrinter() { 
591   RegisterAsmPrinter<LinuxAsmPrinter> X(TheCellSPUTarget);
592 }