Massive check in. This changes the "-fast" flag to "-O#" in llc. If you want to
[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/Support/Mangler.h"
29 #include "llvm/Support/MathExtras.h"
30 #include "llvm/Support/CommandLine.h"
31 #include "llvm/Support/Debug.h"
32 #include "llvm/Support/Compiler.h"
33 #include "llvm/Support/raw_ostream.h"
34 #include "llvm/Target/TargetAsmInfo.h"
35 #include "llvm/Target/TargetRegisterInfo.h"
36 #include "llvm/Target/TargetInstrInfo.h"
37 #include "llvm/Target/TargetOptions.h"
38 #include "llvm/ADT/Statistic.h"
39 #include "llvm/ADT/StringExtras.h"
40 #include <set>
41 using namespace llvm;
42
43 namespace {
44   STATISTIC(EmittedInsts, "Number of machine instrs printed");
45
46   const std::string bss_section(".bss");
47
48   class VISIBILITY_HIDDEN SPUAsmPrinter : public AsmPrinter {
49     std::set<std::string> FnStubs, GVStubs;
50   public:
51     explicit SPUAsmPrinter(raw_ostream &O, TargetMachine &TM,
52                            const TargetAsmInfo *T, unsigned OL, bool V) :
53       AsmPrinter(O, TM, T, OL, V) {}
54
55     virtual const char *getPassName() const {
56       return "STI CBEA SPU Assembly Printer";
57     }
58
59     SPUTargetMachine &getTM() {
60       return static_cast<SPUTargetMachine&>(TM);
61     }
62
63     /// printInstruction - This method is automatically generated by tablegen
64     /// from the instruction set description.  This method returns true if the
65     /// machine instruction was sufficiently described to print it, otherwise it
66     /// returns false.
67     bool printInstruction(const MachineInstr *MI);
68
69     void printMachineInstruction(const MachineInstr *MI);
70     void printOp(const MachineOperand &MO);
71
72     /// printRegister - Print register according to target requirements.
73     ///
74     void printRegister(const MachineOperand &MO, bool R0AsZero) {
75       unsigned RegNo = MO.getReg();
76       assert(TargetRegisterInfo::isPhysicalRegister(RegNo) &&
77              "Not physreg??");
78       O << TM.getRegisterInfo()->get(RegNo).AsmName;
79     }
80
81     void printOperand(const MachineInstr *MI, unsigned OpNo) {
82       const MachineOperand &MO = MI->getOperand(OpNo);
83       if (MO.isReg()) {
84         assert(TargetRegisterInfo::isPhysicalRegister(MO.getReg())&&"Not physreg??");
85         O << TM.getRegisterInfo()->get(MO.getReg()).AsmName;
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 << TM.getRegisterInfo()->get(MO.getReg()).AsmName;
153       O << ", ";
154       printOperand(MI, OpNo+1);
155     }
156
157     void
158     printU18ImmOperand(const MachineInstr *MI, unsigned OpNo)
159     {
160       unsigned int value = MI->getOperand(OpNo).getImm();
161       assert(value <= (1 << 19) - 1 && "Invalid u18 argument");
162       O << value;
163     }
164
165     void
166     printS10ImmOperand(const MachineInstr *MI, unsigned OpNo)
167     {
168       short value = (short) (((int) MI->getOperand(OpNo).getImm() << 16)
169                              >> 16);
170       assert((value >= -(1 << 9) && value <= (1 << 9) - 1)
171              && "Invalid s10 argument");
172       O << value;
173     }
174
175     void
176     printU10ImmOperand(const MachineInstr *MI, unsigned OpNo)
177     {
178       short value = (short) (((int) MI->getOperand(OpNo).getImm() << 16)
179                              >> 16);
180       assert((value <= (1 << 10) - 1) && "Invalid u10 argument");
181       O << value;
182     }
183
184     void
185     printDFormAddr(const MachineInstr *MI, unsigned OpNo)
186     {
187       assert(MI->getOperand(OpNo).isImm() &&
188              "printDFormAddr first operand is not immediate");
189       int64_t value = int64_t(MI->getOperand(OpNo).getImm());
190       int16_t value16 = int16_t(value);
191       assert((value16 >= -(1 << (9+4)) && value16 <= (1 << (9+4)) - 1)
192              && "Invalid dform s10 offset argument");
193       O << (value16 & ~0xf) << "(";
194       printOperand(MI, OpNo+1);
195       O << ")";
196     }
197
198     void
199     printAddr256K(const MachineInstr *MI, unsigned OpNo)
200     {
201       /* Note: operand 1 is an offset or symbol name. */
202       if (MI->getOperand(OpNo).isImm()) {
203         printS16ImmOperand(MI, OpNo);
204       } else {
205         printOp(MI->getOperand(OpNo));
206         if (MI->getOperand(OpNo+1).isImm()) {
207           int displ = int(MI->getOperand(OpNo+1).getImm());
208           if (displ > 0)
209             O << "+" << displ;
210           else if (displ < 0)
211             O << displ;
212         }
213       }
214     }
215
216     void printCallOperand(const MachineInstr *MI, unsigned OpNo) {
217       printOp(MI->getOperand(OpNo));
218     }
219
220     void printPCRelativeOperand(const MachineInstr *MI, unsigned OpNo) {
221       // Used to generate a ".-<target>", but it turns out that the assembler
222       // really wants the target.
223       //
224       // N.B.: This operand is used for call targets. Branch hints are another
225       // animal entirely.
226       printOp(MI->getOperand(OpNo));
227     }
228
229     void printHBROperand(const MachineInstr *MI, unsigned OpNo) {
230       // HBR operands are generated in front of branches, hence, the
231       // program counter plus the target.
232       O << ".+";
233       printOp(MI->getOperand(OpNo));
234     }
235
236     void printSymbolHi(const MachineInstr *MI, unsigned OpNo) {
237       if (MI->getOperand(OpNo).isImm()) {
238         printS16ImmOperand(MI, OpNo);
239       } else {
240         printOp(MI->getOperand(OpNo));
241         O << "@h";
242       }
243     }
244
245     void printSymbolLo(const MachineInstr *MI, unsigned OpNo) {
246       if (MI->getOperand(OpNo).isImm()) {
247         printS16ImmOperand(MI, OpNo);
248       } else {
249         printOp(MI->getOperand(OpNo));
250         O << "@l";
251       }
252     }
253
254     /// Print local store address
255     void printSymbolLSA(const MachineInstr *MI, unsigned OpNo) {
256       printOp(MI->getOperand(OpNo));
257     }
258
259     void printROTHNeg7Imm(const MachineInstr *MI, unsigned OpNo) {
260       if (MI->getOperand(OpNo).isImm()) {
261         int value = (int) MI->getOperand(OpNo).getImm();
262         assert((value >= 0 && value < 16)
263                && "Invalid negated immediate rotate 7-bit argument");
264         O << -value;
265       } else {
266         assert(0 &&"Invalid/non-immediate rotate amount in printRotateNeg7Imm");
267       }
268     }
269
270     void printROTNeg7Imm(const MachineInstr *MI, unsigned OpNo) {
271       if (MI->getOperand(OpNo).isImm()) {
272         int value = (int) MI->getOperand(OpNo).getImm();
273         assert((value >= 0 && value <= 32)
274                && "Invalid negated immediate rotate 7-bit argument");
275         O << -value;
276       } else {
277         assert(0 &&"Invalid/non-immediate rotate amount in printRotateNeg7Imm");
278       }
279     }
280
281     virtual bool runOnMachineFunction(MachineFunction &F) = 0;
282     //! Assembly printer cleanup after function has been emitted
283     virtual bool doFinalization(Module &M) = 0;
284   };
285
286   /// LinuxAsmPrinter - SPU assembly printer, customized for Linux
287   class VISIBILITY_HIDDEN LinuxAsmPrinter : public SPUAsmPrinter {
288     DwarfWriter *DW;
289     MachineModuleInfo *MMI;
290   public:
291     LinuxAsmPrinter(raw_ostream &O, SPUTargetMachine &TM,
292                     const TargetAsmInfo *T, bool F, bool V)
293       : SPUAsmPrinter(O, TM, T, F, V), DW(0), MMI(0) {}
294
295     virtual const char *getPassName() const {
296       return "STI CBEA SPU Assembly Printer";
297     }
298
299     bool runOnMachineFunction(MachineFunction &F);
300     bool doInitialization(Module &M);
301     //! Dump globals, perform cleanup after function emission
302     bool doFinalization(Module &M);
303
304     void getAnalysisUsage(AnalysisUsage &AU) const {
305       AU.setPreservesAll();
306       AU.addRequired<MachineModuleInfo>();
307       AU.addRequired<DwarfWriter>();
308       SPUAsmPrinter::getAnalysisUsage(AU);
309     }
310
311     //! Emit a global variable according to its section and type
312     void printModuleLevelGV(const GlobalVariable* GVar);
313   };
314 } // end of anonymous namespace
315
316 // Include the auto-generated portion of the assembly writer
317 #include "SPUGenAsmWriter.inc"
318
319 void SPUAsmPrinter::printOp(const MachineOperand &MO) {
320   switch (MO.getType()) {
321   case MachineOperand::MO_Immediate:
322     cerr << "printOp() does not handle immediate values\n";
323     abort();
324     return;
325
326   case MachineOperand::MO_MachineBasicBlock:
327     printBasicBlockLabel(MO.getMBB());
328     return;
329   case MachineOperand::MO_JumpTableIndex:
330     O << TAI->getPrivateGlobalPrefix() << "JTI" << getFunctionNumber()
331       << '_' << MO.getIndex();
332     return;
333   case MachineOperand::MO_ConstantPoolIndex:
334     O << TAI->getPrivateGlobalPrefix() << "CPI" << getFunctionNumber()
335       << '_' << MO.getIndex();
336     return;
337   case MachineOperand::MO_ExternalSymbol:
338     // Computing the address of an external symbol, not calling it.
339     if (TM.getRelocationModel() != Reloc::Static) {
340       std::string Name(TAI->getGlobalPrefix()); Name += MO.getSymbolName();
341       GVStubs.insert(Name);
342       O << "L" << Name << "$non_lazy_ptr";
343       return;
344     }
345     O << TAI->getGlobalPrefix() << MO.getSymbolName();
346     return;
347   case MachineOperand::MO_GlobalAddress: {
348     // Computing the address of a global symbol, not calling it.
349     GlobalValue *GV = MO.getGlobal();
350     std::string Name = Mang->getValueName(GV);
351
352     // External or weakly linked global variables need non-lazily-resolved
353     // stubs
354     if (TM.getRelocationModel() != Reloc::Static) {
355       if (((GV->isDeclaration() || GV->hasWeakLinkage() ||
356             GV->hasLinkOnceLinkage() || GV->hasCommonLinkage()))) {
357         GVStubs.insert(Name);
358         O << "L" << Name << "$non_lazy_ptr";
359         return;
360       }
361     }
362     O << Name;
363
364     if (GV->hasExternalWeakLinkage())
365       ExtWeakSymbols.insert(GV);
366     return;
367   }
368
369   default:
370     O << "<unknown operand type: " << MO.getType() << ">";
371     return;
372   }
373 }
374
375 /// PrintAsmOperand - Print out an operand for an inline asm expression.
376 ///
377 bool SPUAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
378                                     unsigned AsmVariant,
379                                     const char *ExtraCode) {
380   // Does this asm operand have a single letter operand modifier?
381   if (ExtraCode && ExtraCode[0]) {
382     if (ExtraCode[1] != 0) return true; // Unknown modifier.
383
384     switch (ExtraCode[0]) {
385     default: return true;  // Unknown modifier.
386     case 'L': // Write second word of DImode reference.
387       // Verify that this operand has two consecutive registers.
388       if (!MI->getOperand(OpNo).isReg() ||
389           OpNo+1 == MI->getNumOperands() ||
390           !MI->getOperand(OpNo+1).isReg())
391         return true;
392       ++OpNo;   // Return the high-part.
393       break;
394     }
395   }
396
397   printOperand(MI, OpNo);
398   return false;
399 }
400
401 bool SPUAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
402                                           unsigned OpNo,
403                                           unsigned AsmVariant,
404                                           const char *ExtraCode) {
405   if (ExtraCode && ExtraCode[0])
406     return true; // Unknown modifier.
407   printMemRegReg(MI, OpNo);
408   return false;
409 }
410
411 /// printMachineInstruction -- Print out a single PowerPC MI in Darwin syntax
412 /// to the current output stream.
413 ///
414 void SPUAsmPrinter::printMachineInstruction(const MachineInstr *MI) {
415   ++EmittedInsts;
416   printInstruction(MI);
417 }
418
419 /// runOnMachineFunction - This uses the printMachineInstruction()
420 /// method to print assembly for each instruction.
421 ///
422 bool
423 LinuxAsmPrinter::runOnMachineFunction(MachineFunction &MF)
424 {
425   this->MF = &MF;
426
427   SetupMachineFunction(MF);
428   O << "\n\n";
429
430   // Print out constants referenced by the function
431   EmitConstantPool(MF.getConstantPool());
432
433   // Print out labels for the function.
434   const Function *F = MF.getFunction();
435
436   SwitchToSection(TAI->SectionForGlobal(F));
437   EmitAlignment(3, F);
438
439   switch (F->getLinkage()) {
440   default: assert(0 && "Unknown linkage type!");
441   case Function::PrivateLinkage:
442   case Function::InternalLinkage:  // Symbols default to internal.
443     break;
444   case Function::ExternalLinkage:
445     O << "\t.global\t" << CurrentFnName << "\n"
446       << "\t.type\t" << CurrentFnName << ", @function\n";
447     break;
448   case Function::WeakAnyLinkage:
449   case Function::WeakODRLinkage:
450   case Function::LinkOnceAnyLinkage:
451   case Function::LinkOnceODRLinkage:
452     O << "\t.global\t" << CurrentFnName << "\n";
453     O << "\t.weak_definition\t" << CurrentFnName << "\n";
454     break;
455   }
456   O << CurrentFnName << ":\n";
457
458   // Emit pre-function debug information.
459   DW->BeginFunction(&MF);
460
461   // Print out code for the function.
462   for (MachineFunction::const_iterator I = MF.begin(), E = MF.end();
463        I != E; ++I) {
464     // Print a label for the basic block.
465     if (I != MF.begin()) {
466       printBasicBlockLabel(I, true, true);
467       O << '\n';
468     }
469     for (MachineBasicBlock::const_iterator II = I->begin(), E = I->end();
470          II != E; ++II) {
471       // Print the assembly for the instruction.
472       printMachineInstruction(II);
473     }
474   }
475
476   O << "\t.size\t" << CurrentFnName << ",.-" << CurrentFnName << "\n";
477
478   // Print out jump tables referenced by the function.
479   EmitJumpTableInfo(MF.getJumpTableInfo(), MF);
480
481   // Emit post-function debug information.
482   DW->EndFunction(&MF);
483
484   // We didn't modify anything.
485   return false;
486 }
487
488
489 bool LinuxAsmPrinter::doInitialization(Module &M) {
490   bool Result = AsmPrinter::doInitialization(M);
491   SwitchToTextSection("\t.text");
492   // Emit initial debug information.
493   DW = getAnalysisIfAvailable<DwarfWriter>();
494   assert(DW && "Dwarf Writer is not available");
495   MMI = getAnalysisIfAvailable<MachineModuleInfo>();
496   DW->BeginModule(&M, MMI, O, this, TAI);
497   return Result;
498 }
499
500 /// PrintUnmangledNameSafely - Print out the printable characters in the name.
501 /// Don't print things like \\n or \\0.
502 static void PrintUnmangledNameSafely(const Value *V, raw_ostream &OS) {
503   for (const char *Name = V->getNameStart(), *E = Name+V->getNameLen();
504        Name != E; ++Name)
505     if (isprint(*Name))
506       OS << *Name;
507 }
508
509 /*!
510   Emit a global variable according to its section, alignment, etc.
511
512   \note This code was shamelessly copied from the PowerPC's assembly printer,
513   which sort of screams for some kind of refactorization of common code.
514  */
515 void LinuxAsmPrinter::printModuleLevelGV(const GlobalVariable* GVar) {
516   const TargetData *TD = TM.getTargetData();
517
518   if (!GVar->hasInitializer())
519     return;
520
521   // Check to see if this is a special global used by LLVM, if so, emit it.
522   if (EmitSpecialLLVMGlobal(GVar))
523     return;
524
525   std::string name = Mang->getValueName(GVar);
526
527   printVisibility(name, GVar->getVisibility());
528
529   Constant *C = GVar->getInitializer();
530   const Type *Type = C->getType();
531   unsigned Size = TD->getTypePaddedSize(Type);
532   unsigned Align = TD->getPreferredAlignmentLog(GVar);
533
534   SwitchToSection(TAI->SectionForGlobal(GVar));
535
536   if (C->isNullValue() && /* FIXME: Verify correct */
537       !GVar->hasSection() &&
538       (GVar->hasLocalLinkage() || GVar->hasExternalLinkage() ||
539        GVar->isWeakForLinker())) {
540       if (Size == 0) Size = 1;   // .comm Foo, 0 is undefined, avoid it.
541
542       if (GVar->hasExternalLinkage()) {
543         O << "\t.global " << name << '\n';
544         O << "\t.type " << name << ", @object\n";
545         O << name << ":\n";
546         O << "\t.zero " << Size << '\n';
547       } else if (GVar->hasLocalLinkage()) {
548         O << TAI->getLCOMMDirective() << name << ',' << Size;
549       } else {
550         O << ".comm " << name << ',' << Size;
551       }
552       O << "\t\t" << TAI->getCommentString() << " '";
553       PrintUnmangledNameSafely(GVar, O);
554       O << "'\n";
555       return;
556   }
557
558   switch (GVar->getLinkage()) {
559     // Should never be seen for the CellSPU platform...
560    case GlobalValue::LinkOnceAnyLinkage:
561    case GlobalValue::LinkOnceODRLinkage:
562    case GlobalValue::WeakAnyLinkage:
563    case GlobalValue::WeakODRLinkage:
564    case GlobalValue::CommonLinkage:
565     O << "\t.global " << name << '\n'
566       << "\t.type " << name << ", @object\n"
567       << "\t.weak " << name << '\n';
568     break;
569    case GlobalValue::AppendingLinkage:
570     // FIXME: appending linkage variables should go into a section of
571     // their name or something.  For now, just emit them as external.
572    case GlobalValue::ExternalLinkage:
573     // If external or appending, declare as a global symbol
574     O << "\t.global " << name << '\n'
575       << "\t.type " << name << ", @object\n";
576     // FALL THROUGH
577    case GlobalValue::PrivateLinkage:
578    case GlobalValue::InternalLinkage:
579     break;
580    default:
581     cerr << "Unknown linkage type!";
582     abort();
583   }
584
585   EmitAlignment(Align, GVar);
586   O << name << ":\t\t\t\t" << TAI->getCommentString() << " '";
587   PrintUnmangledNameSafely(GVar, O);
588   O << "'\n";
589
590   // If the initializer is a extern weak symbol, remember to emit the weak
591   // reference!
592   if (const GlobalValue *GV = dyn_cast<GlobalValue>(C))
593     if (GV->hasExternalWeakLinkage())
594       ExtWeakSymbols.insert(GV);
595
596   EmitGlobalConstant(C);
597   O << '\n';
598 }
599
600 bool LinuxAsmPrinter::doFinalization(Module &M) {
601   // Print out module-level global variables here.
602   for (Module::const_global_iterator I = M.global_begin(), E = M.global_end();
603        I != E; ++I)
604     printModuleLevelGV(I);
605
606   // Emit initial debug information.
607   DW->EndModule();
608
609   return AsmPrinter::doFinalization(M);
610 }
611
612 /// createSPUCodePrinterPass - Returns a pass that prints the Cell SPU
613 /// assembly code for a MachineFunction to the given output stream, in a format
614 /// that the Linux SPU assembler can deal with.
615 ///
616 FunctionPass *llvm::createSPUAsmPrinterPass(raw_ostream &o,
617                                             SPUTargetMachine &tm,
618                                             unsigned OptLevel, bool verbose) {
619   return new LinuxAsmPrinter(o, tm, tm.getTargetAsmInfo(), OptLevel, verbose);
620 }