1 //===- lib/MC/MCAsmStreamer.cpp - Text Assembly Output --------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #include "llvm/MC/MCStreamer.h"
11 #include "llvm/MC/MCAsmInfo.h"
12 #include "llvm/MC/MCCodeEmitter.h"
13 #include "llvm/MC/MCContext.h"
14 #include "llvm/MC/MCExpr.h"
15 #include "llvm/MC/MCInst.h"
16 #include "llvm/MC/MCInstPrinter.h"
17 #include "llvm/MC/MCSectionMachO.h"
18 #include "llvm/MC/MCSymbol.h"
19 #include "llvm/ADT/SmallString.h"
20 #include "llvm/ADT/Twine.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"
29 class MCAsmStreamer : public MCStreamer {
30 formatted_raw_ostream &OS;
32 bool IsLittleEndian, IsVerboseAsm;
33 MCInstPrinter *InstPrinter;
34 MCCodeEmitter *Emitter;
36 SmallString<128> CommentToEmit;
37 raw_svector_ostream CommentStream;
39 MCAsmStreamer(MCContext &Context, formatted_raw_ostream &os,
41 bool isLittleEndian, bool isVerboseAsm, MCInstPrinter *printer,
42 MCCodeEmitter *emitter)
43 : MCStreamer(Context), OS(os), MAI(mai), IsLittleEndian(isLittleEndian),
44 IsVerboseAsm(isVerboseAsm), InstPrinter(printer), Emitter(emitter),
45 CommentStream(CommentToEmit) {}
48 bool isLittleEndian() const { return IsLittleEndian; }
50 inline void EmitEOL() {
51 // If we don't have any comments, just emit a \n.
58 void EmitCommentsAndEOL();
60 /// isVerboseAsm - Return true if this streamer supports verbose assembly at
62 virtual bool isVerboseAsm() const { return IsVerboseAsm; }
64 /// AddComment - Add a comment that can be emitted to the generated .s
65 /// file if applicable as a QoI issue to make the output of the compiler
66 /// more readable. This only affects the MCAsmStreamer, and only when
67 /// verbose assembly output is enabled.
68 virtual void AddComment(const Twine &T);
70 /// GetCommentOS - Return a raw_ostream that comments can be written to.
71 /// Unlike AddComment, you are required to terminate comments with \n if you
73 virtual raw_ostream &GetCommentOS() {
75 return nulls(); // Discard comments unless in verbose asm mode.
79 /// AddBlankLine - Emit a blank line to a .s file to pretty it up.
80 virtual void AddBlankLine() {
84 /// @name MCStreamer Interface
87 virtual void SwitchSection(const MCSection *Section);
89 virtual void EmitLabel(MCSymbol *Symbol);
91 virtual void EmitAssemblerFlag(MCAssemblerFlag Flag);
93 virtual void EmitAssignment(MCSymbol *Symbol, const MCExpr *Value);
95 virtual void EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute);
97 virtual void EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue);
99 virtual void EmitELFSize(MCSymbol *Symbol, const MCExpr *Value);
100 virtual void EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
101 unsigned ByteAlignment);
103 /// EmitLocalCommonSymbol - Emit a local common (.lcomm) symbol.
105 /// @param Symbol - The common symbol to emit.
106 /// @param Size - The size of the common symbol.
107 virtual void EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size);
109 virtual void EmitZerofill(const MCSection *Section, MCSymbol *Symbol = 0,
110 unsigned Size = 0, unsigned ByteAlignment = 0);
112 virtual void EmitBytes(StringRef Data, unsigned AddrSpace);
114 virtual void EmitValue(const MCExpr *Value, unsigned Size,unsigned AddrSpace);
115 virtual void EmitIntValue(uint64_t Value, unsigned Size, unsigned AddrSpace);
116 virtual void EmitGPRel32Value(const MCExpr *Value);
119 virtual void EmitFill(uint64_t NumBytes, uint8_t FillValue,
122 virtual void EmitValueToAlignment(unsigned ByteAlignment, int64_t Value = 0,
123 unsigned ValueSize = 1,
124 unsigned MaxBytesToEmit = 0);
126 virtual void EmitValueToOffset(const MCExpr *Offset,
127 unsigned char Value = 0);
129 virtual void EmitFileDirective(StringRef Filename);
130 virtual void EmitDwarfFileDirective(unsigned FileNo, StringRef Filename);
132 virtual void EmitInstruction(const MCInst &Inst);
134 virtual void Finish();
139 } // end anonymous namespace.
141 /// AddComment - Add a comment that can be emitted to the generated .s
142 /// file if applicable as a QoI issue to make the output of the compiler
143 /// more readable. This only affects the MCAsmStreamer, and only when
144 /// verbose assembly output is enabled.
145 void MCAsmStreamer::AddComment(const Twine &T) {
146 if (!IsVerboseAsm) return;
148 // Make sure that CommentStream is flushed.
149 CommentStream.flush();
151 T.toVector(CommentToEmit);
152 // Each comment goes on its own line.
153 CommentToEmit.push_back('\n');
155 // Tell the comment stream that the vector changed underneath it.
156 CommentStream.resync();
159 void MCAsmStreamer::EmitCommentsAndEOL() {
160 if (CommentToEmit.empty() && CommentStream.GetNumBytesInBuffer() == 0) {
165 CommentStream.flush();
166 StringRef Comments = CommentToEmit.str();
168 assert(Comments.back() == '\n' &&
169 "Comment array not newline terminated");
171 // Emit a line of comments.
172 OS.PadToColumn(MAI.getCommentColumn());
173 size_t Position = Comments.find('\n');
174 OS << MAI.getCommentString() << ' ' << Comments.substr(0, Position) << '\n';
176 Comments = Comments.substr(Position+1);
177 } while (!Comments.empty());
179 CommentToEmit.clear();
180 // Tell the comment stream that the vector changed underneath it.
181 CommentStream.resync();
185 static inline int64_t truncateToSize(int64_t Value, unsigned Bytes) {
186 assert(Bytes && "Invalid size!");
187 return Value & ((uint64_t) (int64_t) -1 >> (64 - Bytes * 8));
190 void MCAsmStreamer::SwitchSection(const MCSection *Section) {
191 assert(Section && "Cannot switch to a null section!");
192 if (Section != CurSection) {
193 CurSection = Section;
194 Section->PrintSwitchToSection(MAI, OS);
198 void MCAsmStreamer::EmitLabel(MCSymbol *Symbol) {
199 assert(Symbol->isUndefined() && "Cannot define a symbol twice!");
200 assert(CurSection && "Cannot emit before setting section!");
202 OS << *Symbol << ":";
204 Symbol->setSection(*CurSection);
207 void MCAsmStreamer::EmitAssemblerFlag(MCAssemblerFlag Flag) {
209 default: assert(0 && "Invalid flag!");
210 case MCAF_SubsectionsViaSymbols: OS << ".subsections_via_symbols"; break;
215 void MCAsmStreamer::EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) {
216 // Only absolute symbols can be redefined.
217 assert((Symbol->isUndefined() || Symbol->isAbsolute()) &&
218 "Cannot define a symbol twice!");
220 OS << *Symbol << " = " << *Value;
223 // FIXME: Lift context changes into super class.
224 // FIXME: Set associated section.
225 Symbol->setValue(Value);
228 void MCAsmStreamer::EmitSymbolAttribute(MCSymbol *Symbol,
229 MCSymbolAttr Attribute) {
231 case MCSA_Invalid: assert(0 && "Invalid symbol attribute");
232 case MCSA_ELF_TypeFunction: /// .type _foo, STT_FUNC # aka @function
233 case MCSA_ELF_TypeIndFunction: /// .type _foo, STT_GNU_IFUNC
234 case MCSA_ELF_TypeObject: /// .type _foo, STT_OBJECT # aka @object
235 case MCSA_ELF_TypeTLS: /// .type _foo, STT_TLS # aka @tls_object
236 case MCSA_ELF_TypeCommon: /// .type _foo, STT_COMMON # aka @common
237 case MCSA_ELF_TypeNoType: /// .type _foo, STT_NOTYPE # aka @notype
238 assert(MAI.hasDotTypeDotSizeDirective() && "Symbol Attr not supported");
239 OS << "\t.type " << *Symbol << ','
240 << ((MAI.getCommentString()[0] != '@') ? '@' : '%');
242 default: assert(0 && "Unknown ELF .type");
243 case MCSA_ELF_TypeFunction: OS << "function"; break;
244 case MCSA_ELF_TypeIndFunction: OS << "gnu_indirect_function"; break;
245 case MCSA_ELF_TypeObject: OS << "object"; break;
246 case MCSA_ELF_TypeTLS: OS << "tls_object"; break;
247 case MCSA_ELF_TypeCommon: OS << "common"; break;
248 case MCSA_ELF_TypeNoType: OS << "no_type"; break;
252 case MCSA_Global: // .globl/.global
253 OS << MAI.getGlobalDirective();
255 case MCSA_Hidden: OS << ".hidden "; break;
256 case MCSA_IndirectSymbol: OS << ".indirect_symbol "; break;
257 case MCSA_Internal: OS << ".internal "; break;
258 case MCSA_LazyReference: OS << ".lazy_reference "; break;
259 case MCSA_Local: OS << ".local "; break;
260 case MCSA_NoDeadStrip: OS << ".no_dead_strip "; break;
261 case MCSA_PrivateExtern: OS << ".private_extern "; break;
262 case MCSA_Protected: OS << ".protected "; break;
263 case MCSA_Reference: OS << ".reference "; break;
264 case MCSA_Weak: OS << ".weak "; break;
265 case MCSA_WeakDefinition: OS << ".weak_definition "; break;
267 case MCSA_WeakReference: OS << MAI.getWeakRefDirective(); break;
274 void MCAsmStreamer::EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) {
275 OS << ".desc" << ' ' << *Symbol << ',' << DescValue;
279 void MCAsmStreamer::EmitELFSize(MCSymbol *Symbol, const MCExpr *Value) {
280 assert(MAI.hasDotTypeDotSizeDirective());
281 OS << "\t.size\t" << *Symbol << ", " << *Value << '\n';
284 void MCAsmStreamer::EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
285 unsigned ByteAlignment) {
286 OS << "\t.comm\t" << *Symbol << ',' << Size;
287 if (ByteAlignment != 0) {
288 if (MAI.getCOMMDirectiveAlignmentIsInBytes())
289 OS << ',' << ByteAlignment;
291 OS << ',' << Log2_32(ByteAlignment);
296 /// EmitLocalCommonSymbol - Emit a local common (.lcomm) symbol.
298 /// @param Symbol - The common symbol to emit.
299 /// @param Size - The size of the common symbol.
300 void MCAsmStreamer::EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size) {
301 assert(MAI.hasLCOMMDirective() && "Doesn't have .lcomm, can't emit it!");
302 OS << "\t.lcomm\t" << *Symbol << ',' << Size;
306 void MCAsmStreamer::EmitZerofill(const MCSection *Section, MCSymbol *Symbol,
307 unsigned Size, unsigned ByteAlignment) {
308 // Note: a .zerofill directive does not switch sections.
311 // This is a mach-o specific directive.
312 const MCSectionMachO *MOSection = ((const MCSectionMachO*)Section);
313 OS << MOSection->getSegmentName() << "," << MOSection->getSectionName();
315 if (Symbol != NULL) {
316 OS << ',' << *Symbol << ',' << Size;
317 if (ByteAlignment != 0)
318 OS << ',' << Log2_32(ByteAlignment);
323 static inline char toOctal(int X) { return (X&7)+'0'; }
325 static void PrintQuotedString(StringRef Data, raw_ostream &OS) {
328 for (unsigned i = 0, e = Data.size(); i != e; ++i) {
329 unsigned char C = Data[i];
330 if (C == '"' || C == '\\') {
331 OS << '\\' << (char)C;
335 if (isprint((unsigned char)C)) {
341 case '\b': OS << "\\b"; break;
342 case '\f': OS << "\\f"; break;
343 case '\n': OS << "\\n"; break;
344 case '\r': OS << "\\r"; break;
345 case '\t': OS << "\\t"; break;
348 OS << toOctal(C >> 6);
349 OS << toOctal(C >> 3);
350 OS << toOctal(C >> 0);
359 void MCAsmStreamer::EmitBytes(StringRef Data, unsigned AddrSpace) {
360 assert(CurSection && "Cannot emit contents before setting section!");
361 if (Data.empty()) return;
363 if (Data.size() == 1) {
364 OS << MAI.getData8bitsDirective(AddrSpace);
365 OS << (unsigned)(unsigned char)Data[0];
370 // If the data ends with 0 and the target supports .asciz, use it, otherwise
372 if (MAI.getAscizDirective() && Data.back() == 0) {
373 OS << MAI.getAscizDirective();
374 Data = Data.substr(0, Data.size()-1);
376 OS << MAI.getAsciiDirective();
380 PrintQuotedString(Data, OS);
384 /// EmitIntValue - Special case of EmitValue that avoids the client having
385 /// to pass in a MCExpr for constant integers.
386 void MCAsmStreamer::EmitIntValue(uint64_t Value, unsigned Size,
387 unsigned AddrSpace) {
388 assert(CurSection && "Cannot emit contents before setting section!");
389 const char *Directive = 0;
392 case 1: Directive = MAI.getData8bitsDirective(AddrSpace); break;
393 case 2: Directive = MAI.getData16bitsDirective(AddrSpace); break;
394 case 4: Directive = MAI.getData32bitsDirective(AddrSpace); break;
396 Directive = MAI.getData64bitsDirective(AddrSpace);
397 // If the target doesn't support 64-bit data, emit as two 32-bit halves.
398 if (Directive) break;
399 if (isLittleEndian()) {
400 EmitIntValue((uint32_t)(Value >> 0 ), 4, AddrSpace);
401 EmitIntValue((uint32_t)(Value >> 32), 4, AddrSpace);
403 EmitIntValue((uint32_t)(Value >> 32), 4, AddrSpace);
404 EmitIntValue((uint32_t)(Value >> 0 ), 4, AddrSpace);
409 assert(Directive && "Invalid size for machine code value!");
410 OS << Directive << truncateToSize(Value, Size);
414 void MCAsmStreamer::EmitValue(const MCExpr *Value, unsigned Size,
415 unsigned AddrSpace) {
416 assert(CurSection && "Cannot emit contents before setting section!");
417 const char *Directive = 0;
420 case 1: Directive = MAI.getData8bitsDirective(AddrSpace); break;
421 case 2: Directive = MAI.getData16bitsDirective(AddrSpace); break;
422 case 4: Directive = MAI.getData32bitsDirective(AddrSpace); break;
423 case 8: Directive = MAI.getData64bitsDirective(AddrSpace); break;
426 assert(Directive && "Invalid size for machine code value!");
427 OS << Directive << *Value;
431 void MCAsmStreamer::EmitGPRel32Value(const MCExpr *Value) {
432 assert(MAI.getGPRel32Directive() != 0);
433 OS << MAI.getGPRel32Directive() << *Value;
438 /// EmitFill - Emit NumBytes bytes worth of the value specified by
439 /// FillValue. This implements directives such as '.space'.
440 void MCAsmStreamer::EmitFill(uint64_t NumBytes, uint8_t FillValue,
441 unsigned AddrSpace) {
442 if (NumBytes == 0) return;
445 if (const char *ZeroDirective = MAI.getZeroDirective()) {
446 OS << ZeroDirective << NumBytes;
448 OS << ',' << (int)FillValue;
453 // Emit a byte at a time.
454 MCStreamer::EmitFill(NumBytes, FillValue, AddrSpace);
457 void MCAsmStreamer::EmitValueToAlignment(unsigned ByteAlignment, int64_t Value,
459 unsigned MaxBytesToEmit) {
460 // Some assemblers don't support non-power of two alignments, so we always
461 // emit alignments as a power of two if possible.
462 if (isPowerOf2_32(ByteAlignment)) {
464 default: llvm_unreachable("Invalid size for machine code value!");
465 case 1: OS << MAI.getAlignDirective(); break;
466 // FIXME: use MAI for this!
467 case 2: OS << ".p2alignw "; break;
468 case 4: OS << ".p2alignl "; break;
469 case 8: llvm_unreachable("Unsupported alignment size!");
472 if (MAI.getAlignmentIsInBytes())
475 OS << Log2_32(ByteAlignment);
477 if (Value || MaxBytesToEmit) {
479 OS.write_hex(truncateToSize(Value, ValueSize));
482 OS << ", " << MaxBytesToEmit;
488 // Non-power of two alignment. This is not widely supported by assemblers.
489 // FIXME: Parameterize this based on MAI.
491 default: llvm_unreachable("Invalid size for machine code value!");
492 case 1: OS << ".balign"; break;
493 case 2: OS << ".balignw"; break;
494 case 4: OS << ".balignl"; break;
495 case 8: llvm_unreachable("Unsupported alignment size!");
498 OS << ' ' << ByteAlignment;
499 OS << ", " << truncateToSize(Value, ValueSize);
501 OS << ", " << MaxBytesToEmit;
505 void MCAsmStreamer::EmitValueToOffset(const MCExpr *Offset,
506 unsigned char Value) {
507 // FIXME: Verify that Offset is associated with the current section.
508 OS << ".org " << *Offset << ", " << (unsigned) Value;
513 void MCAsmStreamer::EmitFileDirective(StringRef Filename) {
514 assert(MAI.hasSingleParameterDotFile());
516 PrintQuotedString(Filename, OS);
520 void MCAsmStreamer::EmitDwarfFileDirective(unsigned FileNo, StringRef Filename){
521 OS << "\t.file\t" << FileNo << ' ';
522 PrintQuotedString(Filename, OS);
527 void MCAsmStreamer::EmitInstruction(const MCInst &Inst) {
528 assert(CurSection && "Cannot emit contents before setting section!");
530 // Show the encoding in a comment if we have a code emitter.
532 SmallString<256> Code;
533 raw_svector_ostream VecOS(Code);
534 Emitter->EncodeInstruction(Inst, VecOS);
537 raw_ostream &OS = GetCommentOS();
539 for (unsigned i = 0, e = Code.size(); i != e; ++i) {
542 OS << format("%#04x", uint8_t(Code[i]));
547 // If we have an AsmPrinter, use that to print.
549 InstPrinter->printInst(&Inst);
554 // Otherwise fall back to a structural printing for now. Eventually we should
555 // always have access to the target specific printer.
556 Inst.print(OS, &MAI);
560 void MCAsmStreamer::Finish() {
564 MCStreamer *llvm::createAsmStreamer(MCContext &Context,
565 formatted_raw_ostream &OS,
566 const MCAsmInfo &MAI, bool isLittleEndian,
567 bool isVerboseAsm, MCInstPrinter *IP,
569 return new MCAsmStreamer(Context, OS, MAI, isLittleEndian, isVerboseAsm,