2672 lines · cpp
1//===- lib/MC/MCAsmStreamer.cpp - Text Assembly Output ----------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "llvm/ADT/SmallString.h"10#include "llvm/ADT/StringExtras.h"11#include "llvm/ADT/Twine.h"12#include "llvm/DebugInfo/CodeView/SymbolRecord.h"13#include "llvm/MC/MCAsmBackend.h"14#include "llvm/MC/MCAsmInfo.h"15#include "llvm/MC/MCAssembler.h"16#include "llvm/MC/MCCodeEmitter.h"17#include "llvm/MC/MCCodeView.h"18#include "llvm/MC/MCContext.h"19#include "llvm/MC/MCExpr.h"20#include "llvm/MC/MCInst.h"21#include "llvm/MC/MCInstPrinter.h"22#include "llvm/MC/MCObjectFileInfo.h"23#include "llvm/MC/MCObjectWriter.h"24#include "llvm/MC/MCPseudoProbe.h"25#include "llvm/MC/MCRegister.h"26#include "llvm/MC/MCRegisterInfo.h"27#include "llvm/MC/MCSectionMachO.h"28#include "llvm/MC/MCStreamer.h"29#include "llvm/MC/MCSymbolXCOFF.h"30#include "llvm/MC/TargetRegistry.h"31#include "llvm/Support/ErrorHandling.h"32#include "llvm/Support/Format.h"33#include "llvm/Support/FormattedStream.h"34#include "llvm/Support/LEB128.h"35#include "llvm/Support/MathExtras.h"36#include "llvm/Support/Path.h"37#include <algorithm>38#include <optional>39 40using namespace llvm;41 42namespace {43 44class MCAsmStreamer final : public MCStreamer {45 std::unique_ptr<formatted_raw_ostream> OSOwner;46 formatted_raw_ostream &OS;47 const MCAsmInfo *MAI;48 std::unique_ptr<MCInstPrinter> InstPrinter;49 std::unique_ptr<MCAssembler> Assembler;50 51 SmallString<128> ExplicitCommentToEmit;52 SmallString<128> CommentToEmit;53 raw_svector_ostream CommentStream;54 raw_null_ostream NullStream;55 56 bool EmittedSectionDirective = false;57 58 bool IsVerboseAsm = false;59 bool ShowInst = false;60 bool UseDwarfDirectory = false;61 62 void EmitRegisterName(int64_t Register);63 void PrintQuotedString(StringRef Data, raw_ostream &OS) const;64 void printDwarfFileDirective(unsigned FileNo, StringRef Directory,65 StringRef Filename,66 std::optional<MD5::MD5Result> Checksum,67 std::optional<StringRef> Source,68 bool UseDwarfDirectory,69 raw_svector_ostream &OS) const;70 void emitCFIStartProcImpl(MCDwarfFrameInfo &Frame) override;71 void emitCFIEndProcImpl(MCDwarfFrameInfo &Frame) override;72 73public:74 MCAsmStreamer(MCContext &Context, std::unique_ptr<formatted_raw_ostream> os,75 std::unique_ptr<MCInstPrinter> printer,76 std::unique_ptr<MCCodeEmitter> emitter,77 std::unique_ptr<MCAsmBackend> asmbackend)78 : MCStreamer(Context), OSOwner(std::move(os)), OS(*OSOwner),79 MAI(Context.getAsmInfo()), InstPrinter(std::move(printer)),80 Assembler(std::make_unique<MCAssembler>(81 Context, std::move(asmbackend), std::move(emitter),82 (asmbackend) ? asmbackend->createObjectWriter(NullStream)83 : nullptr)),84 CommentStream(CommentToEmit) {85 assert(InstPrinter);86 if (Assembler->getBackendPtr())87 setAllowAutoPadding(Assembler->getBackend().allowAutoPadding());88 89 Context.setUseNamesOnTempLabels(true);90 91 auto *TO = Context.getTargetOptions();92 if (!TO)93 return;94 IsVerboseAsm = TO->AsmVerbose;95 if (IsVerboseAsm)96 InstPrinter->setCommentStream(CommentStream);97 ShowInst = TO->ShowMCInst;98 switch (TO->MCUseDwarfDirectory) {99 case MCTargetOptions::DisableDwarfDirectory:100 UseDwarfDirectory = false;101 break;102 case MCTargetOptions::EnableDwarfDirectory:103 UseDwarfDirectory = true;104 break;105 case MCTargetOptions::DefaultDwarfDirectory:106 UseDwarfDirectory =107 Context.getAsmInfo()->enableDwarfFileDirectoryDefault();108 break;109 }110 }111 112 MCAssembler &getAssembler() { return *Assembler; }113 MCAssembler *getAssemblerPtr() override { return nullptr; }114 115 inline void EmitEOL() {116 // Dump Explicit Comments here.117 emitExplicitComments();118 // If we don't have any comments, just emit a \n.119 if (!IsVerboseAsm) {120 OS << '\n';121 return;122 }123 EmitCommentsAndEOL();124 }125 126 void emitSyntaxDirective() override;127 128 void EmitCommentsAndEOL();129 130 /// Return true if this streamer supports verbose assembly at all.131 bool isVerboseAsm() const override { return IsVerboseAsm; }132 133 /// Do we support EmitRawText?134 bool hasRawTextSupport() const override { return true; }135 136 /// Add a comment that can be emitted to the generated .s file to make the137 /// output of the compiler more readable. This only affects the MCAsmStreamer138 /// and only when verbose assembly output is enabled.139 void AddComment(const Twine &T, bool EOL = true) override;140 141 /// Add a comment showing the encoding of an instruction.142 void AddEncodingComment(const MCInst &Inst, const MCSubtargetInfo &);143 144 /// Return a raw_ostream that comments can be written to.145 /// Unlike AddComment, you are required to terminate comments with \n if you146 /// use this method.147 raw_ostream &getCommentOS() override {148 if (!IsVerboseAsm)149 return nulls(); // Discard comments unless in verbose asm mode.150 return CommentStream;151 }152 153 void emitRawComment(const Twine &T, bool TabPrefix = true) override;154 155 void addExplicitComment(const Twine &T) override;156 void emitExplicitComments() override;157 158 /// Emit a blank line to a .s file to pretty it up.159 void addBlankLine() override { EmitEOL(); }160 161 /// @name MCStreamer Interface162 /// @{163 164 void switchSection(MCSection *Section, uint32_t Subsection) override;165 bool popSection() override;166 167 void emitELFSymverDirective(const MCSymbol *OriginalSym, StringRef Name,168 bool KeepOriginalSym) override;169 170 void emitLOHDirective(MCLOHType Kind, const MCLOHArgs &Args) override;171 172 void emitGNUAttribute(unsigned Tag, unsigned Value) override;173 174 StringRef getMnemonic(const MCInst &MI) const override {175 auto [Ptr, Bits] = InstPrinter->getMnemonic(MI);176 assert((Bits != 0 || Ptr == nullptr) &&177 "Invalid char pointer for instruction with no mnemonic");178 return Ptr;179 }180 181 void emitLabel(MCSymbol *Symbol, SMLoc Loc = SMLoc()) override;182 183 void emitSubsectionsViaSymbols() override;184 void emitLinkerOptions(ArrayRef<std::string> Options) override;185 void emitDataRegion(MCDataRegionType Kind) override;186 void emitVersionMin(MCVersionMinType Kind, unsigned Major, unsigned Minor,187 unsigned Update, VersionTuple SDKVersion) override;188 void emitBuildVersion(unsigned Platform, unsigned Major, unsigned Minor,189 unsigned Update, VersionTuple SDKVersion) override;190 void emitDarwinTargetVariantBuildVersion(unsigned Platform, unsigned Major,191 unsigned Minor, unsigned Update,192 VersionTuple SDKVersion) override;193 194 void emitAssignment(MCSymbol *Symbol, const MCExpr *Value) override;195 void emitConditionalAssignment(MCSymbol *Symbol,196 const MCExpr *Value) override;197 void emitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol) override;198 bool emitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override;199 200 void emitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) override;201 void beginCOFFSymbolDef(const MCSymbol *Symbol) override;202 void emitCOFFSymbolStorageClass(int StorageClass) override;203 void emitCOFFSymbolType(int Type) override;204 void endCOFFSymbolDef() override;205 void emitCOFFSafeSEH(MCSymbol const *Symbol) override;206 void emitCOFFSymbolIndex(MCSymbol const *Symbol) override;207 void emitCOFFSectionIndex(MCSymbol const *Symbol) override;208 void emitCOFFSecRel32(MCSymbol const *Symbol, uint64_t Offset) override;209 void emitCOFFImgRel32(MCSymbol const *Symbol, int64_t Offset) override;210 void emitCOFFSecNumber(MCSymbol const *Symbol) override;211 void emitCOFFSecOffset(MCSymbol const *Symbol) override;212 void emitXCOFFLocalCommonSymbol(MCSymbol *LabelSym, uint64_t Size,213 MCSymbol *CsectSym, Align Alignment) override;214 void emitXCOFFSymbolLinkageWithVisibility(MCSymbol *Symbol,215 MCSymbolAttr Linkage,216 MCSymbolAttr Visibility) override;217 void emitXCOFFRenameDirective(const MCSymbol *Name,218 StringRef Rename) override;219 220 void emitXCOFFRefDirective(const MCSymbol *Symbol) override;221 222 void emitXCOFFExceptDirective(const MCSymbol *Symbol,223 const MCSymbol *Trap,224 unsigned Lang, unsigned Reason,225 unsigned FunctionSize, bool hasDebug) override;226 void emitXCOFFCInfoSym(StringRef Name, StringRef Metadata) override;227 228 void emitELFSize(MCSymbol *Symbol, const MCExpr *Value) override;229 void emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,230 Align ByteAlignment) override;231 232 /// Emit a local common (.lcomm) symbol.233 ///234 /// @param Symbol - The common symbol to emit.235 /// @param Size - The size of the common symbol.236 /// @param ByteAlignment - The alignment of the common symbol in bytes.237 void emitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size,238 Align ByteAlignment) override;239 240 void emitZerofill(MCSection *Section, MCSymbol *Symbol = nullptr,241 uint64_t Size = 0, Align ByteAlignment = Align(1),242 SMLoc Loc = SMLoc()) override;243 244 void emitTBSSSymbol(MCSection *Section, MCSymbol *Symbol, uint64_t Size,245 Align ByteAlignment = Align(1)) override;246 247 void emitBinaryData(StringRef Data) override;248 249 void emitBytes(StringRef Data) override;250 251 void emitValueImpl(const MCExpr *Value, unsigned Size,252 SMLoc Loc = SMLoc()) override;253 void emitIntValue(uint64_t Value, unsigned Size) override;254 void emitIntValueInHex(uint64_t Value, unsigned Size) override;255 void emitIntValueInHexWithPadding(uint64_t Value, unsigned Size) override;256 257 void emitULEB128Value(const MCExpr *Value) override;258 259 void emitSLEB128Value(const MCExpr *Value) override;260 261 void emitFill(const MCExpr &NumBytes, uint64_t FillValue,262 SMLoc Loc = SMLoc()) override;263 264 void emitFill(const MCExpr &NumValues, int64_t Size, int64_t Expr,265 SMLoc Loc = SMLoc()) override;266 267 void emitAlignmentDirective(uint64_t ByteAlignment,268 std::optional<int64_t> Value, unsigned ValueSize,269 unsigned MaxBytesToEmit);270 271 void emitValueToAlignment(Align Alignment, int64_t Fill = 0,272 uint8_t FillLen = 1,273 unsigned MaxBytesToEmit = 0) override;274 275 void emitCodeAlignment(Align Alignment, const MCSubtargetInfo *STI,276 unsigned MaxBytesToEmit = 0) override;277 278 void emitValueToOffset(const MCExpr *Offset,279 unsigned char Value,280 SMLoc Loc) override;281 282 void emitFileDirective(StringRef Filename) override;283 void emitFileDirective(StringRef Filename, StringRef CompilerVersion,284 StringRef TimeStamp, StringRef Description) override;285 Expected<unsigned> tryEmitDwarfFileDirective(286 unsigned FileNo, StringRef Directory, StringRef Filename,287 std::optional<MD5::MD5Result> Checksum = std::nullopt,288 std::optional<StringRef> Source = std::nullopt,289 unsigned CUID = 0) override;290 void emitDwarfFile0Directive(StringRef Directory, StringRef Filename,291 std::optional<MD5::MD5Result> Checksum,292 std::optional<StringRef> Source,293 unsigned CUID = 0) override;294 void emitDwarfLocDirective(unsigned FileNo, unsigned Line, unsigned Column,295 unsigned Flags, unsigned Isa,296 unsigned Discriminator, StringRef FileName,297 StringRef Location = {}) override;298 void emitDwarfLocLabelDirective(SMLoc Loc, StringRef Name) override;299 300 MCSymbol *getDwarfLineTableSymbol(unsigned CUID) override;301 302 bool emitCVFileDirective(unsigned FileNo, StringRef Filename,303 ArrayRef<uint8_t> Checksum,304 unsigned ChecksumKind) override;305 bool emitCVFuncIdDirective(unsigned FuncId) override;306 bool emitCVInlineSiteIdDirective(unsigned FunctionId, unsigned IAFunc,307 unsigned IAFile, unsigned IALine,308 unsigned IACol, SMLoc Loc) override;309 void emitCVLocDirective(unsigned FunctionId, unsigned FileNo, unsigned Line,310 unsigned Column, bool PrologueEnd, bool IsStmt,311 StringRef FileName, SMLoc Loc) override;312 void emitCVLinetableDirective(unsigned FunctionId, const MCSymbol *FnStart,313 const MCSymbol *FnEnd) override;314 void emitCVInlineLinetableDirective(unsigned PrimaryFunctionId,315 unsigned SourceFileId,316 unsigned SourceLineNum,317 const MCSymbol *FnStartSym,318 const MCSymbol *FnEndSym) override;319 320 void PrintCVDefRangePrefix(321 ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges);322 323 void emitCVDefRangeDirective(324 ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,325 codeview::DefRangeRegisterRelHeader DRHdr) override;326 327 void emitCVDefRangeDirective(328 ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,329 codeview::DefRangeSubfieldRegisterHeader DRHdr) override;330 331 void emitCVDefRangeDirective(332 ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,333 codeview::DefRangeRegisterHeader DRHdr) override;334 335 void emitCVDefRangeDirective(336 ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,337 codeview::DefRangeFramePointerRelHeader DRHdr) override;338 339 void emitCVStringTableDirective() override;340 void emitCVFileChecksumsDirective() override;341 void emitCVFileChecksumOffsetDirective(unsigned FileNo) override;342 void emitCVFPOData(const MCSymbol *ProcSym, SMLoc L) override;343 344 void emitIdent(StringRef IdentString) override;345 void emitCFIBKeyFrame() override;346 void emitCFIMTETaggedFrame() override;347 void emitCFISections(bool EH, bool Debug, bool SFrame) override;348 void emitCFIDefCfa(int64_t Register, int64_t Offset, SMLoc Loc) override;349 void emitCFIDefCfaOffset(int64_t Offset, SMLoc Loc) override;350 void emitCFIDefCfaRegister(int64_t Register, SMLoc Loc) override;351 void emitCFILLVMDefAspaceCfa(int64_t Register, int64_t Offset,352 int64_t AddressSpace, SMLoc Loc) override;353 void emitCFIOffset(int64_t Register, int64_t Offset, SMLoc Loc) override;354 void emitCFIPersonality(const MCSymbol *Sym, unsigned Encoding) override;355 void emitCFILsda(const MCSymbol *Sym, unsigned Encoding) override;356 void emitCFIRememberState(SMLoc Loc) override;357 void emitCFIRestoreState(SMLoc Loc) override;358 void emitCFIRestore(int64_t Register, SMLoc Loc) override;359 void emitCFISameValue(int64_t Register, SMLoc Loc) override;360 void emitCFIRelOffset(int64_t Register, int64_t Offset, SMLoc Loc) override;361 void emitCFIAdjustCfaOffset(int64_t Adjustment, SMLoc Loc) override;362 void emitCFIEscape(StringRef Values, SMLoc Loc) override;363 void emitCFIGnuArgsSize(int64_t Size, SMLoc Loc) override;364 void emitCFISignalFrame() override;365 void emitCFIUndefined(int64_t Register, SMLoc Loc) override;366 void emitCFIRegister(int64_t Register1, int64_t Register2,367 SMLoc Loc) override;368 void emitCFIWindowSave(SMLoc Loc) override;369 void emitCFINegateRAState(SMLoc Loc) override;370 void emitCFINegateRAStateWithPC(SMLoc Loc) override;371 void emitCFIReturnColumn(int64_t Register) override;372 void emitCFILabelDirective(SMLoc Loc, StringRef Name) override;373 void emitCFIValOffset(int64_t Register, int64_t Offset, SMLoc Loc) override;374 375 void emitWinCFIStartProc(const MCSymbol *Symbol, SMLoc Loc) override;376 void emitWinCFIEndProc(SMLoc Loc) override;377 void emitWinCFIFuncletOrFuncEnd(SMLoc Loc) override;378 void emitWinCFIStartChained(SMLoc Loc) override;379 void emitWinCFIEndChained(SMLoc Loc) override;380 void emitWinCFIPushReg(MCRegister Register, SMLoc Loc) override;381 void emitWinCFISetFrame(MCRegister Register, unsigned Offset,382 SMLoc Loc) override;383 void emitWinCFIAllocStack(unsigned Size, SMLoc Loc) override;384 void emitWinCFISaveReg(MCRegister Register, unsigned Offset,385 SMLoc Loc) override;386 void emitWinCFISaveXMM(MCRegister Register, unsigned Offset,387 SMLoc Loc) override;388 void emitWinCFIPushFrame(bool Code, SMLoc Loc) override;389 void emitWinCFIEndProlog(SMLoc Loc) override;390 void emitWinCFIBeginEpilogue(SMLoc Loc) override;391 void emitWinCFIEndEpilogue(SMLoc Loc) override;392 void emitWinCFIUnwindV2Start(SMLoc Loc) override;393 void emitWinCFIUnwindVersion(uint8_t Version, SMLoc Loc) override;394 395 void emitWinEHHandler(const MCSymbol *Sym, bool Unwind, bool Except,396 SMLoc Loc) override;397 void emitWinEHHandlerData(SMLoc Loc) override;398 399 void emitCGProfileEntry(const MCSymbolRefExpr *From,400 const MCSymbolRefExpr *To, uint64_t Count) override;401 402 void emitInstruction(const MCInst &Inst, const MCSubtargetInfo &STI) override;403 404 void emitPseudoProbe(uint64_t Guid, uint64_t Index, uint64_t Type,405 uint64_t Attr, uint64_t Discriminator,406 const MCPseudoProbeInlineStack &InlineStack,407 MCSymbol *FnSym) override;408 409 void emitRelocDirective(const MCExpr &Offset, StringRef Name,410 const MCExpr *Expr, SMLoc Loc) override;411 412 void emitAddrsig() override;413 void emitAddrsigSym(const MCSymbol *Sym) override;414 415 /// If this file is backed by an assembly streamer, this dumps the specified416 /// string in the output .s file. This capability is indicated by the417 /// hasRawTextSupport() predicate.418 void emitRawTextImpl(StringRef String) override;419 420 void finishImpl() override;421 422 void emitDwarfUnitLength(uint64_t Length, const Twine &Comment) override;423 424 MCSymbol *emitDwarfUnitLength(const Twine &Prefix,425 const Twine &Comment) override;426 427 void emitDwarfLineStartLabel(MCSymbol *StartSym) override;428 429 void emitDwarfLineEndEntry(MCSection *Section, MCSymbol *LastLabel,430 MCSymbol *EndLabel = nullptr) override;431 432 void emitDwarfAdvanceLineAddr(int64_t LineDelta, const MCSymbol *LastLabel,433 const MCSymbol *Label,434 unsigned PointerSize) override;435};436 437} // end anonymous namespace.438 439void MCAsmStreamer::AddComment(const Twine &T, bool EOL) {440 if (!IsVerboseAsm) return;441 442 T.toVector(CommentToEmit);443 444 if (EOL)445 CommentToEmit.push_back('\n'); // Place comment in a new line.446}447 448void MCAsmStreamer::EmitCommentsAndEOL() {449 if (CommentToEmit.empty() && CommentStream.GetNumBytesInBuffer() == 0) {450 OS << '\n';451 return;452 }453 454 StringRef Comments = CommentToEmit;455 456 assert(Comments.back() == '\n' &&457 "Comment array not newline terminated");458 do {459 // Emit a line of comments.460 OS.PadToColumn(MAI->getCommentColumn());461 size_t Position = Comments.find('\n');462 OS << MAI->getCommentString() << ' ' << Comments.substr(0, Position) <<'\n';463 464 Comments = Comments.substr(Position+1);465 } while (!Comments.empty());466 467 CommentToEmit.clear();468}469 470static inline int64_t truncateToSize(int64_t Value, unsigned Bytes) {471 assert(Bytes > 0 && Bytes <= 8 && "Invalid size!");472 return Value & ((uint64_t) (int64_t) -1 >> (64 - Bytes * 8));473}474 475void MCAsmStreamer::emitRawComment(const Twine &T, bool TabPrefix) {476 if (TabPrefix)477 OS << '\t';478 OS << MAI->getCommentString() << T;479 EmitEOL();480}481 482void MCAsmStreamer::addExplicitComment(const Twine &T) {483 StringRef c = T.getSingleStringRef();484 if (c == MAI->getSeparatorString())485 return;486 if (c.starts_with(StringRef("//"))) {487 ExplicitCommentToEmit.append("\t");488 ExplicitCommentToEmit.append(MAI->getCommentString());489 // drop //490 ExplicitCommentToEmit.append(c.substr(2).str());491 } else if (c.starts_with(StringRef("/*"))) {492 size_t p = 2, len = c.size() - 2;493 // emit each line in comment as separate newline.494 do {495 size_t newp = std::min(len, c.find_first_of("\r\n", p));496 ExplicitCommentToEmit.append("\t");497 ExplicitCommentToEmit.append(MAI->getCommentString());498 ExplicitCommentToEmit.append(c.slice(p, newp).str());499 // If we have another line in this comment add line500 if (newp < len)501 ExplicitCommentToEmit.append("\n");502 p = newp + 1;503 } while (p < len);504 } else if (c.starts_with(StringRef(MAI->getCommentString()))) {505 ExplicitCommentToEmit.append("\t");506 ExplicitCommentToEmit.append(c.str());507 } else if (c.front() == '#') {508 509 ExplicitCommentToEmit.append("\t");510 ExplicitCommentToEmit.append(MAI->getCommentString());511 ExplicitCommentToEmit.append(c.substr(1).str());512 } else513 assert(false && "Unexpected Assembly Comment");514 // full line comments immediately output515 if (c.back() == '\n')516 emitExplicitComments();517}518 519void MCAsmStreamer::emitExplicitComments() {520 StringRef Comments = ExplicitCommentToEmit;521 if (!Comments.empty())522 OS << Comments;523 ExplicitCommentToEmit.clear();524}525 526void MCAsmStreamer::switchSection(MCSection *Section, uint32_t Subsection) {527 MCSectionSubPair Cur = getCurrentSection();528 if (!EmittedSectionDirective ||529 MCSectionSubPair(Section, Subsection) != Cur) {530 EmittedSectionDirective = true;531 if (MCTargetStreamer *TS = getTargetStreamer()) {532 TS->changeSection(Cur.first, Section, Subsection, OS);533 } else {534 MAI->printSwitchToSection(*Section, Subsection,535 getContext().getTargetTriple(), OS);536 }537 }538 MCStreamer::switchSection(Section, Subsection);539}540 541bool MCAsmStreamer::popSection() {542 if (!MCStreamer::popSection())543 return false;544 auto [Sec, Subsec] = getCurrentSection();545 MAI->printSwitchToSection(*Sec, Subsec, getContext().getTargetTriple(), OS);546 return true;547}548 549void MCAsmStreamer::emitELFSymverDirective(const MCSymbol *OriginalSym,550 StringRef Name,551 bool KeepOriginalSym) {552 OS << ".symver ";553 OriginalSym->print(OS, MAI);554 OS << ", " << Name;555 if (!KeepOriginalSym && !Name.contains("@@@"))556 OS << ", remove";557 EmitEOL();558}559 560void MCAsmStreamer::emitLabel(MCSymbol *Symbol, SMLoc Loc) {561 MCStreamer::emitLabel(Symbol, Loc);562 // FIXME: Fix CodeGen/AArch64/arm64ec-varargs.ll. emitLabel is followed by563 // setVariableValue, leading to an assertion failure if setOffset(0) is564 // called.565 if (!Symbol->isVariable() &&566 getContext().getObjectFileType() != MCContext::IsCOFF)567 Symbol->setOffset(0);568 569 Symbol->print(OS, MAI);570 OS << MAI->getLabelSuffix();571 572 EmitEOL();573}574 575void MCAsmStreamer::emitLOHDirective(MCLOHType Kind, const MCLOHArgs &Args) {576 StringRef str = MCLOHIdToName(Kind);577 578#ifndef NDEBUG579 int NbArgs = MCLOHIdToNbArgs(Kind);580 assert(NbArgs != -1 && ((size_t)NbArgs) == Args.size() && "Malformed LOH!");581 assert(str != "" && "Invalid LOH name");582#endif583 584 OS << "\t" << MCLOHDirectiveName() << " " << str << "\t";585 bool IsFirst = true;586 for (const MCSymbol *Arg : Args) {587 if (!IsFirst)588 OS << ", ";589 IsFirst = false;590 Arg->print(OS, MAI);591 }592 EmitEOL();593}594 595void MCAsmStreamer::emitGNUAttribute(unsigned Tag, unsigned Value) {596 OS << "\t.gnu_attribute " << Tag << ", " << Value << "\n";597}598 599void MCAsmStreamer::emitSubsectionsViaSymbols() {600 OS << ".subsections_via_symbols\n";601}602 603void MCAsmStreamer::emitLinkerOptions(ArrayRef<std::string> Options) {604 assert(!Options.empty() && "At least one option is required!");605 OS << "\t.linker_option \"" << Options[0] << '"';606 for (const std::string &Opt : llvm::drop_begin(Options))607 OS << ", " << '"' << Opt << '"';608 EmitEOL();609}610 611void MCAsmStreamer::emitDataRegion(MCDataRegionType Kind) {612 if (!MAI->doesSupportDataRegionDirectives())613 return;614 switch (Kind) {615 case MCDR_DataRegion: OS << "\t.data_region"; break;616 case MCDR_DataRegionJT8: OS << "\t.data_region jt8"; break;617 case MCDR_DataRegionJT16: OS << "\t.data_region jt16"; break;618 case MCDR_DataRegionJT32: OS << "\t.data_region jt32"; break;619 case MCDR_DataRegionEnd: OS << "\t.end_data_region"; break;620 }621 EmitEOL();622}623 624static const char *getVersionMinDirective(MCVersionMinType Type) {625 switch (Type) {626 case MCVM_WatchOSVersionMin: return ".watchos_version_min";627 case MCVM_TvOSVersionMin: return ".tvos_version_min";628 case MCVM_IOSVersionMin: return ".ios_version_min";629 case MCVM_OSXVersionMin: return ".macosx_version_min";630 }631 llvm_unreachable("Invalid MC version min type");632}633 634static void EmitSDKVersionSuffix(raw_ostream &OS,635 const VersionTuple &SDKVersion) {636 if (SDKVersion.empty())637 return;638 OS << '\t' << "sdk_version " << SDKVersion.getMajor();639 if (auto Minor = SDKVersion.getMinor()) {640 OS << ", " << *Minor;641 if (auto Subminor = SDKVersion.getSubminor()) {642 OS << ", " << *Subminor;643 }644 }645}646 647void MCAsmStreamer::emitVersionMin(MCVersionMinType Type, unsigned Major,648 unsigned Minor, unsigned Update,649 VersionTuple SDKVersion) {650 OS << '\t' << getVersionMinDirective(Type) << ' ' << Major << ", " << Minor;651 if (Update)652 OS << ", " << Update;653 EmitSDKVersionSuffix(OS, SDKVersion);654 EmitEOL();655}656 657static const char *getPlatformName(MachO::PlatformType Type) {658 switch (Type) {659#define PLATFORM(platform, id, name, build_name, target, tapi_target, \660 marketing) \661 case MachO::PLATFORM_##platform: \662 return #build_name;663#include "llvm/BinaryFormat/MachO.def"664 }665 llvm_unreachable("Invalid Mach-O platform type");666}667 668void MCAsmStreamer::emitBuildVersion(unsigned Platform, unsigned Major,669 unsigned Minor, unsigned Update,670 VersionTuple SDKVersion) {671 const char *PlatformName = getPlatformName((MachO::PlatformType)Platform);672 OS << "\t.build_version " << PlatformName << ", " << Major << ", " << Minor;673 if (Update)674 OS << ", " << Update;675 EmitSDKVersionSuffix(OS, SDKVersion);676 EmitEOL();677}678 679void MCAsmStreamer::emitDarwinTargetVariantBuildVersion(680 unsigned Platform, unsigned Major, unsigned Minor, unsigned Update,681 VersionTuple SDKVersion) {682 emitBuildVersion(Platform, Major, Minor, Update, SDKVersion);683}684 685void MCAsmStreamer::emitAssignment(MCSymbol *Symbol, const MCExpr *Value) {686 bool UseSet = MAI->usesSetToEquateSymbol();687 if (UseSet)688 OS << ".set ";689 Symbol->print(OS, MAI);690 OS << (UseSet ? ", " : " = ");691 MAI->printExpr(OS, *Value);692 693 EmitEOL();694 MCStreamer::emitAssignment(Symbol, Value);695}696 697void MCAsmStreamer::emitConditionalAssignment(MCSymbol *Symbol,698 const MCExpr *Value) {699 OS << ".lto_set_conditional ";700 Symbol->print(OS, MAI);701 OS << ", ";702 MAI->printExpr(OS, *Value);703 EmitEOL();704}705 706void MCAsmStreamer::emitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol) {707 OS << ".weakref ";708 Alias->print(OS, MAI);709 OS << ", ";710 Symbol->print(OS, MAI);711 EmitEOL();712}713 714bool MCAsmStreamer::emitSymbolAttribute(MCSymbol *Symbol,715 MCSymbolAttr Attribute) {716 switch (Attribute) {717 case MCSA_Invalid: llvm_unreachable("Invalid symbol attribute");718 case MCSA_ELF_TypeFunction: /// .type _foo, STT_FUNC # aka @function719 case MCSA_ELF_TypeIndFunction: /// .type _foo, STT_GNU_IFUNC720 case MCSA_ELF_TypeObject: /// .type _foo, STT_OBJECT # aka @object721 case MCSA_ELF_TypeTLS: /// .type _foo, STT_TLS # aka @tls_object722 case MCSA_ELF_TypeCommon: /// .type _foo, STT_COMMON # aka @common723 case MCSA_ELF_TypeNoType: /// .type _foo, STT_NOTYPE # aka @notype724 case MCSA_ELF_TypeGnuUniqueObject: /// .type _foo, @gnu_unique_object725 if (!MAI->hasDotTypeDotSizeDirective())726 return false; // Symbol attribute not supported727 OS << "\t.type\t";728 Symbol->print(OS, MAI);729 OS << ',' << ((MAI->getCommentString()[0] != '@') ? '@' : '%');730 switch (Attribute) {731 default: return false;732 case MCSA_ELF_TypeFunction: OS << "function"; break;733 case MCSA_ELF_TypeIndFunction: OS << "gnu_indirect_function"; break;734 case MCSA_ELF_TypeObject: OS << "object"; break;735 case MCSA_ELF_TypeTLS: OS << "tls_object"; break;736 case MCSA_ELF_TypeCommon: OS << "common"; break;737 case MCSA_ELF_TypeNoType: OS << "notype"; break;738 case MCSA_ELF_TypeGnuUniqueObject: OS << "gnu_unique_object"; break;739 }740 EmitEOL();741 return true;742 case MCSA_Global: // .globl/.global743 OS << MAI->getGlobalDirective();744 break;745 case MCSA_LGlobal: OS << "\t.lglobl\t"; break;746 case MCSA_Hidden: OS << "\t.hidden\t"; break;747 case MCSA_IndirectSymbol: OS << "\t.indirect_symbol\t"; break;748 case MCSA_Internal: OS << "\t.internal\t"; break;749 case MCSA_LazyReference: OS << "\t.lazy_reference\t"; break;750 case MCSA_Local: OS << "\t.local\t"; break;751 case MCSA_NoDeadStrip:752 if (!MAI->hasNoDeadStrip())753 return false;754 OS << "\t.no_dead_strip\t";755 break;756 case MCSA_SymbolResolver: OS << "\t.symbol_resolver\t"; break;757 case MCSA_AltEntry: OS << "\t.alt_entry\t"; break;758 case MCSA_PrivateExtern:759 OS << "\t.private_extern\t";760 break;761 case MCSA_Protected: OS << "\t.protected\t"; break;762 case MCSA_Reference: OS << "\t.reference\t"; break;763 case MCSA_Extern:764 OS << "\t.extern\t";765 break;766 case MCSA_Weak: OS << MAI->getWeakDirective(); break;767 case MCSA_WeakDefinition:768 OS << "\t.weak_definition\t";769 break;770 // .weak_reference771 case MCSA_WeakReference: OS << MAI->getWeakRefDirective(); break;772 case MCSA_WeakDefAutoPrivate: OS << "\t.weak_def_can_be_hidden\t"; break;773 case MCSA_Cold:774 // Assemblers currently do not support a .cold directive.775 case MCSA_Exported:776 // Non-AIX assemblers currently do not support exported visibility.777 return false;778 case MCSA_Memtag:779 OS << "\t.memtag\t";780 break;781 case MCSA_WeakAntiDep:782 OS << "\t.weak_anti_dep\t";783 break;784 }785 786 Symbol->print(OS, MAI);787 EmitEOL();788 789 return true;790}791 792void MCAsmStreamer::emitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) {793 OS << ".desc" << ' ';794 Symbol->print(OS, MAI);795 OS << ',' << DescValue;796 EmitEOL();797}798 799void MCAsmStreamer::emitSyntaxDirective() {800 if (MAI->getAssemblerDialect() == 1) {801 OS << "\t.intel_syntax noprefix";802 EmitEOL();803 }804 // FIXME: Currently emit unprefix'ed registers.805 // The intel_syntax directive has one optional argument806 // with may have a value of prefix or noprefix.807}808 809void MCAsmStreamer::beginCOFFSymbolDef(const MCSymbol *Symbol) {810 OS << "\t.def\t";811 Symbol->print(OS, MAI);812 OS << ';';813 EmitEOL();814}815 816void MCAsmStreamer::emitCOFFSymbolStorageClass(int StorageClass) {817 OS << "\t.scl\t" << StorageClass << ';';818 EmitEOL();819}820 821void MCAsmStreamer::emitCOFFSymbolType(int Type) {822 OS << "\t.type\t" << Type << ';';823 EmitEOL();824}825 826void MCAsmStreamer::endCOFFSymbolDef() {827 OS << "\t.endef";828 EmitEOL();829}830 831void MCAsmStreamer::emitCOFFSafeSEH(MCSymbol const *Symbol) {832 OS << "\t.safeseh\t";833 Symbol->print(OS, MAI);834 EmitEOL();835}836 837void MCAsmStreamer::emitCOFFSymbolIndex(MCSymbol const *Symbol) {838 OS << "\t.symidx\t";839 Symbol->print(OS, MAI);840 EmitEOL();841}842 843void MCAsmStreamer::emitCOFFSectionIndex(MCSymbol const *Symbol) {844 OS << "\t.secidx\t";845 Symbol->print(OS, MAI);846 EmitEOL();847}848 849void MCAsmStreamer::emitCOFFSecRel32(MCSymbol const *Symbol, uint64_t Offset) {850 OS << "\t.secrel32\t";851 Symbol->print(OS, MAI);852 if (Offset != 0)853 OS << '+' << Offset;854 EmitEOL();855}856 857void MCAsmStreamer::emitCOFFImgRel32(MCSymbol const *Symbol, int64_t Offset) {858 OS << "\t.rva\t";859 Symbol->print(OS, MAI);860 if (Offset > 0)861 OS << '+' << Offset;862 else if (Offset < 0)863 OS << '-' << -Offset;864 EmitEOL();865}866 867void MCAsmStreamer::emitCOFFSecNumber(MCSymbol const *Symbol) {868 OS << "\t.secnum\t";869 Symbol->print(OS, MAI);870 EmitEOL();871}872 873void MCAsmStreamer::emitCOFFSecOffset(MCSymbol const *Symbol) {874 OS << "\t.secoffset\t";875 Symbol->print(OS, MAI);876 EmitEOL();877}878 879// We need an XCOFF-specific version of this directive as the AIX syntax880// requires a QualName argument identifying the csect name and storage mapping881// class to appear before the alignment if we are specifying it.882void MCAsmStreamer::emitXCOFFLocalCommonSymbol(MCSymbol *LabelSym,883 uint64_t Size,884 MCSymbol *CsectSym,885 Align Alignment) {886 assert(MAI->getLCOMMDirectiveAlignmentType() == LCOMM::Log2Alignment &&887 "We only support writing log base-2 alignment format with XCOFF.");888 889 OS << "\t.lcomm\t";890 LabelSym->print(OS, MAI);891 OS << ',' << Size << ',';892 CsectSym->print(OS, MAI);893 OS << ',' << Log2(Alignment);894 895 EmitEOL();896 897 // Print symbol's rename (original name contains invalid character(s)) if898 // there is one.899 auto *XSym = static_cast<MCSymbolXCOFF *>(CsectSym);900 if (XSym->hasRename())901 emitXCOFFRenameDirective(XSym, XSym->getSymbolTableName());902}903 904void MCAsmStreamer::emitXCOFFSymbolLinkageWithVisibility(905 MCSymbol *Symbol, MCSymbolAttr Linkage, MCSymbolAttr Visibility) {906 auto &Sym = static_cast<MCSymbolXCOFF &>(*Symbol);907 switch (Linkage) {908 case MCSA_Global:909 OS << MAI->getGlobalDirective();910 break;911 case MCSA_Weak:912 OS << MAI->getWeakDirective();913 break;914 case MCSA_Extern:915 OS << "\t.extern\t";916 break;917 case MCSA_LGlobal:918 OS << "\t.lglobl\t";919 break;920 default:921 report_fatal_error("unhandled linkage type");922 }923 924 Symbol->print(OS, MAI);925 926 switch (Visibility) {927 case MCSA_Invalid:928 // Nothing to do.929 break;930 case MCSA_Hidden:931 OS << ",hidden";932 break;933 case MCSA_Protected:934 OS << ",protected";935 break;936 case MCSA_Exported:937 OS << ",exported";938 break;939 default:940 report_fatal_error("unexpected value for Visibility type");941 }942 EmitEOL();943 944 // Print symbol's rename (original name contains invalid character(s)) if945 // there is one.946 if (Sym.hasRename())947 emitXCOFFRenameDirective(&Sym, Sym.getSymbolTableName());948}949 950void MCAsmStreamer::emitXCOFFRenameDirective(const MCSymbol *Name,951 StringRef Rename) {952 OS << "\t.rename\t";953 Name->print(OS, MAI);954 const char DQ = '"';955 OS << ',' << DQ;956 for (char C : Rename) {957 // To escape a double quote character, the character should be doubled.958 if (C == DQ)959 OS << DQ;960 OS << C;961 }962 OS << DQ;963 EmitEOL();964}965 966void MCAsmStreamer::emitXCOFFRefDirective(const MCSymbol *Symbol) {967 OS << "\t.ref ";968 Symbol->print(OS, MAI);969 EmitEOL();970}971 972void MCAsmStreamer::emitXCOFFExceptDirective(const MCSymbol *Symbol,973 const MCSymbol *Trap,974 unsigned Lang,975 unsigned Reason,976 unsigned FunctionSize,977 bool hasDebug) {978 OS << "\t.except\t";979 Symbol->print(OS, MAI);980 OS << ", " << Lang << ", " << Reason;981 EmitEOL();982}983 984void MCAsmStreamer::emitXCOFFCInfoSym(StringRef Name, StringRef Metadata) {985 const char InfoDirective[] = "\t.info ";986 const char *Separator = ", ";987 constexpr int WordSize = sizeof(uint32_t);988 989 // Start by emitting the .info pseudo-op and C_INFO symbol name.990 OS << InfoDirective;991 PrintQuotedString(Name, OS);992 OS << Separator;993 994 size_t MetadataSize = Metadata.size();995 996 // Emit the 4-byte length of the metadata.997 OS << format_hex(MetadataSize, 10) << Separator;998 999 // Nothing left to do if there's no metadata.1000 if (MetadataSize == 0) {1001 EmitEOL();1002 return;1003 }1004 1005 // Metadata needs to be padded out to an even word size when generating1006 // assembly because the .info pseudo-op can only generate words of data. We1007 // apply the same restriction to the object case for consistency, however the1008 // linker doesn't require padding, so it will only save bytes specified by the1009 // length and discard any padding.1010 uint32_t PaddedSize = alignTo(MetadataSize, WordSize);1011 uint32_t PaddingSize = PaddedSize - MetadataSize;1012 1013 // Write out the payload a word at a time.1014 //1015 // The assembler has a limit on the number of operands in an expression,1016 // so we need multiple .info pseudo-ops. We choose a small number of words1017 // per pseudo-op to keep the assembly readable.1018 constexpr int WordsPerDirective = 5;1019 // Force emitting a new directive to keep the first directive purely about the1020 // name and size of the note.1021 int WordsBeforeNextDirective = 0;1022 auto PrintWord = [&](const uint8_t *WordPtr) {1023 if (WordsBeforeNextDirective-- == 0) {1024 EmitEOL();1025 OS << InfoDirective;1026 WordsBeforeNextDirective = WordsPerDirective;1027 }1028 OS << Separator;1029 uint32_t Word = llvm::support::endian::read32be(WordPtr);1030 OS << format_hex(Word, 10);1031 };1032 1033 size_t Index = 0;1034 for (; Index + WordSize <= MetadataSize; Index += WordSize)1035 PrintWord(reinterpret_cast<const uint8_t *>(Metadata.data()) + Index);1036 1037 // If there is padding, then we have at least one byte of payload left1038 // to emit.1039 if (PaddingSize) {1040 assert(PaddedSize - Index == WordSize);1041 std::array<uint8_t, WordSize> LastWord = {0};1042 ::memcpy(LastWord.data(), Metadata.data() + Index, MetadataSize - Index);1043 PrintWord(LastWord.data());1044 }1045 EmitEOL();1046}1047 1048void MCAsmStreamer::emitELFSize(MCSymbol *Symbol, const MCExpr *Value) {1049 assert(MAI->hasDotTypeDotSizeDirective());1050 OS << "\t.size\t";1051 Symbol->print(OS, MAI);1052 OS << ", ";1053 MAI->printExpr(OS, *Value);1054 EmitEOL();1055}1056 1057void MCAsmStreamer::emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,1058 Align ByteAlignment) {1059 OS << "\t.comm\t";1060 Symbol->print(OS, MAI);1061 OS << ',' << Size;1062 1063 if (MAI->getCOMMDirectiveAlignmentIsInBytes())1064 OS << ',' << ByteAlignment.value();1065 else1066 OS << ',' << Log2(ByteAlignment);1067 EmitEOL();1068 1069 // Print symbol's rename (original name contains invalid character(s)) if1070 // there is one.1071 if (getContext().isXCOFF()) {1072 auto *XSym = static_cast<MCSymbolXCOFF *>(Symbol);1073 if (XSym && XSym->hasRename())1074 emitXCOFFRenameDirective(XSym, XSym->getSymbolTableName());1075 }1076}1077 1078void MCAsmStreamer::emitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size,1079 Align ByteAlign) {1080 OS << "\t.lcomm\t";1081 Symbol->print(OS, MAI);1082 OS << ',' << Size;1083 1084 if (ByteAlign > 1) {1085 switch (MAI->getLCOMMDirectiveAlignmentType()) {1086 case LCOMM::NoAlignment:1087 llvm_unreachable("alignment not supported on .lcomm!");1088 case LCOMM::ByteAlignment:1089 OS << ',' << ByteAlign.value();1090 break;1091 case LCOMM::Log2Alignment:1092 OS << ',' << Log2(ByteAlign);1093 break;1094 }1095 }1096 EmitEOL();1097}1098 1099void MCAsmStreamer::emitZerofill(MCSection *Section, MCSymbol *Symbol,1100 uint64_t Size, Align ByteAlignment,1101 SMLoc Loc) {1102 if (Symbol)1103 Symbol->setFragment(&Section->getDummyFragment());1104 1105 // Note: a .zerofill directive does not switch sections.1106 OS << ".zerofill ";1107 1108 assert(getContext().getObjectFileType() == MCContext::IsMachO &&1109 ".zerofill is a Mach-O specific directive");1110 // This is a mach-o specific directive.1111 1112 const MCSectionMachO *MOSection = ((const MCSectionMachO*)Section);1113 OS << MOSection->getSegmentName() << "," << MOSection->getName();1114 1115 if (Symbol) {1116 OS << ',';1117 Symbol->print(OS, MAI);1118 OS << ',' << Size;1119 OS << ',' << Log2(ByteAlignment);1120 }1121 EmitEOL();1122}1123 1124// .tbss sym, size, align1125// This depends that the symbol has already been mangled from the original,1126// e.g. _a.1127void MCAsmStreamer::emitTBSSSymbol(MCSection *Section, MCSymbol *Symbol,1128 uint64_t Size, Align ByteAlignment) {1129 Symbol->setFragment(&Section->getDummyFragment());1130 1131 // Instead of using the Section we'll just use the shortcut.1132 1133 assert(getContext().getObjectFileType() == MCContext::IsMachO &&1134 ".zerofill is a Mach-O specific directive");1135 // This is a mach-o specific directive and section.1136 1137 OS << ".tbss ";1138 Symbol->print(OS, MAI);1139 OS << ", " << Size;1140 1141 // Output align if we have it. We default to 1 so don't bother printing1142 // that.1143 if (ByteAlignment > 1)1144 OS << ", " << Log2(ByteAlignment);1145 1146 EmitEOL();1147}1148 1149static inline bool isPrintableString(StringRef Data) {1150 const auto BeginPtr = Data.begin(), EndPtr = Data.end();1151 for (const unsigned char C : make_range(BeginPtr, EndPtr - 1)) {1152 if (!isPrint(C))1153 return false;1154 }1155 return isPrint(Data.back()) || Data.back() == 0;1156}1157 1158static inline char toOctal(int X) { return (X&7)+'0'; }1159 1160static void PrintByteList(StringRef Data, raw_ostream &OS,1161 MCAsmInfo::AsmCharLiteralSyntax ACLS) {1162 assert(!Data.empty() && "Cannot generate an empty list.");1163 const auto printCharacterInOctal = [&OS](unsigned char C) {1164 OS << '0';1165 OS << toOctal(C >> 6);1166 OS << toOctal(C >> 3);1167 OS << toOctal(C >> 0);1168 };1169 const auto printOneCharacterFor = [printCharacterInOctal](1170 auto printOnePrintingCharacter) {1171 return [printCharacterInOctal, printOnePrintingCharacter](unsigned char C) {1172 if (isPrint(C)) {1173 printOnePrintingCharacter(static_cast<char>(C));1174 return;1175 }1176 printCharacterInOctal(C);1177 };1178 };1179 const auto printCharacterList = [Data, &OS](const auto &printOneCharacter) {1180 const auto BeginPtr = Data.begin(), EndPtr = Data.end();1181 for (const unsigned char C : make_range(BeginPtr, EndPtr - 1)) {1182 printOneCharacter(C);1183 OS << ',';1184 }1185 printOneCharacter(*(EndPtr - 1));1186 };1187 switch (ACLS) {1188 case MCAsmInfo::ACLS_Unknown:1189 printCharacterList(printCharacterInOctal);1190 return;1191 case MCAsmInfo::ACLS_SingleQuotePrefix:1192 printCharacterList(printOneCharacterFor([&OS](char C) {1193 const char AsmCharLitBuf[2] = {'\'', C};1194 OS << StringRef(AsmCharLitBuf, sizeof(AsmCharLitBuf));1195 }));1196 return;1197 }1198 llvm_unreachable("Invalid AsmCharLiteralSyntax value!");1199}1200 1201void MCAsmStreamer::PrintQuotedString(StringRef Data, raw_ostream &OS) const {1202 OS << '"';1203 1204 if (MAI->isAIX()) {1205 for (unsigned char C : Data) {1206 if (C == '"')1207 OS << "\"\"";1208 else1209 OS << (char)C;1210 }1211 } else {1212 for (unsigned char C : Data) {1213 if (C == '"' || C == '\\') {1214 OS << '\\' << (char)C;1215 continue;1216 }1217 1218 if (isPrint(C)) {1219 OS << (char)C;1220 continue;1221 }1222 1223 switch (C) {1224 case '\b':1225 OS << "\\b";1226 break;1227 case '\f':1228 OS << "\\f";1229 break;1230 case '\n':1231 OS << "\\n";1232 break;1233 case '\r':1234 OS << "\\r";1235 break;1236 case '\t':1237 OS << "\\t";1238 break;1239 default:1240 OS << '\\';1241 OS << toOctal(C >> 6);1242 OS << toOctal(C >> 3);1243 OS << toOctal(C >> 0);1244 break;1245 }1246 }1247 }1248 1249 OS << '"';1250}1251 1252void MCAsmStreamer::emitBytes(StringRef Data) {1253 assert(getCurrentSectionOnly() &&1254 "Cannot emit contents before setting section!");1255 if (Data.empty()) return;1256 1257 const auto emitAsString = [this](StringRef Data) {1258 if (MAI->isAIX()) {1259 if (isPrintableString(Data)) {1260 // For target with DoubleQuoteString constants, .string and .byte are1261 // used as replacement of .asciz and .ascii.1262 if (Data.back() == 0) {1263 OS << "\t.string\t";1264 Data = Data.substr(0, Data.size() - 1);1265 } else {1266 OS << "\t.byte\t";1267 }1268 PrintQuotedString(Data, OS);1269 } else {1270 OS << "\t.byte\t";1271 PrintByteList(Data, OS, MAI->characterLiteralSyntax());1272 }1273 EmitEOL();1274 return true;1275 }1276 1277 // If the data ends with 0 and the target supports .asciz, use it, otherwise1278 // use .ascii or a byte-list directive1279 if (MAI->getAscizDirective() && Data.back() == 0) {1280 OS << MAI->getAscizDirective();1281 Data = Data.substr(0, Data.size() - 1);1282 } else if (LLVM_LIKELY(MAI->getAsciiDirective())) {1283 OS << MAI->getAsciiDirective();1284 } else {1285 return false;1286 }1287 1288 PrintQuotedString(Data, OS);1289 EmitEOL();1290 return true;1291 };1292 1293 if (Data.size() != 1 && emitAsString(Data))1294 return;1295 1296 // Only single byte is provided or no ascii, asciz, or byte-list directives1297 // are applicable. Emit as vector of individual 8bits data elements.1298 if (MCTargetStreamer *TS = getTargetStreamer()) {1299 TS->emitRawBytes(Data);1300 return;1301 }1302 const char *Directive = MAI->getData8bitsDirective();1303 for (const unsigned char C : Data.bytes()) {1304 OS << Directive << (unsigned)C;1305 EmitEOL();1306 }1307}1308 1309void MCAsmStreamer::emitBinaryData(StringRef Data) {1310 // This is binary data. Print it in a grid of hex bytes for readability.1311 const size_t Cols = 4;1312 for (size_t I = 0, EI = alignTo(Data.size(), Cols); I < EI; I += Cols) {1313 size_t J = I, EJ = std::min(I + Cols, Data.size());1314 assert(EJ > 0);1315 OS << MAI->getData8bitsDirective();1316 for (; J < EJ - 1; ++J)1317 OS << format("0x%02x", uint8_t(Data[J])) << ", ";1318 OS << format("0x%02x", uint8_t(Data[J]));1319 EmitEOL();1320 }1321}1322 1323void MCAsmStreamer::emitIntValue(uint64_t Value, unsigned Size) {1324 emitValue(MCConstantExpr::create(Value, getContext()), Size);1325}1326 1327void MCAsmStreamer::emitIntValueInHex(uint64_t Value, unsigned Size) {1328 emitValue(MCConstantExpr::create(Value, getContext(), true), Size);1329}1330 1331void MCAsmStreamer::emitIntValueInHexWithPadding(uint64_t Value,1332 unsigned Size) {1333 emitValue(MCConstantExpr::create(Value, getContext(), true, Size), Size);1334}1335 1336void MCAsmStreamer::emitValueImpl(const MCExpr *Value, unsigned Size,1337 SMLoc Loc) {1338 assert(Size <= 8 && "Invalid size");1339 assert(getCurrentSectionOnly() &&1340 "Cannot emit contents before setting section!");1341 const char *Directive = nullptr;1342 switch (Size) {1343 default: break;1344 case 1: Directive = MAI->getData8bitsDirective(); break;1345 case 2: Directive = MAI->getData16bitsDirective(); break;1346 case 4: Directive = MAI->getData32bitsDirective(); break;1347 case 8: Directive = MAI->getData64bitsDirective(); break;1348 }1349 1350 if (!Directive) {1351 int64_t IntValue;1352 if (!Value->evaluateAsAbsolute(IntValue))1353 report_fatal_error("Don't know how to emit this value.");1354 1355 // We couldn't handle the requested integer size so we fallback by breaking1356 // the request down into several, smaller, integers.1357 // Since sizes greater or equal to "Size" are invalid, we use the greatest1358 // power of 2 that is less than "Size" as our largest piece of granularity.1359 bool IsLittleEndian = MAI->isLittleEndian();1360 for (unsigned Emitted = 0; Emitted != Size;) {1361 unsigned Remaining = Size - Emitted;1362 // The size of our partial emission must be a power of two less than1363 // Size.1364 unsigned EmissionSize = llvm::bit_floor(std::min(Remaining, Size - 1));1365 // Calculate the byte offset of our partial emission taking into account1366 // the endianness of the target.1367 unsigned ByteOffset =1368 IsLittleEndian ? Emitted : (Remaining - EmissionSize);1369 uint64_t ValueToEmit = IntValue >> (ByteOffset * 8);1370 // We truncate our partial emission to fit within the bounds of the1371 // emission domain. This produces nicer output and silences potential1372 // truncation warnings when round tripping through another assembler.1373 uint64_t Shift = 64 - EmissionSize * 8;1374 assert(Shift < static_cast<uint64_t>(1375 std::numeric_limits<unsigned long long>::digits) &&1376 "undefined behavior");1377 ValueToEmit &= ~0ULL >> Shift;1378 emitIntValue(ValueToEmit, EmissionSize);1379 Emitted += EmissionSize;1380 }1381 return;1382 }1383 1384 assert(Directive && "Invalid size for machine code value!");1385 OS << Directive;1386 if (MCTargetStreamer *TS = getTargetStreamer()) {1387 TS->emitValue(Value);1388 } else {1389 MAI->printExpr(OS, *Value);1390 EmitEOL();1391 }1392}1393 1394void MCAsmStreamer::emitULEB128Value(const MCExpr *Value) {1395 int64_t IntValue;1396 if (Value->evaluateAsAbsolute(IntValue)) {1397 emitULEB128IntValue(IntValue);1398 return;1399 }1400 OS << "\t.uleb128 ";1401 MAI->printExpr(OS, *Value);1402 EmitEOL();1403}1404 1405void MCAsmStreamer::emitSLEB128Value(const MCExpr *Value) {1406 int64_t IntValue;1407 if (Value->evaluateAsAbsolute(IntValue)) {1408 emitSLEB128IntValue(IntValue);1409 return;1410 }1411 OS << "\t.sleb128 ";1412 MAI->printExpr(OS, *Value);1413 EmitEOL();1414}1415 1416void MCAsmStreamer::emitFill(const MCExpr &NumBytes, uint64_t FillValue,1417 SMLoc Loc) {1418 int64_t IntNumBytes;1419 const bool IsAbsolute = NumBytes.evaluateAsAbsolute(IntNumBytes);1420 if (IsAbsolute && IntNumBytes == 0)1421 return;1422 1423 if (const char *ZeroDirective = MAI->getZeroDirective()) {1424 if (!MAI->isAIX() || FillValue == 0) {1425 // FIXME: Emit location directives1426 OS << ZeroDirective;1427 MAI->printExpr(OS, NumBytes);1428 if (FillValue != 0)1429 OS << ',' << (int)FillValue;1430 EmitEOL();1431 } else {1432 if (!IsAbsolute)1433 report_fatal_error(1434 "Cannot emit non-absolute expression lengths of fill.");1435 for (int i = 0; i < IntNumBytes; ++i) {1436 OS << MAI->getData8bitsDirective() << (int)FillValue;1437 EmitEOL();1438 }1439 }1440 return;1441 }1442 1443 MCStreamer::emitFill(NumBytes, FillValue);1444}1445 1446void MCAsmStreamer::emitFill(const MCExpr &NumValues, int64_t Size,1447 int64_t Expr, SMLoc Loc) {1448 // FIXME: Emit location directives1449 OS << "\t.fill\t";1450 MAI->printExpr(OS, NumValues);1451 OS << ", " << Size << ", 0x";1452 OS.write_hex(truncateToSize(Expr, 4));1453 EmitEOL();1454}1455 1456void MCAsmStreamer::emitAlignmentDirective(uint64_t ByteAlignment,1457 std::optional<int64_t> Value,1458 unsigned ValueSize,1459 unsigned MaxBytesToEmit) {1460 if (MAI->isAIX()) {1461 if (!isPowerOf2_64(ByteAlignment))1462 report_fatal_error("Only power-of-two alignments are supported "1463 "with .align.");1464 OS << "\t.align\t";1465 OS << Log2_64(ByteAlignment);1466 EmitEOL();1467 return;1468 }1469 1470 // Some assemblers don't support non-power of two alignments, so we always1471 // emit alignments as a power of two if possible.1472 if (isPowerOf2_64(ByteAlignment)) {1473 switch (ValueSize) {1474 default:1475 llvm_unreachable("Invalid size for machine code value!");1476 case 1:1477 OS << "\t.p2align\t";1478 break;1479 case 2:1480 OS << ".p2alignw ";1481 break;1482 case 4:1483 OS << ".p2alignl ";1484 break;1485 case 8:1486 llvm_unreachable("Unsupported alignment size!");1487 }1488 1489 OS << Log2_64(ByteAlignment);1490 1491 if (Value.has_value() || MaxBytesToEmit) {1492 if (Value.has_value()) {1493 OS << ", 0x";1494 OS.write_hex(truncateToSize(*Value, ValueSize));1495 } else {1496 OS << ", ";1497 }1498 1499 if (MaxBytesToEmit)1500 OS << ", " << MaxBytesToEmit;1501 }1502 EmitEOL();1503 return;1504 }1505 1506 // Non-power of two alignment. This is not widely supported by assemblers.1507 // FIXME: Parameterize this based on MAI.1508 switch (ValueSize) {1509 default: llvm_unreachable("Invalid size for machine code value!");1510 case 1: OS << ".balign"; break;1511 case 2: OS << ".balignw"; break;1512 case 4: OS << ".balignl"; break;1513 case 8: llvm_unreachable("Unsupported alignment size!");1514 }1515 1516 OS << ' ' << ByteAlignment;1517 if (Value.has_value())1518 OS << ", " << truncateToSize(*Value, ValueSize);1519 else if (MaxBytesToEmit)1520 OS << ", ";1521 if (MaxBytesToEmit)1522 OS << ", " << MaxBytesToEmit;1523 EmitEOL();1524}1525 1526void MCAsmStreamer::emitValueToAlignment(Align Alignment, int64_t Fill,1527 uint8_t FillLen,1528 unsigned MaxBytesToEmit) {1529 emitAlignmentDirective(Alignment.value(), Fill, FillLen, MaxBytesToEmit);1530}1531 1532void MCAsmStreamer::emitCodeAlignment(Align Alignment,1533 const MCSubtargetInfo *STI,1534 unsigned MaxBytesToEmit) {1535 // Emit with a text fill value.1536 if (MAI->getTextAlignFillValue())1537 emitAlignmentDirective(Alignment.value(), MAI->getTextAlignFillValue(), 1,1538 MaxBytesToEmit);1539 else1540 emitAlignmentDirective(Alignment.value(), std::nullopt, 1, MaxBytesToEmit);1541}1542 1543void MCAsmStreamer::emitValueToOffset(const MCExpr *Offset,1544 unsigned char Value,1545 SMLoc Loc) {1546 // FIXME: Verify that Offset is associated with the current section.1547 OS << ".org ";1548 MAI->printExpr(OS, *Offset);1549 OS << ", " << (unsigned)Value;1550 EmitEOL();1551}1552 1553void MCAsmStreamer::emitFileDirective(StringRef Filename) {1554 assert(MAI->hasSingleParameterDotFile());1555 OS << "\t.file\t";1556 PrintQuotedString(Filename, OS);1557 EmitEOL();1558}1559 1560void MCAsmStreamer::emitFileDirective(StringRef Filename,1561 StringRef CompilerVersion,1562 StringRef TimeStamp,1563 StringRef Description) {1564 assert(MAI->isAIX());1565 OS << "\t.file\t";1566 PrintQuotedString(Filename, OS);1567 bool useTimeStamp = !TimeStamp.empty();1568 bool useCompilerVersion = !CompilerVersion.empty();1569 bool useDescription = !Description.empty();1570 if (useTimeStamp || useCompilerVersion || useDescription) {1571 OS << ",";1572 if (useTimeStamp)1573 PrintQuotedString(TimeStamp, OS);1574 if (useCompilerVersion || useDescription) {1575 OS << ",";1576 if (useCompilerVersion)1577 PrintQuotedString(CompilerVersion, OS);1578 if (useDescription) {1579 OS << ",";1580 PrintQuotedString(Description, OS);1581 }1582 }1583 }1584 EmitEOL();1585}1586 1587void MCAsmStreamer::printDwarfFileDirective(1588 unsigned FileNo, StringRef Directory, StringRef Filename,1589 std::optional<MD5::MD5Result> Checksum, std::optional<StringRef> Source,1590 bool UseDwarfDirectory, raw_svector_ostream &OS) const {1591 SmallString<128> FullPathName;1592 1593 if (!UseDwarfDirectory && !Directory.empty()) {1594 if (sys::path::is_absolute(Filename))1595 Directory = "";1596 else {1597 FullPathName = Directory;1598 sys::path::append(FullPathName, Filename);1599 Directory = "";1600 Filename = FullPathName;1601 }1602 }1603 1604 OS << "\t.file\t" << FileNo << ' ';1605 if (!Directory.empty()) {1606 PrintQuotedString(Directory, OS);1607 OS << ' ';1608 }1609 PrintQuotedString(Filename, OS);1610 if (Checksum)1611 OS << " md5 0x" << Checksum->digest();1612 if (Source) {1613 OS << " source ";1614 PrintQuotedString(*Source, OS);1615 }1616}1617 1618Expected<unsigned> MCAsmStreamer::tryEmitDwarfFileDirective(1619 unsigned FileNo, StringRef Directory, StringRef Filename,1620 std::optional<MD5::MD5Result> Checksum, std::optional<StringRef> Source,1621 unsigned CUID) {1622 assert(CUID == 0 && "multiple CUs not supported by MCAsmStreamer");1623 1624 MCDwarfLineTable &Table = getContext().getMCDwarfLineTable(CUID);1625 unsigned NumFiles = Table.getMCDwarfFiles().size();1626 Expected<unsigned> FileNoOrErr =1627 Table.tryGetFile(Directory, Filename, Checksum, Source,1628 getContext().getDwarfVersion(), FileNo);1629 if (!FileNoOrErr)1630 return FileNoOrErr.takeError();1631 FileNo = FileNoOrErr.get();1632 1633 // Return early if this file is already emitted before or if target doesn't1634 // support .file directive.1635 if (NumFiles == Table.getMCDwarfFiles().size() || MAI->isAIX())1636 return FileNo;1637 1638 SmallString<128> Str;1639 raw_svector_ostream OS1(Str);1640 printDwarfFileDirective(FileNo, Directory, Filename, Checksum, Source,1641 UseDwarfDirectory, OS1);1642 1643 if (MCTargetStreamer *TS = getTargetStreamer())1644 TS->emitDwarfFileDirective(OS1.str());1645 else1646 emitRawText(OS1.str());1647 1648 return FileNo;1649}1650 1651void MCAsmStreamer::emitDwarfFile0Directive(1652 StringRef Directory, StringRef Filename,1653 std::optional<MD5::MD5Result> Checksum, std::optional<StringRef> Source,1654 unsigned CUID) {1655 assert(CUID == 0);1656 // .file 0 is new for DWARF v5.1657 if (getContext().getDwarfVersion() < 5)1658 return;1659 // Inform MCDwarf about the root file.1660 getContext().setMCLineTableRootFile(CUID, Directory, Filename, Checksum,1661 Source);1662 1663 // Target doesn't support .loc/.file directives, return early.1664 if (MAI->isAIX())1665 return;1666 1667 SmallString<128> Str;1668 raw_svector_ostream OS1(Str);1669 printDwarfFileDirective(0, Directory, Filename, Checksum, Source,1670 UseDwarfDirectory, OS1);1671 1672 if (MCTargetStreamer *TS = getTargetStreamer())1673 TS->emitDwarfFileDirective(OS1.str());1674 else1675 emitRawText(OS1.str());1676}1677 1678void MCAsmStreamer::emitDwarfLocDirective(unsigned FileNo, unsigned Line,1679 unsigned Column, unsigned Flags,1680 unsigned Isa, unsigned Discriminator,1681 StringRef FileName,1682 StringRef Comment) {1683 // If target doesn't support .loc/.file directive, we need to record the lines1684 // same way like we do in object mode.1685 if (MAI->isAIX()) {1686 // In case we see two .loc directives in a row, make sure the1687 // first one gets a line entry.1688 MCDwarfLineEntry::make(this, getCurrentSectionOnly());1689 this->MCStreamer::emitDwarfLocDirective(FileNo, Line, Column, Flags, Isa,1690 Discriminator, FileName, Comment);1691 return;1692 }1693 1694 OS << "\t.loc\t" << FileNo << " " << Line << " " << Column;1695 if (MAI->supportsExtendedDwarfLocDirective()) {1696 if (Flags & DWARF2_FLAG_BASIC_BLOCK)1697 OS << " basic_block";1698 if (Flags & DWARF2_FLAG_PROLOGUE_END)1699 OS << " prologue_end";1700 if (Flags & DWARF2_FLAG_EPILOGUE_BEGIN)1701 OS << " epilogue_begin";1702 1703 unsigned OldFlags = getContext().getCurrentDwarfLoc().getFlags();1704 if ((Flags & DWARF2_FLAG_IS_STMT) != (OldFlags & DWARF2_FLAG_IS_STMT)) {1705 OS << " is_stmt ";1706 1707 if (Flags & DWARF2_FLAG_IS_STMT)1708 OS << "1";1709 else1710 OS << "0";1711 }1712 1713 if (Isa)1714 OS << " isa " << Isa;1715 if (Discriminator)1716 OS << " discriminator " << Discriminator;1717 }1718 1719 if (IsVerboseAsm) {1720 OS.PadToColumn(MAI->getCommentColumn());1721 OS << MAI->getCommentString() << ' ';1722 if (Comment.empty())1723 OS << FileName << ':' << Line << ':' << Column;1724 else1725 OS << Comment;1726 }1727 EmitEOL();1728 this->MCStreamer::emitDwarfLocDirective(FileNo, Line, Column, Flags, Isa,1729 Discriminator, FileName, Comment);1730}1731 1732void MCAsmStreamer::emitDwarfLocLabelDirective(SMLoc Loc, StringRef Name) {1733 MCStreamer::emitDwarfLocLabelDirective(Loc, Name);1734 OS << ".loc_label\t" << Name;1735 EmitEOL();1736}1737 1738MCSymbol *MCAsmStreamer::getDwarfLineTableSymbol(unsigned CUID) {1739 // Always use the zeroth line table, since asm syntax only supports one line1740 // table for now.1741 return MCStreamer::getDwarfLineTableSymbol(0);1742}1743 1744bool MCAsmStreamer::emitCVFileDirective(unsigned FileNo, StringRef Filename,1745 ArrayRef<uint8_t> Checksum,1746 unsigned ChecksumKind) {1747 if (!getContext().getCVContext().addFile(*this, FileNo, Filename, Checksum,1748 ChecksumKind))1749 return false;1750 1751 OS << "\t.cv_file\t" << FileNo << ' ';1752 PrintQuotedString(Filename, OS);1753 1754 if (!ChecksumKind) {1755 EmitEOL();1756 return true;1757 }1758 1759 OS << ' ';1760 PrintQuotedString(toHex(Checksum), OS);1761 OS << ' ' << ChecksumKind;1762 1763 EmitEOL();1764 return true;1765}1766 1767bool MCAsmStreamer::emitCVFuncIdDirective(unsigned FuncId) {1768 OS << "\t.cv_func_id " << FuncId << '\n';1769 return MCStreamer::emitCVFuncIdDirective(FuncId);1770}1771 1772bool MCAsmStreamer::emitCVInlineSiteIdDirective(unsigned FunctionId,1773 unsigned IAFunc,1774 unsigned IAFile,1775 unsigned IALine, unsigned IACol,1776 SMLoc Loc) {1777 OS << "\t.cv_inline_site_id " << FunctionId << " within " << IAFunc1778 << " inlined_at " << IAFile << ' ' << IALine << ' ' << IACol << '\n';1779 return MCStreamer::emitCVInlineSiteIdDirective(FunctionId, IAFunc, IAFile,1780 IALine, IACol, Loc);1781}1782 1783void MCAsmStreamer::emitCVLocDirective(unsigned FunctionId, unsigned FileNo,1784 unsigned Line, unsigned Column,1785 bool PrologueEnd, bool IsStmt,1786 StringRef FileName, SMLoc Loc) {1787 // Validate the directive.1788 if (!checkCVLocSection(FunctionId, FileNo, Loc))1789 return;1790 1791 OS << "\t.cv_loc\t" << FunctionId << " " << FileNo << " " << Line << " "1792 << Column;1793 if (PrologueEnd)1794 OS << " prologue_end";1795 1796 if (IsStmt)1797 OS << " is_stmt 1";1798 1799 if (IsVerboseAsm) {1800 OS.PadToColumn(MAI->getCommentColumn());1801 OS << MAI->getCommentString() << ' ' << FileName << ':' << Line << ':'1802 << Column;1803 }1804 EmitEOL();1805}1806 1807void MCAsmStreamer::emitCVLinetableDirective(unsigned FunctionId,1808 const MCSymbol *FnStart,1809 const MCSymbol *FnEnd) {1810 OS << "\t.cv_linetable\t" << FunctionId << ", ";1811 FnStart->print(OS, MAI);1812 OS << ", ";1813 FnEnd->print(OS, MAI);1814 EmitEOL();1815 this->MCStreamer::emitCVLinetableDirective(FunctionId, FnStart, FnEnd);1816}1817 1818void MCAsmStreamer::emitCVInlineLinetableDirective(unsigned PrimaryFunctionId,1819 unsigned SourceFileId,1820 unsigned SourceLineNum,1821 const MCSymbol *FnStartSym,1822 const MCSymbol *FnEndSym) {1823 OS << "\t.cv_inline_linetable\t" << PrimaryFunctionId << ' ' << SourceFileId1824 << ' ' << SourceLineNum << ' ';1825 FnStartSym->print(OS, MAI);1826 OS << ' ';1827 FnEndSym->print(OS, MAI);1828 EmitEOL();1829 this->MCStreamer::emitCVInlineLinetableDirective(1830 PrimaryFunctionId, SourceFileId, SourceLineNum, FnStartSym, FnEndSym);1831}1832 1833void MCAsmStreamer::PrintCVDefRangePrefix(1834 ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges) {1835 OS << "\t.cv_def_range\t";1836 for (std::pair<const MCSymbol *, const MCSymbol *> Range : Ranges) {1837 OS << ' ';1838 Range.first->print(OS, MAI);1839 OS << ' ';1840 Range.second->print(OS, MAI);1841 }1842}1843 1844void MCAsmStreamer::emitCVDefRangeDirective(1845 ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,1846 codeview::DefRangeRegisterRelHeader DRHdr) {1847 PrintCVDefRangePrefix(Ranges);1848 OS << ", reg_rel, ";1849 OS << DRHdr.Register << ", " << DRHdr.Flags << ", "1850 << DRHdr.BasePointerOffset;1851 EmitEOL();1852}1853 1854void MCAsmStreamer::emitCVDefRangeDirective(1855 ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,1856 codeview::DefRangeSubfieldRegisterHeader DRHdr) {1857 PrintCVDefRangePrefix(Ranges);1858 OS << ", subfield_reg, ";1859 OS << DRHdr.Register << ", " << DRHdr.OffsetInParent;1860 EmitEOL();1861}1862 1863void MCAsmStreamer::emitCVDefRangeDirective(1864 ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,1865 codeview::DefRangeRegisterHeader DRHdr) {1866 PrintCVDefRangePrefix(Ranges);1867 OS << ", reg, ";1868 OS << DRHdr.Register;1869 EmitEOL();1870}1871 1872void MCAsmStreamer::emitCVDefRangeDirective(1873 ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,1874 codeview::DefRangeFramePointerRelHeader DRHdr) {1875 PrintCVDefRangePrefix(Ranges);1876 OS << ", frame_ptr_rel, ";1877 OS << DRHdr.Offset;1878 EmitEOL();1879}1880 1881void MCAsmStreamer::emitCVStringTableDirective() {1882 OS << "\t.cv_stringtable";1883 EmitEOL();1884}1885 1886void MCAsmStreamer::emitCVFileChecksumsDirective() {1887 OS << "\t.cv_filechecksums";1888 EmitEOL();1889}1890 1891void MCAsmStreamer::emitCVFileChecksumOffsetDirective(unsigned FileNo) {1892 OS << "\t.cv_filechecksumoffset\t" << FileNo;1893 EmitEOL();1894}1895 1896void MCAsmStreamer::emitCVFPOData(const MCSymbol *ProcSym, SMLoc L) {1897 OS << "\t.cv_fpo_data\t";1898 ProcSym->print(OS, MAI);1899 EmitEOL();1900}1901 1902void MCAsmStreamer::emitIdent(StringRef IdentString) {1903 assert(MAI->hasIdentDirective() && ".ident directive not supported");1904 OS << "\t.ident\t";1905 PrintQuotedString(IdentString, OS);1906 EmitEOL();1907}1908 1909void MCAsmStreamer::emitCFISections(bool EH, bool Debug, bool SFrame) {1910 MCStreamer::emitCFISections(EH, Debug, SFrame);1911 OS << "\t.cfi_sections ";1912 bool C = false;1913 if (EH) {1914 OS << ".eh_frame";1915 C = true;1916 }1917 if (Debug) {1918 if (C)1919 OS << ", ";1920 OS << ".debug_frame";1921 C = true;1922 }1923 if (SFrame) {1924 if (C)1925 OS << ", ";1926 OS << ".sframe";1927 }1928 1929 EmitEOL();1930}1931 1932void MCAsmStreamer::emitCFIStartProcImpl(MCDwarfFrameInfo &Frame) {1933 OS << "\t.cfi_startproc";1934 if (Frame.IsSimple)1935 OS << " simple";1936 EmitEOL();1937}1938 1939void MCAsmStreamer::emitCFIEndProcImpl(MCDwarfFrameInfo &Frame) {1940 MCStreamer::emitCFIEndProcImpl(Frame);1941 OS << "\t.cfi_endproc";1942 EmitEOL();1943}1944 1945void MCAsmStreamer::EmitRegisterName(int64_t Register) {1946 if (!MAI->useDwarfRegNumForCFI()) {1947 // User .cfi_* directives can use arbitrary DWARF register numbers, not1948 // just ones that map to LLVM register numbers and have known names.1949 // Fall back to using the original number directly if no name is known.1950 const MCRegisterInfo *MRI = getContext().getRegisterInfo();1951 if (std::optional<MCRegister> LLVMRegister =1952 MRI->getLLVMRegNum(Register, true)) {1953 InstPrinter->printRegName(OS, *LLVMRegister);1954 return;1955 }1956 }1957 OS << Register;1958}1959 1960void MCAsmStreamer::emitCFIDefCfa(int64_t Register, int64_t Offset, SMLoc Loc) {1961 MCStreamer::emitCFIDefCfa(Register, Offset, Loc);1962 OS << "\t.cfi_def_cfa ";1963 EmitRegisterName(Register);1964 OS << ", " << Offset;1965 EmitEOL();1966}1967 1968void MCAsmStreamer::emitCFIDefCfaOffset(int64_t Offset, SMLoc Loc) {1969 MCStreamer::emitCFIDefCfaOffset(Offset, Loc);1970 OS << "\t.cfi_def_cfa_offset " << Offset;1971 EmitEOL();1972}1973 1974void MCAsmStreamer::emitCFILLVMDefAspaceCfa(int64_t Register, int64_t Offset,1975 int64_t AddressSpace, SMLoc Loc) {1976 MCStreamer::emitCFILLVMDefAspaceCfa(Register, Offset, AddressSpace, Loc);1977 OS << "\t.cfi_llvm_def_aspace_cfa ";1978 EmitRegisterName(Register);1979 OS << ", " << Offset;1980 OS << ", " << AddressSpace;1981 EmitEOL();1982}1983 1984static void PrintCFIEscape(llvm::formatted_raw_ostream &OS, StringRef Values) {1985 OS << "\t.cfi_escape ";1986 if (!Values.empty()) {1987 size_t e = Values.size() - 1;1988 for (size_t i = 0; i < e; ++i)1989 OS << format("0x%02x", uint8_t(Values[i])) << ", ";1990 OS << format("0x%02x", uint8_t(Values[e]));1991 }1992}1993 1994void MCAsmStreamer::emitCFIEscape(StringRef Values, SMLoc Loc) {1995 MCStreamer::emitCFIEscape(Values, Loc);1996 PrintCFIEscape(OS, Values);1997 EmitEOL();1998}1999 2000void MCAsmStreamer::emitCFIGnuArgsSize(int64_t Size, SMLoc Loc) {2001 MCStreamer::emitCFIGnuArgsSize(Size, Loc);2002 2003 uint8_t Buffer[16] = { dwarf::DW_CFA_GNU_args_size };2004 unsigned Len = encodeULEB128(Size, Buffer + 1) + 1;2005 2006 PrintCFIEscape(OS, StringRef((const char *)&Buffer[0], Len));2007 EmitEOL();2008}2009 2010void MCAsmStreamer::emitCFIDefCfaRegister(int64_t Register, SMLoc Loc) {2011 MCStreamer::emitCFIDefCfaRegister(Register, Loc);2012 OS << "\t.cfi_def_cfa_register ";2013 EmitRegisterName(Register);2014 EmitEOL();2015}2016 2017void MCAsmStreamer::emitCFIOffset(int64_t Register, int64_t Offset, SMLoc Loc) {2018 MCStreamer::emitCFIOffset(Register, Offset, Loc);2019 OS << "\t.cfi_offset ";2020 EmitRegisterName(Register);2021 OS << ", " << Offset;2022 EmitEOL();2023}2024 2025void MCAsmStreamer::emitCFIPersonality(const MCSymbol *Sym,2026 unsigned Encoding) {2027 MCStreamer::emitCFIPersonality(Sym, Encoding);2028 OS << "\t.cfi_personality " << Encoding << ", ";2029 Sym->print(OS, MAI);2030 EmitEOL();2031}2032 2033void MCAsmStreamer::emitCFILsda(const MCSymbol *Sym, unsigned Encoding) {2034 MCStreamer::emitCFILsda(Sym, Encoding);2035 OS << "\t.cfi_lsda " << Encoding << ", ";2036 Sym->print(OS, MAI);2037 EmitEOL();2038}2039 2040void MCAsmStreamer::emitCFIRememberState(SMLoc Loc) {2041 MCStreamer::emitCFIRememberState(Loc);2042 OS << "\t.cfi_remember_state";2043 EmitEOL();2044}2045 2046void MCAsmStreamer::emitCFIRestoreState(SMLoc Loc) {2047 MCStreamer::emitCFIRestoreState(Loc);2048 OS << "\t.cfi_restore_state";2049 EmitEOL();2050}2051 2052void MCAsmStreamer::emitCFIRestore(int64_t Register, SMLoc Loc) {2053 MCStreamer::emitCFIRestore(Register, Loc);2054 OS << "\t.cfi_restore ";2055 EmitRegisterName(Register);2056 EmitEOL();2057}2058 2059void MCAsmStreamer::emitCFISameValue(int64_t Register, SMLoc Loc) {2060 MCStreamer::emitCFISameValue(Register, Loc);2061 OS << "\t.cfi_same_value ";2062 EmitRegisterName(Register);2063 EmitEOL();2064}2065 2066void MCAsmStreamer::emitCFIRelOffset(int64_t Register, int64_t Offset,2067 SMLoc Loc) {2068 MCStreamer::emitCFIRelOffset(Register, Offset, Loc);2069 OS << "\t.cfi_rel_offset ";2070 EmitRegisterName(Register);2071 OS << ", " << Offset;2072 EmitEOL();2073}2074 2075void MCAsmStreamer::emitCFIAdjustCfaOffset(int64_t Adjustment, SMLoc Loc) {2076 MCStreamer::emitCFIAdjustCfaOffset(Adjustment, Loc);2077 OS << "\t.cfi_adjust_cfa_offset " << Adjustment;2078 EmitEOL();2079}2080 2081void MCAsmStreamer::emitCFISignalFrame() {2082 MCStreamer::emitCFISignalFrame();2083 OS << "\t.cfi_signal_frame";2084 EmitEOL();2085}2086 2087void MCAsmStreamer::emitCFIUndefined(int64_t Register, SMLoc Loc) {2088 MCStreamer::emitCFIUndefined(Register, Loc);2089 OS << "\t.cfi_undefined ";2090 EmitRegisterName(Register);2091 EmitEOL();2092}2093 2094void MCAsmStreamer::emitCFIRegister(int64_t Register1, int64_t Register2,2095 SMLoc Loc) {2096 MCStreamer::emitCFIRegister(Register1, Register2, Loc);2097 OS << "\t.cfi_register ";2098 EmitRegisterName(Register1);2099 OS << ", ";2100 EmitRegisterName(Register2);2101 EmitEOL();2102}2103 2104void MCAsmStreamer::emitCFIWindowSave(SMLoc Loc) {2105 MCStreamer::emitCFIWindowSave(Loc);2106 OS << "\t.cfi_window_save";2107 EmitEOL();2108}2109 2110void MCAsmStreamer::emitCFINegateRAState(SMLoc Loc) {2111 MCStreamer::emitCFINegateRAState(Loc);2112 OS << "\t.cfi_negate_ra_state";2113 EmitEOL();2114}2115 2116void MCAsmStreamer::emitCFINegateRAStateWithPC(SMLoc Loc) {2117 MCStreamer::emitCFINegateRAStateWithPC(Loc);2118 OS << "\t.cfi_negate_ra_state_with_pc";2119 EmitEOL();2120}2121 2122void MCAsmStreamer::emitCFIReturnColumn(int64_t Register) {2123 MCStreamer::emitCFIReturnColumn(Register);2124 OS << "\t.cfi_return_column ";2125 EmitRegisterName(Register);2126 EmitEOL();2127}2128 2129void MCAsmStreamer::emitCFILabelDirective(SMLoc Loc, StringRef Name) {2130 MCStreamer::emitCFILabelDirective(Loc, Name);2131 OS << "\t.cfi_label " << Name;2132 EmitEOL();2133}2134 2135void MCAsmStreamer::emitCFIBKeyFrame() {2136 MCStreamer::emitCFIBKeyFrame();2137 OS << "\t.cfi_b_key_frame";2138 EmitEOL();2139}2140 2141void MCAsmStreamer::emitCFIMTETaggedFrame() {2142 MCStreamer::emitCFIMTETaggedFrame();2143 OS << "\t.cfi_mte_tagged_frame";2144 EmitEOL();2145}2146 2147void MCAsmStreamer::emitCFIValOffset(int64_t Register, int64_t Offset,2148 SMLoc Loc) {2149 MCStreamer::emitCFIValOffset(Register, Offset, Loc);2150 OS << "\t.cfi_val_offset ";2151 EmitRegisterName(Register);2152 OS << ", " << Offset;2153 EmitEOL();2154}2155 2156void MCAsmStreamer::emitWinCFIStartProc(const MCSymbol *Symbol, SMLoc Loc) {2157 MCStreamer::emitWinCFIStartProc(Symbol, Loc);2158 2159 OS << ".seh_proc ";2160 Symbol->print(OS, MAI);2161 EmitEOL();2162}2163 2164void MCAsmStreamer::emitWinCFIEndProc(SMLoc Loc) {2165 MCStreamer::emitWinCFIEndProc(Loc);2166 2167 OS << "\t.seh_endproc";2168 EmitEOL();2169}2170 2171void MCAsmStreamer::emitWinCFIFuncletOrFuncEnd(SMLoc Loc) {2172 MCStreamer::emitWinCFIFuncletOrFuncEnd(Loc);2173 2174 OS << "\t.seh_endfunclet";2175 EmitEOL();2176}2177 2178void MCAsmStreamer::emitWinCFIStartChained(SMLoc Loc) {2179 MCStreamer::emitWinCFIStartChained(Loc);2180 2181 OS << "\t.seh_startchained";2182 EmitEOL();2183}2184 2185void MCAsmStreamer::emitWinCFIEndChained(SMLoc Loc) {2186 MCStreamer::emitWinCFIEndChained(Loc);2187 2188 OS << "\t.seh_endchained";2189 EmitEOL();2190}2191 2192void MCAsmStreamer::emitWinEHHandler(const MCSymbol *Sym, bool Unwind,2193 bool Except, SMLoc Loc) {2194 MCStreamer::emitWinEHHandler(Sym, Unwind, Except, Loc);2195 2196 OS << "\t.seh_handler ";2197 Sym->print(OS, MAI);2198 char Marker = '@';2199 const Triple &T = getContext().getTargetTriple();2200 if (T.getArch() == Triple::arm || T.getArch() == Triple::thumb)2201 Marker = '%';2202 if (Unwind)2203 OS << ", " << Marker << "unwind";2204 if (Except)2205 OS << ", " << Marker << "except";2206 EmitEOL();2207}2208 2209void MCAsmStreamer::emitWinEHHandlerData(SMLoc Loc) {2210 MCStreamer::emitWinEHHandlerData(Loc);2211 2212 // Switch sections. Don't call switchSection directly, because that will2213 // cause the section switch to be visible in the emitted assembly.2214 // We only do this so the section switch that terminates the handler2215 // data block is visible.2216 WinEH::FrameInfo *CurFrame = getCurrentWinFrameInfo();2217 2218 // Do nothing if no frame is open. MCStreamer should've already reported an2219 // error.2220 if (!CurFrame)2221 return;2222 2223 MCSection *TextSec = &CurFrame->Function->getSection();2224 MCSection *XData = getAssociatedXDataSection(TextSec);2225 switchSectionNoPrint(XData);2226 2227 OS << "\t.seh_handlerdata";2228 EmitEOL();2229}2230 2231void MCAsmStreamer::emitWinCFIPushReg(MCRegister Register, SMLoc Loc) {2232 MCStreamer::emitWinCFIPushReg(Register, Loc);2233 2234 OS << "\t.seh_pushreg ";2235 InstPrinter->printRegName(OS, Register);2236 EmitEOL();2237}2238 2239void MCAsmStreamer::emitWinCFISetFrame(MCRegister Register, unsigned Offset,2240 SMLoc Loc) {2241 MCStreamer::emitWinCFISetFrame(Register, Offset, Loc);2242 2243 OS << "\t.seh_setframe ";2244 InstPrinter->printRegName(OS, Register);2245 OS << ", " << Offset;2246 EmitEOL();2247}2248 2249void MCAsmStreamer::emitWinCFIAllocStack(unsigned Size, SMLoc Loc) {2250 MCStreamer::emitWinCFIAllocStack(Size, Loc);2251 2252 OS << "\t.seh_stackalloc " << Size;2253 EmitEOL();2254}2255 2256void MCAsmStreamer::emitWinCFISaveReg(MCRegister Register, unsigned Offset,2257 SMLoc Loc) {2258 MCStreamer::emitWinCFISaveReg(Register, Offset, Loc);2259 2260 OS << "\t.seh_savereg ";2261 InstPrinter->printRegName(OS, Register);2262 OS << ", " << Offset;2263 EmitEOL();2264}2265 2266void MCAsmStreamer::emitWinCFISaveXMM(MCRegister Register, unsigned Offset,2267 SMLoc Loc) {2268 MCStreamer::emitWinCFISaveXMM(Register, Offset, Loc);2269 2270 OS << "\t.seh_savexmm ";2271 InstPrinter->printRegName(OS, Register);2272 OS << ", " << Offset;2273 EmitEOL();2274}2275 2276void MCAsmStreamer::emitWinCFIPushFrame(bool Code, SMLoc Loc) {2277 MCStreamer::emitWinCFIPushFrame(Code, Loc);2278 2279 OS << "\t.seh_pushframe";2280 if (Code)2281 OS << " @code";2282 EmitEOL();2283}2284 2285void MCAsmStreamer::emitWinCFIEndProlog(SMLoc Loc) {2286 MCStreamer::emitWinCFIEndProlog(Loc);2287 2288 OS << "\t.seh_endprologue";2289 EmitEOL();2290}2291 2292void MCAsmStreamer::emitWinCFIBeginEpilogue(SMLoc Loc) {2293 MCStreamer::emitWinCFIBeginEpilogue(Loc);2294 2295 OS << "\t.seh_startepilogue";2296 EmitEOL();2297}2298 2299void MCAsmStreamer::emitWinCFIEndEpilogue(SMLoc Loc) {2300 MCStreamer::emitWinCFIEndEpilogue(Loc);2301 2302 OS << "\t.seh_endepilogue";2303 EmitEOL();2304}2305 2306void MCAsmStreamer::emitWinCFIUnwindV2Start(SMLoc Loc) {2307 MCStreamer::emitWinCFIUnwindV2Start(Loc);2308 2309 OS << "\t.seh_unwindv2start";2310 EmitEOL();2311}2312 2313void MCAsmStreamer::emitWinCFIUnwindVersion(uint8_t Version, SMLoc Loc) {2314 MCStreamer::emitWinCFIUnwindVersion(Version, Loc);2315 2316 OS << "\t.seh_unwindversion " << (unsigned)Version;2317 EmitEOL();2318}2319 2320void MCAsmStreamer::emitCGProfileEntry(const MCSymbolRefExpr *From,2321 const MCSymbolRefExpr *To,2322 uint64_t Count) {2323 OS << "\t.cg_profile ";2324 From->getSymbol().print(OS, MAI);2325 OS << ", ";2326 To->getSymbol().print(OS, MAI);2327 OS << ", " << Count;2328 EmitEOL();2329}2330 2331void MCAsmStreamer::AddEncodingComment(const MCInst &Inst,2332 const MCSubtargetInfo &STI) {2333 raw_ostream &OS = getCommentOS();2334 SmallString<256> Code;2335 SmallVector<MCFixup, 4> Fixups;2336 2337 // If we have no code emitter, don't emit code.2338 if (!getAssembler().getEmitterPtr())2339 return;2340 2341 getAssembler().getEmitter().encodeInstruction(Inst, Code, Fixups, STI);2342 2343 // RISC-V instructions are always little-endian, even on BE systems.2344 bool ForceLE = getContext().getTargetTriple().isRISCV();2345 2346 // If we are showing fixups, create symbolic markers in the encoded2347 // representation. We do this by making a per-bit map to the fixup item index,2348 // then trying to display it as nicely as possible.2349 SmallVector<uint8_t, 64> FixupMap;2350 FixupMap.resize(Code.size() * 8);2351 for (unsigned i = 0, e = Code.size() * 8; i != e; ++i)2352 FixupMap[i] = 0;2353 2354 for (unsigned i = 0, e = Fixups.size(); i != e; ++i) {2355 MCFixup &F = Fixups[i];2356 MCFixupKindInfo Info =2357 getAssembler().getBackend().getFixupKindInfo(F.getKind());2358 for (unsigned j = 0; j != Info.TargetSize; ++j) {2359 unsigned Index = F.getOffset() * 8 + Info.TargetOffset + j;2360 assert(Index < Code.size() * 8 && "Invalid offset in fixup!");2361 FixupMap[Index] = 1 + i;2362 }2363 }2364 2365 // FIXME: Note the fixup comments for Thumb2 are completely bogus since the2366 // high order halfword of a 32-bit Thumb2 instruction is emitted first.2367 OS << "encoding: [";2368 for (unsigned i = 0, e = Code.size(); i != e; ++i) {2369 if (i)2370 OS << ',';2371 2372 // See if all bits are the same map entry.2373 uint8_t MapEntry = FixupMap[i * 8 + 0];2374 for (unsigned j = 1; j != 8; ++j) {2375 if (FixupMap[i * 8 + j] == MapEntry)2376 continue;2377 2378 MapEntry = uint8_t(~0U);2379 break;2380 }2381 2382 if (MapEntry != uint8_t(~0U)) {2383 if (MapEntry == 0) {2384 OS << format("0x%02x", uint8_t(Code[i]));2385 } else {2386 if (Code[i]) {2387 // FIXME: Some of the 8 bits require fix up.2388 OS << format("0x%02x", uint8_t(Code[i])) << '\''2389 << char('A' + MapEntry - 1) << '\'';2390 } else2391 OS << char('A' + MapEntry - 1);2392 }2393 } else {2394 // Otherwise, write out in binary.2395 OS << "0b";2396 for (unsigned j = 8; j--;) {2397 unsigned Bit = (Code[i] >> j) & 1;2398 2399 unsigned FixupBit;2400 // RISC-V instructions are always little-endian.2401 // The FixupMap is indexed by actual bit positions in the LE2402 // instruction.2403 if (MAI->isLittleEndian() || ForceLE)2404 FixupBit = i * 8 + j;2405 else2406 FixupBit = i * 8 + (7-j);2407 2408 if (uint8_t MapEntry = FixupMap[FixupBit]) {2409 assert(Bit == 0 && "Encoder wrote into fixed up bit!");2410 OS << char('A' + MapEntry - 1);2411 } else2412 OS << Bit;2413 }2414 }2415 }2416 OS << "]\n";2417 2418 for (unsigned i = 0, e = Fixups.size(); i != e; ++i) {2419 MCFixup &F = Fixups[i];2420 OS << " fixup " << char('A' + i) << " - "2421 << "offset: " << F.getOffset() << ", value: ";2422 MAI->printExpr(OS, *F.getValue());2423 auto Kind = F.getKind();2424 if (mc::isRelocation(Kind))2425 OS << ", relocation type: " << Kind;2426 else {2427 OS << ", kind: ";2428 auto Info = getAssembler().getBackend().getFixupKindInfo(Kind);2429 if (F.isPCRel() && StringRef(Info.Name).starts_with("FK_Data_"))2430 OS << "FK_PCRel_" << (Info.TargetSize / 8);2431 else2432 OS << Info.Name;2433 }2434 OS << '\n';2435 }2436}2437 2438void MCAsmStreamer::emitInstruction(const MCInst &Inst,2439 const MCSubtargetInfo &STI) {2440 if (CurFrag) {2441 MCSection *Sec = getCurrentSectionOnly();2442 Sec->setHasInstructions(true);2443 }2444 2445 if (MAI->isAIX() && CurFrag)2446 // Now that a machine instruction has been assembled into this section, make2447 // a line entry for any .loc directive that has been seen.2448 MCDwarfLineEntry::make(this, getCurrentSectionOnly());2449 2450 // Show the encoding in a comment if we have a code emitter.2451 AddEncodingComment(Inst, STI);2452 2453 // Show the MCInst if enabled.2454 if (ShowInst) {2455 Inst.dump_pretty(getCommentOS(), InstPrinter.get(), "\n ");2456 getCommentOS() << "\n";2457 }2458 2459 if(getTargetStreamer())2460 getTargetStreamer()->prettyPrintAsm(*InstPrinter, 0, Inst, STI, OS);2461 else2462 InstPrinter->printInst(&Inst, 0, "", STI, OS);2463 2464 StringRef Comments = CommentToEmit;2465 if (Comments.size() && Comments.back() != '\n')2466 getCommentOS() << "\n";2467 2468 EmitEOL();2469}2470 2471void MCAsmStreamer::emitPseudoProbe(uint64_t Guid, uint64_t Index,2472 uint64_t Type, uint64_t Attr,2473 uint64_t Discriminator,2474 const MCPseudoProbeInlineStack &InlineStack,2475 MCSymbol *FnSym) {2476 OS << "\t.pseudoprobe\t" << Guid << " " << Index << " " << Type << " " << Attr;2477 if (Discriminator)2478 OS << " " << Discriminator;2479 // Emit inline stack like2480 // @ GUIDmain:3 @ GUIDCaller:1 @ GUIDDirectCaller:112481 for (const auto &Site : InlineStack)2482 OS << " @ " << std::get<0>(Site) << ":" << std::get<1>(Site);2483 2484 OS << " ";2485 FnSym->print(OS, MAI);2486 2487 EmitEOL();2488}2489 2490void MCAsmStreamer::emitRelocDirective(const MCExpr &Offset, StringRef Name,2491 const MCExpr *Expr, SMLoc) {2492 OS << "\t.reloc ";2493 MAI->printExpr(OS, Offset);2494 OS << ", " << Name;2495 if (Expr) {2496 OS << ", ";2497 MAI->printExpr(OS, *Expr);2498 }2499 EmitEOL();2500}2501 2502void MCAsmStreamer::emitAddrsig() {2503 OS << "\t.addrsig";2504 EmitEOL();2505}2506 2507void MCAsmStreamer::emitAddrsigSym(const MCSymbol *Sym) {2508 OS << "\t.addrsig_sym ";2509 Sym->print(OS, MAI);2510 EmitEOL();2511}2512 2513/// EmitRawText - If this file is backed by an assembly streamer, this dumps2514/// the specified string in the output .s file. This capability is2515/// indicated by the hasRawTextSupport() predicate.2516void MCAsmStreamer::emitRawTextImpl(StringRef String) {2517 String.consume_back("\n");2518 OS << String;2519 EmitEOL();2520}2521 2522void MCAsmStreamer::finishImpl() {2523 // If we are generating dwarf for assembly source files dump out the sections.2524 if (getContext().getGenDwarfForAssembly())2525 MCGenDwarfInfo::Emit(this);2526 2527 // Now it is time to emit debug line sections if target doesn't support .loc2528 // and .line directives.2529 if (MAI->isAIX()) {2530 MCDwarfLineTable::emit(this, getAssembler().getDWARFLinetableParams());2531 return;2532 }2533 2534 // Emit the label for the line table, if requested - since the rest of the2535 // line table will be defined by .loc/.file directives, and not emitted2536 // directly, the label is the only work required here.2537 const auto &Tables = getContext().getMCDwarfLineTables();2538 if (!Tables.empty()) {2539 assert(Tables.size() == 1 && "asm output only supports one line table");2540 if (auto *Label = Tables.begin()->second.getLabel()) {2541 switchSection(getContext().getObjectFileInfo()->getDwarfLineSection(), 0);2542 emitLabel(Label);2543 }2544 }2545}2546 2547void MCAsmStreamer::emitDwarfUnitLength(uint64_t Length, const Twine &Comment) {2548 // If the assembler on some target fills in the DWARF unit length, we2549 // don't want to emit the length in the compiler. For example, the AIX2550 // assembler requires the assembly file with the unit length omitted from2551 // the debug section headers. In such cases, any label we placed occurs2552 // after the implied length field. We need to adjust the reference here2553 // to account for the offset introduced by the inserted length field.2554 if (MAI->isAIX())2555 return;2556 MCStreamer::emitDwarfUnitLength(Length, Comment);2557}2558 2559MCSymbol *MCAsmStreamer::emitDwarfUnitLength(const Twine &Prefix,2560 const Twine &Comment) {2561 // If the assembler on some target fills in the DWARF unit length, we2562 // don't want to emit the length in the compiler. For example, the AIX2563 // assembler requires the assembly file with the unit length omitted from2564 // the debug section headers. In such cases, any label we placed occurs2565 // after the implied length field. We need to adjust the reference here2566 // to account for the offset introduced by the inserted length field.2567 if (MAI->isAIX())2568 return getContext().createTempSymbol(Prefix + "_end");2569 return MCStreamer::emitDwarfUnitLength(Prefix, Comment);2570}2571 2572void MCAsmStreamer::emitDwarfLineStartLabel(MCSymbol *StartSym) {2573 // If the assembler on some target fills in the DWARF unit length, we2574 // don't want to emit the length in the compiler. For example, the AIX2575 // assembler requires the assembly file with the unit length omitted from2576 // the debug section headers. In such cases, any label we placed occurs2577 // after the implied length field. We need to adjust the reference here2578 // to account for the offset introduced by the inserted length field.2579 MCContext &Ctx = getContext();2580 if (MAI->isAIX()) {2581 MCSymbol *DebugLineSymTmp = Ctx.createTempSymbol("debug_line_");2582 // Emit the symbol which does not contain the unit length field.2583 emitLabel(DebugLineSymTmp);2584 2585 // Adjust the outer reference to account for the offset introduced by the2586 // inserted length field.2587 unsigned LengthFieldSize =2588 dwarf::getUnitLengthFieldByteSize(Ctx.getDwarfFormat());2589 const MCExpr *EntrySize = MCConstantExpr::create(LengthFieldSize, Ctx);2590 const MCExpr *OuterSym = MCBinaryExpr::createSub(2591 MCSymbolRefExpr::create(DebugLineSymTmp, Ctx), EntrySize, Ctx);2592 2593 emitAssignment(StartSym, OuterSym);2594 return;2595 }2596 MCStreamer::emitDwarfLineStartLabel(StartSym);2597}2598 2599void MCAsmStreamer::emitDwarfLineEndEntry(MCSection *Section,2600 MCSymbol *LastLabel,2601 MCSymbol *EndLabel) {2602 // If the targets write the raw debug line data for assembly output (We can2603 // not switch to Section and add the end symbol there for assembly output)2604 // we currently use the .text end label as any section end. This will not2605 // impact the debugability as we will jump to the caller of the last function2606 // in the section before we come into the .text end address.2607 assert(MAI->isAIX() &&2608 ".loc should not be generated together with raw data!");2609 2610 MCContext &Ctx = getContext();2611 2612 // FIXME: use section end symbol as end of the Section. We need to consider2613 // the explicit sections and -ffunction-sections when we try to generate or2614 // find section end symbol for the Section.2615 MCSection *TextSection = Ctx.getObjectFileInfo()->getTextSection();2616 assert(TextSection->hasEnded() && ".text section is not end!");2617 2618 if (!EndLabel)2619 EndLabel = TextSection->getEndSymbol(Ctx);2620 const MCAsmInfo *AsmInfo = Ctx.getAsmInfo();2621 emitDwarfAdvanceLineAddr(INT64_MAX, LastLabel, EndLabel,2622 AsmInfo->getCodePointerSize());2623}2624 2625// Generate DWARF line sections for assembly mode without .loc/.file2626void MCAsmStreamer::emitDwarfAdvanceLineAddr(int64_t LineDelta,2627 const MCSymbol *LastLabel,2628 const MCSymbol *Label,2629 unsigned PointerSize) {2630 assert(MAI->isAIX() &&2631 ".loc/.file don't need raw data in debug line section!");2632 2633 // Set to new address.2634 AddComment("Set address to " + Label->getName());2635 emitIntValue(dwarf::DW_LNS_extended_op, 1);2636 emitULEB128IntValue(PointerSize + 1);2637 emitIntValue(dwarf::DW_LNE_set_address, 1);2638 emitSymbolValue(Label, PointerSize);2639 2640 if (!LastLabel) {2641 // Emit the sequence for the LineDelta (from 1) and a zero address delta.2642 AddComment("Start sequence");2643 MCDwarfLineAddr::Emit(this, MCDwarfLineTableParams(), LineDelta, 0);2644 return;2645 }2646 2647 // INT64_MAX is a signal of the end of the section. Emit DW_LNE_end_sequence2648 // for the end of the section.2649 if (LineDelta == INT64_MAX) {2650 AddComment("End sequence");2651 emitIntValue(dwarf::DW_LNS_extended_op, 1);2652 emitULEB128IntValue(1);2653 emitIntValue(dwarf::DW_LNE_end_sequence, 1);2654 return;2655 }2656 2657 // Advance line.2658 AddComment("Advance line " + Twine(LineDelta));2659 emitIntValue(dwarf::DW_LNS_advance_line, 1);2660 emitSLEB128IntValue(LineDelta);2661 emitIntValue(dwarf::DW_LNS_copy, 1);2662}2663 2664MCStreamer *llvm::createAsmStreamer(MCContext &Context,2665 std::unique_ptr<formatted_raw_ostream> OS,2666 std::unique_ptr<MCInstPrinter> IP,2667 std::unique_ptr<MCCodeEmitter> CE,2668 std::unique_ptr<MCAsmBackend> MAB) {2669 return new MCAsmStreamer(Context, std::move(OS), std::move(IP), std::move(CE),2670 std::move(MAB));2671}2672