MCAsmStreamer.cpp revision 738734501635a15d8ed2d1c8d52962ed5f319bd3
1//===- lib/MC/MCAsmStreamer.cpp - 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/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/OwningPtr.h" 20#include "llvm/ADT/SmallString.h" 21#include "llvm/ADT/Twine.h" 22#include "llvm/Support/ErrorHandling.h" 23#include "llvm/Support/MathExtras.h" 24#include "llvm/Support/Format.h" 25#include "llvm/Support/FormattedStream.h" 26using namespace llvm; 27 28namespace { 29 30class MCAsmStreamer : 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 43public: 44 MCAsmStreamer(MCContext &Context, formatted_raw_ostream &os, 45 bool isLittleEndian, bool isVerboseAsm, MCInstPrinter *printer, 46 MCCodeEmitter *emitter, bool showInst) 47 : MCStreamer(Context), OS(os), MAI(Context.getAsmInfo()), 48 InstPrinter(printer), Emitter(emitter), CommentStream(CommentToEmit), 49 IsLittleEndian(isLittleEndian), IsVerboseAsm(isVerboseAsm), 50 ShowInst(showInst) { 51 if (InstPrinter && IsVerboseAsm) 52 InstPrinter->setCommentStream(CommentStream); 53 } 54 ~MCAsmStreamer() {} 55 56 bool isLittleEndian() const { return IsLittleEndian; } 57 58 inline void EmitEOL() { 59 // If we don't have any comments, just emit a \n. 60 if (!IsVerboseAsm) { 61 OS << '\n'; 62 return; 63 } 64 EmitCommentsAndEOL(); 65 } 66 void EmitCommentsAndEOL(); 67 68 /// isVerboseAsm - Return true if this streamer supports verbose assembly at 69 /// all. 70 virtual bool isVerboseAsm() const { return IsVerboseAsm; } 71 72 /// hasRawTextSupport - We support EmitRawText. 73 virtual bool hasRawTextSupport() const { return true; } 74 75 /// AddComment - Add a comment that can be emitted to the generated .s 76 /// file if applicable as a QoI issue to make the output of the compiler 77 /// more readable. This only affects the MCAsmStreamer, and only when 78 /// verbose assembly output is enabled. 79 virtual void AddComment(const Twine &T); 80 81 /// AddEncodingComment - Add a comment showing the encoding of an instruction. 82 virtual void AddEncodingComment(const MCInst &Inst); 83 84 /// GetCommentOS - Return a raw_ostream that comments can be written to. 85 /// Unlike AddComment, you are required to terminate comments with \n if you 86 /// use this method. 87 virtual raw_ostream &GetCommentOS() { 88 if (!IsVerboseAsm) 89 return nulls(); // Discard comments unless in verbose asm mode. 90 return CommentStream; 91 } 92 93 /// AddBlankLine - Emit a blank line to a .s file to pretty it up. 94 virtual void AddBlankLine() { 95 EmitEOL(); 96 } 97 98 /// @name MCStreamer Interface 99 /// @{ 100 101 virtual void SwitchSection(const MCSection *Section); 102 103 virtual void InitSections() { 104 // FIXME, this is MachO specific, but the testsuite 105 // expects this. 106 SwitchSection(getContext().getMachOSection("__TEXT", "__text", 107 MCSectionMachO::S_ATTR_PURE_INSTRUCTIONS, 108 0, SectionKind::getText())); 109 } 110 111 virtual void EmitLabel(MCSymbol *Symbol); 112 113 virtual void EmitAssemblerFlag(MCAssemblerFlag Flag); 114 115 virtual void EmitAssignment(MCSymbol *Symbol, const MCExpr *Value); 116 virtual void EmitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol); 117 118 virtual void EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute); 119 120 virtual void EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue); 121 virtual void BeginCOFFSymbolDef(const MCSymbol *Symbol); 122 virtual void EmitCOFFSymbolStorageClass(int StorageClass); 123 virtual void EmitCOFFSymbolType(int Type); 124 virtual void EndCOFFSymbolDef(); 125 virtual void EmitELFSize(MCSymbol *Symbol, const MCExpr *Value); 126 virtual void EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, 127 unsigned ByteAlignment); 128 129 /// EmitLocalCommonSymbol - Emit a local common (.lcomm) symbol. 130 /// 131 /// @param Symbol - The common symbol to emit. 132 /// @param Size - The size of the common symbol. 133 virtual void EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size); 134 135 virtual void EmitZerofill(const MCSection *Section, MCSymbol *Symbol = 0, 136 unsigned Size = 0, unsigned ByteAlignment = 0); 137 138 virtual void EmitTBSSSymbol (const MCSection *Section, MCSymbol *Symbol, 139 uint64_t Size, unsigned ByteAlignment = 0); 140 141 virtual void EmitBytes(StringRef Data, unsigned AddrSpace); 142 143 virtual void EmitValue(const MCExpr *Value, unsigned Size,unsigned AddrSpace); 144 145 virtual void EmitIntValue(uint64_t Value, unsigned Size, unsigned AddrSpace); 146 147 virtual void EmitULEB128Value(const MCExpr *Value, unsigned AddrSpace = 0); 148 149 virtual void EmitSLEB128Value(const MCExpr *Value, unsigned AddrSpace = 0); 150 151 virtual void EmitGPRel32Value(const MCExpr *Value); 152 153 154 virtual void EmitFill(uint64_t NumBytes, uint8_t FillValue, 155 unsigned AddrSpace); 156 157 virtual void EmitValueToAlignment(unsigned ByteAlignment, int64_t Value = 0, 158 unsigned ValueSize = 1, 159 unsigned MaxBytesToEmit = 0); 160 161 virtual void EmitCodeAlignment(unsigned ByteAlignment, 162 unsigned MaxBytesToEmit = 0); 163 164 virtual void EmitValueToOffset(const MCExpr *Offset, 165 unsigned char Value = 0); 166 167 virtual void EmitFileDirective(StringRef Filename); 168 virtual void EmitDwarfFileDirective(unsigned FileNo, StringRef Filename); 169 170 virtual void EmitInstruction(const MCInst &Inst); 171 172 /// EmitRawText - If this file is backed by an assembly streamer, this dumps 173 /// the specified string in the output .s file. This capability is 174 /// indicated by the hasRawTextSupport() predicate. 175 virtual void EmitRawText(StringRef String); 176 177 virtual void Finish(); 178 179 /// @} 180}; 181 182} // end anonymous namespace. 183 184/// AddComment - Add a comment that can be emitted to the generated .s 185/// file if applicable as a QoI issue to make the output of the compiler 186/// more readable. This only affects the MCAsmStreamer, and only when 187/// verbose assembly output is enabled. 188void MCAsmStreamer::AddComment(const Twine &T) { 189 if (!IsVerboseAsm) return; 190 191 // Make sure that CommentStream is flushed. 192 CommentStream.flush(); 193 194 T.toVector(CommentToEmit); 195 // Each comment goes on its own line. 196 CommentToEmit.push_back('\n'); 197 198 // Tell the comment stream that the vector changed underneath it. 199 CommentStream.resync(); 200} 201 202void MCAsmStreamer::EmitCommentsAndEOL() { 203 if (CommentToEmit.empty() && CommentStream.GetNumBytesInBuffer() == 0) { 204 OS << '\n'; 205 return; 206 } 207 208 CommentStream.flush(); 209 StringRef Comments = CommentToEmit.str(); 210 211 assert(Comments.back() == '\n' && 212 "Comment array not newline terminated"); 213 do { 214 // Emit a line of comments. 215 OS.PadToColumn(MAI.getCommentColumn()); 216 size_t Position = Comments.find('\n'); 217 OS << MAI.getCommentString() << ' ' << Comments.substr(0, Position) << '\n'; 218 219 Comments = Comments.substr(Position+1); 220 } while (!Comments.empty()); 221 222 CommentToEmit.clear(); 223 // Tell the comment stream that the vector changed underneath it. 224 CommentStream.resync(); 225} 226 227static inline int64_t truncateToSize(int64_t Value, unsigned Bytes) { 228 assert(Bytes && "Invalid size!"); 229 return Value & ((uint64_t) (int64_t) -1 >> (64 - Bytes * 8)); 230} 231 232void MCAsmStreamer::SwitchSection(const MCSection *Section) { 233 assert(Section && "Cannot switch to a null section!"); 234 if (Section != CurSection) { 235 PrevSection = CurSection; 236 CurSection = Section; 237 Section->PrintSwitchToSection(MAI, OS); 238 } 239} 240 241void MCAsmStreamer::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 251void MCAsmStreamer::EmitAssemblerFlag(MCAssemblerFlag Flag) { 252 switch (Flag) { 253 default: assert(0 && "Invalid flag!"); 254 case MCAF_SyntaxUnified: OS << "\t.syntax unified"; break; 255 case MCAF_SubsectionsViaSymbols: OS << ".subsections_via_symbols"; break; 256 } 257 EmitEOL(); 258} 259 260void MCAsmStreamer::EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) { 261 OS << *Symbol << " = " << *Value; 262 EmitEOL(); 263 264 // FIXME: Lift context changes into super class. 265 Symbol->setVariableValue(Value); 266} 267 268void MCAsmStreamer::EmitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol) { 269 OS << ".weakref " << *Alias << ", " << *Symbol; 270 EmitEOL(); 271} 272 273void MCAsmStreamer::EmitSymbolAttribute(MCSymbol *Symbol, 274 MCSymbolAttr Attribute) { 275 switch (Attribute) { 276 case MCSA_Invalid: assert(0 && "Invalid symbol attribute"); 277 case MCSA_ELF_TypeFunction: /// .type _foo, STT_FUNC # aka @function 278 case MCSA_ELF_TypeIndFunction: /// .type _foo, STT_GNU_IFUNC 279 case MCSA_ELF_TypeObject: /// .type _foo, STT_OBJECT # aka @object 280 case MCSA_ELF_TypeTLS: /// .type _foo, STT_TLS # aka @tls_object 281 case MCSA_ELF_TypeCommon: /// .type _foo, STT_COMMON # aka @common 282 case MCSA_ELF_TypeNoType: /// .type _foo, STT_NOTYPE # aka @notype 283 assert(MAI.hasDotTypeDotSizeDirective() && "Symbol Attr not supported"); 284 OS << "\t.type\t" << *Symbol << ',' 285 << ((MAI.getCommentString()[0] != '@') ? '@' : '%'); 286 switch (Attribute) { 287 default: assert(0 && "Unknown ELF .type"); 288 case MCSA_ELF_TypeFunction: OS << "function"; break; 289 case MCSA_ELF_TypeIndFunction: OS << "gnu_indirect_function"; break; 290 case MCSA_ELF_TypeObject: OS << "object"; break; 291 case MCSA_ELF_TypeTLS: OS << "tls_object"; break; 292 case MCSA_ELF_TypeCommon: OS << "common"; break; 293 case MCSA_ELF_TypeNoType: OS << "no_type"; break; 294 } 295 EmitEOL(); 296 return; 297 case MCSA_Global: // .globl/.global 298 OS << MAI.getGlobalDirective(); 299 break; 300 case MCSA_Hidden: OS << "\t.hidden\t"; break; 301 case MCSA_IndirectSymbol: OS << "\t.indirect_symbol\t"; break; 302 case MCSA_Internal: OS << "\t.internal\t"; break; 303 case MCSA_LazyReference: OS << "\t.lazy_reference\t"; break; 304 case MCSA_Local: OS << "\t.local\t"; break; 305 case MCSA_NoDeadStrip: OS << "\t.no_dead_strip\t"; break; 306 case MCSA_PrivateExtern: OS << "\t.private_extern\t"; break; 307 case MCSA_Protected: OS << "\t.protected\t"; break; 308 case MCSA_Reference: OS << "\t.reference\t"; break; 309 case MCSA_Weak: OS << "\t.weak\t"; break; 310 case MCSA_WeakDefinition: OS << "\t.weak_definition\t"; break; 311 // .weak_reference 312 case MCSA_WeakReference: OS << MAI.getWeakRefDirective(); break; 313 case MCSA_WeakDefAutoPrivate: OS << "\t.weak_def_can_be_hidden\t"; break; 314 } 315 316 OS << *Symbol; 317 EmitEOL(); 318} 319 320void MCAsmStreamer::EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) { 321 OS << ".desc" << ' ' << *Symbol << ',' << DescValue; 322 EmitEOL(); 323} 324 325void MCAsmStreamer::BeginCOFFSymbolDef(const MCSymbol *Symbol) { 326 OS << "\t.def\t " << *Symbol << ';'; 327 EmitEOL(); 328} 329 330void MCAsmStreamer::EmitCOFFSymbolStorageClass (int StorageClass) { 331 OS << "\t.scl\t" << StorageClass << ';'; 332 EmitEOL(); 333} 334 335void MCAsmStreamer::EmitCOFFSymbolType (int Type) { 336 OS << "\t.type\t" << Type << ';'; 337 EmitEOL(); 338} 339 340void MCAsmStreamer::EndCOFFSymbolDef() { 341 OS << "\t.endef"; 342 EmitEOL(); 343} 344 345void MCAsmStreamer::EmitELFSize(MCSymbol *Symbol, const MCExpr *Value) { 346 assert(MAI.hasDotTypeDotSizeDirective()); 347 OS << "\t.size\t" << *Symbol << ", " << *Value << '\n'; 348} 349 350void MCAsmStreamer::EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, 351 unsigned ByteAlignment) { 352 OS << "\t.comm\t" << *Symbol << ',' << Size; 353 if (ByteAlignment != 0) { 354 if (MAI.getCOMMDirectiveAlignmentIsInBytes()) 355 OS << ',' << ByteAlignment; 356 else 357 OS << ',' << Log2_32(ByteAlignment); 358 } 359 EmitEOL(); 360} 361 362/// EmitLocalCommonSymbol - Emit a local common (.lcomm) symbol. 363/// 364/// @param Symbol - The common symbol to emit. 365/// @param Size - The size of the common symbol. 366void MCAsmStreamer::EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size) { 367 assert(MAI.hasLCOMMDirective() && "Doesn't have .lcomm, can't emit it!"); 368 OS << "\t.lcomm\t" << *Symbol << ',' << Size; 369 EmitEOL(); 370} 371 372void MCAsmStreamer::EmitZerofill(const MCSection *Section, MCSymbol *Symbol, 373 unsigned Size, unsigned ByteAlignment) { 374 // Note: a .zerofill directive does not switch sections. 375 OS << ".zerofill "; 376 377 // This is a mach-o specific directive. 378 const MCSectionMachO *MOSection = ((const MCSectionMachO*)Section); 379 OS << MOSection->getSegmentName() << "," << MOSection->getSectionName(); 380 381 if (Symbol != NULL) { 382 OS << ',' << *Symbol << ',' << Size; 383 if (ByteAlignment != 0) 384 OS << ',' << Log2_32(ByteAlignment); 385 } 386 EmitEOL(); 387} 388 389// .tbss sym, size, align 390// This depends that the symbol has already been mangled from the original, 391// e.g. _a. 392void MCAsmStreamer::EmitTBSSSymbol(const MCSection *Section, MCSymbol *Symbol, 393 uint64_t Size, unsigned ByteAlignment) { 394 assert(Symbol != NULL && "Symbol shouldn't be NULL!"); 395 // Instead of using the Section we'll just use the shortcut. 396 // This is a mach-o specific directive and section. 397 OS << ".tbss " << *Symbol << ", " << Size; 398 399 // Output align if we have it. We default to 1 so don't bother printing 400 // that. 401 if (ByteAlignment > 1) OS << ", " << Log2_32(ByteAlignment); 402 403 EmitEOL(); 404} 405 406static inline char toOctal(int X) { return (X&7)+'0'; } 407 408static void PrintQuotedString(StringRef Data, raw_ostream &OS) { 409 OS << '"'; 410 411 for (unsigned i = 0, e = Data.size(); i != e; ++i) { 412 unsigned char C = Data[i]; 413 if (C == '"' || C == '\\') { 414 OS << '\\' << (char)C; 415 continue; 416 } 417 418 if (isprint((unsigned char)C)) { 419 OS << (char)C; 420 continue; 421 } 422 423 switch (C) { 424 case '\b': OS << "\\b"; break; 425 case '\f': OS << "\\f"; break; 426 case '\n': OS << "\\n"; break; 427 case '\r': OS << "\\r"; break; 428 case '\t': OS << "\\t"; break; 429 default: 430 OS << '\\'; 431 OS << toOctal(C >> 6); 432 OS << toOctal(C >> 3); 433 OS << toOctal(C >> 0); 434 break; 435 } 436 } 437 438 OS << '"'; 439} 440 441 442void MCAsmStreamer::EmitBytes(StringRef Data, unsigned AddrSpace) { 443 assert(CurSection && "Cannot emit contents before setting section!"); 444 if (Data.empty()) return; 445 446 if (Data.size() == 1) { 447 OS << MAI.getData8bitsDirective(AddrSpace); 448 OS << (unsigned)(unsigned char)Data[0]; 449 EmitEOL(); 450 return; 451 } 452 453 // If the data ends with 0 and the target supports .asciz, use it, otherwise 454 // use .ascii 455 if (MAI.getAscizDirective() && Data.back() == 0) { 456 OS << MAI.getAscizDirective(); 457 Data = Data.substr(0, Data.size()-1); 458 } else { 459 OS << MAI.getAsciiDirective(); 460 } 461 462 OS << ' '; 463 PrintQuotedString(Data, OS); 464 EmitEOL(); 465} 466 467/// EmitIntValue - Special case of EmitValue that avoids the client having 468/// to pass in a MCExpr for constant integers. 469void MCAsmStreamer::EmitIntValue(uint64_t Value, unsigned Size, 470 unsigned AddrSpace) { 471 assert(CurSection && "Cannot emit contents before setting section!"); 472 const char *Directive = 0; 473 switch (Size) { 474 default: break; 475 case 1: Directive = MAI.getData8bitsDirective(AddrSpace); break; 476 case 2: Directive = MAI.getData16bitsDirective(AddrSpace); break; 477 case 4: Directive = MAI.getData32bitsDirective(AddrSpace); break; 478 case 8: 479 Directive = MAI.getData64bitsDirective(AddrSpace); 480 // If the target doesn't support 64-bit data, emit as two 32-bit halves. 481 if (Directive) break; 482 if (isLittleEndian()) { 483 EmitIntValue((uint32_t)(Value >> 0 ), 4, AddrSpace); 484 EmitIntValue((uint32_t)(Value >> 32), 4, AddrSpace); 485 } else { 486 EmitIntValue((uint32_t)(Value >> 32), 4, AddrSpace); 487 EmitIntValue((uint32_t)(Value >> 0 ), 4, AddrSpace); 488 } 489 return; 490 } 491 492 assert(Directive && "Invalid size for machine code value!"); 493 OS << Directive << truncateToSize(Value, Size); 494 EmitEOL(); 495} 496 497void MCAsmStreamer::EmitValue(const MCExpr *Value, unsigned Size, 498 unsigned AddrSpace) { 499 assert(CurSection && "Cannot emit contents before setting section!"); 500 const char *Directive = 0; 501 switch (Size) { 502 default: break; 503 case 1: Directive = MAI.getData8bitsDirective(AddrSpace); break; 504 case 2: Directive = MAI.getData16bitsDirective(AddrSpace); break; 505 case 4: Directive = MAI.getData32bitsDirective(AddrSpace); break; 506 case 8: Directive = MAI.getData64bitsDirective(AddrSpace); break; 507 } 508 509 assert(Directive && "Invalid size for machine code value!"); 510 OS << Directive << *Value; 511 EmitEOL(); 512} 513 514void MCAsmStreamer::EmitULEB128Value(const MCExpr *Value, unsigned AddrSpace) { 515 assert(MAI.hasLEB128() && "Cannot print a .uleb"); 516 OS << ".uleb128 " << *Value; 517 EmitEOL(); 518} 519 520void MCAsmStreamer::EmitSLEB128Value(const MCExpr *Value, unsigned AddrSpace) { 521 assert(MAI.hasLEB128() && "Cannot print a .sleb"); 522 OS << ".sleb128 " << *Value; 523 EmitEOL(); 524} 525 526void MCAsmStreamer::EmitGPRel32Value(const MCExpr *Value) { 527 assert(MAI.getGPRel32Directive() != 0); 528 OS << MAI.getGPRel32Directive() << *Value; 529 EmitEOL(); 530} 531 532 533/// EmitFill - Emit NumBytes bytes worth of the value specified by 534/// FillValue. This implements directives such as '.space'. 535void MCAsmStreamer::EmitFill(uint64_t NumBytes, uint8_t FillValue, 536 unsigned AddrSpace) { 537 if (NumBytes == 0) return; 538 539 if (AddrSpace == 0) 540 if (const char *ZeroDirective = MAI.getZeroDirective()) { 541 OS << ZeroDirective << NumBytes; 542 if (FillValue != 0) 543 OS << ',' << (int)FillValue; 544 EmitEOL(); 545 return; 546 } 547 548 // Emit a byte at a time. 549 MCStreamer::EmitFill(NumBytes, FillValue, AddrSpace); 550} 551 552void MCAsmStreamer::EmitValueToAlignment(unsigned ByteAlignment, int64_t Value, 553 unsigned ValueSize, 554 unsigned MaxBytesToEmit) { 555 // Some assemblers don't support non-power of two alignments, so we always 556 // emit alignments as a power of two if possible. 557 if (isPowerOf2_32(ByteAlignment)) { 558 switch (ValueSize) { 559 default: llvm_unreachable("Invalid size for machine code value!"); 560 case 1: OS << MAI.getAlignDirective(); break; 561 // FIXME: use MAI for this! 562 case 2: OS << ".p2alignw "; break; 563 case 4: OS << ".p2alignl "; break; 564 case 8: llvm_unreachable("Unsupported alignment size!"); 565 } 566 567 if (MAI.getAlignmentIsInBytes()) 568 OS << ByteAlignment; 569 else 570 OS << Log2_32(ByteAlignment); 571 572 if (Value || MaxBytesToEmit) { 573 OS << ", 0x"; 574 OS.write_hex(truncateToSize(Value, ValueSize)); 575 576 if (MaxBytesToEmit) 577 OS << ", " << MaxBytesToEmit; 578 } 579 EmitEOL(); 580 return; 581 } 582 583 // Non-power of two alignment. This is not widely supported by assemblers. 584 // FIXME: Parameterize this based on MAI. 585 switch (ValueSize) { 586 default: llvm_unreachable("Invalid size for machine code value!"); 587 case 1: OS << ".balign"; break; 588 case 2: OS << ".balignw"; break; 589 case 4: OS << ".balignl"; break; 590 case 8: llvm_unreachable("Unsupported alignment size!"); 591 } 592 593 OS << ' ' << ByteAlignment; 594 OS << ", " << truncateToSize(Value, ValueSize); 595 if (MaxBytesToEmit) 596 OS << ", " << MaxBytesToEmit; 597 EmitEOL(); 598} 599 600void MCAsmStreamer::EmitCodeAlignment(unsigned ByteAlignment, 601 unsigned MaxBytesToEmit) { 602 // Emit with a text fill value. 603 EmitValueToAlignment(ByteAlignment, MAI.getTextAlignFillValue(), 604 1, MaxBytesToEmit); 605} 606 607void MCAsmStreamer::EmitValueToOffset(const MCExpr *Offset, 608 unsigned char Value) { 609 // FIXME: Verify that Offset is associated with the current section. 610 OS << ".org " << *Offset << ", " << (unsigned) Value; 611 EmitEOL(); 612} 613 614 615void MCAsmStreamer::EmitFileDirective(StringRef Filename) { 616 assert(MAI.hasSingleParameterDotFile()); 617 OS << "\t.file\t"; 618 PrintQuotedString(Filename, OS); 619 EmitEOL(); 620} 621 622void MCAsmStreamer::EmitDwarfFileDirective(unsigned FileNo, StringRef Filename){ 623 OS << "\t.file\t" << FileNo << ' '; 624 PrintQuotedString(Filename, OS); 625 EmitEOL(); 626} 627 628void MCAsmStreamer::AddEncodingComment(const MCInst &Inst) { 629 raw_ostream &OS = GetCommentOS(); 630 SmallString<256> Code; 631 SmallVector<MCFixup, 4> Fixups; 632 raw_svector_ostream VecOS(Code); 633 Emitter->EncodeInstruction(Inst, VecOS, Fixups); 634 VecOS.flush(); 635 636 // If we are showing fixups, create symbolic markers in the encoded 637 // representation. We do this by making a per-bit map to the fixup item index, 638 // then trying to display it as nicely as possible. 639 SmallVector<uint8_t, 64> FixupMap; 640 FixupMap.resize(Code.size() * 8); 641 for (unsigned i = 0, e = Code.size() * 8; i != e; ++i) 642 FixupMap[i] = 0; 643 644 for (unsigned i = 0, e = Fixups.size(); i != e; ++i) { 645 MCFixup &F = Fixups[i]; 646 const MCFixupKindInfo &Info = Emitter->getFixupKindInfo(F.getKind()); 647 for (unsigned j = 0; j != Info.TargetSize; ++j) { 648 unsigned Index = F.getOffset() * 8 + Info.TargetOffset + j; 649 assert(Index < Code.size() * 8 && "Invalid offset in fixup!"); 650 FixupMap[Index] = 1 + i; 651 } 652 } 653 654 OS << "encoding: ["; 655 for (unsigned i = 0, e = Code.size(); i != e; ++i) { 656 if (i) 657 OS << ','; 658 659 // See if all bits are the same map entry. 660 uint8_t MapEntry = FixupMap[i * 8 + 0]; 661 for (unsigned j = 1; j != 8; ++j) { 662 if (FixupMap[i * 8 + j] == MapEntry) 663 continue; 664 665 MapEntry = uint8_t(~0U); 666 break; 667 } 668 669 if (MapEntry != uint8_t(~0U)) { 670 if (MapEntry == 0) { 671 OS << format("0x%02x", uint8_t(Code[i])); 672 } else { 673 assert(Code[i] == 0 && "Encoder wrote into fixed up bit!"); 674 OS << char('A' + MapEntry - 1); 675 } 676 } else { 677 // Otherwise, write out in binary. 678 OS << "0b"; 679 for (unsigned j = 8; j--;) { 680 unsigned Bit = (Code[i] >> j) & 1; 681 if (uint8_t MapEntry = FixupMap[i * 8 + j]) { 682 assert(Bit == 0 && "Encoder wrote into fixed up bit!"); 683 OS << char('A' + MapEntry - 1); 684 } else 685 OS << Bit; 686 } 687 } 688 } 689 OS << "]\n"; 690 691 for (unsigned i = 0, e = Fixups.size(); i != e; ++i) { 692 MCFixup &F = Fixups[i]; 693 const MCFixupKindInfo &Info = Emitter->getFixupKindInfo(F.getKind()); 694 OS << " fixup " << char('A' + i) << " - " << "offset: " << F.getOffset() 695 << ", value: " << *F.getValue() << ", kind: " << Info.Name << "\n"; 696 } 697} 698 699void MCAsmStreamer::EmitInstruction(const MCInst &Inst) { 700 assert(CurSection && "Cannot emit contents before setting section!"); 701 702 // Show the encoding in a comment if we have a code emitter. 703 if (Emitter) 704 AddEncodingComment(Inst); 705 706 // Show the MCInst if enabled. 707 if (ShowInst) { 708 Inst.dump_pretty(GetCommentOS(), &MAI, InstPrinter.get(), "\n "); 709 GetCommentOS() << "\n"; 710 } 711 712 // If we have an AsmPrinter, use that to print, otherwise print the MCInst. 713 if (InstPrinter) 714 InstPrinter->printInst(&Inst, OS); 715 else 716 Inst.print(OS, &MAI); 717 EmitEOL(); 718} 719 720/// EmitRawText - If this file is backed by an assembly streamer, this dumps 721/// the specified string in the output .s file. This capability is 722/// indicated by the hasRawTextSupport() predicate. 723void MCAsmStreamer::EmitRawText(StringRef String) { 724 if (!String.empty() && String.back() == '\n') 725 String = String.substr(0, String.size()-1); 726 OS << String; 727 EmitEOL(); 728} 729 730void MCAsmStreamer::Finish() { 731} 732 733MCStreamer *llvm::createAsmStreamer(MCContext &Context, 734 formatted_raw_ostream &OS, 735 bool isLittleEndian, 736 bool isVerboseAsm, MCInstPrinter *IP, 737 MCCodeEmitter *CE, bool ShowInst) { 738 return new MCAsmStreamer(Context, OS, isLittleEndian, isVerboseAsm, 739 IP, CE, ShowInst); 740} 741