There are two reasons why we might want to use
[oota-llvm.git] / lib / Target / PTX / PTXMCAsmStreamer.cpp
1 //===- lib/Target/PTX/PTXMCAsmStreamer.cpp - PTX Text Assembly Output -----===//
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 #include "llvm/ADT/OwningPtr.h"
11 #include "llvm/ADT/SmallString.h"
12 #include "llvm/ADT/Twine.h"
13 #include "llvm/MC/MCAsmInfo.h"
14 #include "llvm/MC/MCContext.h"
15 #include "llvm/MC/MCCodeEmitter.h"
16 #include "llvm/MC/MCExpr.h"
17 #include "llvm/MC/MCInst.h"
18 #include "llvm/MC/MCInstPrinter.h"
19 #include "llvm/MC/MCStreamer.h"
20 #include "llvm/MC/MCSymbol.h"
21 #include "llvm/Support/ErrorHandling.h"
22 #include "llvm/Support/MathExtras.h"
23 #include "llvm/Support/Format.h"
24 #include "llvm/Support/FormattedStream.h"
25 #include "llvm/Support/raw_ostream.h"
26
27 using namespace llvm;
28
29 namespace {
30 class PTXMCAsmStreamer : public MCStreamer {
31   formatted_raw_ostream &OS;
32   const MCAsmInfo &MAI;
33   OwningPtr<MCInstPrinter> InstPrinter;
34   OwningPtr<MCCodeEmitter> Emitter;
35
36   SmallString<128> CommentToEmit;
37   raw_svector_ostream CommentStream;
38
39   unsigned IsLittleEndian : 1;
40   unsigned IsVerboseAsm : 1;
41   unsigned ShowInst : 1;
42
43 public:
44   PTXMCAsmStreamer(MCContext &Context,
45                    formatted_raw_ostream &os,
46                    bool isLittleEndian,
47                    bool isVerboseAsm,
48                    MCInstPrinter *printer,
49                    MCCodeEmitter *emitter,
50                    bool showInst)
51     : MCStreamer(Context), OS(os), MAI(Context.getAsmInfo()),
52       InstPrinter(printer), Emitter(emitter), CommentStream(CommentToEmit),
53       IsLittleEndian(isLittleEndian), IsVerboseAsm(isVerboseAsm),
54       ShowInst(showInst) {
55     if (InstPrinter && IsVerboseAsm)
56       InstPrinter->setCommentStream(CommentStream);
57   }
58
59   ~PTXMCAsmStreamer() {}
60
61   bool isLittleEndian() const { return IsLittleEndian; }
62
63   inline void EmitEOL() {
64     // If we don't have any comments, just emit a \n.
65     if (!IsVerboseAsm) {
66       OS << '\n';
67       return;
68     }
69     EmitCommentsAndEOL();
70   }
71   void EmitCommentsAndEOL();
72
73   /// isVerboseAsm - Return true if this streamer supports verbose assembly at
74   /// all.
75   virtual bool isVerboseAsm() const { return IsVerboseAsm; }
76
77   /// hasRawTextSupport - We support EmitRawText.
78   virtual bool hasRawTextSupport() const { return true; }
79
80   /// AddComment - Add a comment that can be emitted to the generated .s
81   /// file if applicable as a QoI issue to make the output of the compiler
82   /// more readable.  This only affects the MCAsmStreamer, and only when
83   /// verbose assembly output is enabled.
84   virtual void AddComment(const Twine &T);
85
86   /// AddEncodingComment - Add a comment showing the encoding of an instruction.
87   virtual void AddEncodingComment(const MCInst &Inst);
88
89   /// GetCommentOS - Return a raw_ostream that comments can be written to.
90   /// Unlike AddComment, you are required to terminate comments with \n if you
91   /// use this method.
92   virtual raw_ostream &GetCommentOS() {
93     if (!IsVerboseAsm)
94       return nulls();  // Discard comments unless in verbose asm mode.
95     return CommentStream;
96   }
97
98   /// AddBlankLine - Emit a blank line to a .s file to pretty it up.
99   virtual void AddBlankLine() {
100     EmitEOL();
101   }
102
103   /// @name MCStreamer Interface
104   /// @{
105
106   virtual void SwitchSection(const MCSection *Section);
107
108   virtual void InitSections() {
109   }
110
111   virtual void EmitLabel(MCSymbol *Symbol);
112
113   virtual void EmitAssemblerFlag(MCAssemblerFlag Flag);
114
115   virtual void EmitThumbFunc(MCSymbol *Func);
116
117   virtual void EmitAssignment(MCSymbol *Symbol, const MCExpr *Value);
118
119   virtual void EmitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol);
120
121   virtual void EmitDwarfAdvanceLineAddr(int64_t LineDelta,
122                                         const MCSymbol *LastLabel,
123                                         const MCSymbol *Label);
124
125   virtual void EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute);
126
127   virtual void EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue);
128   virtual void BeginCOFFSymbolDef(const MCSymbol *Symbol);
129   virtual void EmitCOFFSymbolStorageClass(int StorageClass);
130   virtual void EmitCOFFSymbolType(int Type);
131   virtual void EndCOFFSymbolDef();
132   virtual void EmitELFSize(MCSymbol *Symbol, const MCExpr *Value);
133   virtual void EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
134                                 unsigned ByteAlignment);
135
136   /// EmitLocalCommonSymbol - Emit a local common (.lcomm) symbol.
137   ///
138   /// @param Symbol - The common symbol to emit.
139   /// @param Size - The size of the common symbol.
140   virtual void EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size);
141
142   virtual void EmitZerofill(const MCSection *Section, MCSymbol *Symbol = 0,
143                             unsigned Size = 0, unsigned ByteAlignment = 0);
144
145   virtual void EmitTBSSSymbol(const MCSection *Section, MCSymbol *Symbol,
146                               uint64_t Size, unsigned ByteAlignment = 0);
147
148   virtual void EmitBytes(StringRef Data, unsigned AddrSpace);
149
150   virtual void EmitValue(const MCExpr *Value, unsigned Size,unsigned AddrSpace);
151   virtual void EmitULEB128Value(const MCExpr *Value, unsigned AddrSpace = 0);
152   virtual void EmitSLEB128Value(const MCExpr *Value, unsigned AddrSpace = 0);
153   virtual void EmitGPRel32Value(const MCExpr *Value);
154
155
156   virtual void EmitFill(uint64_t NumBytes, uint8_t FillValue,
157                         unsigned AddrSpace);
158
159   virtual void EmitValueToAlignment(unsigned ByteAlignment, int64_t Value = 0,
160                                     unsigned ValueSize = 1,
161                                     unsigned MaxBytesToEmit = 0);
162
163   virtual void EmitCodeAlignment(unsigned ByteAlignment,
164                                  unsigned MaxBytesToEmit = 0);
165
166   virtual void EmitValueToOffset(const MCExpr *Offset,
167                                  unsigned char Value = 0);
168
169   virtual void EmitFileDirective(StringRef Filename);
170   virtual bool EmitDwarfFileDirective(unsigned FileNo, StringRef Filename);
171
172   virtual void EmitInstruction(const MCInst &Inst);
173
174   /// EmitRawText - If this file is backed by an assembly streamer, this dumps
175   /// the specified string in the output .s file.  This capability is
176   /// indicated by the hasRawTextSupport() predicate.
177   virtual void EmitRawText(StringRef String);
178
179   virtual void Finish();
180
181   /// @}
182
183 }; // class PTXMCAsmStreamer
184
185 }
186
187 /// TODO: Add appropriate implementation of Emit*() methods when needed
188
189 void PTXMCAsmStreamer::AddComment(const Twine &T) {
190   if (!IsVerboseAsm) return;
191
192   // Make sure that CommentStream is flushed.
193   CommentStream.flush();
194
195   T.toVector(CommentToEmit);
196   // Each comment goes on its own line.
197   CommentToEmit.push_back('\n');
198
199   // Tell the comment stream that the vector changed underneath it.
200   CommentStream.resync();
201 }
202
203 void PTXMCAsmStreamer::EmitCommentsAndEOL() {
204   if (CommentToEmit.empty() && CommentStream.GetNumBytesInBuffer() == 0) {
205     OS << '\n';
206     return;
207   }
208
209   CommentStream.flush();
210   StringRef Comments = CommentToEmit.str();
211
212   assert(Comments.back() == '\n' &&
213          "Comment array not newline terminated");
214   do {
215     // Emit a line of comments.
216     OS.PadToColumn(MAI.getCommentColumn());
217     size_t Position = Comments.find('\n');
218     OS << MAI.getCommentString() << ' ' << Comments.substr(0, Position) << '\n';
219
220     Comments = Comments.substr(Position+1);
221   } while (!Comments.empty());
222
223   CommentToEmit.clear();
224   // Tell the comment stream that the vector changed underneath it.
225   CommentStream.resync();
226 }
227
228 static inline int64_t truncateToSize(int64_t Value, unsigned Bytes) {
229   assert(Bytes && "Invalid size!");
230   return Value & ((uint64_t) (int64_t) -1 >> (64 - Bytes * 8));
231 }
232
233 void PTXMCAsmStreamer::SwitchSection(const MCSection *Section) {
234   assert(Section && "Cannot switch to a null section!");
235   if (Section != CurSection) {
236     PrevSection = CurSection;
237     CurSection = Section;
238   }
239 }
240
241 void PTXMCAsmStreamer::EmitLabel(MCSymbol *Symbol) {
242   assert(Symbol->isUndefined() && "Cannot define a symbol twice!");
243   assert(!Symbol->isVariable() && "Cannot emit a variable symbol!");
244   assert(CurSection && "Cannot emit before setting section!");
245
246   OS << *Symbol << MAI.getLabelSuffix();
247   EmitEOL();
248   Symbol->setSection(*CurSection);
249 }
250
251 void PTXMCAsmStreamer::EmitAssemblerFlag(MCAssemblerFlag Flag) {}
252
253 void PTXMCAsmStreamer::EmitThumbFunc(MCSymbol *Func) {}
254
255 void PTXMCAsmStreamer::EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) {
256   OS << *Symbol << " = " << *Value;
257   EmitEOL();
258
259   // FIXME: Lift context changes into super class.
260   Symbol->setVariableValue(Value);
261 }
262
263 void PTXMCAsmStreamer::EmitWeakReference(MCSymbol *Alias,
264                                          const MCSymbol *Symbol) {
265   OS << ".weakref " << *Alias << ", " << *Symbol;
266   EmitEOL();
267 }
268
269 void PTXMCAsmStreamer::EmitDwarfAdvanceLineAddr(int64_t LineDelta,
270                                                 const MCSymbol *LastLabel,
271                                                 const MCSymbol *Label) {
272   report_fatal_error("Unimplemented.");
273 }
274
275 void PTXMCAsmStreamer::EmitSymbolAttribute(MCSymbol *Symbol,
276                                            MCSymbolAttr Attribute) {}
277
278 void PTXMCAsmStreamer::EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) {}
279
280 void PTXMCAsmStreamer::BeginCOFFSymbolDef(const MCSymbol *Symbol) {}
281
282 void PTXMCAsmStreamer::EmitCOFFSymbolStorageClass (int StorageClass) {}
283
284 void PTXMCAsmStreamer::EmitCOFFSymbolType (int Type) {}
285
286 void PTXMCAsmStreamer::EndCOFFSymbolDef() {}
287
288 void PTXMCAsmStreamer::EmitELFSize(MCSymbol *Symbol, const MCExpr *Value) {}
289
290 void PTXMCAsmStreamer::EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
291                                         unsigned ByteAlignment) {}
292
293 void PTXMCAsmStreamer::EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size) {}
294
295 void PTXMCAsmStreamer::EmitZerofill(const MCSection *Section, MCSymbol *Symbol,
296                                     unsigned Size, unsigned ByteAlignment) {}
297
298 void PTXMCAsmStreamer::EmitTBSSSymbol(const MCSection *Section,
299                                       MCSymbol *Symbol,
300                                       uint64_t Size, unsigned ByteAlignment) {}
301
302 static inline char toOctal(int X) { return (X&7)+'0'; }
303
304 static void PrintQuotedString(StringRef Data, raw_ostream &OS) {
305   OS << '"';
306
307   for (unsigned i = 0, e = Data.size(); i != e; ++i) {
308     unsigned char C = Data[i];
309     if (C == '"' || C == '\\') {
310       OS << '\\' << (char)C;
311       continue;
312     }
313
314     if (isprint((unsigned char)C)) {
315       OS << (char)C;
316       continue;
317     }
318
319     switch (C) {
320       case '\b': OS << "\\b"; break;
321       case '\f': OS << "\\f"; break;
322       case '\n': OS << "\\n"; break;
323       case '\r': OS << "\\r"; break;
324       case '\t': OS << "\\t"; break;
325       default:
326         OS << '\\';
327         OS << toOctal(C >> 6);
328         OS << toOctal(C >> 3);
329         OS << toOctal(C >> 0);
330         break;
331     }
332   }
333
334   OS << '"';
335 }
336
337 void PTXMCAsmStreamer::EmitBytes(StringRef Data, unsigned AddrSpace) {
338   assert(CurSection && "Cannot emit contents before setting section!");
339   if (Data.empty()) return;
340
341   if (Data.size() == 1) {
342     OS << MAI.getData8bitsDirective(AddrSpace);
343     OS << (unsigned)(unsigned char)Data[0];
344     EmitEOL();
345     return;
346   }
347
348   // If the data ends with 0 and the target supports .asciz, use it, otherwise
349   // use .ascii
350   if (MAI.getAscizDirective() && Data.back() == 0) {
351     OS << MAI.getAscizDirective();
352     Data = Data.substr(0, Data.size()-1);
353   } else {
354     OS << MAI.getAsciiDirective();
355   }
356
357   OS << ' ';
358   PrintQuotedString(Data, OS);
359   EmitEOL();
360 }
361
362 void PTXMCAsmStreamer::EmitValue(const MCExpr *Value, unsigned Size,
363                                  unsigned AddrSpace) {
364   assert(CurSection && "Cannot emit contents before setting section!");
365   const char *Directive = 0;
366   switch (Size) {
367   default: break;
368   case 1: Directive = MAI.getData8bitsDirective(AddrSpace); break;
369   case 2: Directive = MAI.getData16bitsDirective(AddrSpace); break;
370   case 4: Directive = MAI.getData32bitsDirective(AddrSpace); break;
371   case 8:
372     Directive = MAI.getData64bitsDirective(AddrSpace);
373     // If the target doesn't support 64-bit data, emit as two 32-bit halves.
374     if (Directive) break;
375     int64_t IntValue;
376     if (!Value->EvaluateAsAbsolute(IntValue))
377       report_fatal_error("Don't know how to emit this value.");
378     if (isLittleEndian()) {
379       EmitIntValue((uint32_t)(IntValue >> 0 ), 4, AddrSpace);
380       EmitIntValue((uint32_t)(IntValue >> 32), 4, AddrSpace);
381     } else {
382       EmitIntValue((uint32_t)(IntValue >> 32), 4, AddrSpace);
383       EmitIntValue((uint32_t)(IntValue >> 0 ), 4, AddrSpace);
384     }
385     return;
386   }
387
388   assert(Directive && "Invalid size for machine code value!");
389   OS << Directive << *Value;
390   EmitEOL();
391 }
392
393 void PTXMCAsmStreamer::EmitULEB128Value(const MCExpr *Value,
394                                         unsigned AddrSpace) {
395   assert(MAI.hasLEB128() && "Cannot print a .uleb");
396   OS << ".uleb128 " << *Value;
397   EmitEOL();
398 }
399
400 void PTXMCAsmStreamer::EmitSLEB128Value(const MCExpr *Value,
401                                         unsigned AddrSpace) {
402   assert(MAI.hasLEB128() && "Cannot print a .sleb");
403   OS << ".sleb128 " << *Value;
404   EmitEOL();
405 }
406
407 void PTXMCAsmStreamer::EmitGPRel32Value(const MCExpr *Value) {
408   assert(MAI.getGPRel32Directive() != 0);
409   OS << MAI.getGPRel32Directive() << *Value;
410   EmitEOL();
411 }
412
413
414 /// EmitFill - Emit NumBytes bytes worth of the value specified by
415 /// FillValue.  This implements directives such as '.space'.
416 void PTXMCAsmStreamer::EmitFill(uint64_t NumBytes, uint8_t FillValue,
417                                 unsigned AddrSpace) {
418   if (NumBytes == 0) return;
419
420   if (AddrSpace == 0)
421     if (const char *ZeroDirective = MAI.getZeroDirective()) {
422       OS << ZeroDirective << NumBytes;
423       if (FillValue != 0)
424         OS << ',' << (int)FillValue;
425       EmitEOL();
426       return;
427     }
428
429   // Emit a byte at a time.
430   MCStreamer::EmitFill(NumBytes, FillValue, AddrSpace);
431 }
432
433 void PTXMCAsmStreamer::EmitValueToAlignment(unsigned ByteAlignment, int64_t Value,
434                                             unsigned ValueSize,
435                                             unsigned MaxBytesToEmit) {
436   // Some assemblers don't support non-power of two alignments, so we always
437   // emit alignments as a power of two if possible.
438   if (isPowerOf2_32(ByteAlignment)) {
439     switch (ValueSize) {
440     default: llvm_unreachable("Invalid size for machine code value!");
441     case 1: OS << MAI.getAlignDirective(); break;
442     // FIXME: use MAI for this!
443     case 2: OS << ".p2alignw "; break;
444     case 4: OS << ".p2alignl "; break;
445     case 8: llvm_unreachable("Unsupported alignment size!");
446     }
447
448     if (MAI.getAlignmentIsInBytes())
449       OS << ByteAlignment;
450     else
451       OS << Log2_32(ByteAlignment);
452
453     if (Value || MaxBytesToEmit) {
454       OS << ", 0x";
455       OS.write_hex(truncateToSize(Value, ValueSize));
456
457       if (MaxBytesToEmit)
458         OS << ", " << MaxBytesToEmit;
459     }
460     EmitEOL();
461     return;
462   }
463
464   // Non-power of two alignment.  This is not widely supported by assemblers.
465   // FIXME: Parameterize this based on MAI.
466   switch (ValueSize) {
467   default: llvm_unreachable("Invalid size for machine code value!");
468   case 1: OS << ".balign";  break;
469   case 2: OS << ".balignw"; break;
470   case 4: OS << ".balignl"; break;
471   case 8: llvm_unreachable("Unsupported alignment size!");
472   }
473
474   OS << ' ' << ByteAlignment;
475   OS << ", " << truncateToSize(Value, ValueSize);
476   if (MaxBytesToEmit)
477     OS << ", " << MaxBytesToEmit;
478   EmitEOL();
479 }
480
481 void PTXMCAsmStreamer::EmitCodeAlignment(unsigned ByteAlignment,
482                                          unsigned MaxBytesToEmit) {}
483
484 void PTXMCAsmStreamer::EmitValueToOffset(const MCExpr *Offset,
485                                          unsigned char Value) {}
486
487
488 void PTXMCAsmStreamer::EmitFileDirective(StringRef Filename) {
489   assert(MAI.hasSingleParameterDotFile());
490   OS << "\t.file\t";
491   PrintQuotedString(Filename, OS);
492   EmitEOL();
493 }
494
495 // FIXME: should we inherit from MCAsmStreamer?
496 bool PTXMCAsmStreamer::EmitDwarfFileDirective(unsigned FileNo,
497                                               StringRef Filename){
498   OS << "\t.file\t" << FileNo << ' ';
499   PrintQuotedString(Filename, OS);
500   EmitEOL();
501   return this->MCStreamer::EmitDwarfFileDirective(FileNo, Filename);
502 }
503
504 void PTXMCAsmStreamer::AddEncodingComment(const MCInst &Inst) {}
505
506 void PTXMCAsmStreamer::EmitInstruction(const MCInst &Inst) {
507   assert(CurSection && "Cannot emit contents before setting section!");
508
509   // Show the encoding in a comment if we have a code emitter.
510   if (Emitter)
511     AddEncodingComment(Inst);
512
513   // Show the MCInst if enabled.
514   if (ShowInst) {
515     Inst.dump_pretty(GetCommentOS(), &MAI, InstPrinter.get(), "\n ");
516     GetCommentOS() << "\n";
517   }
518
519   // If we have an AsmPrinter, use that to print, otherwise print the MCInst.
520   if (InstPrinter)
521     InstPrinter->printInst(&Inst, OS);
522   else
523     Inst.print(OS, &MAI);
524   EmitEOL();
525 }
526
527 /// EmitRawText - If this file is backed by an assembly streamer, this dumps
528 /// the specified string in the output .s file.  This capability is
529 /// indicated by the hasRawTextSupport() predicate.
530 void PTXMCAsmStreamer::EmitRawText(StringRef String) {
531   if (!String.empty() && String.back() == '\n')
532     String = String.substr(0, String.size()-1);
533   OS << String;
534   EmitEOL();
535 }
536
537 void PTXMCAsmStreamer::Finish() {}
538
539 namespace llvm {
540   MCStreamer *createPTXAsmStreamer(MCContext &Context,
541                                    formatted_raw_ostream &OS,
542                                    bool isLittleEndian,
543                                    bool isVerboseAsm, MCInstPrinter *IP,
544                                    MCCodeEmitter *CE, bool ShowInst) {
545     return new PTXMCAsmStreamer(Context, OS, isLittleEndian, isVerboseAsm,
546                                 IP, CE, ShowInst);
547   }
548 }