[llvm-branch-commits] [llvm] [MC] Rename MCAsmStreamer to MCGNUAsmStreamer (PR #183763)

Kai Nacke via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Fri Feb 27 08:20:31 PST 2026


https://github.com/redstar created https://github.com/llvm/llvm-project/pull/183763

Also rename MCBaseAsmStreamer to MCAsmStreamer.

>From 681d7b2949b36e5a7917b76fec099557fceb7165 Mon Sep 17 00:00:00 2001
From: Kai Nacke <kai.peter.nacke at ibm.com>
Date: Fri, 27 Feb 2026 11:19:14 -0500
Subject: [PATCH] [MC] Rename MCAsmStreamer to MCGNUAsmStreamer

Also rename MCBaseAsmStreamer to MCAsmStreamer.
---
 .../{MCAsmBaseStreamer.h => MCAsmStreamer.h}  |   16 +-
 llvm/lib/MC/CMakeLists.txt                    |    2 +-
 llvm/lib/MC/MCAsmBaseStreamer.cpp             |  143 -
 llvm/lib/MC/MCAsmStreamer.cpp                 | 2660 +----------------
 llvm/lib/MC/MCGNUAsmStreamer.cpp              | 2605 ++++++++++++++++
 .../MCTargetDesc/SystemZHLASMAsmStreamer.h    |    6 +-
 6 files changed, 2717 insertions(+), 2715 deletions(-)
 rename llvm/include/llvm/MC/{MCAsmBaseStreamer.h => MCAsmStreamer.h} (77%)
 delete mode 100644 llvm/lib/MC/MCAsmBaseStreamer.cpp
 create mode 100644 llvm/lib/MC/MCGNUAsmStreamer.cpp

diff --git a/llvm/include/llvm/MC/MCAsmBaseStreamer.h b/llvm/include/llvm/MC/MCAsmStreamer.h
similarity index 77%
rename from llvm/include/llvm/MC/MCAsmBaseStreamer.h
rename to llvm/include/llvm/MC/MCAsmStreamer.h
index f034c9501bb6b..1acad32ac2fc3 100644
--- a/llvm/include/llvm/MC/MCAsmBaseStreamer.h
+++ b/llvm/include/llvm/MC/MCAsmStreamer.h
@@ -1,4 +1,4 @@
-//===- MCAsmBaseStreamer.h - Base Class for Asm Streamers -------*- C++ -*-===//
+//===- MCAsmStreamer.h - Base Class for Asm Streamers -----------*- C++ -*-===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -6,13 +6,13 @@
 //
 //===----------------------------------------------------------------------===//
 //
-// This file declares the MCAsmBaseStreamer class, a base class for streamers
+// This file declares the MCAsmStreamer class, a base class for streamers
 // which emits assembly text.
 //
 //===----------------------------------------------------------------------===//
 
-#ifndef LLVM_MC_MCASMBASESTREAMER_H
-#define LLVM_MC_MCASMBASESTREAMER_H
+#ifndef LLVM_MC_MCASMSTREAMER_H
+#define LLVM_MC_MCASMSTREAMER_H
 
 #include "llvm/MC/MCAsmBackend.h"
 #include "llvm/MC/MCAssembler.h"
@@ -28,15 +28,15 @@ class MCContext;
 class MCInst;
 class MCSubtargetInfo;
 
-class MCAsmBaseStreamer : public MCStreamer {
+class MCAsmStreamer : public MCStreamer {
 protected:
   std::unique_ptr<MCAssembler> Assembler;
   SmallString<128> CommentToEmit;
   raw_svector_ostream CommentStream;
   raw_null_ostream NullStream;
 
-  MCAsmBaseStreamer(MCContext &Context, std::unique_ptr<MCCodeEmitter> Emitter,
-                    std::unique_ptr<MCAsmBackend> AsmBackend);
+  MCAsmStreamer(MCContext &Context, std::unique_ptr<MCCodeEmitter> Emitter,
+                std::unique_ptr<MCAsmBackend> AsmBackend);
 
 public:
   /// Return a raw_ostream that comments can be written to.
@@ -58,4 +58,4 @@ class MCAsmBaseStreamer : public MCStreamer {
 
 } // end namespace llvm
 
-#endif // LLVM_MC_MCASMBASESTREAMER_H
+#endif // LLVM_MC_MCASMSTREAMER_H
diff --git a/llvm/lib/MC/CMakeLists.txt b/llvm/lib/MC/CMakeLists.txt
index d42b735f1b130..653962f9c7937 100644
--- a/llvm/lib/MC/CMakeLists.txt
+++ b/llvm/lib/MC/CMakeLists.txt
@@ -5,7 +5,6 @@ add_llvm_component_library(LLVMMC
   ELFObjectWriter.cpp
   GOFFObjectWriter.cpp
   MCAsmBackend.cpp
-  MCAsmBaseStreamer.cpp
   MCAsmInfo.cpp
   MCAsmInfoCOFF.cpp
   MCAsmInfoDarwin.cpp
@@ -26,6 +25,7 @@ add_llvm_component_library(LLVMMC
   MCELFStreamer.cpp
   MCExpr.cpp
   MCFragment.cpp
+  MCGNUAsmStreamer.cpp
   MCGOFFStreamer.cpp
   MCInst.cpp
   MCInstPrinter.cpp
diff --git a/llvm/lib/MC/MCAsmBaseStreamer.cpp b/llvm/lib/MC/MCAsmBaseStreamer.cpp
deleted file mode 100644
index c05b80e8f9d83..0000000000000
--- a/llvm/lib/MC/MCAsmBaseStreamer.cpp
+++ /dev/null
@@ -1,143 +0,0 @@
-//===- MCAsmBaseStreamer.cpp - Base Class for Asm Streamers -----*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/MC/MCAsmBaseStreamer.h"
-#include "llvm/ADT/SmallString.h"
-#include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/MC/MCAsmBackend.h"
-#include "llvm/MC/MCAsmInfo.h"
-#include "llvm/MC/MCAssembler.h"
-#include "llvm/MC/MCCodeEmitter.h"
-#include "llvm/MC/MCContext.h"
-#include "llvm/MC/MCFixup.h"
-#include "llvm/MC/MCInst.h"
-#include "llvm/MC/MCObjectWriter.h"
-#include "llvm/MC/MCSubtargetInfo.h"
-#include "llvm/Support/Format.h"
-#include "llvm/Support/raw_ostream.h"
-
-using namespace llvm;
-
-MCAsmBaseStreamer::MCAsmBaseStreamer(MCContext &Context,
-                                     std::unique_ptr<MCCodeEmitter> Emitter,
-                                     std::unique_ptr<MCAsmBackend> AsmBackend)
-    : MCStreamer(Context),
-      Assembler(std::make_unique<MCAssembler>(
-          Context, std::move(AsmBackend), std::move(Emitter),
-          (AsmBackend) ? AsmBackend->createObjectWriter(NullStream) : nullptr)),
-      CommentStream(CommentToEmit) {}
-
-void MCAsmBaseStreamer::addEncodingComment(const MCInst &Inst,
-                                           const MCSubtargetInfo &STI) {
-  raw_ostream &OS = getCommentOS();
-  SmallString<256> Code;
-  SmallVector<MCFixup, 4> Fixups;
-
-  // If we have no code emitter, don't emit code.
-  if (!getAssembler().getEmitterPtr())
-    return;
-
-  getAssembler().getEmitter().encodeInstruction(Inst, Code, Fixups, STI);
-
-  // RISC-V instructions are always little-endian, even on BE systems.
-  bool ForceLE = getContext().getTargetTriple().isRISCV();
-
-  const MCAsmInfo *MAI = getContext().getAsmInfo();
-
-  // If we are showing fixups, create symbolic markers in the encoded
-  // representation. We do this by making a per-bit map to the fixup item index,
-  // then trying to display it as nicely as possible.
-  SmallVector<uint8_t, 64> FixupMap;
-  FixupMap.resize(Code.size() * 8);
-  for (unsigned I = 0, E = Code.size() * 8; I != E; ++I)
-    FixupMap[I] = 0;
-
-  for (unsigned I = 0, E = Fixups.size(); I != E; ++I) {
-    MCFixup &F = Fixups[I];
-    MCFixupKindInfo Info =
-        getAssembler().getBackend().getFixupKindInfo(F.getKind());
-    for (unsigned J = 0; J != Info.TargetSize; ++J) {
-      unsigned Index = F.getOffset() * 8 + Info.TargetOffset + J;
-      assert(Index < Code.size() * 8 && "Invalid offset in fixup!");
-      FixupMap[Index] = 1 + I;
-    }
-  }
-
-  // FIXME: Note the fixup comments for Thumb2 are completely bogus since the
-  // high order halfword of a 32-bit Thumb2 instruction is emitted first.
-  OS << "encoding: [";
-  for (unsigned I = 0, E = Code.size(); I != E; ++I) {
-    if (I)
-      OS << ',';
-
-    // See if all bits are the same map entry.
-    uint8_t MapEntry = FixupMap[I * 8 + 0];
-    for (unsigned J = 1; J != 8; ++J) {
-      if (FixupMap[I * 8 + J] == MapEntry)
-        continue;
-
-      MapEntry = uint8_t(~0U);
-      break;
-    }
-
-    if (MapEntry != uint8_t(~0U)) {
-      if (MapEntry == 0) {
-        OS << format("0x%02x", uint8_t(Code[I]));
-      } else {
-        if (Code[I]) {
-          // FIXME: Some of the 8 bits require fix up.
-          OS << format("0x%02x", uint8_t(Code[I])) << '\''
-             << char('A' + MapEntry - 1) << '\'';
-        } else
-          OS << char('A' + MapEntry - 1);
-      }
-    } else {
-      // Otherwise, write out in binary.
-      OS << "0b";
-      for (unsigned J = 8; J--;) {
-        unsigned Bit = (Code[I] >> J) & 1;
-
-        unsigned FixupBit;
-        // RISC-V instructions are always little-endian.
-        // The FixupMap is indexed by actual bit positions in the LE
-        // instruction.
-        if (MAI->isLittleEndian() || ForceLE)
-          FixupBit = I * 8 + J;
-        else
-          FixupBit = I * 8 + (7 - J);
-
-        if (uint8_t MapEntry = FixupMap[FixupBit]) {
-          assert(Bit == 0 && "Encoder wrote into fixed up bit!");
-          OS << char('A' + MapEntry - 1);
-        } else
-          OS << Bit;
-      }
-    }
-  }
-  OS << "]\n";
-
-  for (unsigned I = 0, E = Fixups.size(); I != E; ++I) {
-    MCFixup &F = Fixups[I];
-    OS << "  fixup " << char('A' + I) << " - "
-       << "offset: " << F.getOffset() << ", value: ";
-    MAI->printExpr(OS, *F.getValue());
-    auto Kind = F.getKind();
-    if (mc::isRelocation(Kind))
-      OS << ", relocation type: " << Kind;
-    else {
-      OS << ", kind: ";
-      auto Info = getAssembler().getBackend().getFixupKindInfo(Kind);
-      if (F.isPCRel() && StringRef(Info.Name).starts_with("FK_Data_"))
-        OS << "FK_PCRel_" << (Info.TargetSize / 8);
-      else
-        OS << Info.Name;
-    }
-    OS << '\n';
-  }
-}
diff --git a/llvm/lib/MC/MCAsmStreamer.cpp b/llvm/lib/MC/MCAsmStreamer.cpp
index b451abba2e70c..f3ab3f0c48ac3 100644
--- a/llvm/lib/MC/MCAsmStreamer.cpp
+++ b/llvm/lib/MC/MCAsmStreamer.cpp
@@ -1,4 +1,4 @@
-//===- lib/MC/MCAsmStreamer.cpp - Text Assembly Output ----------*- C++ -*-===//
+//===- MCAsmStreamer.cpp - Base Class for Asm Streamers ---------*- C++ -*-===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -6,2598 +6,138 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "llvm/MC/MCAsmStreamer.h"
 #include "llvm/ADT/SmallString.h"
-#include "llvm/ADT/StringExtras.h"
-#include "llvm/ADT/Twine.h"
-#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
 #include "llvm/MC/MCAsmBackend.h"
-#include "llvm/MC/MCAsmBaseStreamer.h"
 #include "llvm/MC/MCAsmInfo.h"
 #include "llvm/MC/MCAssembler.h"
 #include "llvm/MC/MCCodeEmitter.h"
-#include "llvm/MC/MCCodeView.h"
 #include "llvm/MC/MCContext.h"
-#include "llvm/MC/MCExpr.h"
+#include "llvm/MC/MCFixup.h"
 #include "llvm/MC/MCInst.h"
-#include "llvm/MC/MCInstPrinter.h"
-#include "llvm/MC/MCLFIRewriter.h"
-#include "llvm/MC/MCObjectFileInfo.h"
 #include "llvm/MC/MCObjectWriter.h"
-#include "llvm/MC/MCPseudoProbe.h"
-#include "llvm/MC/MCRegister.h"
-#include "llvm/MC/MCRegisterInfo.h"
-#include "llvm/MC/MCSectionMachO.h"
-#include "llvm/MC/MCStreamer.h"
-#include "llvm/MC/MCSymbolXCOFF.h"
-#include "llvm/MC/TargetRegistry.h"
-#include "llvm/Support/ErrorHandling.h"
+#include "llvm/MC/MCSubtargetInfo.h"
 #include "llvm/Support/Format.h"
-#include "llvm/Support/FormattedStream.h"
-#include "llvm/Support/LEB128.h"
-#include "llvm/Support/MathExtras.h"
-#include "llvm/Support/Path.h"
-#include <algorithm>
-#include <optional>
+#include "llvm/Support/raw_ostream.h"
 
 using namespace llvm;
 
-namespace {
+MCAsmStreamer::MCAsmStreamer(MCContext &Context,
+                             std::unique_ptr<MCCodeEmitter> Emitter,
+                             std::unique_ptr<MCAsmBackend> AsmBackend)
+    : MCStreamer(Context),
+      Assembler(std::make_unique<MCAssembler>(
+          Context, std::move(AsmBackend), std::move(Emitter),
+          (AsmBackend) ? AsmBackend->createObjectWriter(NullStream) : nullptr)),
+      CommentStream(CommentToEmit) {}
 
-class MCAsmStreamer final : public MCAsmBaseStreamer {
-  std::unique_ptr<formatted_raw_ostream> OSOwner;
-  formatted_raw_ostream &OS;
-  const MCAsmInfo *MAI;
-  std::unique_ptr<MCInstPrinter> InstPrinter;
+void MCAsmStreamer::addEncodingComment(const MCInst &Inst,
+                                       const MCSubtargetInfo &STI) {
+  raw_ostream &OS = getCommentOS();
+  SmallString<256> Code;
+  SmallVector<MCFixup, 4> Fixups;
 
-  SmallString<128> ExplicitCommentToEmit;
-
-  bool EmittedSectionDirective = false;
-
-  bool IsVerboseAsm = false;
-  bool ShowInst = false;
-  bool UseDwarfDirectory = false;
-
-  void EmitRegisterName(int64_t Register);
-  void PrintQuotedString(StringRef Data, raw_ostream &OS) const;
-  void printDwarfFileDirective(unsigned FileNo, StringRef Directory,
-                               StringRef Filename,
-                               std::optional<MD5::MD5Result> Checksum,
-                               std::optional<StringRef> Source,
-                               bool UseDwarfDirectory,
-                               raw_svector_ostream &OS) const;
-  void emitCFIStartProcImpl(MCDwarfFrameInfo &Frame) override;
-  void emitCFIEndProcImpl(MCDwarfFrameInfo &Frame) override;
-
-  /// Helper to emit common .loc directive flags, isa, and discriminator.
-  void emitDwarfLocDirectiveFlags(unsigned Flags, unsigned Isa,
-                                  unsigned Discriminator);
-
-  /// Helper to emit the common suffix of .loc directives (flags, comment, EOL,
-  /// parent call).
-  void emitDwarfLocDirectiveSuffix(unsigned FileNo, unsigned Line,
-                                   unsigned Column, unsigned Flags,
-                                   unsigned Isa, unsigned Discriminator,
-                                   StringRef FileName, StringRef Comment);
-
-public:
-  MCAsmStreamer(MCContext &Context, std::unique_ptr<formatted_raw_ostream> OS,
-                std::unique_ptr<MCInstPrinter> Printer,
-                std::unique_ptr<MCCodeEmitter> Emitter,
-                std::unique_ptr<MCAsmBackend> AsmBackend)
-      : MCAsmBaseStreamer(Context, std::move(Emitter), std::move(AsmBackend)),
-        OSOwner(std::move(OS)), OS(*OSOwner), MAI(Context.getAsmInfo()),
-        InstPrinter(std::move(Printer)) {
-    assert(InstPrinter);
-    if (Assembler->getBackendPtr())
-      setAllowAutoPadding(Assembler->getBackend().allowAutoPadding());
-
-    Context.setUseNamesOnTempLabels(true);
-
-    auto *TO = Context.getTargetOptions();
-    if (!TO)
-      return;
-    IsVerboseAsm = TO->AsmVerbose;
-    if (IsVerboseAsm)
-      InstPrinter->setCommentStream(CommentStream);
-    ShowInst = TO->ShowMCInst;
-    switch (TO->MCUseDwarfDirectory) {
-    case MCTargetOptions::DisableDwarfDirectory:
-      UseDwarfDirectory = false;
-      break;
-    case MCTargetOptions::EnableDwarfDirectory:
-      UseDwarfDirectory = true;
-      break;
-    case MCTargetOptions::DefaultDwarfDirectory:
-      UseDwarfDirectory =
-          Context.getAsmInfo()->enableDwarfFileDirectoryDefault();
-      break;
-    }
-  }
-
-  inline void EmitEOL() {
-    // Dump Explicit Comments here.
-    emitExplicitComments();
-    // If we don't have any comments, just emit a \n.
-    if (!IsVerboseAsm) {
-      OS << '\n';
-      return;
-    }
-    EmitCommentsAndEOL();
-  }
-
-  void emitSyntaxDirective(StringRef Syntax, StringRef Options) override;
-
-  void EmitCommentsAndEOL();
-
-  /// Return true if this streamer supports verbose assembly at all.
-  bool isVerboseAsm() const override { return IsVerboseAsm; }
-
-  /// Do we support EmitRawText?
-  bool hasRawTextSupport() const override { return true; }
-
-  /// Add a comment that can be emitted to the generated .s file to make the
-  /// output of the compiler more readable. This only affects the MCAsmStreamer
-  /// and only when verbose assembly output is enabled.
-  void AddComment(const Twine &T, bool EOL = true) override;
-
-  void emitRawComment(const Twine &T, bool TabPrefix = true) override;
-
-  void addExplicitComment(const Twine &T) override;
-  void emitExplicitComments() override;
-
-  /// Emit a blank line to a .s file to pretty it up.
-  void addBlankLine() override { EmitEOL(); }
-
-  /// @name MCStreamer Interface
-  /// @{
-
-  void switchSection(MCSection *Section, uint32_t Subsection) override;
-  bool popSection() override;
-
-  void emitELFSymverDirective(const MCSymbol *OriginalSym, StringRef Name,
-                              bool KeepOriginalSym) override;
-
-  void emitLOHDirective(MCLOHType Kind, const MCLOHArgs &Args) override;
-
-  void emitGNUAttribute(unsigned Tag, unsigned Value) override;
-
-  StringRef getMnemonic(const MCInst &MI) const override {
-    auto [Ptr, Bits] = InstPrinter->getMnemonic(MI);
-    assert((Bits != 0 || Ptr == nullptr) &&
-           "Invalid char pointer for instruction with no mnemonic");
-    return Ptr;
-  }
-
-  void emitLabel(MCSymbol *Symbol, SMLoc Loc = SMLoc()) override;
-
-  void emitSubsectionsViaSymbols() override;
-  void emitLinkerOptions(ArrayRef<std::string> Options) override;
-  void emitDataRegion(MCDataRegionType Kind) override;
-  void emitVersionMin(MCVersionMinType Kind, unsigned Major, unsigned Minor,
-                      unsigned Update, VersionTuple SDKVersion) override;
-  void emitBuildVersion(unsigned Platform, unsigned Major, unsigned Minor,
-                        unsigned Update, VersionTuple SDKVersion) override;
-  void emitDarwinTargetVariantBuildVersion(unsigned Platform, unsigned Major,
-                                           unsigned Minor, unsigned Update,
-                                           VersionTuple SDKVersion) override;
-
-  void emitAssignment(MCSymbol *Symbol, const MCExpr *Value) override;
-  void emitConditionalAssignment(MCSymbol *Symbol,
-                                 const MCExpr *Value) override;
-  void emitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol) override;
-  bool emitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override;
-
-  void emitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) override;
-  void beginCOFFSymbolDef(const MCSymbol *Symbol) override;
-  void emitCOFFSymbolStorageClass(int StorageClass) override;
-  void emitCOFFSymbolType(int Type) override;
-  void endCOFFSymbolDef() override;
-  void emitCOFFSafeSEH(MCSymbol const *Symbol) override;
-  void emitCOFFSymbolIndex(MCSymbol const *Symbol) override;
-  void emitCOFFSectionIndex(MCSymbol const *Symbol) override;
-  void emitCOFFSecRel32(MCSymbol const *Symbol, uint64_t Offset) override;
-  void emitCOFFImgRel32(MCSymbol const *Symbol, int64_t Offset) override;
-  void emitCOFFSecNumber(MCSymbol const *Symbol) override;
-  void emitCOFFSecOffset(MCSymbol const *Symbol) override;
-  void emitXCOFFLocalCommonSymbol(MCSymbol *LabelSym, uint64_t Size,
-                                  MCSymbol *CsectSym, Align Alignment) override;
-  void emitXCOFFSymbolLinkageWithVisibility(MCSymbol *Symbol,
-                                            MCSymbolAttr Linkage,
-                                            MCSymbolAttr Visibility) override;
-  void emitXCOFFRenameDirective(const MCSymbol *Name,
-                                StringRef Rename) override;
-
-  void emitXCOFFRefDirective(const MCSymbol *Symbol) override;
-
-  void emitXCOFFExceptDirective(const MCSymbol *Symbol,
-                                const MCSymbol *Trap,
-                                unsigned Lang, unsigned Reason,
-                                unsigned FunctionSize, bool hasDebug) override;
-  void emitXCOFFCInfoSym(StringRef Name, StringRef Metadata) override;
-
-  void emitELFSize(MCSymbol *Symbol, const MCExpr *Value) override;
-  void emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
-                        Align ByteAlignment) override;
-
-  /// Emit a local common (.lcomm) symbol.
-  ///
-  /// @param Symbol - The common symbol to emit.
-  /// @param Size - The size of the common symbol.
-  /// @param ByteAlignment - The alignment of the common symbol in bytes.
-  void emitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size,
-                             Align ByteAlignment) override;
-
-  void emitZerofill(MCSection *Section, MCSymbol *Symbol = nullptr,
-                    uint64_t Size = 0, Align ByteAlignment = Align(1),
-                    SMLoc Loc = SMLoc()) override;
-
-  void emitTBSSSymbol(MCSection *Section, MCSymbol *Symbol, uint64_t Size,
-                      Align ByteAlignment = Align(1)) override;
-
-  void emitBinaryData(StringRef Data) override;
-
-  void emitBytes(StringRef Data) override;
-
-  void emitValueImpl(const MCExpr *Value, unsigned Size,
-                     SMLoc Loc = SMLoc()) override;
-  void emitIntValue(uint64_t Value, unsigned Size) override;
-  void emitIntValueInHex(uint64_t Value, unsigned Size) override;
-  void emitIntValueInHexWithPadding(uint64_t Value, unsigned Size) override;
-
-  void emitULEB128Value(const MCExpr *Value) override;
-
-  void emitSLEB128Value(const MCExpr *Value) override;
-
-  void emitFill(const MCExpr &NumBytes, uint64_t FillValue,
-                SMLoc Loc = SMLoc()) override;
-
-  void emitFill(const MCExpr &NumValues, int64_t Size, int64_t Expr,
-                SMLoc Loc = SMLoc()) override;
-
-  void emitAlignmentDirective(uint64_t ByteAlignment,
-                              std::optional<int64_t> Value, unsigned ValueSize,
-                              unsigned MaxBytesToEmit);
-
-  void emitValueToAlignment(Align Alignment, int64_t Fill = 0,
-                            uint8_t FillLen = 1,
-                            unsigned MaxBytesToEmit = 0) override;
-
-  void emitCodeAlignment(Align Alignment, const MCSubtargetInfo *STI,
-                         unsigned MaxBytesToEmit = 0) override;
-  void emitPrefAlign(Align Alignment) override;
-
-  void emitValueToOffset(const MCExpr *Offset,
-                         unsigned char Value,
-                         SMLoc Loc) override;
-
-  void emitFileDirective(StringRef Filename) override;
-  void emitFileDirective(StringRef Filename, StringRef CompilerVersion,
-                         StringRef TimeStamp, StringRef Description) override;
-  Expected<unsigned> tryEmitDwarfFileDirective(
-      unsigned FileNo, StringRef Directory, StringRef Filename,
-      std::optional<MD5::MD5Result> Checksum = std::nullopt,
-      std::optional<StringRef> Source = std::nullopt,
-      unsigned CUID = 0) override;
-  void emitDwarfFile0Directive(StringRef Directory, StringRef Filename,
-                               std::optional<MD5::MD5Result> Checksum,
-                               std::optional<StringRef> Source,
-                               unsigned CUID = 0) override;
-  void emitDwarfLocDirective(unsigned FileNo, unsigned Line, unsigned Column,
-                             unsigned Flags, unsigned Isa,
-                             unsigned Discriminator, StringRef FileName,
-                             StringRef Location = {}) override;
-  void emitDwarfLocLabelDirective(SMLoc Loc, StringRef Name) override;
-
-  /// This is same as emitDwarfLocDirective, except also emits inlined function
-  /// and inlined callsite information.
-  void emitDwarfLocDirectiveWithInlinedAt(unsigned FileNo, unsigned Line,
-                                          unsigned Column, unsigned FileIA,
-                                          unsigned LineIA, unsigned ColIA,
-                                          const MCSymbol *Sym, unsigned Flags,
-                                          unsigned Isa, unsigned Discriminator,
-                                          StringRef FileName,
-                                          StringRef Comment = {}) override;
-
-  MCSymbol *getDwarfLineTableSymbol(unsigned CUID) override;
-
-  bool emitCVFileDirective(unsigned FileNo, StringRef Filename,
-                           ArrayRef<uint8_t> Checksum,
-                           unsigned ChecksumKind) override;
-  bool emitCVFuncIdDirective(unsigned FuncId) override;
-  bool emitCVInlineSiteIdDirective(unsigned FunctionId, unsigned IAFunc,
-                                   unsigned IAFile, unsigned IALine,
-                                   unsigned IACol, SMLoc Loc) override;
-  void emitCVLocDirective(unsigned FunctionId, unsigned FileNo, unsigned Line,
-                          unsigned Column, bool PrologueEnd, bool IsStmt,
-                          StringRef FileName, SMLoc Loc) override;
-  void emitCVLinetableDirective(unsigned FunctionId, const MCSymbol *FnStart,
-                                const MCSymbol *FnEnd) override;
-  void emitCVInlineLinetableDirective(unsigned PrimaryFunctionId,
-                                      unsigned SourceFileId,
-                                      unsigned SourceLineNum,
-                                      const MCSymbol *FnStartSym,
-                                      const MCSymbol *FnEndSym) override;
-
-  void PrintCVDefRangePrefix(
-      ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges);
-
-  void emitCVDefRangeDirective(
-      ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,
-      codeview::DefRangeRegisterRelHeader DRHdr) override;
-
-  void emitCVDefRangeDirective(
-      ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,
-      codeview::DefRangeSubfieldRegisterHeader DRHdr) override;
-
-  void emitCVDefRangeDirective(
-      ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,
-      codeview::DefRangeRegisterHeader DRHdr) override;
-
-  void emitCVDefRangeDirective(
-      ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,
-      codeview::DefRangeFramePointerRelHeader DRHdr) override;
-
-  void emitCVStringTableDirective() override;
-  void emitCVFileChecksumsDirective() override;
-  void emitCVFileChecksumOffsetDirective(unsigned FileNo) override;
-  void emitCVFPOData(const MCSymbol *ProcSym, SMLoc L) override;
-
-  void emitIdent(StringRef IdentString) override;
-  void emitCFIBKeyFrame() override;
-  void emitCFIMTETaggedFrame() override;
-  void emitCFISections(bool EH, bool Debug, bool SFrame) override;
-  void emitCFIDefCfa(int64_t Register, int64_t Offset, SMLoc Loc) override;
-  void emitCFIDefCfaOffset(int64_t Offset, SMLoc Loc) override;
-  void emitCFIDefCfaRegister(int64_t Register, SMLoc Loc) override;
-  void emitCFILLVMDefAspaceCfa(int64_t Register, int64_t Offset,
-                               int64_t AddressSpace, SMLoc Loc) override;
-  void emitCFIOffset(int64_t Register, int64_t Offset, SMLoc Loc) override;
-  void emitCFIPersonality(const MCSymbol *Sym, unsigned Encoding) override;
-  void emitCFILsda(const MCSymbol *Sym, unsigned Encoding) override;
-  void emitCFIRememberState(SMLoc Loc) override;
-  void emitCFIRestoreState(SMLoc Loc) override;
-  void emitCFIRestore(int64_t Register, SMLoc Loc) override;
-  void emitCFISameValue(int64_t Register, SMLoc Loc) override;
-  void emitCFIRelOffset(int64_t Register, int64_t Offset, SMLoc Loc) override;
-  void emitCFIAdjustCfaOffset(int64_t Adjustment, SMLoc Loc) override;
-  void emitCFIEscape(StringRef Values, SMLoc Loc) override;
-  void emitCFIGnuArgsSize(int64_t Size, SMLoc Loc) override;
-  void emitCFISignalFrame() override;
-  void emitCFIUndefined(int64_t Register, SMLoc Loc) override;
-  void emitCFIRegister(int64_t Register1, int64_t Register2,
-                       SMLoc Loc) override;
-  void emitCFIWindowSave(SMLoc Loc) override;
-  void emitCFINegateRAState(SMLoc Loc) override;
-  void emitCFINegateRAStateWithPC(SMLoc Loc) override;
-  void emitCFIReturnColumn(int64_t Register) override;
-  void emitCFILabelDirective(SMLoc Loc, StringRef Name) override;
-  void emitCFIValOffset(int64_t Register, int64_t Offset, SMLoc Loc) override;
-
-  void emitWinCFIStartProc(const MCSymbol *Symbol, SMLoc Loc) override;
-  void emitWinCFIEndProc(SMLoc Loc) override;
-  void emitWinCFIFuncletOrFuncEnd(SMLoc Loc) override;
-  void emitWinCFISplitChained(SMLoc Loc) override;
-  void emitWinCFIPushReg(MCRegister Register, SMLoc Loc) override;
-  void emitWinCFISetFrame(MCRegister Register, unsigned Offset,
-                          SMLoc Loc) override;
-  void emitWinCFIAllocStack(unsigned Size, SMLoc Loc) override;
-  void emitWinCFISaveReg(MCRegister Register, unsigned Offset,
-                         SMLoc Loc) override;
-  void emitWinCFISaveXMM(MCRegister Register, unsigned Offset,
-                         SMLoc Loc) override;
-  void emitWinCFIPushFrame(bool Code, SMLoc Loc) override;
-  void emitWinCFIEndProlog(SMLoc Loc) override;
-  void emitWinCFIBeginEpilogue(SMLoc Loc) override;
-  void emitWinCFIEndEpilogue(SMLoc Loc) override;
-  void emitWinCFIUnwindV2Start(SMLoc Loc) override;
-  void emitWinCFIUnwindVersion(uint8_t Version, SMLoc Loc) override;
-
-  void emitWinEHHandler(const MCSymbol *Sym, bool Unwind, bool Except,
-                        SMLoc Loc) override;
-  void emitWinEHHandlerData(SMLoc Loc) override;
-
-  void emitCGProfileEntry(const MCSymbolRefExpr *From,
-                          const MCSymbolRefExpr *To, uint64_t Count) override;
-
-  void emitInstruction(const MCInst &Inst, const MCSubtargetInfo &STI) override;
-
-  void emitPseudoProbe(uint64_t Guid, uint64_t Index, uint64_t Type,
-                       uint64_t Attr, uint64_t Discriminator,
-                       const MCPseudoProbeInlineStack &InlineStack,
-                       MCSymbol *FnSym) override;
-
-  void emitRelocDirective(const MCExpr &Offset, StringRef Name,
-                          const MCExpr *Expr, SMLoc Loc) override;
-
-  void emitAddrsig() override;
-  void emitAddrsigSym(const MCSymbol *Sym) override;
-
-  /// If this file is backed by an assembly streamer, this dumps the specified
-  /// string in the output .s file. This capability is indicated by the
-  /// hasRawTextSupport() predicate.
-  void emitRawTextImpl(StringRef String) override;
-
-  void finishImpl() override;
-
-  void emitDwarfUnitLength(uint64_t Length, const Twine &Comment) override;
-
-  MCSymbol *emitDwarfUnitLength(const Twine &Prefix,
-                                const Twine &Comment) override;
-
-  void emitDwarfLineStartLabel(MCSymbol *StartSym) override;
-
-  void emitDwarfLineEndEntry(MCSection *Section, MCSymbol *LastLabel,
-                             MCSymbol *EndLabel = nullptr) override;
-
-  void emitDwarfAdvanceLineAddr(int64_t LineDelta, const MCSymbol *LastLabel,
-                                const MCSymbol *Label,
-                                unsigned PointerSize) override;
-};
-
-} // end anonymous namespace.
-
-void MCAsmStreamer::AddComment(const Twine &T, bool EOL) {
-  if (!IsVerboseAsm) return;
-
-  T.toVector(CommentToEmit);
-
-  if (EOL)
-    CommentToEmit.push_back('\n'); // Place comment in a new line.
-}
-
-void MCAsmStreamer::EmitCommentsAndEOL() {
-  if (CommentToEmit.empty() && CommentStream.GetNumBytesInBuffer() == 0) {
-    OS << '\n';
-    return;
-  }
-
-  StringRef Comments = CommentToEmit;
-
-  assert(Comments.back() == '\n' &&
-         "Comment array not newline terminated");
-  do {
-    // Emit a line of comments.
-    OS.PadToColumn(MAI->getCommentColumn());
-    size_t Position = Comments.find('\n');
-    OS << MAI->getCommentString() << ' ' << Comments.substr(0, Position) <<'\n';
-
-    Comments = Comments.substr(Position+1);
-  } while (!Comments.empty());
-
-  CommentToEmit.clear();
-}
-
-static inline int64_t truncateToSize(int64_t Value, unsigned Bytes) {
-  assert(Bytes > 0 && Bytes <= 8 && "Invalid size!");
-  return Value & ((uint64_t) (int64_t) -1 >> (64 - Bytes * 8));
-}
-
-void MCAsmStreamer::emitRawComment(const Twine &T, bool TabPrefix) {
-  if (TabPrefix)
-    OS << '\t';
-  OS << MAI->getCommentString() << T;
-  EmitEOL();
-}
-
-void MCAsmStreamer::addExplicitComment(const Twine &T) {
-  StringRef c = T.getSingleStringRef();
-  if (c == MAI->getSeparatorString())
-    return;
-  if (c.starts_with(StringRef("//"))) {
-    ExplicitCommentToEmit.append("\t");
-    ExplicitCommentToEmit.append(MAI->getCommentString());
-    // drop //
-    ExplicitCommentToEmit.append(c.substr(2).str());
-  } else if (c.starts_with(StringRef("/*"))) {
-    size_t p = 2, len = c.size() - 2;
-    // emit each line in comment as separate newline.
-    do {
-      size_t newp = std::min(len, c.find_first_of("\r\n", p));
-      ExplicitCommentToEmit.append("\t");
-      ExplicitCommentToEmit.append(MAI->getCommentString());
-      ExplicitCommentToEmit.append(c.slice(p, newp).str());
-      // If we have another line in this comment add line
-      if (newp < len)
-        ExplicitCommentToEmit.append("\n");
-      p = newp + 1;
-    } while (p < len);
-  } else if (c.starts_with(StringRef(MAI->getCommentString()))) {
-    ExplicitCommentToEmit.append("\t");
-    ExplicitCommentToEmit.append(c.str());
-  } else if (c.front() == '#') {
-
-    ExplicitCommentToEmit.append("\t");
-    ExplicitCommentToEmit.append(MAI->getCommentString());
-    ExplicitCommentToEmit.append(c.substr(1).str());
-  } else
-    assert(false && "Unexpected Assembly Comment");
-  // full line comments immediately output
-  if (c.back() == '\n')
-    emitExplicitComments();
-}
-
-void MCAsmStreamer::emitExplicitComments() {
-  StringRef Comments = ExplicitCommentToEmit;
-  if (!Comments.empty())
-    OS << Comments;
-  ExplicitCommentToEmit.clear();
-}
-
-void MCAsmStreamer::switchSection(MCSection *Section, uint32_t Subsection) {
-  MCSectionSubPair Cur = getCurrentSection();
-  if (!EmittedSectionDirective ||
-      MCSectionSubPair(Section, Subsection) != Cur) {
-    EmittedSectionDirective = true;
-    if (MCTargetStreamer *TS = getTargetStreamer()) {
-      TS->changeSection(Cur.first, Section, Subsection, OS);
-    } else {
-      MAI->printSwitchToSection(*Section, Subsection,
-                                getContext().getTargetTriple(), OS);
-    }
-  }
-  MCStreamer::switchSection(Section, Subsection);
-}
-
-bool MCAsmStreamer::popSection() {
-  if (!MCStreamer::popSection())
-    return false;
-  auto [Sec, Subsec] = getCurrentSection();
-  MAI->printSwitchToSection(*Sec, Subsec, getContext().getTargetTriple(), OS);
-  return true;
-}
-
-void MCAsmStreamer::emitELFSymverDirective(const MCSymbol *OriginalSym,
-                                           StringRef Name,
-                                           bool KeepOriginalSym) {
-  OS << ".symver ";
-  OriginalSym->print(OS, MAI);
-  OS << ", " << Name;
-  if (!KeepOriginalSym && !Name.contains("@@@"))
-    OS << ", remove";
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitLabel(MCSymbol *Symbol, SMLoc Loc) {
-  MCStreamer::emitLabel(Symbol, Loc);
-  // FIXME: Fix CodeGen/AArch64/arm64ec-varargs.ll. emitLabel is followed by
-  // setVariableValue, leading to an assertion failure if setOffset(0) is
-  // called.
-  if (!Symbol->isVariable() &&
-      getContext().getObjectFileType() != MCContext::IsCOFF)
-    Symbol->setOffset(0);
-
-  Symbol->print(OS, MAI);
-  OS << MAI->getLabelSuffix();
-
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitLOHDirective(MCLOHType Kind, const MCLOHArgs &Args) {
-  StringRef str = MCLOHIdToName(Kind);
-
-#ifndef NDEBUG
-  int NbArgs = MCLOHIdToNbArgs(Kind);
-  assert(NbArgs != -1 && ((size_t)NbArgs) == Args.size() && "Malformed LOH!");
-  assert(str != "" && "Invalid LOH name");
-#endif
-
-  OS << "\t" << MCLOHDirectiveName() << " " << str << "\t";
-  bool IsFirst = true;
-  for (const MCSymbol *Arg : Args) {
-    if (!IsFirst)
-      OS << ", ";
-    IsFirst = false;
-    Arg->print(OS, MAI);
-  }
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitGNUAttribute(unsigned Tag, unsigned Value) {
-  OS << "\t.gnu_attribute " << Tag << ", " << Value << "\n";
-}
-
-void MCAsmStreamer::emitSubsectionsViaSymbols() {
-  OS << ".subsections_via_symbols\n";
-}
-
-void MCAsmStreamer::emitLinkerOptions(ArrayRef<std::string> Options) {
-  assert(!Options.empty() && "At least one option is required!");
-  OS << "\t.linker_option \"" << Options[0] << '"';
-  for (const std::string &Opt : llvm::drop_begin(Options))
-    OS << ", " << '"' << Opt << '"';
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitDataRegion(MCDataRegionType Kind) {
-  if (!MAI->doesSupportDataRegionDirectives())
-    return;
-  switch (Kind) {
-  case MCDR_DataRegion:            OS << "\t.data_region"; break;
-  case MCDR_DataRegionJT8:         OS << "\t.data_region jt8"; break;
-  case MCDR_DataRegionJT16:        OS << "\t.data_region jt16"; break;
-  case MCDR_DataRegionJT32:        OS << "\t.data_region jt32"; break;
-  case MCDR_DataRegionEnd:         OS << "\t.end_data_region"; break;
-  }
-  EmitEOL();
-}
-
-static const char *getVersionMinDirective(MCVersionMinType Type) {
-  switch (Type) {
-  case MCVM_WatchOSVersionMin: return ".watchos_version_min";
-  case MCVM_TvOSVersionMin:    return ".tvos_version_min";
-  case MCVM_IOSVersionMin:     return ".ios_version_min";
-  case MCVM_OSXVersionMin:     return ".macosx_version_min";
-  }
-  llvm_unreachable("Invalid MC version min type");
-}
-
-static void EmitSDKVersionSuffix(raw_ostream &OS,
-                                 const VersionTuple &SDKVersion) {
-  if (SDKVersion.empty())
+  // If we have no code emitter, don't emit code.
+  if (!getAssembler().getEmitterPtr())
     return;
-  OS << '\t' << "sdk_version " << SDKVersion.getMajor();
-  if (auto Minor = SDKVersion.getMinor()) {
-    OS << ", " << *Minor;
-    if (auto Subminor = SDKVersion.getSubminor()) {
-      OS << ", " << *Subminor;
-    }
-  }
-}
-
-void MCAsmStreamer::emitVersionMin(MCVersionMinType Type, unsigned Major,
-                                   unsigned Minor, unsigned Update,
-                                   VersionTuple SDKVersion) {
-  OS << '\t' << getVersionMinDirective(Type) << ' ' << Major << ", " << Minor;
-  if (Update)
-    OS << ", " << Update;
-  EmitSDKVersionSuffix(OS, SDKVersion);
-  EmitEOL();
-}
-
-static const char *getPlatformName(MachO::PlatformType Type) {
-  switch (Type) {
-#define PLATFORM(platform, id, name, build_name, target, tapi_target,          \
-                 marketing)                                                    \
-  case MachO::PLATFORM_##platform:                                             \
-    return #build_name;
-#include "llvm/BinaryFormat/MachO.def"
-  }
-  llvm_unreachable("Invalid Mach-O platform type");
-}
-
-void MCAsmStreamer::emitBuildVersion(unsigned Platform, unsigned Major,
-                                     unsigned Minor, unsigned Update,
-                                     VersionTuple SDKVersion) {
-  const char *PlatformName = getPlatformName((MachO::PlatformType)Platform);
-  OS << "\t.build_version " << PlatformName << ", " << Major << ", " << Minor;
-  if (Update)
-    OS << ", " << Update;
-  EmitSDKVersionSuffix(OS, SDKVersion);
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitDarwinTargetVariantBuildVersion(
-    unsigned Platform, unsigned Major, unsigned Minor, unsigned Update,
-    VersionTuple SDKVersion) {
-  emitBuildVersion(Platform, Major, Minor, Update, SDKVersion);
-}
-
-void MCAsmStreamer::emitAssignment(MCSymbol *Symbol, const MCExpr *Value) {
-  bool UseSet = MAI->usesSetToEquateSymbol();
-  if (UseSet)
-    OS << ".set ";
-  Symbol->print(OS, MAI);
-  OS << (UseSet ? ", " : " = ");
-  MAI->printExpr(OS, *Value);
-
-  EmitEOL();
-  MCStreamer::emitAssignment(Symbol, Value);
-}
-
-void MCAsmStreamer::emitConditionalAssignment(MCSymbol *Symbol,
-                                              const MCExpr *Value) {
-  OS << ".lto_set_conditional ";
-  Symbol->print(OS, MAI);
-  OS << ", ";
-  MAI->printExpr(OS, *Value);
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol) {
-  OS << ".weakref ";
-  Alias->print(OS, MAI);
-  OS << ", ";
-  Symbol->print(OS, MAI);
-  EmitEOL();
-}
-
-bool MCAsmStreamer::emitSymbolAttribute(MCSymbol *Symbol,
-                                        MCSymbolAttr Attribute) {
-  switch (Attribute) {
-  case MCSA_Invalid: llvm_unreachable("Invalid symbol attribute");
-  case MCSA_ELF_TypeFunction:    /// .type _foo, STT_FUNC  # aka @function
-  case MCSA_ELF_TypeIndFunction: /// .type _foo, STT_GNU_IFUNC
-  case MCSA_ELF_TypeObject:      /// .type _foo, STT_OBJECT  # aka @object
-  case MCSA_ELF_TypeTLS:         /// .type _foo, STT_TLS     # aka @tls_object
-  case MCSA_ELF_TypeCommon:      /// .type _foo, STT_COMMON  # aka @common
-  case MCSA_ELF_TypeNoType:      /// .type _foo, STT_NOTYPE  # aka @notype
-  case MCSA_ELF_TypeGnuUniqueObject:  /// .type _foo, @gnu_unique_object
-    if (!MAI->hasDotTypeDotSizeDirective())
-      return false; // Symbol attribute not supported
-    OS << "\t.type\t";
-    Symbol->print(OS, MAI);
-    OS << ',' << ((MAI->getCommentString()[0] != '@') ? '@' : '%');
-    switch (Attribute) {
-    default: return false;
-    case MCSA_ELF_TypeFunction:    OS << "function"; break;
-    case MCSA_ELF_TypeIndFunction: OS << "gnu_indirect_function"; break;
-    case MCSA_ELF_TypeObject:      OS << "object"; break;
-    case MCSA_ELF_TypeTLS:         OS << "tls_object"; break;
-    case MCSA_ELF_TypeCommon:      OS << "common"; break;
-    case MCSA_ELF_TypeNoType:      OS << "notype"; break;
-    case MCSA_ELF_TypeGnuUniqueObject: OS << "gnu_unique_object"; break;
-    }
-    EmitEOL();
-    return true;
-  case MCSA_Global: // .globl/.global
-    OS << MAI->getGlobalDirective();
-    break;
-  case MCSA_LGlobal:        OS << "\t.lglobl\t";          break;
-  case MCSA_Hidden:         OS << "\t.hidden\t";          break;
-  case MCSA_IndirectSymbol: OS << "\t.indirect_symbol\t"; break;
-  case MCSA_Internal:       OS << "\t.internal\t";        break;
-  case MCSA_LazyReference:  OS << "\t.lazy_reference\t";  break;
-  case MCSA_Local:          OS << "\t.local\t";           break;
-  case MCSA_NoDeadStrip:
-    if (!MAI->hasNoDeadStrip())
-      return false;
-    OS << "\t.no_dead_strip\t";
-    break;
-  case MCSA_SymbolResolver: OS << "\t.symbol_resolver\t"; break;
-  case MCSA_AltEntry:       OS << "\t.alt_entry\t";       break;
-  case MCSA_PrivateExtern:
-    OS << "\t.private_extern\t";
-    break;
-  case MCSA_Protected:      OS << "\t.protected\t";       break;
-  case MCSA_Reference:      OS << "\t.reference\t";       break;
-  case MCSA_Extern:
-    OS << "\t.extern\t";
-    break;
-  case MCSA_Weak:           OS << MAI->getWeakDirective(); break;
-  case MCSA_WeakDefinition:
-    OS << "\t.weak_definition\t";
-    break;
-      // .weak_reference
-  case MCSA_WeakReference:  OS << MAI->getWeakRefDirective(); break;
-  case MCSA_WeakDefAutoPrivate: OS << "\t.weak_def_can_be_hidden\t"; break;
-  case MCSA_Cold:
-    // Assemblers currently do not support a .cold directive.
-  case MCSA_Exported:
-    // Non-AIX assemblers currently do not support exported visibility.
-  case MCSA_OSLinkage:
-  case MCSA_XPLinkage:
-    // Only for HLASM.
-    return false;
-  case MCSA_Memtag:
-    OS << "\t.memtag\t";
-    break;
-  case MCSA_WeakAntiDep:
-    OS << "\t.weak_anti_dep\t";
-    break;
-  }
-
-  Symbol->print(OS, MAI);
-  EmitEOL();
-
-  return true;
-}
-
-void MCAsmStreamer::emitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) {
-  OS << ".desc" << ' ';
-  Symbol->print(OS, MAI);
-  OS << ',' << DescValue;
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitSyntaxDirective(StringRef Syntax, StringRef Options) {
-  OS << "\t." << Syntax << "_syntax";
-  if (!Options.empty())
-    OS << " " << Options;
-  EmitEOL();
-}
-
-void MCAsmStreamer::beginCOFFSymbolDef(const MCSymbol *Symbol) {
-  OS << "\t.def\t";
-  Symbol->print(OS, MAI);
-  OS << ';';
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitCOFFSymbolStorageClass(int StorageClass) {
-  OS << "\t.scl\t" << StorageClass << ';';
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitCOFFSymbolType(int Type) {
-  OS << "\t.type\t" << Type << ';';
-  EmitEOL();
-}
-
-void MCAsmStreamer::endCOFFSymbolDef() {
-  OS << "\t.endef";
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitCOFFSafeSEH(MCSymbol const *Symbol) {
-  OS << "\t.safeseh\t";
-  Symbol->print(OS, MAI);
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitCOFFSymbolIndex(MCSymbol const *Symbol) {
-  OS << "\t.symidx\t";
-  Symbol->print(OS, MAI);
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitCOFFSectionIndex(MCSymbol const *Symbol) {
-  OS << "\t.secidx\t";
-  Symbol->print(OS, MAI);
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitCOFFSecRel32(MCSymbol const *Symbol, uint64_t Offset) {
-  OS << "\t.secrel32\t";
-  Symbol->print(OS, MAI);
-  if (Offset != 0)
-    OS << '+' << Offset;
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitCOFFImgRel32(MCSymbol const *Symbol, int64_t Offset) {
-  OS << "\t.rva\t";
-  Symbol->print(OS, MAI);
-  if (Offset > 0)
-    OS << '+' << Offset;
-  else if (Offset < 0)
-    OS << '-' << -Offset;
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitCOFFSecNumber(MCSymbol const *Symbol) {
-  OS << "\t.secnum\t";
-  Symbol->print(OS, MAI);
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitCOFFSecOffset(MCSymbol const *Symbol) {
-  OS << "\t.secoffset\t";
-  Symbol->print(OS, MAI);
-  EmitEOL();
-}
-
-// We need an XCOFF-specific version of this directive as the AIX syntax
-// requires a QualName argument identifying the csect name and storage mapping
-// class to appear before the alignment if we are specifying it.
-void MCAsmStreamer::emitXCOFFLocalCommonSymbol(MCSymbol *LabelSym,
-                                               uint64_t Size,
-                                               MCSymbol *CsectSym,
-                                               Align Alignment) {
-  assert(MAI->getLCOMMDirectiveAlignmentType() == LCOMM::Log2Alignment &&
-         "We only support writing log base-2 alignment format with XCOFF.");
-
-  OS << "\t.lcomm\t";
-  LabelSym->print(OS, MAI);
-  OS << ',' << Size << ',';
-  CsectSym->print(OS, MAI);
-  OS << ',' << Log2(Alignment);
-
-  EmitEOL();
-
-  // Print symbol's rename (original name contains invalid character(s)) if
-  // there is one.
-  auto *XSym = static_cast<MCSymbolXCOFF *>(CsectSym);
-  if (XSym->hasRename())
-    emitXCOFFRenameDirective(XSym, XSym->getSymbolTableName());
-}
-
-void MCAsmStreamer::emitXCOFFSymbolLinkageWithVisibility(
-    MCSymbol *Symbol, MCSymbolAttr Linkage, MCSymbolAttr Visibility) {
-  auto &Sym = static_cast<MCSymbolXCOFF &>(*Symbol);
-  switch (Linkage) {
-  case MCSA_Global:
-    OS << MAI->getGlobalDirective();
-    break;
-  case MCSA_Weak:
-    OS << MAI->getWeakDirective();
-    break;
-  case MCSA_Extern:
-    OS << "\t.extern\t";
-    break;
-  case MCSA_LGlobal:
-    OS << "\t.lglobl\t";
-    break;
-  default:
-    report_fatal_error("unhandled linkage type");
-  }
-
-  Symbol->print(OS, MAI);
 
-  switch (Visibility) {
-  case MCSA_Invalid:
-    // Nothing to do.
-    break;
-  case MCSA_Hidden:
-    OS << ",hidden";
-    break;
-  case MCSA_Protected:
-    OS << ",protected";
-    break;
-  case MCSA_Exported:
-    OS << ",exported";
-    break;
-  default:
-    report_fatal_error("unexpected value for Visibility type");
-  }
-  EmitEOL();
-
-  // Print symbol's rename (original name contains invalid character(s)) if
-  // there is one.
-  if (Sym.hasRename())
-    emitXCOFFRenameDirective(&Sym, Sym.getSymbolTableName());
-}
-
-void MCAsmStreamer::emitXCOFFRenameDirective(const MCSymbol *Name,
-                                             StringRef Rename) {
-  OS << "\t.rename\t";
-  Name->print(OS, MAI);
-  const char DQ = '"';
-  OS << ',' << DQ;
-  for (char C : Rename) {
-    // To escape a double quote character, the character should be doubled.
-    if (C == DQ)
-      OS << DQ;
-    OS << C;
-  }
-  OS << DQ;
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitXCOFFRefDirective(const MCSymbol *Symbol) {
-  OS << "\t.ref ";
-  Symbol->print(OS, MAI);
-  EmitEOL();
-}
+  getAssembler().getEmitter().encodeInstruction(Inst, Code, Fixups, STI);
 
-void MCAsmStreamer::emitXCOFFExceptDirective(const MCSymbol *Symbol,
-                                             const MCSymbol *Trap,
-                                             unsigned Lang,
-                                             unsigned Reason,
-                                             unsigned FunctionSize,
-                                             bool hasDebug) {
-  OS << "\t.except\t";
-  Symbol->print(OS, MAI);
-  OS << ", " << Lang << ", " << Reason;
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitXCOFFCInfoSym(StringRef Name, StringRef Metadata) {
-  const char InfoDirective[] = "\t.info ";
-  const char *Separator = ", ";
-  constexpr int WordSize = sizeof(uint32_t);
-
-  // Start by emitting the .info pseudo-op and C_INFO symbol name.
-  OS << InfoDirective;
-  PrintQuotedString(Name, OS);
-  OS << Separator;
-
-  size_t MetadataSize = Metadata.size();
+  // RISC-V instructions are always little-endian, even on BE systems.
+  bool ForceLE = getContext().getTargetTriple().isRISCV();
 
-  // Emit the 4-byte length of the metadata.
-  OS << format_hex(MetadataSize, 10) << Separator;
+  const MCAsmInfo *MAI = getContext().getAsmInfo();
 
-  // Nothing left to do if there's no metadata.
-  if (MetadataSize == 0) {
-    EmitEOL();
-    return;
-  }
+  // If we are showing fixups, create symbolic markers in the encoded
+  // representation. We do this by making a per-bit map to the fixup item index,
+  // then trying to display it as nicely as possible.
+  SmallVector<uint8_t, 64> FixupMap;
+  FixupMap.resize(Code.size() * 8);
+  for (unsigned I = 0, E = Code.size() * 8; I != E; ++I)
+    FixupMap[I] = 0;
 
-  // Metadata needs to be padded out to an even word size when generating
-  // assembly because the .info pseudo-op can only generate words of data. We
-  // apply the same restriction to the object case for consistency, however the
-  // linker doesn't require padding, so it will only save bytes specified by the
-  // length and discard any padding.
-  uint32_t PaddedSize = alignTo(MetadataSize, WordSize);
-  uint32_t PaddingSize = PaddedSize - MetadataSize;
-
-  // Write out the payload a word at a time.
-  //
-  // The assembler has a limit on the number of operands in an expression,
-  // so we need multiple .info pseudo-ops. We choose a small number of words
-  // per pseudo-op to keep the assembly readable.
-  constexpr int WordsPerDirective = 5;
-  // Force emitting a new directive to keep the first directive purely about the
-  // name and size of the note.
-  int WordsBeforeNextDirective = 0;
-  auto PrintWord = [&](const uint8_t *WordPtr) {
-    if (WordsBeforeNextDirective-- == 0) {
-      EmitEOL();
-      OS << InfoDirective;
-      WordsBeforeNextDirective = WordsPerDirective;
+  for (unsigned I = 0, E = Fixups.size(); I != E; ++I) {
+    MCFixup &F = Fixups[I];
+    MCFixupKindInfo Info =
+        getAssembler().getBackend().getFixupKindInfo(F.getKind());
+    for (unsigned J = 0; J != Info.TargetSize; ++J) {
+      unsigned Index = F.getOffset() * 8 + Info.TargetOffset + J;
+      assert(Index < Code.size() * 8 && "Invalid offset in fixup!");
+      FixupMap[Index] = 1 + I;
     }
-    OS << Separator;
-    uint32_t Word = llvm::support::endian::read32be(WordPtr);
-    OS << format_hex(Word, 10);
-  };
-
-  size_t Index = 0;
-  for (; Index + WordSize <= MetadataSize; Index += WordSize)
-    PrintWord(reinterpret_cast<const uint8_t *>(Metadata.data()) + Index);
-
-  // If there is padding, then we have at least one byte of payload left
-  // to emit.
-  if (PaddingSize) {
-    assert(PaddedSize - Index == WordSize);
-    std::array<uint8_t, WordSize> LastWord = {0};
-    ::memcpy(LastWord.data(), Metadata.data() + Index, MetadataSize - Index);
-    PrintWord(LastWord.data());
   }
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitELFSize(MCSymbol *Symbol, const MCExpr *Value) {
-  assert(MAI->hasDotTypeDotSizeDirective());
-  OS << "\t.size\t";
-  Symbol->print(OS, MAI);
-  OS << ", ";
-  MAI->printExpr(OS, *Value);
-  EmitEOL();
-}
 
-void MCAsmStreamer::emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
-                                     Align ByteAlignment) {
-  OS << "\t.comm\t";
-  Symbol->print(OS, MAI);
-  OS << ',' << Size;
-
-  if (MAI->getCOMMDirectiveAlignmentIsInBytes())
-    OS << ',' << ByteAlignment.value();
-  else
-    OS << ',' << Log2(ByteAlignment);
-  EmitEOL();
-
-  // Print symbol's rename (original name contains invalid character(s)) if
-  // there is one.
-  if (getContext().isXCOFF()) {
-    auto *XSym = static_cast<MCSymbolXCOFF *>(Symbol);
-    if (XSym && XSym->hasRename())
-      emitXCOFFRenameDirective(XSym, XSym->getSymbolTableName());
-  }
-}
+  // FIXME: Note the fixup comments for Thumb2 are completely bogus since the
+  // high order halfword of a 32-bit Thumb2 instruction is emitted first.
+  OS << "encoding: [";
+  for (unsigned I = 0, E = Code.size(); I != E; ++I) {
+    if (I)
+      OS << ',';
 
-void MCAsmStreamer::emitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size,
-                                          Align ByteAlign) {
-  OS << "\t.lcomm\t";
-  Symbol->print(OS, MAI);
-  OS << ',' << Size;
+    // See if all bits are the same map entry.
+    uint8_t MapEntry = FixupMap[I * 8 + 0];
+    for (unsigned J = 1; J != 8; ++J) {
+      if (FixupMap[I * 8 + J] == MapEntry)
+        continue;
 
-  if (ByteAlign > 1) {
-    switch (MAI->getLCOMMDirectiveAlignmentType()) {
-    case LCOMM::NoAlignment:
-      llvm_unreachable("alignment not supported on .lcomm!");
-    case LCOMM::ByteAlignment:
-      OS << ',' << ByteAlign.value();
-      break;
-    case LCOMM::Log2Alignment:
-      OS << ',' << Log2(ByteAlign);
+      MapEntry = uint8_t(~0U);
       break;
     }
-  }
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitZerofill(MCSection *Section, MCSymbol *Symbol,
-                                 uint64_t Size, Align ByteAlignment,
-                                 SMLoc Loc) {
-  if (Symbol)
-    Symbol->setFragment(&Section->getDummyFragment());
-
-  // Note: a .zerofill directive does not switch sections.
-  OS << ".zerofill ";
-
-  assert(getContext().getObjectFileType() == MCContext::IsMachO &&
-         ".zerofill is a Mach-O specific directive");
-  // This is a mach-o specific directive.
 
-  const MCSectionMachO *MOSection = ((const MCSectionMachO*)Section);
-  OS << MOSection->getSegmentName() << "," << MOSection->getName();
-
-  if (Symbol) {
-    OS << ',';
-    Symbol->print(OS, MAI);
-    OS << ',' << Size;
-    OS << ',' << Log2(ByteAlignment);
-  }
-  EmitEOL();
-}
-
-// .tbss sym, size, align
-// This depends that the symbol has already been mangled from the original,
-// e.g. _a.
-void MCAsmStreamer::emitTBSSSymbol(MCSection *Section, MCSymbol *Symbol,
-                                   uint64_t Size, Align ByteAlignment) {
-  Symbol->setFragment(&Section->getDummyFragment());
-
-  // Instead of using the Section we'll just use the shortcut.
-
-  assert(getContext().getObjectFileType() == MCContext::IsMachO &&
-         ".zerofill is a Mach-O specific directive");
-  // This is a mach-o specific directive and section.
-
-  OS << ".tbss ";
-  Symbol->print(OS, MAI);
-  OS << ", " << Size;
-
-  // Output align if we have it.  We default to 1 so don't bother printing
-  // that.
-  if (ByteAlignment > 1)
-    OS << ", " << Log2(ByteAlignment);
-
-  EmitEOL();
-}
-
-static inline bool isPrintableString(StringRef Data) {
-  const auto BeginPtr = Data.begin(), EndPtr = Data.end();
-  for (const unsigned char C : make_range(BeginPtr, EndPtr - 1)) {
-    if (!isPrint(C))
-      return false;
-  }
-  return isPrint(Data.back()) || Data.back() == 0;
-}
-
-static inline char toOctal(int X) { return (X&7)+'0'; }
-
-static void PrintByteList(StringRef Data, raw_ostream &OS,
-                          MCAsmInfo::AsmCharLiteralSyntax ACLS) {
-  assert(!Data.empty() && "Cannot generate an empty list.");
-  const auto printCharacterInOctal = [&OS](unsigned char C) {
-    OS << '0';
-    OS << toOctal(C >> 6);
-    OS << toOctal(C >> 3);
-    OS << toOctal(C >> 0);
-  };
-  const auto printOneCharacterFor = [printCharacterInOctal](
-                                        auto printOnePrintingCharacter) {
-    return [printCharacterInOctal, printOnePrintingCharacter](unsigned char C) {
-      if (isPrint(C)) {
-        printOnePrintingCharacter(static_cast<char>(C));
-        return;
+    if (MapEntry != uint8_t(~0U)) {
+      if (MapEntry == 0) {
+        OS << format("0x%02x", uint8_t(Code[I]));
+      } else {
+        if (Code[I]) {
+          // FIXME: Some of the 8 bits require fix up.
+          OS << format("0x%02x", uint8_t(Code[I])) << '\''
+             << char('A' + MapEntry - 1) << '\'';
+        } else
+          OS << char('A' + MapEntry - 1);
+      }
+    } else {
+      // Otherwise, write out in binary.
+      OS << "0b";
+      for (unsigned J = 8; J--;) {
+        unsigned Bit = (Code[I] >> J) & 1;
+
+        unsigned FixupBit;
+        // RISC-V instructions are always little-endian.
+        // The FixupMap is indexed by actual bit positions in the LE
+        // instruction.
+        if (MAI->isLittleEndian() || ForceLE)
+          FixupBit = I * 8 + J;
+        else
+          FixupBit = I * 8 + (7 - J);
+
+        if (uint8_t MapEntry = FixupMap[FixupBit]) {
+          assert(Bit == 0 && "Encoder wrote into fixed up bit!");
+          OS << char('A' + MapEntry - 1);
+        } else
+          OS << Bit;
       }
-      printCharacterInOctal(C);
-    };
-  };
-  const auto printCharacterList = [Data, &OS](const auto &printOneCharacter) {
-    const auto BeginPtr = Data.begin(), EndPtr = Data.end();
-    for (const unsigned char C : make_range(BeginPtr, EndPtr - 1)) {
-      printOneCharacter(C);
-      OS << ',';
     }
-    printOneCharacter(*(EndPtr - 1));
-  };
-  switch (ACLS) {
-  case MCAsmInfo::ACLS_Unknown:
-    printCharacterList(printCharacterInOctal);
-    return;
-  case MCAsmInfo::ACLS_SingleQuotePrefix:
-    printCharacterList(printOneCharacterFor([&OS](char C) {
-      const char AsmCharLitBuf[2] = {'\'', C};
-      OS << StringRef(AsmCharLitBuf, sizeof(AsmCharLitBuf));
-    }));
-    return;
   }
-  llvm_unreachable("Invalid AsmCharLiteralSyntax value!");
-}
+  OS << "]\n";
 
-void MCAsmStreamer::PrintQuotedString(StringRef Data, raw_ostream &OS) const {
-  OS << '"';
-
-  if (MAI->isAIX()) {
-    for (unsigned char C : Data) {
-      if (C == '"')
-        OS << "\"\"";
+  for (unsigned I = 0, E = Fixups.size(); I != E; ++I) {
+    MCFixup &F = Fixups[I];
+    OS << "  fixup " << char('A' + I) << " - "
+       << "offset: " << F.getOffset() << ", value: ";
+    MAI->printExpr(OS, *F.getValue());
+    auto Kind = F.getKind();
+    if (mc::isRelocation(Kind))
+      OS << ", relocation type: " << Kind;
+    else {
+      OS << ", kind: ";
+      auto Info = getAssembler().getBackend().getFixupKindInfo(Kind);
+      if (F.isPCRel() && StringRef(Info.Name).starts_with("FK_Data_"))
+        OS << "FK_PCRel_" << (Info.TargetSize / 8);
       else
-        OS << (char)C;
-    }
-  } else {
-    for (unsigned char C : Data) {
-      if (C == '"' || C == '\\') {
-        OS << '\\' << (char)C;
-        continue;
-      }
-
-      if (isPrint(C)) {
-        OS << (char)C;
-        continue;
-      }
-
-      switch (C) {
-      case '\b':
-        OS << "\\b";
-        break;
-      case '\f':
-        OS << "\\f";
-        break;
-      case '\n':
-        OS << "\\n";
-        break;
-      case '\r':
-        OS << "\\r";
-        break;
-      case '\t':
-        OS << "\\t";
-        break;
-      default:
-        OS << '\\';
-        OS << toOctal(C >> 6);
-        OS << toOctal(C >> 3);
-        OS << toOctal(C >> 0);
-        break;
-      }
+        OS << Info.Name;
     }
+    OS << '\n';
   }
-
-  OS << '"';
-}
-
-void MCAsmStreamer::emitBytes(StringRef Data) {
-  assert(getCurrentSectionOnly() &&
-         "Cannot emit contents before setting section!");
-  if (Data.empty()) return;
-
-  const auto emitAsString = [this](StringRef Data) {
-    if (MAI->isAIX()) {
-      if (isPrintableString(Data)) {
-        // For target with DoubleQuoteString constants, .string and .byte are
-        // used as replacement of .asciz and .ascii.
-        if (Data.back() == 0) {
-          OS << "\t.string\t";
-          Data = Data.substr(0, Data.size() - 1);
-        } else {
-          OS << "\t.byte\t";
-        }
-        PrintQuotedString(Data, OS);
-      } else {
-        OS << "\t.byte\t";
-        PrintByteList(Data, OS, MAI->characterLiteralSyntax());
-      }
-      EmitEOL();
-      return true;
-    }
-
-    // If the data ends with 0 and the target supports .asciz, use it, otherwise
-    // use .ascii or a byte-list directive
-    if (MAI->getAscizDirective() && Data.back() == 0) {
-      OS << MAI->getAscizDirective();
-      Data = Data.substr(0, Data.size() - 1);
-    } else if (LLVM_LIKELY(MAI->getAsciiDirective())) {
-      OS << MAI->getAsciiDirective();
-    } else {
-      return false;
-    }
-
-    PrintQuotedString(Data, OS);
-    EmitEOL();
-    return true;
-  };
-
-  if (Data.size() != 1 && emitAsString(Data))
-    return;
-
-  // Only single byte is provided or no ascii, asciz, or byte-list directives
-  // are applicable. Emit as vector of individual 8bits data elements.
-  if (MCTargetStreamer *TS = getTargetStreamer()) {
-    TS->emitRawBytes(Data);
-    return;
-  }
-  const char *Directive = MAI->getData8bitsDirective();
-  for (const unsigned char C : Data.bytes()) {
-    OS << Directive << (unsigned)C;
-    EmitEOL();
-  }
-}
-
-void MCAsmStreamer::emitBinaryData(StringRef Data) {
-  // This is binary data. Print it in a grid of hex bytes for readability.
-  const size_t Cols = 4;
-  for (size_t I = 0, EI = alignTo(Data.size(), Cols); I < EI; I += Cols) {
-    size_t J = I, EJ = std::min(I + Cols, Data.size());
-    assert(EJ > 0);
-    OS << MAI->getData8bitsDirective();
-    for (; J < EJ - 1; ++J)
-      OS << format("0x%02x", uint8_t(Data[J])) << ", ";
-    OS << format("0x%02x", uint8_t(Data[J]));
-    EmitEOL();
-  }
-}
-
-void MCAsmStreamer::emitIntValue(uint64_t Value, unsigned Size) {
-  emitValue(MCConstantExpr::create(Value, getContext()), Size);
-}
-
-void MCAsmStreamer::emitIntValueInHex(uint64_t Value, unsigned Size) {
-  emitValue(MCConstantExpr::create(Value, getContext(), true), Size);
-}
-
-void MCAsmStreamer::emitIntValueInHexWithPadding(uint64_t Value,
-                                                 unsigned Size) {
-  emitValue(MCConstantExpr::create(Value, getContext(), true, Size), Size);
-}
-
-void MCAsmStreamer::emitValueImpl(const MCExpr *Value, unsigned Size,
-                                  SMLoc Loc) {
-  assert(Size <= 8 && "Invalid size");
-  assert(getCurrentSectionOnly() &&
-         "Cannot emit contents before setting section!");
-  const char *Directive = nullptr;
-  switch (Size) {
-  default: break;
-  case 1: Directive = MAI->getData8bitsDirective();  break;
-  case 2: Directive = MAI->getData16bitsDirective(); break;
-  case 4: Directive = MAI->getData32bitsDirective(); break;
-  case 8: Directive = MAI->getData64bitsDirective(); break;
-  }
-
-  if (!Directive) {
-    int64_t IntValue;
-    if (!Value->evaluateAsAbsolute(IntValue))
-      report_fatal_error("Don't know how to emit this value.");
-
-    // We couldn't handle the requested integer size so we fallback by breaking
-    // the request down into several, smaller, integers.
-    // Since sizes greater or equal to "Size" are invalid, we use the greatest
-    // power of 2 that is less than "Size" as our largest piece of granularity.
-    bool IsLittleEndian = MAI->isLittleEndian();
-    for (unsigned Emitted = 0; Emitted != Size;) {
-      unsigned Remaining = Size - Emitted;
-      // The size of our partial emission must be a power of two less than
-      // Size.
-      unsigned EmissionSize = llvm::bit_floor(std::min(Remaining, Size - 1));
-      // Calculate the byte offset of our partial emission taking into account
-      // the endianness of the target.
-      unsigned ByteOffset =
-          IsLittleEndian ? Emitted : (Remaining - EmissionSize);
-      uint64_t ValueToEmit = IntValue >> (ByteOffset * 8);
-      // We truncate our partial emission to fit within the bounds of the
-      // emission domain.  This produces nicer output and silences potential
-      // truncation warnings when round tripping through another assembler.
-      uint64_t Shift = 64 - EmissionSize * 8;
-      assert(Shift < static_cast<uint64_t>(
-                         std::numeric_limits<unsigned long long>::digits) &&
-             "undefined behavior");
-      ValueToEmit &= ~0ULL >> Shift;
-      emitIntValue(ValueToEmit, EmissionSize);
-      Emitted += EmissionSize;
-    }
-    return;
-  }
-
-  assert(Directive && "Invalid size for machine code value!");
-  OS << Directive;
-  if (MCTargetStreamer *TS = getTargetStreamer()) {
-    TS->emitValue(Value);
-  } else {
-    MAI->printExpr(OS, *Value);
-    EmitEOL();
-  }
-}
-
-void MCAsmStreamer::emitULEB128Value(const MCExpr *Value) {
-  int64_t IntValue;
-  if (Value->evaluateAsAbsolute(IntValue)) {
-    emitULEB128IntValue(IntValue);
-    return;
-  }
-  OS << "\t.uleb128 ";
-  MAI->printExpr(OS, *Value);
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitSLEB128Value(const MCExpr *Value) {
-  int64_t IntValue;
-  if (Value->evaluateAsAbsolute(IntValue)) {
-    emitSLEB128IntValue(IntValue);
-    return;
-  }
-  OS << "\t.sleb128 ";
-  MAI->printExpr(OS, *Value);
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitFill(const MCExpr &NumBytes, uint64_t FillValue,
-                             SMLoc Loc) {
-  int64_t IntNumBytes;
-  const bool IsAbsolute = NumBytes.evaluateAsAbsolute(IntNumBytes);
-  if (IsAbsolute && IntNumBytes == 0)
-    return;
-
-  if (const char *ZeroDirective = MAI->getZeroDirective()) {
-    if (!MAI->isAIX() || FillValue == 0) {
-      // FIXME: Emit location directives
-      OS << ZeroDirective;
-      MAI->printExpr(OS, NumBytes);
-      if (FillValue != 0)
-        OS << ',' << (int)FillValue;
-      EmitEOL();
-    } else {
-      if (!IsAbsolute)
-        report_fatal_error(
-            "Cannot emit non-absolute expression lengths of fill.");
-      for (int i = 0; i < IntNumBytes; ++i) {
-        OS << MAI->getData8bitsDirective() << (int)FillValue;
-        EmitEOL();
-      }
-    }
-    return;
-  }
-
-  MCStreamer::emitFill(NumBytes, FillValue);
-}
-
-void MCAsmStreamer::emitFill(const MCExpr &NumValues, int64_t Size,
-                             int64_t Expr, SMLoc Loc) {
-  // FIXME: Emit location directives
-  OS << "\t.fill\t";
-  MAI->printExpr(OS, NumValues);
-  OS << ", " << Size << ", 0x";
-  OS.write_hex(truncateToSize(Expr, 4));
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitAlignmentDirective(uint64_t ByteAlignment,
-                                           std::optional<int64_t> Value,
-                                           unsigned ValueSize,
-                                           unsigned MaxBytesToEmit) {
-  if (MAI->isAIX()) {
-    if (!isPowerOf2_64(ByteAlignment))
-      report_fatal_error("Only power-of-two alignments are supported "
-                         "with .align.");
-    OS << "\t.align\t";
-    OS << Log2_64(ByteAlignment);
-    EmitEOL();
-    return;
-  }
-
-  // Some assemblers don't support non-power of two alignments, so we always
-  // emit alignments as a power of two if possible.
-  if (isPowerOf2_64(ByteAlignment)) {
-    switch (ValueSize) {
-    default:
-      llvm_unreachable("Invalid size for machine code value!");
-    case 1:
-      OS << "\t.p2align\t";
-      break;
-    case 2:
-      OS << ".p2alignw ";
-      break;
-    case 4:
-      OS << ".p2alignl ";
-      break;
-    case 8:
-      llvm_unreachable("Unsupported alignment size!");
-    }
-
-    OS << Log2_64(ByteAlignment);
-
-    if (Value.has_value() || MaxBytesToEmit) {
-      if (Value.has_value()) {
-        OS << ", 0x";
-        OS.write_hex(truncateToSize(*Value, ValueSize));
-      } else {
-        OS << ", ";
-      }
-
-      if (MaxBytesToEmit)
-        OS << ", " << MaxBytesToEmit;
-    }
-    EmitEOL();
-    return;
-  }
-
-  // Non-power of two alignment.  This is not widely supported by assemblers.
-  // FIXME: Parameterize this based on MAI.
-  switch (ValueSize) {
-  default: llvm_unreachable("Invalid size for machine code value!");
-  case 1: OS << ".balign";  break;
-  case 2: OS << ".balignw"; break;
-  case 4: OS << ".balignl"; break;
-  case 8: llvm_unreachable("Unsupported alignment size!");
-  }
-
-  OS << ' ' << ByteAlignment;
-  if (Value.has_value())
-    OS << ", " << truncateToSize(*Value, ValueSize);
-  else if (MaxBytesToEmit)
-    OS << ", ";
-  if (MaxBytesToEmit)
-    OS << ", " << MaxBytesToEmit;
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitValueToAlignment(Align Alignment, int64_t Fill,
-                                         uint8_t FillLen,
-                                         unsigned MaxBytesToEmit) {
-  emitAlignmentDirective(Alignment.value(), Fill, FillLen, MaxBytesToEmit);
-}
-
-void MCAsmStreamer::emitCodeAlignment(Align Alignment,
-                                      const MCSubtargetInfo *STI,
-                                      unsigned MaxBytesToEmit) {
-  // Emit with a text fill value.
-  if (MAI->getTextAlignFillValue())
-    emitAlignmentDirective(Alignment.value(), MAI->getTextAlignFillValue(), 1,
-                           MaxBytesToEmit);
-  else
-    emitAlignmentDirective(Alignment.value(), std::nullopt, 1, MaxBytesToEmit);
-}
-
-void MCAsmStreamer::emitPrefAlign(Align Alignment) {
-  OS << "\t.prefalign\t" << Alignment.value();
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitValueToOffset(const MCExpr *Offset,
-                                      unsigned char Value,
-                                      SMLoc Loc) {
-  // FIXME: Verify that Offset is associated with the current section.
-  OS << ".org ";
-  MAI->printExpr(OS, *Offset);
-  OS << ", " << (unsigned)Value;
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitFileDirective(StringRef Filename) {
-  assert(MAI->hasSingleParameterDotFile());
-  OS << "\t.file\t";
-  PrintQuotedString(Filename, OS);
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitFileDirective(StringRef Filename,
-                                      StringRef CompilerVersion,
-                                      StringRef TimeStamp,
-                                      StringRef Description) {
-  assert(MAI->isAIX());
-  OS << "\t.file\t";
-  PrintQuotedString(Filename, OS);
-  bool useTimeStamp = !TimeStamp.empty();
-  bool useCompilerVersion = !CompilerVersion.empty();
-  bool useDescription = !Description.empty();
-  if (useTimeStamp || useCompilerVersion || useDescription) {
-    OS << ",";
-    if (useTimeStamp)
-      PrintQuotedString(TimeStamp, OS);
-    if (useCompilerVersion || useDescription) {
-      OS << ",";
-      if (useCompilerVersion)
-        PrintQuotedString(CompilerVersion, OS);
-      if (useDescription) {
-        OS << ",";
-        PrintQuotedString(Description, OS);
-      }
-    }
-  }
-  EmitEOL();
-}
-
-void MCAsmStreamer::printDwarfFileDirective(
-    unsigned FileNo, StringRef Directory, StringRef Filename,
-    std::optional<MD5::MD5Result> Checksum, std::optional<StringRef> Source,
-    bool UseDwarfDirectory, raw_svector_ostream &OS) const {
-  SmallString<128> FullPathName;
-
-  if (!UseDwarfDirectory && !Directory.empty()) {
-    if (sys::path::is_absolute(Filename))
-      Directory = "";
-    else {
-      FullPathName = Directory;
-      sys::path::append(FullPathName, Filename);
-      Directory = "";
-      Filename = FullPathName;
-    }
-  }
-
-  OS << "\t.file\t" << FileNo << ' ';
-  if (!Directory.empty()) {
-    PrintQuotedString(Directory, OS);
-    OS << ' ';
-  }
-  PrintQuotedString(Filename, OS);
-  if (Checksum)
-    OS << " md5 0x" << Checksum->digest();
-  if (Source) {
-    OS << " source ";
-    PrintQuotedString(*Source, OS);
-  }
-}
-
-Expected<unsigned> MCAsmStreamer::tryEmitDwarfFileDirective(
-    unsigned FileNo, StringRef Directory, StringRef Filename,
-    std::optional<MD5::MD5Result> Checksum, std::optional<StringRef> Source,
-    unsigned CUID) {
-  assert(CUID == 0 && "multiple CUs not supported by MCAsmStreamer");
-
-  MCDwarfLineTable &Table = getContext().getMCDwarfLineTable(CUID);
-  unsigned NumFiles = Table.getMCDwarfFiles().size();
-  Expected<unsigned> FileNoOrErr =
-      Table.tryGetFile(Directory, Filename, Checksum, Source,
-                       getContext().getDwarfVersion(), FileNo);
-  if (!FileNoOrErr)
-    return FileNoOrErr.takeError();
-  FileNo = FileNoOrErr.get();
-
-  // Return early if this file is already emitted before or if target doesn't
-  // support .file directive.
-  if (NumFiles == Table.getMCDwarfFiles().size() || MAI->isAIX())
-    return FileNo;
-
-  SmallString<128> Str;
-  raw_svector_ostream OS1(Str);
-  printDwarfFileDirective(FileNo, Directory, Filename, Checksum, Source,
-                          UseDwarfDirectory, OS1);
-
-  if (MCTargetStreamer *TS = getTargetStreamer())
-    TS->emitDwarfFileDirective(OS1.str());
-  else
-    emitRawText(OS1.str());
-
-  return FileNo;
-}
-
-void MCAsmStreamer::emitDwarfFile0Directive(
-    StringRef Directory, StringRef Filename,
-    std::optional<MD5::MD5Result> Checksum, std::optional<StringRef> Source,
-    unsigned CUID) {
-  assert(CUID == 0);
-  // .file 0 is new for DWARF v5.
-  if (getContext().getDwarfVersion() < 5)
-    return;
-  // Inform MCDwarf about the root file.
-  getContext().setMCLineTableRootFile(CUID, Directory, Filename, Checksum,
-                                      Source);
-
-  // Target doesn't support .loc/.file directives, return early.
-  if (MAI->isAIX())
-    return;
-
-  SmallString<128> Str;
-  raw_svector_ostream OS1(Str);
-  printDwarfFileDirective(0, Directory, Filename, Checksum, Source,
-                          UseDwarfDirectory, OS1);
-
-  if (MCTargetStreamer *TS = getTargetStreamer())
-    TS->emitDwarfFileDirective(OS1.str());
-  else
-    emitRawText(OS1.str());
-}
-
-/// Helper to emit common .loc directive flags, isa, and discriminator.
-void MCAsmStreamer::emitDwarfLocDirectiveFlags(unsigned Flags, unsigned Isa,
-                                               unsigned Discriminator) {
-  if (!MAI->supportsExtendedDwarfLocDirective())
-    return;
-
-  if (Flags & DWARF2_FLAG_BASIC_BLOCK)
-    OS << " basic_block";
-  if (Flags & DWARF2_FLAG_PROLOGUE_END)
-    OS << " prologue_end";
-  if (Flags & DWARF2_FLAG_EPILOGUE_BEGIN)
-    OS << " epilogue_begin";
-
-  const unsigned OldFlags = getContext().getCurrentDwarfLoc().getFlags();
-  if ((Flags & DWARF2_FLAG_IS_STMT) != (OldFlags & DWARF2_FLAG_IS_STMT)) {
-    OS << " is_stmt ";
-    OS << ((Flags & DWARF2_FLAG_IS_STMT) ? "1" : "0");
-  }
-
-  if (Isa)
-    OS << " isa " << Isa;
-  if (Discriminator)
-    OS << " discriminator " << Discriminator;
-}
-
-/// Helper to emit the common suffix of .loc directives.
-void MCAsmStreamer::emitDwarfLocDirectiveSuffix(unsigned FileNo, unsigned Line,
-                                                unsigned Column, unsigned Flags,
-                                                unsigned Isa,
-                                                unsigned Discriminator,
-                                                StringRef FileName,
-                                                StringRef Comment) {
-  // Emit flags, isa, and discriminator.
-  emitDwarfLocDirectiveFlags(Flags, Isa, Discriminator);
-
-  // Emit verbose comment if enabled.
-  if (IsVerboseAsm) {
-    OS.PadToColumn(MAI->getCommentColumn());
-    OS << MAI->getCommentString() << ' ';
-    if (Comment.empty())
-      OS << FileName << ':' << Line << ':' << Column;
-    else
-      OS << Comment;
-  }
-
-  // Emit end of line and update the baseclass state.
-  EmitEOL();
-  MCStreamer::emitDwarfLocDirective(FileNo, Line, Column, Flags, Isa,
-                                    Discriminator, FileName, Comment);
-}
-
-void MCAsmStreamer::emitDwarfLocDirective(unsigned FileNo, unsigned Line,
-                                          unsigned Column, unsigned Flags,
-                                          unsigned Isa, unsigned Discriminator,
-                                          StringRef FileName,
-                                          StringRef Comment) {
-  // If target doesn't support .loc/.file directive, we need to record the lines
-  // same way like we do in object mode.
-  if (MAI->isAIX()) {
-    // In case we see two .loc directives in a row, make sure the
-    // first one gets a line entry.
-    MCDwarfLineEntry::make(this, getCurrentSectionOnly());
-    this->MCStreamer::emitDwarfLocDirective(FileNo, Line, Column, Flags, Isa,
-                                            Discriminator, FileName, Comment);
-    return;
-  }
-
-  // Emit the basic .loc directive.
-  OS << "\t.loc\t" << FileNo << " " << Line << " " << Column;
-
-  // Emit common suffix (flags, comment, EOL, parent call).
-  emitDwarfLocDirectiveSuffix(FileNo, Line, Column, Flags, Isa, Discriminator,
-                              FileName, Comment);
-}
-
-/// This is same as emitDwarfLocDirective, except also emits inlined function
-/// and inlined callsite information.
-void MCAsmStreamer::emitDwarfLocDirectiveWithInlinedAt(
-    unsigned FileNo, unsigned Line, unsigned Column, unsigned FileIA,
-    unsigned LineIA, unsigned ColIA, const MCSymbol *Sym, unsigned Flags,
-    unsigned Isa, unsigned Discriminator, StringRef FileName,
-    StringRef Comment) {
-  // Emit the basic .loc directive with NVPTX-specific extensions.
-  OS << "\t.loc\t" << FileNo << " " << Line << " " << Column;
-  OS << ", function_name " << *Sym;
-  OS << ", inlined_at " << FileIA << " " << LineIA << " " << ColIA;
-
-  // Emit common suffix (flags, comment, EOL, parent call).
-  emitDwarfLocDirectiveSuffix(FileNo, Line, Column, Flags, Isa, Discriminator,
-                              FileName, Comment);
-}
-
-void MCAsmStreamer::emitDwarfLocLabelDirective(SMLoc Loc, StringRef Name) {
-  MCStreamer::emitDwarfLocLabelDirective(Loc, Name);
-  OS << ".loc_label\t" << Name;
-  EmitEOL();
-}
-
-MCSymbol *MCAsmStreamer::getDwarfLineTableSymbol(unsigned CUID) {
-  // Always use the zeroth line table, since asm syntax only supports one line
-  // table for now.
-  return MCStreamer::getDwarfLineTableSymbol(0);
-}
-
-bool MCAsmStreamer::emitCVFileDirective(unsigned FileNo, StringRef Filename,
-                                        ArrayRef<uint8_t> Checksum,
-                                        unsigned ChecksumKind) {
-  if (!getContext().getCVContext().addFile(*this, FileNo, Filename, Checksum,
-                                           ChecksumKind))
-    return false;
-
-  OS << "\t.cv_file\t" << FileNo << ' ';
-  PrintQuotedString(Filename, OS);
-
-  if (!ChecksumKind) {
-    EmitEOL();
-    return true;
-  }
-
-  OS << ' ';
-  PrintQuotedString(toHex(Checksum), OS);
-  OS << ' ' << ChecksumKind;
-
-  EmitEOL();
-  return true;
-}
-
-bool MCAsmStreamer::emitCVFuncIdDirective(unsigned FuncId) {
-  OS << "\t.cv_func_id " << FuncId << '\n';
-  return MCStreamer::emitCVFuncIdDirective(FuncId);
-}
-
-bool MCAsmStreamer::emitCVInlineSiteIdDirective(unsigned FunctionId,
-                                                unsigned IAFunc,
-                                                unsigned IAFile,
-                                                unsigned IALine, unsigned IACol,
-                                                SMLoc Loc) {
-  OS << "\t.cv_inline_site_id " << FunctionId << " within " << IAFunc
-     << " inlined_at " << IAFile << ' ' << IALine << ' ' << IACol << '\n';
-  return MCStreamer::emitCVInlineSiteIdDirective(FunctionId, IAFunc, IAFile,
-                                                 IALine, IACol, Loc);
-}
-
-void MCAsmStreamer::emitCVLocDirective(unsigned FunctionId, unsigned FileNo,
-                                       unsigned Line, unsigned Column,
-                                       bool PrologueEnd, bool IsStmt,
-                                       StringRef FileName, SMLoc Loc) {
-  // Validate the directive.
-  if (!checkCVLocSection(FunctionId, FileNo, Loc))
-    return;
-
-  OS << "\t.cv_loc\t" << FunctionId << " " << FileNo << " " << Line << " "
-     << Column;
-  if (PrologueEnd)
-    OS << " prologue_end";
-
-  if (IsStmt)
-    OS << " is_stmt 1";
-
-  if (IsVerboseAsm) {
-    OS.PadToColumn(MAI->getCommentColumn());
-    OS << MAI->getCommentString() << ' ' << FileName << ':' << Line << ':'
-       << Column;
-  }
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitCVLinetableDirective(unsigned FunctionId,
-                                             const MCSymbol *FnStart,
-                                             const MCSymbol *FnEnd) {
-  OS << "\t.cv_linetable\t" << FunctionId << ", ";
-  FnStart->print(OS, MAI);
-  OS << ", ";
-  FnEnd->print(OS, MAI);
-  EmitEOL();
-  this->MCStreamer::emitCVLinetableDirective(FunctionId, FnStart, FnEnd);
-}
-
-void MCAsmStreamer::emitCVInlineLinetableDirective(unsigned PrimaryFunctionId,
-                                                   unsigned SourceFileId,
-                                                   unsigned SourceLineNum,
-                                                   const MCSymbol *FnStartSym,
-                                                   const MCSymbol *FnEndSym) {
-  OS << "\t.cv_inline_linetable\t" << PrimaryFunctionId << ' ' << SourceFileId
-     << ' ' << SourceLineNum << ' ';
-  FnStartSym->print(OS, MAI);
-  OS << ' ';
-  FnEndSym->print(OS, MAI);
-  EmitEOL();
-  this->MCStreamer::emitCVInlineLinetableDirective(
-      PrimaryFunctionId, SourceFileId, SourceLineNum, FnStartSym, FnEndSym);
-}
-
-void MCAsmStreamer::PrintCVDefRangePrefix(
-    ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges) {
-  OS << "\t.cv_def_range\t";
-  for (std::pair<const MCSymbol *, const MCSymbol *> Range : Ranges) {
-    OS << ' ';
-    Range.first->print(OS, MAI);
-    OS << ' ';
-    Range.second->print(OS, MAI);
-  }
-}
-
-void MCAsmStreamer::emitCVDefRangeDirective(
-    ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,
-    codeview::DefRangeRegisterRelHeader DRHdr) {
-  PrintCVDefRangePrefix(Ranges);
-  OS << ", reg_rel, ";
-  OS << DRHdr.Register << ", " << DRHdr.Flags << ", "
-     << DRHdr.BasePointerOffset;
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitCVDefRangeDirective(
-    ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,
-    codeview::DefRangeSubfieldRegisterHeader DRHdr) {
-  PrintCVDefRangePrefix(Ranges);
-  OS << ", subfield_reg, ";
-  OS << DRHdr.Register << ", " << DRHdr.OffsetInParent;
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitCVDefRangeDirective(
-    ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,
-    codeview::DefRangeRegisterHeader DRHdr) {
-  PrintCVDefRangePrefix(Ranges);
-  OS << ", reg, ";
-  OS << DRHdr.Register;
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitCVDefRangeDirective(
-    ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,
-    codeview::DefRangeFramePointerRelHeader DRHdr) {
-  PrintCVDefRangePrefix(Ranges);
-  OS << ", frame_ptr_rel, ";
-  OS << DRHdr.Offset;
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitCVStringTableDirective() {
-  OS << "\t.cv_stringtable";
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitCVFileChecksumsDirective() {
-  OS << "\t.cv_filechecksums";
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitCVFileChecksumOffsetDirective(unsigned FileNo) {
-  OS << "\t.cv_filechecksumoffset\t" << FileNo;
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitCVFPOData(const MCSymbol *ProcSym, SMLoc L) {
-  OS << "\t.cv_fpo_data\t";
-  ProcSym->print(OS, MAI);
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitIdent(StringRef IdentString) {
-  assert(MAI->hasIdentDirective() && ".ident directive not supported");
-  OS << "\t.ident\t";
-  PrintQuotedString(IdentString, OS);
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitCFISections(bool EH, bool Debug, bool SFrame) {
-  MCStreamer::emitCFISections(EH, Debug, SFrame);
-  OS << "\t.cfi_sections ";
-  bool C = false;
-  if (EH) {
-    OS << ".eh_frame";
-    C = true;
-  }
-  if (Debug) {
-    if (C)
-      OS << ", ";
-    OS << ".debug_frame";
-    C = true;
-  }
-  if (SFrame) {
-    if (C)
-      OS << ", ";
-    OS << ".sframe";
-  }
-
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitCFIStartProcImpl(MCDwarfFrameInfo &Frame) {
-  OS << "\t.cfi_startproc";
-  if (Frame.IsSimple)
-    OS << " simple";
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitCFIEndProcImpl(MCDwarfFrameInfo &Frame) {
-  MCStreamer::emitCFIEndProcImpl(Frame);
-  OS << "\t.cfi_endproc";
-  EmitEOL();
-}
-
-void MCAsmStreamer::EmitRegisterName(int64_t Register) {
-  if (!MAI->useDwarfRegNumForCFI()) {
-    // User .cfi_* directives can use arbitrary DWARF register numbers, not
-    // just ones that map to LLVM register numbers and have known names.
-    // Fall back to using the original number directly if no name is known.
-    const MCRegisterInfo *MRI = getContext().getRegisterInfo();
-    if (std::optional<MCRegister> LLVMRegister =
-            MRI->getLLVMRegNum(Register, true)) {
-      InstPrinter->printRegName(OS, *LLVMRegister);
-      return;
-    }
-  }
-  OS << Register;
-}
-
-void MCAsmStreamer::emitCFIDefCfa(int64_t Register, int64_t Offset, SMLoc Loc) {
-  MCStreamer::emitCFIDefCfa(Register, Offset, Loc);
-  OS << "\t.cfi_def_cfa ";
-  EmitRegisterName(Register);
-  OS << ", " << Offset;
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitCFIDefCfaOffset(int64_t Offset, SMLoc Loc) {
-  MCStreamer::emitCFIDefCfaOffset(Offset, Loc);
-  OS << "\t.cfi_def_cfa_offset " << Offset;
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitCFILLVMDefAspaceCfa(int64_t Register, int64_t Offset,
-                                            int64_t AddressSpace, SMLoc Loc) {
-  MCStreamer::emitCFILLVMDefAspaceCfa(Register, Offset, AddressSpace, Loc);
-  OS << "\t.cfi_llvm_def_aspace_cfa ";
-  EmitRegisterName(Register);
-  OS << ", " << Offset;
-  OS << ", " << AddressSpace;
-  EmitEOL();
-}
-
-static void PrintCFIEscape(llvm::formatted_raw_ostream &OS, StringRef Values) {
-  OS << "\t.cfi_escape ";
-  if (!Values.empty()) {
-    size_t e = Values.size() - 1;
-    for (size_t i = 0; i < e; ++i)
-      OS << format("0x%02x", uint8_t(Values[i])) << ", ";
-    OS << format("0x%02x", uint8_t(Values[e]));
-  }
-}
-
-void MCAsmStreamer::emitCFIEscape(StringRef Values, SMLoc Loc) {
-  MCStreamer::emitCFIEscape(Values, Loc);
-  PrintCFIEscape(OS, Values);
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitCFIGnuArgsSize(int64_t Size, SMLoc Loc) {
-  MCStreamer::emitCFIGnuArgsSize(Size, Loc);
-
-  uint8_t Buffer[16] = { dwarf::DW_CFA_GNU_args_size };
-  unsigned Len = encodeULEB128(Size, Buffer + 1) + 1;
-
-  PrintCFIEscape(OS, StringRef((const char *)&Buffer[0], Len));
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitCFIDefCfaRegister(int64_t Register, SMLoc Loc) {
-  MCStreamer::emitCFIDefCfaRegister(Register, Loc);
-  OS << "\t.cfi_def_cfa_register ";
-  EmitRegisterName(Register);
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitCFIOffset(int64_t Register, int64_t Offset, SMLoc Loc) {
-  MCStreamer::emitCFIOffset(Register, Offset, Loc);
-  OS << "\t.cfi_offset ";
-  EmitRegisterName(Register);
-  OS << ", " << Offset;
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitCFIPersonality(const MCSymbol *Sym,
-                                       unsigned Encoding) {
-  MCStreamer::emitCFIPersonality(Sym, Encoding);
-  OS << "\t.cfi_personality " << Encoding << ", ";
-  Sym->print(OS, MAI);
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitCFILsda(const MCSymbol *Sym, unsigned Encoding) {
-  MCStreamer::emitCFILsda(Sym, Encoding);
-  OS << "\t.cfi_lsda " << Encoding << ", ";
-  Sym->print(OS, MAI);
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitCFIRememberState(SMLoc Loc) {
-  MCStreamer::emitCFIRememberState(Loc);
-  OS << "\t.cfi_remember_state";
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitCFIRestoreState(SMLoc Loc) {
-  MCStreamer::emitCFIRestoreState(Loc);
-  OS << "\t.cfi_restore_state";
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitCFIRestore(int64_t Register, SMLoc Loc) {
-  MCStreamer::emitCFIRestore(Register, Loc);
-  OS << "\t.cfi_restore ";
-  EmitRegisterName(Register);
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitCFISameValue(int64_t Register, SMLoc Loc) {
-  MCStreamer::emitCFISameValue(Register, Loc);
-  OS << "\t.cfi_same_value ";
-  EmitRegisterName(Register);
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitCFIRelOffset(int64_t Register, int64_t Offset,
-                                     SMLoc Loc) {
-  MCStreamer::emitCFIRelOffset(Register, Offset, Loc);
-  OS << "\t.cfi_rel_offset ";
-  EmitRegisterName(Register);
-  OS << ", " << Offset;
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitCFIAdjustCfaOffset(int64_t Adjustment, SMLoc Loc) {
-  MCStreamer::emitCFIAdjustCfaOffset(Adjustment, Loc);
-  OS << "\t.cfi_adjust_cfa_offset " << Adjustment;
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitCFISignalFrame() {
-  MCStreamer::emitCFISignalFrame();
-  OS << "\t.cfi_signal_frame";
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitCFIUndefined(int64_t Register, SMLoc Loc) {
-  MCStreamer::emitCFIUndefined(Register, Loc);
-  OS << "\t.cfi_undefined ";
-  EmitRegisterName(Register);
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitCFIRegister(int64_t Register1, int64_t Register2,
-                                    SMLoc Loc) {
-  MCStreamer::emitCFIRegister(Register1, Register2, Loc);
-  OS << "\t.cfi_register ";
-  EmitRegisterName(Register1);
-  OS << ", ";
-  EmitRegisterName(Register2);
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitCFIWindowSave(SMLoc Loc) {
-  MCStreamer::emitCFIWindowSave(Loc);
-  OS << "\t.cfi_window_save";
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitCFINegateRAState(SMLoc Loc) {
-  MCStreamer::emitCFINegateRAState(Loc);
-  OS << "\t.cfi_negate_ra_state";
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitCFINegateRAStateWithPC(SMLoc Loc) {
-  MCStreamer::emitCFINegateRAStateWithPC(Loc);
-  OS << "\t.cfi_negate_ra_state_with_pc";
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitCFIReturnColumn(int64_t Register) {
-  MCStreamer::emitCFIReturnColumn(Register);
-  OS << "\t.cfi_return_column ";
-  EmitRegisterName(Register);
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitCFILabelDirective(SMLoc Loc, StringRef Name) {
-  MCStreamer::emitCFILabelDirective(Loc, Name);
-  OS << "\t.cfi_label " << Name;
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitCFIBKeyFrame() {
-  MCStreamer::emitCFIBKeyFrame();
-  OS << "\t.cfi_b_key_frame";
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitCFIMTETaggedFrame() {
-  MCStreamer::emitCFIMTETaggedFrame();
-  OS << "\t.cfi_mte_tagged_frame";
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitCFIValOffset(int64_t Register, int64_t Offset,
-                                     SMLoc Loc) {
-  MCStreamer::emitCFIValOffset(Register, Offset, Loc);
-  OS << "\t.cfi_val_offset ";
-  EmitRegisterName(Register);
-  OS << ", " << Offset;
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitWinCFIStartProc(const MCSymbol *Symbol, SMLoc Loc) {
-  MCStreamer::emitWinCFIStartProc(Symbol, Loc);
-
-  OS << ".seh_proc ";
-  Symbol->print(OS, MAI);
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitWinCFIEndProc(SMLoc Loc) {
-  MCStreamer::emitWinCFIEndProc(Loc);
-
-  OS << "\t.seh_endproc";
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitWinCFIFuncletOrFuncEnd(SMLoc Loc) {
-  MCStreamer::emitWinCFIFuncletOrFuncEnd(Loc);
-
-  OS << "\t.seh_endfunclet";
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitWinCFISplitChained(SMLoc Loc) {
-  MCStreamer::emitWinCFISplitChained(Loc);
-
-  OS << "\t.seh_splitchained";
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitWinEHHandler(const MCSymbol *Sym, bool Unwind,
-                                     bool Except, SMLoc Loc) {
-  MCStreamer::emitWinEHHandler(Sym, Unwind, Except, Loc);
-
-  OS << "\t.seh_handler ";
-  Sym->print(OS, MAI);
-  char Marker = '@';
-  const Triple &T = getContext().getTargetTriple();
-  if (T.getArch() == Triple::arm || T.getArch() == Triple::thumb)
-    Marker = '%';
-  if (Unwind)
-    OS << ", " << Marker << "unwind";
-  if (Except)
-    OS << ", " << Marker << "except";
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitWinEHHandlerData(SMLoc Loc) {
-  MCStreamer::emitWinEHHandlerData(Loc);
-
-  // Switch sections. Don't call switchSection directly, because that will
-  // cause the section switch to be visible in the emitted assembly.
-  // We only do this so the section switch that terminates the handler
-  // data block is visible.
-  WinEH::FrameInfo *CurFrame = getCurrentWinFrameInfo();
-
-  // Do nothing if no frame is open. MCStreamer should've already reported an
-  // error.
-  if (!CurFrame)
-    return;
-
-  MCSection *TextSec = &CurFrame->Function->getSection();
-  MCSection *XData = getAssociatedXDataSection(TextSec);
-  switchSectionNoPrint(XData);
-
-  OS << "\t.seh_handlerdata";
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitWinCFIPushReg(MCRegister Register, SMLoc Loc) {
-  MCStreamer::emitWinCFIPushReg(Register, Loc);
-
-  OS << "\t.seh_pushreg ";
-  InstPrinter->printRegName(OS, Register);
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitWinCFISetFrame(MCRegister Register, unsigned Offset,
-                                       SMLoc Loc) {
-  MCStreamer::emitWinCFISetFrame(Register, Offset, Loc);
-
-  OS << "\t.seh_setframe ";
-  InstPrinter->printRegName(OS, Register);
-  OS << ", " << Offset;
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitWinCFIAllocStack(unsigned Size, SMLoc Loc) {
-  MCStreamer::emitWinCFIAllocStack(Size, Loc);
-
-  OS << "\t.seh_stackalloc " << Size;
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitWinCFISaveReg(MCRegister Register, unsigned Offset,
-                                      SMLoc Loc) {
-  MCStreamer::emitWinCFISaveReg(Register, Offset, Loc);
-
-  OS << "\t.seh_savereg ";
-  InstPrinter->printRegName(OS, Register);
-  OS << ", " << Offset;
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitWinCFISaveXMM(MCRegister Register, unsigned Offset,
-                                      SMLoc Loc) {
-  MCStreamer::emitWinCFISaveXMM(Register, Offset, Loc);
-
-  OS << "\t.seh_savexmm ";
-  InstPrinter->printRegName(OS, Register);
-  OS << ", " << Offset;
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitWinCFIPushFrame(bool Code, SMLoc Loc) {
-  MCStreamer::emitWinCFIPushFrame(Code, Loc);
-
-  OS << "\t.seh_pushframe";
-  if (Code)
-    OS << " @code";
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitWinCFIEndProlog(SMLoc Loc) {
-  MCStreamer::emitWinCFIEndProlog(Loc);
-
-  OS << "\t.seh_endprologue";
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitWinCFIBeginEpilogue(SMLoc Loc) {
-  MCStreamer::emitWinCFIBeginEpilogue(Loc);
-
-  OS << "\t.seh_startepilogue";
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitWinCFIEndEpilogue(SMLoc Loc) {
-  MCStreamer::emitWinCFIEndEpilogue(Loc);
-
-  OS << "\t.seh_endepilogue";
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitWinCFIUnwindV2Start(SMLoc Loc) {
-  MCStreamer::emitWinCFIUnwindV2Start(Loc);
-
-  OS << "\t.seh_unwindv2start";
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitWinCFIUnwindVersion(uint8_t Version, SMLoc Loc) {
-  MCStreamer::emitWinCFIUnwindVersion(Version, Loc);
-
-  OS << "\t.seh_unwindversion " << (unsigned)Version;
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitCGProfileEntry(const MCSymbolRefExpr *From,
-                                       const MCSymbolRefExpr *To,
-                                       uint64_t Count) {
-  OS << "\t.cg_profile ";
-  From->getSymbol().print(OS, MAI);
-  OS << ", ";
-  To->getSymbol().print(OS, MAI);
-  OS << ", " << Count;
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitInstruction(const MCInst &Inst,
-                                    const MCSubtargetInfo &STI) {
-  if (LFIRewriter && LFIRewriter->rewriteInst(Inst, *this, STI))
-    return;
-
-  if (CurFrag) {
-    MCSection *Sec = getCurrentSectionOnly();
-    Sec->setHasInstructions(true);
-  }
-
-  if (MAI->isAIX() && CurFrag)
-    // Now that a machine instruction has been assembled into this section, make
-    // a line entry for any .loc directive that has been seen.
-    MCDwarfLineEntry::make(this, getCurrentSectionOnly());
-
-  // Show the encoding in a comment if we have a code emitter.
-  addEncodingComment(Inst, STI);
-
-  // Show the MCInst if enabled.
-  if (ShowInst) {
-    Inst.dump_pretty(getCommentOS(), InstPrinter.get(), "\n ", &getContext());
-    getCommentOS() << "\n";
-  }
-
-  if(getTargetStreamer())
-    getTargetStreamer()->prettyPrintAsm(*InstPrinter, 0, Inst, STI, OS);
-  else
-    InstPrinter->printInst(&Inst, 0, "", STI, OS);
-
-  StringRef Comments = CommentToEmit;
-  if (Comments.size() && Comments.back() != '\n')
-    getCommentOS() << "\n";
-
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitPseudoProbe(uint64_t Guid, uint64_t Index,
-                                    uint64_t Type, uint64_t Attr,
-                                    uint64_t Discriminator,
-                                    const MCPseudoProbeInlineStack &InlineStack,
-                                    MCSymbol *FnSym) {
-  OS << "\t.pseudoprobe\t" << Guid << " " << Index << " " << Type << " " << Attr;
-  if (Discriminator)
-    OS << " " << Discriminator;
-  // Emit inline stack like
-  //  @ GUIDmain:3 @ GUIDCaller:1 @ GUIDDirectCaller:11
-  for (const auto &Site : InlineStack)
-    OS << " @ " << std::get<0>(Site) << ":" << std::get<1>(Site);
-
-  OS << " ";
-  FnSym->print(OS, MAI);
-
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitRelocDirective(const MCExpr &Offset, StringRef Name,
-                                       const MCExpr *Expr, SMLoc) {
-  OS << "\t.reloc ";
-  MAI->printExpr(OS, Offset);
-  OS << ", " << Name;
-  if (Expr) {
-    OS << ", ";
-    MAI->printExpr(OS, *Expr);
-  }
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitAddrsig() {
-  OS << "\t.addrsig";
-  EmitEOL();
-}
-
-void MCAsmStreamer::emitAddrsigSym(const MCSymbol *Sym) {
-  OS << "\t.addrsig_sym ";
-  Sym->print(OS, MAI);
-  EmitEOL();
-}
-
-/// EmitRawText - If this file is backed by an assembly streamer, this dumps
-/// the specified string in the output .s file.  This capability is
-/// indicated by the hasRawTextSupport() predicate.
-void MCAsmStreamer::emitRawTextImpl(StringRef String) {
-  String.consume_back("\n");
-  OS << String;
-  EmitEOL();
-}
-
-void MCAsmStreamer::finishImpl() {
-  // If we are generating dwarf for assembly source files dump out the sections.
-  if (getContext().getGenDwarfForAssembly())
-    MCGenDwarfInfo::Emit(this);
-
-  // Now it is time to emit debug line sections if target doesn't support .loc
-  // and .line directives.
-  if (MAI->isAIX()) {
-    MCDwarfLineTable::emit(this, getAssembler().getDWARFLinetableParams());
-    return;
-  }
-
-  // Emit the label for the line table, if requested - since the rest of the
-  // line table will be defined by .loc/.file directives, and not emitted
-  // directly, the label is the only work required here.
-  const auto &Tables = getContext().getMCDwarfLineTables();
-  if (!Tables.empty()) {
-    assert(Tables.size() == 1 && "asm output only supports one line table");
-    if (auto *Label = Tables.begin()->second.getLabel()) {
-      switchSection(getContext().getObjectFileInfo()->getDwarfLineSection(), 0);
-      emitLabel(Label);
-    }
-  }
-}
-
-void MCAsmStreamer::emitDwarfUnitLength(uint64_t Length, const Twine &Comment) {
-  // If the assembler on some target fills in the DWARF unit length, we
-  // don't want to emit the length in the compiler. For example, the AIX
-  // assembler requires the assembly file with the unit length omitted from
-  // the debug section headers. In such cases, any label we placed occurs
-  // after the implied length field. We need to adjust the reference here
-  // to account for the offset introduced by the inserted length field.
-  if (MAI->isAIX())
-    return;
-  MCStreamer::emitDwarfUnitLength(Length, Comment);
-}
-
-MCSymbol *MCAsmStreamer::emitDwarfUnitLength(const Twine &Prefix,
-                                             const Twine &Comment) {
-  // If the assembler on some target fills in the DWARF unit length, we
-  // don't want to emit the length in the compiler. For example, the AIX
-  // assembler requires the assembly file with the unit length omitted from
-  // the debug section headers. In such cases, any label we placed occurs
-  // after the implied length field. We need to adjust the reference here
-  // to account for the offset introduced by the inserted length field.
-  if (MAI->isAIX())
-    return getContext().createTempSymbol(Prefix + "_end");
-  return MCStreamer::emitDwarfUnitLength(Prefix, Comment);
-}
-
-void MCAsmStreamer::emitDwarfLineStartLabel(MCSymbol *StartSym) {
-  // If the assembler on some target fills in the DWARF unit length, we
-  // don't want to emit the length in the compiler. For example, the AIX
-  // assembler requires the assembly file with the unit length omitted from
-  // the debug section headers. In such cases, any label we placed occurs
-  // after the implied length field. We need to adjust the reference here
-  // to account for the offset introduced by the inserted length field.
-  MCContext &Ctx = getContext();
-  if (MAI->isAIX()) {
-    MCSymbol *DebugLineSymTmp = Ctx.createTempSymbol("debug_line_");
-    // Emit the symbol which does not contain the unit length field.
-    emitLabel(DebugLineSymTmp);
-
-    // Adjust the outer reference to account for the offset introduced by the
-    // inserted length field.
-    unsigned LengthFieldSize =
-        dwarf::getUnitLengthFieldByteSize(Ctx.getDwarfFormat());
-    const MCExpr *EntrySize = MCConstantExpr::create(LengthFieldSize, Ctx);
-    const MCExpr *OuterSym = MCBinaryExpr::createSub(
-        MCSymbolRefExpr::create(DebugLineSymTmp, Ctx), EntrySize, Ctx);
-
-    emitAssignment(StartSym, OuterSym);
-    return;
-  }
-  MCStreamer::emitDwarfLineStartLabel(StartSym);
-}
-
-void MCAsmStreamer::emitDwarfLineEndEntry(MCSection *Section,
-                                          MCSymbol *LastLabel,
-                                          MCSymbol *EndLabel) {
-  // If the targets write the raw debug line data for assembly output (We can
-  // not switch to Section and add the end symbol there for assembly output)
-  // we currently use the .text end label as any section end. This will not
-  // impact the debugability as we will jump to the caller of the last function
-  // in the section before we come into the .text end address.
-  assert(MAI->isAIX() &&
-         ".loc should not be generated together with raw data!");
-
-  MCContext &Ctx = getContext();
-
-  // FIXME: use section end symbol as end of the Section. We need to consider
-  // the explicit sections and -ffunction-sections when we try to generate or
-  // find section end symbol for the Section.
-  MCSection *TextSection = Ctx.getObjectFileInfo()->getTextSection();
-  assert(TextSection->hasEnded() && ".text section is not end!");
-
-  if (!EndLabel)
-    EndLabel = TextSection->getEndSymbol(Ctx);
-  const MCAsmInfo *AsmInfo = Ctx.getAsmInfo();
-  emitDwarfAdvanceLineAddr(INT64_MAX, LastLabel, EndLabel,
-                           AsmInfo->getCodePointerSize());
-}
-
-// Generate DWARF line sections for assembly mode without .loc/.file
-void MCAsmStreamer::emitDwarfAdvanceLineAddr(int64_t LineDelta,
-                                             const MCSymbol *LastLabel,
-                                             const MCSymbol *Label,
-                                             unsigned PointerSize) {
-  assert(MAI->isAIX() &&
-         ".loc/.file don't need raw data in debug line section!");
-
-  // Set to new address.
-  AddComment("Set address to " + Label->getName());
-  emitIntValue(dwarf::DW_LNS_extended_op, 1);
-  emitULEB128IntValue(PointerSize + 1);
-  emitIntValue(dwarf::DW_LNE_set_address, 1);
-  emitSymbolValue(Label, PointerSize);
-
-  if (!LastLabel) {
-    // Emit the sequence for the LineDelta (from 1) and a zero address delta.
-    AddComment("Start sequence");
-    MCDwarfLineAddr::Emit(this, MCDwarfLineTableParams(), LineDelta, 0);
-    return;
-  }
-
-  // INT64_MAX is a signal of the end of the section. Emit DW_LNE_end_sequence
-  // for the end of the section.
-  if (LineDelta == INT64_MAX) {
-    AddComment("End sequence");
-    emitIntValue(dwarf::DW_LNS_extended_op, 1);
-    emitULEB128IntValue(1);
-    emitIntValue(dwarf::DW_LNE_end_sequence, 1);
-    return;
-  }
-
-  // Advance line.
-  AddComment("Advance line " + Twine(LineDelta));
-  emitIntValue(dwarf::DW_LNS_advance_line, 1);
-  emitSLEB128IntValue(LineDelta);
-  emitIntValue(dwarf::DW_LNS_copy, 1);
-}
-
-MCStreamer *llvm::createAsmStreamer(MCContext &Context,
-                                    std::unique_ptr<formatted_raw_ostream> OS,
-                                    std::unique_ptr<MCInstPrinter> IP,
-                                    std::unique_ptr<MCCodeEmitter> CE,
-                                    std::unique_ptr<MCAsmBackend> MAB) {
-  return new MCAsmStreamer(Context, std::move(OS), std::move(IP), std::move(CE),
-                           std::move(MAB));
 }
diff --git a/llvm/lib/MC/MCGNUAsmStreamer.cpp b/llvm/lib/MC/MCGNUAsmStreamer.cpp
new file mode 100644
index 0000000000000..c1dd1ef53f3c8
--- /dev/null
+++ b/llvm/lib/MC/MCGNUAsmStreamer.cpp
@@ -0,0 +1,2605 @@
+//===- lib/MC/MCGNUAsmStreamer.cpp - Text Assembly Output -------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
+#include "llvm/MC/MCAsmBackend.h"
+#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/MC/MCAsmStreamer.h"
+#include "llvm/MC/MCAssembler.h"
+#include "llvm/MC/MCCodeEmitter.h"
+#include "llvm/MC/MCCodeView.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCExpr.h"
+#include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCInstPrinter.h"
+#include "llvm/MC/MCLFIRewriter.h"
+#include "llvm/MC/MCObjectFileInfo.h"
+#include "llvm/MC/MCObjectWriter.h"
+#include "llvm/MC/MCPseudoProbe.h"
+#include "llvm/MC/MCRegister.h"
+#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/MC/MCSectionMachO.h"
+#include "llvm/MC/MCStreamer.h"
+#include "llvm/MC/MCSymbolXCOFF.h"
+#include "llvm/MC/TargetRegistry.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/FormattedStream.h"
+#include "llvm/Support/LEB128.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/Path.h"
+#include <algorithm>
+#include <optional>
+
+using namespace llvm;
+
+namespace {
+
+class MCGNUAsmStreamer final : public MCAsmStreamer {
+  std::unique_ptr<formatted_raw_ostream> OSOwner;
+  formatted_raw_ostream &OS;
+  const MCAsmInfo *MAI;
+  std::unique_ptr<MCInstPrinter> InstPrinter;
+
+  SmallString<128> ExplicitCommentToEmit;
+
+  bool EmittedSectionDirective = false;
+
+  bool IsVerboseAsm = false;
+  bool ShowInst = false;
+  bool UseDwarfDirectory = false;
+
+  void EmitRegisterName(int64_t Register);
+  void PrintQuotedString(StringRef Data, raw_ostream &OS) const;
+  void printDwarfFileDirective(unsigned FileNo, StringRef Directory,
+                               StringRef Filename,
+                               std::optional<MD5::MD5Result> Checksum,
+                               std::optional<StringRef> Source,
+                               bool UseDwarfDirectory,
+                               raw_svector_ostream &OS) const;
+  void emitCFIStartProcImpl(MCDwarfFrameInfo &Frame) override;
+  void emitCFIEndProcImpl(MCDwarfFrameInfo &Frame) override;
+
+  /// Helper to emit common .loc directive flags, isa, and discriminator.
+  void emitDwarfLocDirectiveFlags(unsigned Flags, unsigned Isa,
+                                  unsigned Discriminator);
+
+  /// Helper to emit the common suffix of .loc directives (flags, comment, EOL,
+  /// parent call).
+  void emitDwarfLocDirectiveSuffix(unsigned FileNo, unsigned Line,
+                                   unsigned Column, unsigned Flags,
+                                   unsigned Isa, unsigned Discriminator,
+                                   StringRef FileName, StringRef Comment);
+
+public:
+  MCGNUAsmStreamer(MCContext &Context,
+                   std::unique_ptr<formatted_raw_ostream> OS,
+                   std::unique_ptr<MCInstPrinter> Printer,
+                   std::unique_ptr<MCCodeEmitter> Emitter,
+                   std::unique_ptr<MCAsmBackend> AsmBackend)
+      : MCAsmStreamer(Context, std::move(Emitter), std::move(AsmBackend)),
+        OSOwner(std::move(OS)), OS(*OSOwner), MAI(Context.getAsmInfo()),
+        InstPrinter(std::move(Printer)) {
+    assert(InstPrinter);
+    if (Assembler->getBackendPtr())
+      setAllowAutoPadding(Assembler->getBackend().allowAutoPadding());
+
+    Context.setUseNamesOnTempLabels(true);
+
+    auto *TO = Context.getTargetOptions();
+    if (!TO)
+      return;
+    IsVerboseAsm = TO->AsmVerbose;
+    if (IsVerboseAsm)
+      InstPrinter->setCommentStream(CommentStream);
+    ShowInst = TO->ShowMCInst;
+    switch (TO->MCUseDwarfDirectory) {
+    case MCTargetOptions::DisableDwarfDirectory:
+      UseDwarfDirectory = false;
+      break;
+    case MCTargetOptions::EnableDwarfDirectory:
+      UseDwarfDirectory = true;
+      break;
+    case MCTargetOptions::DefaultDwarfDirectory:
+      UseDwarfDirectory =
+          Context.getAsmInfo()->enableDwarfFileDirectoryDefault();
+      break;
+    }
+  }
+
+  inline void EmitEOL() {
+    // Dump Explicit Comments here.
+    emitExplicitComments();
+    // If we don't have any comments, just emit a \n.
+    if (!IsVerboseAsm) {
+      OS << '\n';
+      return;
+    }
+    EmitCommentsAndEOL();
+  }
+
+  void emitSyntaxDirective(StringRef Syntax, StringRef Options) override;
+
+  void EmitCommentsAndEOL();
+
+  /// Return true if this streamer supports verbose assembly at all.
+  bool isVerboseAsm() const override { return IsVerboseAsm; }
+
+  /// Do we support EmitRawText?
+  bool hasRawTextSupport() const override { return true; }
+
+  /// Add a comment that can be emitted to the generated .s file to make the
+  /// output of the compiler more readable. This only affects the
+  /// MCGNUAsmStreamer and only when verbose assembly output is enabled.
+  void AddComment(const Twine &T, bool EOL = true) override;
+
+  void emitRawComment(const Twine &T, bool TabPrefix = true) override;
+
+  void addExplicitComment(const Twine &T) override;
+  void emitExplicitComments() override;
+
+  /// Emit a blank line to a .s file to pretty it up.
+  void addBlankLine() override { EmitEOL(); }
+
+  /// @name MCStreamer Interface
+  /// @{
+
+  void switchSection(MCSection *Section, uint32_t Subsection) override;
+  bool popSection() override;
+
+  void emitELFSymverDirective(const MCSymbol *OriginalSym, StringRef Name,
+                              bool KeepOriginalSym) override;
+
+  void emitLOHDirective(MCLOHType Kind, const MCLOHArgs &Args) override;
+
+  void emitGNUAttribute(unsigned Tag, unsigned Value) override;
+
+  StringRef getMnemonic(const MCInst &MI) const override {
+    auto [Ptr, Bits] = InstPrinter->getMnemonic(MI);
+    assert((Bits != 0 || Ptr == nullptr) &&
+           "Invalid char pointer for instruction with no mnemonic");
+    return Ptr;
+  }
+
+  void emitLabel(MCSymbol *Symbol, SMLoc Loc = SMLoc()) override;
+
+  void emitSubsectionsViaSymbols() override;
+  void emitLinkerOptions(ArrayRef<std::string> Options) override;
+  void emitDataRegion(MCDataRegionType Kind) override;
+  void emitVersionMin(MCVersionMinType Kind, unsigned Major, unsigned Minor,
+                      unsigned Update, VersionTuple SDKVersion) override;
+  void emitBuildVersion(unsigned Platform, unsigned Major, unsigned Minor,
+                        unsigned Update, VersionTuple SDKVersion) override;
+  void emitDarwinTargetVariantBuildVersion(unsigned Platform, unsigned Major,
+                                           unsigned Minor, unsigned Update,
+                                           VersionTuple SDKVersion) override;
+
+  void emitAssignment(MCSymbol *Symbol, const MCExpr *Value) override;
+  void emitConditionalAssignment(MCSymbol *Symbol,
+                                 const MCExpr *Value) override;
+  void emitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol) override;
+  bool emitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override;
+
+  void emitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) override;
+  void beginCOFFSymbolDef(const MCSymbol *Symbol) override;
+  void emitCOFFSymbolStorageClass(int StorageClass) override;
+  void emitCOFFSymbolType(int Type) override;
+  void endCOFFSymbolDef() override;
+  void emitCOFFSafeSEH(MCSymbol const *Symbol) override;
+  void emitCOFFSymbolIndex(MCSymbol const *Symbol) override;
+  void emitCOFFSectionIndex(MCSymbol const *Symbol) override;
+  void emitCOFFSecRel32(MCSymbol const *Symbol, uint64_t Offset) override;
+  void emitCOFFImgRel32(MCSymbol const *Symbol, int64_t Offset) override;
+  void emitCOFFSecNumber(MCSymbol const *Symbol) override;
+  void emitCOFFSecOffset(MCSymbol const *Symbol) override;
+  void emitXCOFFLocalCommonSymbol(MCSymbol *LabelSym, uint64_t Size,
+                                  MCSymbol *CsectSym, Align Alignment) override;
+  void emitXCOFFSymbolLinkageWithVisibility(MCSymbol *Symbol,
+                                            MCSymbolAttr Linkage,
+                                            MCSymbolAttr Visibility) override;
+  void emitXCOFFRenameDirective(const MCSymbol *Name,
+                                StringRef Rename) override;
+
+  void emitXCOFFRefDirective(const MCSymbol *Symbol) override;
+
+  void emitXCOFFExceptDirective(const MCSymbol *Symbol, const MCSymbol *Trap,
+                                unsigned Lang, unsigned Reason,
+                                unsigned FunctionSize, bool hasDebug) override;
+  void emitXCOFFCInfoSym(StringRef Name, StringRef Metadata) override;
+
+  void emitELFSize(MCSymbol *Symbol, const MCExpr *Value) override;
+  void emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
+                        Align ByteAlignment) override;
+
+  /// Emit a local common (.lcomm) symbol.
+  ///
+  /// @param Symbol - The common symbol to emit.
+  /// @param Size - The size of the common symbol.
+  /// @param ByteAlignment - The alignment of the common symbol in bytes.
+  void emitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size,
+                             Align ByteAlignment) override;
+
+  void emitZerofill(MCSection *Section, MCSymbol *Symbol = nullptr,
+                    uint64_t Size = 0, Align ByteAlignment = Align(1),
+                    SMLoc Loc = SMLoc()) override;
+
+  void emitTBSSSymbol(MCSection *Section, MCSymbol *Symbol, uint64_t Size,
+                      Align ByteAlignment = Align(1)) override;
+
+  void emitBinaryData(StringRef Data) override;
+
+  void emitBytes(StringRef Data) override;
+
+  void emitValueImpl(const MCExpr *Value, unsigned Size,
+                     SMLoc Loc = SMLoc()) override;
+  void emitIntValue(uint64_t Value, unsigned Size) override;
+  void emitIntValueInHex(uint64_t Value, unsigned Size) override;
+  void emitIntValueInHexWithPadding(uint64_t Value, unsigned Size) override;
+
+  void emitULEB128Value(const MCExpr *Value) override;
+
+  void emitSLEB128Value(const MCExpr *Value) override;
+
+  void emitFill(const MCExpr &NumBytes, uint64_t FillValue,
+                SMLoc Loc = SMLoc()) override;
+
+  void emitFill(const MCExpr &NumValues, int64_t Size, int64_t Expr,
+                SMLoc Loc = SMLoc()) override;
+
+  void emitAlignmentDirective(uint64_t ByteAlignment,
+                              std::optional<int64_t> Value, unsigned ValueSize,
+                              unsigned MaxBytesToEmit);
+
+  void emitValueToAlignment(Align Alignment, int64_t Fill = 0,
+                            uint8_t FillLen = 1,
+                            unsigned MaxBytesToEmit = 0) override;
+
+  void emitCodeAlignment(Align Alignment, const MCSubtargetInfo *STI,
+                         unsigned MaxBytesToEmit = 0) override;
+  void emitPrefAlign(Align Alignment) override;
+
+  void emitValueToOffset(const MCExpr *Offset, unsigned char Value,
+                         SMLoc Loc) override;
+
+  void emitFileDirective(StringRef Filename) override;
+  void emitFileDirective(StringRef Filename, StringRef CompilerVersion,
+                         StringRef TimeStamp, StringRef Description) override;
+  Expected<unsigned> tryEmitDwarfFileDirective(
+      unsigned FileNo, StringRef Directory, StringRef Filename,
+      std::optional<MD5::MD5Result> Checksum = std::nullopt,
+      std::optional<StringRef> Source = std::nullopt,
+      unsigned CUID = 0) override;
+  void emitDwarfFile0Directive(StringRef Directory, StringRef Filename,
+                               std::optional<MD5::MD5Result> Checksum,
+                               std::optional<StringRef> Source,
+                               unsigned CUID = 0) override;
+  void emitDwarfLocDirective(unsigned FileNo, unsigned Line, unsigned Column,
+                             unsigned Flags, unsigned Isa,
+                             unsigned Discriminator, StringRef FileName,
+                             StringRef Location = {}) override;
+  void emitDwarfLocLabelDirective(SMLoc Loc, StringRef Name) override;
+
+  /// This is same as emitDwarfLocDirective, except also emits inlined function
+  /// and inlined callsite information.
+  void emitDwarfLocDirectiveWithInlinedAt(unsigned FileNo, unsigned Line,
+                                          unsigned Column, unsigned FileIA,
+                                          unsigned LineIA, unsigned ColIA,
+                                          const MCSymbol *Sym, unsigned Flags,
+                                          unsigned Isa, unsigned Discriminator,
+                                          StringRef FileName,
+                                          StringRef Comment = {}) override;
+
+  MCSymbol *getDwarfLineTableSymbol(unsigned CUID) override;
+
+  bool emitCVFileDirective(unsigned FileNo, StringRef Filename,
+                           ArrayRef<uint8_t> Checksum,
+                           unsigned ChecksumKind) override;
+  bool emitCVFuncIdDirective(unsigned FuncId) override;
+  bool emitCVInlineSiteIdDirective(unsigned FunctionId, unsigned IAFunc,
+                                   unsigned IAFile, unsigned IALine,
+                                   unsigned IACol, SMLoc Loc) override;
+  void emitCVLocDirective(unsigned FunctionId, unsigned FileNo, unsigned Line,
+                          unsigned Column, bool PrologueEnd, bool IsStmt,
+                          StringRef FileName, SMLoc Loc) override;
+  void emitCVLinetableDirective(unsigned FunctionId, const MCSymbol *FnStart,
+                                const MCSymbol *FnEnd) override;
+  void emitCVInlineLinetableDirective(unsigned PrimaryFunctionId,
+                                      unsigned SourceFileId,
+                                      unsigned SourceLineNum,
+                                      const MCSymbol *FnStartSym,
+                                      const MCSymbol *FnEndSym) override;
+
+  void PrintCVDefRangePrefix(
+      ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges);
+
+  void emitCVDefRangeDirective(
+      ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,
+      codeview::DefRangeRegisterRelHeader DRHdr) override;
+
+  void emitCVDefRangeDirective(
+      ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,
+      codeview::DefRangeSubfieldRegisterHeader DRHdr) override;
+
+  void emitCVDefRangeDirective(
+      ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,
+      codeview::DefRangeRegisterHeader DRHdr) override;
+
+  void emitCVDefRangeDirective(
+      ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,
+      codeview::DefRangeFramePointerRelHeader DRHdr) override;
+
+  void emitCVStringTableDirective() override;
+  void emitCVFileChecksumsDirective() override;
+  void emitCVFileChecksumOffsetDirective(unsigned FileNo) override;
+  void emitCVFPOData(const MCSymbol *ProcSym, SMLoc L) override;
+
+  void emitIdent(StringRef IdentString) override;
+  void emitCFIBKeyFrame() override;
+  void emitCFIMTETaggedFrame() override;
+  void emitCFISections(bool EH, bool Debug, bool SFrame) override;
+  void emitCFIDefCfa(int64_t Register, int64_t Offset, SMLoc Loc) override;
+  void emitCFIDefCfaOffset(int64_t Offset, SMLoc Loc) override;
+  void emitCFIDefCfaRegister(int64_t Register, SMLoc Loc) override;
+  void emitCFILLVMDefAspaceCfa(int64_t Register, int64_t Offset,
+                               int64_t AddressSpace, SMLoc Loc) override;
+  void emitCFIOffset(int64_t Register, int64_t Offset, SMLoc Loc) override;
+  void emitCFIPersonality(const MCSymbol *Sym, unsigned Encoding) override;
+  void emitCFILsda(const MCSymbol *Sym, unsigned Encoding) override;
+  void emitCFIRememberState(SMLoc Loc) override;
+  void emitCFIRestoreState(SMLoc Loc) override;
+  void emitCFIRestore(int64_t Register, SMLoc Loc) override;
+  void emitCFISameValue(int64_t Register, SMLoc Loc) override;
+  void emitCFIRelOffset(int64_t Register, int64_t Offset, SMLoc Loc) override;
+  void emitCFIAdjustCfaOffset(int64_t Adjustment, SMLoc Loc) override;
+  void emitCFIEscape(StringRef Values, SMLoc Loc) override;
+  void emitCFIGnuArgsSize(int64_t Size, SMLoc Loc) override;
+  void emitCFISignalFrame() override;
+  void emitCFIUndefined(int64_t Register, SMLoc Loc) override;
+  void emitCFIRegister(int64_t Register1, int64_t Register2,
+                       SMLoc Loc) override;
+  void emitCFIWindowSave(SMLoc Loc) override;
+  void emitCFINegateRAState(SMLoc Loc) override;
+  void emitCFINegateRAStateWithPC(SMLoc Loc) override;
+  void emitCFIReturnColumn(int64_t Register) override;
+  void emitCFILabelDirective(SMLoc Loc, StringRef Name) override;
+  void emitCFIValOffset(int64_t Register, int64_t Offset, SMLoc Loc) override;
+
+  void emitWinCFIStartProc(const MCSymbol *Symbol, SMLoc Loc) override;
+  void emitWinCFIEndProc(SMLoc Loc) override;
+  void emitWinCFIFuncletOrFuncEnd(SMLoc Loc) override;
+  void emitWinCFISplitChained(SMLoc Loc) override;
+  void emitWinCFIPushReg(MCRegister Register, SMLoc Loc) override;
+  void emitWinCFISetFrame(MCRegister Register, unsigned Offset,
+                          SMLoc Loc) override;
+  void emitWinCFIAllocStack(unsigned Size, SMLoc Loc) override;
+  void emitWinCFISaveReg(MCRegister Register, unsigned Offset,
+                         SMLoc Loc) override;
+  void emitWinCFISaveXMM(MCRegister Register, unsigned Offset,
+                         SMLoc Loc) override;
+  void emitWinCFIPushFrame(bool Code, SMLoc Loc) override;
+  void emitWinCFIEndProlog(SMLoc Loc) override;
+  void emitWinCFIBeginEpilogue(SMLoc Loc) override;
+  void emitWinCFIEndEpilogue(SMLoc Loc) override;
+  void emitWinCFIUnwindV2Start(SMLoc Loc) override;
+  void emitWinCFIUnwindVersion(uint8_t Version, SMLoc Loc) override;
+
+  void emitWinEHHandler(const MCSymbol *Sym, bool Unwind, bool Except,
+                        SMLoc Loc) override;
+  void emitWinEHHandlerData(SMLoc Loc) override;
+
+  void emitCGProfileEntry(const MCSymbolRefExpr *From,
+                          const MCSymbolRefExpr *To, uint64_t Count) override;
+
+  void emitInstruction(const MCInst &Inst, const MCSubtargetInfo &STI) override;
+
+  void emitPseudoProbe(uint64_t Guid, uint64_t Index, uint64_t Type,
+                       uint64_t Attr, uint64_t Discriminator,
+                       const MCPseudoProbeInlineStack &InlineStack,
+                       MCSymbol *FnSym) override;
+
+  void emitRelocDirective(const MCExpr &Offset, StringRef Name,
+                          const MCExpr *Expr, SMLoc Loc) override;
+
+  void emitAddrsig() override;
+  void emitAddrsigSym(const MCSymbol *Sym) override;
+
+  /// If this file is backed by an assembly streamer, this dumps the specified
+  /// string in the output .s file. This capability is indicated by the
+  /// hasRawTextSupport() predicate.
+  void emitRawTextImpl(StringRef String) override;
+
+  void finishImpl() override;
+
+  void emitDwarfUnitLength(uint64_t Length, const Twine &Comment) override;
+
+  MCSymbol *emitDwarfUnitLength(const Twine &Prefix,
+                                const Twine &Comment) override;
+
+  void emitDwarfLineStartLabel(MCSymbol *StartSym) override;
+
+  void emitDwarfLineEndEntry(MCSection *Section, MCSymbol *LastLabel,
+                             MCSymbol *EndLabel = nullptr) override;
+
+  void emitDwarfAdvanceLineAddr(int64_t LineDelta, const MCSymbol *LastLabel,
+                                const MCSymbol *Label,
+                                unsigned PointerSize) override;
+};
+
+} // end anonymous namespace.
+
+void MCGNUAsmStreamer::AddComment(const Twine &T, bool EOL) {
+  if (!IsVerboseAsm) return;
+
+  T.toVector(CommentToEmit);
+
+  if (EOL)
+    CommentToEmit.push_back('\n'); // Place comment in a new line.
+}
+
+void MCGNUAsmStreamer::EmitCommentsAndEOL() {
+  if (CommentToEmit.empty() && CommentStream.GetNumBytesInBuffer() == 0) {
+    OS << '\n';
+    return;
+  }
+
+  StringRef Comments = CommentToEmit;
+
+  assert(Comments.back() == '\n' &&
+         "Comment array not newline terminated");
+  do {
+    // Emit a line of comments.
+    OS.PadToColumn(MAI->getCommentColumn());
+    size_t Position = Comments.find('\n');
+    OS << MAI->getCommentString() << ' ' << Comments.substr(0, Position) <<'\n';
+
+    Comments = Comments.substr(Position+1);
+  } while (!Comments.empty());
+
+  CommentToEmit.clear();
+}
+
+static inline int64_t truncateToSize(int64_t Value, unsigned Bytes) {
+  assert(Bytes > 0 && Bytes <= 8 && "Invalid size!");
+  return Value & ((uint64_t) (int64_t) -1 >> (64 - Bytes * 8));
+}
+
+void MCGNUAsmStreamer::emitRawComment(const Twine &T, bool TabPrefix) {
+  if (TabPrefix)
+    OS << '\t';
+  OS << MAI->getCommentString() << T;
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::addExplicitComment(const Twine &T) {
+  StringRef c = T.getSingleStringRef();
+  if (c == MAI->getSeparatorString())
+    return;
+  if (c.starts_with(StringRef("//"))) {
+    ExplicitCommentToEmit.append("\t");
+    ExplicitCommentToEmit.append(MAI->getCommentString());
+    // drop //
+    ExplicitCommentToEmit.append(c.substr(2).str());
+  } else if (c.starts_with(StringRef("/*"))) {
+    size_t p = 2, len = c.size() - 2;
+    // emit each line in comment as separate newline.
+    do {
+      size_t newp = std::min(len, c.find_first_of("\r\n", p));
+      ExplicitCommentToEmit.append("\t");
+      ExplicitCommentToEmit.append(MAI->getCommentString());
+      ExplicitCommentToEmit.append(c.slice(p, newp).str());
+      // If we have another line in this comment add line
+      if (newp < len)
+        ExplicitCommentToEmit.append("\n");
+      p = newp + 1;
+    } while (p < len);
+  } else if (c.starts_with(StringRef(MAI->getCommentString()))) {
+    ExplicitCommentToEmit.append("\t");
+    ExplicitCommentToEmit.append(c.str());
+  } else if (c.front() == '#') {
+
+    ExplicitCommentToEmit.append("\t");
+    ExplicitCommentToEmit.append(MAI->getCommentString());
+    ExplicitCommentToEmit.append(c.substr(1).str());
+  } else
+    assert(false && "Unexpected Assembly Comment");
+  // full line comments immediately output
+  if (c.back() == '\n')
+    emitExplicitComments();
+}
+
+void MCGNUAsmStreamer::emitExplicitComments() {
+  StringRef Comments = ExplicitCommentToEmit;
+  if (!Comments.empty())
+    OS << Comments;
+  ExplicitCommentToEmit.clear();
+}
+
+void MCGNUAsmStreamer::switchSection(MCSection *Section, uint32_t Subsection) {
+  MCSectionSubPair Cur = getCurrentSection();
+  if (!EmittedSectionDirective ||
+      MCSectionSubPair(Section, Subsection) != Cur) {
+    EmittedSectionDirective = true;
+    if (MCTargetStreamer *TS = getTargetStreamer()) {
+      TS->changeSection(Cur.first, Section, Subsection, OS);
+    } else {
+      MAI->printSwitchToSection(*Section, Subsection,
+                                getContext().getTargetTriple(), OS);
+    }
+  }
+  MCStreamer::switchSection(Section, Subsection);
+}
+
+bool MCGNUAsmStreamer::popSection() {
+  if (!MCStreamer::popSection())
+    return false;
+  auto [Sec, Subsec] = getCurrentSection();
+  MAI->printSwitchToSection(*Sec, Subsec, getContext().getTargetTriple(), OS);
+  return true;
+}
+
+void MCGNUAsmStreamer::emitELFSymverDirective(const MCSymbol *OriginalSym,
+                                              StringRef Name,
+                                              bool KeepOriginalSym) {
+  OS << ".symver ";
+  OriginalSym->print(OS, MAI);
+  OS << ", " << Name;
+  if (!KeepOriginalSym && !Name.contains("@@@"))
+    OS << ", remove";
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitLabel(MCSymbol *Symbol, SMLoc Loc) {
+  MCStreamer::emitLabel(Symbol, Loc);
+  // FIXME: Fix CodeGen/AArch64/arm64ec-varargs.ll. emitLabel is followed by
+  // setVariableValue, leading to an assertion failure if setOffset(0) is
+  // called.
+  if (!Symbol->isVariable() &&
+      getContext().getObjectFileType() != MCContext::IsCOFF)
+    Symbol->setOffset(0);
+
+  Symbol->print(OS, MAI);
+  OS << MAI->getLabelSuffix();
+
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitLOHDirective(MCLOHType Kind, const MCLOHArgs &Args) {
+  StringRef str = MCLOHIdToName(Kind);
+
+#ifndef NDEBUG
+  int NbArgs = MCLOHIdToNbArgs(Kind);
+  assert(NbArgs != -1 && ((size_t)NbArgs) == Args.size() && "Malformed LOH!");
+  assert(str != "" && "Invalid LOH name");
+#endif
+
+  OS << "\t" << MCLOHDirectiveName() << " " << str << "\t";
+  bool IsFirst = true;
+  for (const MCSymbol *Arg : Args) {
+    if (!IsFirst)
+      OS << ", ";
+    IsFirst = false;
+    Arg->print(OS, MAI);
+  }
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitGNUAttribute(unsigned Tag, unsigned Value) {
+  OS << "\t.gnu_attribute " << Tag << ", " << Value << "\n";
+}
+
+void MCGNUAsmStreamer::emitSubsectionsViaSymbols() {
+  OS << ".subsections_via_symbols\n";
+}
+
+void MCGNUAsmStreamer::emitLinkerOptions(ArrayRef<std::string> Options) {
+  assert(!Options.empty() && "At least one option is required!");
+  OS << "\t.linker_option \"" << Options[0] << '"';
+  for (const std::string &Opt : llvm::drop_begin(Options))
+    OS << ", " << '"' << Opt << '"';
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitDataRegion(MCDataRegionType Kind) {
+  if (!MAI->doesSupportDataRegionDirectives())
+    return;
+  switch (Kind) {
+  case MCDR_DataRegion:            OS << "\t.data_region"; break;
+  case MCDR_DataRegionJT8:         OS << "\t.data_region jt8"; break;
+  case MCDR_DataRegionJT16:        OS << "\t.data_region jt16"; break;
+  case MCDR_DataRegionJT32:        OS << "\t.data_region jt32"; break;
+  case MCDR_DataRegionEnd:         OS << "\t.end_data_region"; break;
+  }
+  EmitEOL();
+}
+
+static const char *getVersionMinDirective(MCVersionMinType Type) {
+  switch (Type) {
+  case MCVM_WatchOSVersionMin: return ".watchos_version_min";
+  case MCVM_TvOSVersionMin:    return ".tvos_version_min";
+  case MCVM_IOSVersionMin:     return ".ios_version_min";
+  case MCVM_OSXVersionMin:     return ".macosx_version_min";
+  }
+  llvm_unreachable("Invalid MC version min type");
+}
+
+static void EmitSDKVersionSuffix(raw_ostream &OS,
+                                 const VersionTuple &SDKVersion) {
+  if (SDKVersion.empty())
+    return;
+  OS << '\t' << "sdk_version " << SDKVersion.getMajor();
+  if (auto Minor = SDKVersion.getMinor()) {
+    OS << ", " << *Minor;
+    if (auto Subminor = SDKVersion.getSubminor()) {
+      OS << ", " << *Subminor;
+    }
+  }
+}
+
+void MCGNUAsmStreamer::emitVersionMin(MCVersionMinType Type, unsigned Major,
+                                      unsigned Minor, unsigned Update,
+                                      VersionTuple SDKVersion) {
+  OS << '\t' << getVersionMinDirective(Type) << ' ' << Major << ", " << Minor;
+  if (Update)
+    OS << ", " << Update;
+  EmitSDKVersionSuffix(OS, SDKVersion);
+  EmitEOL();
+}
+
+static const char *getPlatformName(MachO::PlatformType Type) {
+  switch (Type) {
+#define PLATFORM(platform, id, name, build_name, target, tapi_target,          \
+                 marketing)                                                    \
+  case MachO::PLATFORM_##platform:                                             \
+    return #build_name;
+#include "llvm/BinaryFormat/MachO.def"
+  }
+  llvm_unreachable("Invalid Mach-O platform type");
+}
+
+void MCGNUAsmStreamer::emitBuildVersion(unsigned Platform, unsigned Major,
+                                        unsigned Minor, unsigned Update,
+                                        VersionTuple SDKVersion) {
+  const char *PlatformName = getPlatformName((MachO::PlatformType)Platform);
+  OS << "\t.build_version " << PlatformName << ", " << Major << ", " << Minor;
+  if (Update)
+    OS << ", " << Update;
+  EmitSDKVersionSuffix(OS, SDKVersion);
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitDarwinTargetVariantBuildVersion(
+    unsigned Platform, unsigned Major, unsigned Minor, unsigned Update,
+    VersionTuple SDKVersion) {
+  emitBuildVersion(Platform, Major, Minor, Update, SDKVersion);
+}
+
+void MCGNUAsmStreamer::emitAssignment(MCSymbol *Symbol, const MCExpr *Value) {
+  bool UseSet = MAI->usesSetToEquateSymbol();
+  if (UseSet)
+    OS << ".set ";
+  Symbol->print(OS, MAI);
+  OS << (UseSet ? ", " : " = ");
+  MAI->printExpr(OS, *Value);
+
+  EmitEOL();
+  MCStreamer::emitAssignment(Symbol, Value);
+}
+
+void MCGNUAsmStreamer::emitConditionalAssignment(MCSymbol *Symbol,
+                                                 const MCExpr *Value) {
+  OS << ".lto_set_conditional ";
+  Symbol->print(OS, MAI);
+  OS << ", ";
+  MAI->printExpr(OS, *Value);
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitWeakReference(MCSymbol *Alias,
+                                         const MCSymbol *Symbol) {
+  OS << ".weakref ";
+  Alias->print(OS, MAI);
+  OS << ", ";
+  Symbol->print(OS, MAI);
+  EmitEOL();
+}
+
+bool MCGNUAsmStreamer::emitSymbolAttribute(MCSymbol *Symbol,
+                                           MCSymbolAttr Attribute) {
+  switch (Attribute) {
+  case MCSA_Invalid: llvm_unreachable("Invalid symbol attribute");
+  case MCSA_ELF_TypeFunction:    /// .type _foo, STT_FUNC  # aka @function
+  case MCSA_ELF_TypeIndFunction: /// .type _foo, STT_GNU_IFUNC
+  case MCSA_ELF_TypeObject:      /// .type _foo, STT_OBJECT  # aka @object
+  case MCSA_ELF_TypeTLS:         /// .type _foo, STT_TLS     # aka @tls_object
+  case MCSA_ELF_TypeCommon:      /// .type _foo, STT_COMMON  # aka @common
+  case MCSA_ELF_TypeNoType:      /// .type _foo, STT_NOTYPE  # aka @notype
+  case MCSA_ELF_TypeGnuUniqueObject:  /// .type _foo, @gnu_unique_object
+    if (!MAI->hasDotTypeDotSizeDirective())
+      return false; // Symbol attribute not supported
+    OS << "\t.type\t";
+    Symbol->print(OS, MAI);
+    OS << ',' << ((MAI->getCommentString()[0] != '@') ? '@' : '%');
+    switch (Attribute) {
+    default: return false;
+    case MCSA_ELF_TypeFunction:    OS << "function"; break;
+    case MCSA_ELF_TypeIndFunction: OS << "gnu_indirect_function"; break;
+    case MCSA_ELF_TypeObject:      OS << "object"; break;
+    case MCSA_ELF_TypeTLS:         OS << "tls_object"; break;
+    case MCSA_ELF_TypeCommon:      OS << "common"; break;
+    case MCSA_ELF_TypeNoType:      OS << "notype"; break;
+    case MCSA_ELF_TypeGnuUniqueObject: OS << "gnu_unique_object"; break;
+    }
+    EmitEOL();
+    return true;
+  case MCSA_Global: // .globl/.global
+    OS << MAI->getGlobalDirective();
+    break;
+  case MCSA_LGlobal:        OS << "\t.lglobl\t";          break;
+  case MCSA_Hidden:         OS << "\t.hidden\t";          break;
+  case MCSA_IndirectSymbol: OS << "\t.indirect_symbol\t"; break;
+  case MCSA_Internal:       OS << "\t.internal\t";        break;
+  case MCSA_LazyReference:  OS << "\t.lazy_reference\t";  break;
+  case MCSA_Local:          OS << "\t.local\t";           break;
+  case MCSA_NoDeadStrip:
+    if (!MAI->hasNoDeadStrip())
+      return false;
+    OS << "\t.no_dead_strip\t";
+    break;
+  case MCSA_SymbolResolver: OS << "\t.symbol_resolver\t"; break;
+  case MCSA_AltEntry:       OS << "\t.alt_entry\t";       break;
+  case MCSA_PrivateExtern:
+    OS << "\t.private_extern\t";
+    break;
+  case MCSA_Protected:      OS << "\t.protected\t";       break;
+  case MCSA_Reference:      OS << "\t.reference\t";       break;
+  case MCSA_Extern:
+    OS << "\t.extern\t";
+    break;
+  case MCSA_Weak:           OS << MAI->getWeakDirective(); break;
+  case MCSA_WeakDefinition:
+    OS << "\t.weak_definition\t";
+    break;
+    // .weak_reference
+  case MCSA_WeakReference:  OS << MAI->getWeakRefDirective(); break;
+  case MCSA_WeakDefAutoPrivate: OS << "\t.weak_def_can_be_hidden\t"; break;
+  case MCSA_Cold:
+    // Assemblers currently do not support a .cold directive.
+  case MCSA_Exported:
+    // Non-AIX assemblers currently do not support exported visibility.
+  case MCSA_OSLinkage:
+  case MCSA_XPLinkage:
+    // Only for HLASM.
+    return false;
+  case MCSA_Memtag:
+    OS << "\t.memtag\t";
+    break;
+  case MCSA_WeakAntiDep:
+    OS << "\t.weak_anti_dep\t";
+    break;
+  }
+
+  Symbol->print(OS, MAI);
+  EmitEOL();
+
+  return true;
+}
+
+void MCGNUAsmStreamer::emitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) {
+  OS << ".desc" << ' ';
+  Symbol->print(OS, MAI);
+  OS << ',' << DescValue;
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitSyntaxDirective(StringRef Syntax,
+                                           StringRef Options) {
+  OS << "\t." << Syntax << "_syntax";
+  if (!Options.empty())
+    OS << " " << Options;
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::beginCOFFSymbolDef(const MCSymbol *Symbol) {
+  OS << "\t.def\t";
+  Symbol->print(OS, MAI);
+  OS << ';';
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitCOFFSymbolStorageClass(int StorageClass) {
+  OS << "\t.scl\t" << StorageClass << ';';
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitCOFFSymbolType(int Type) {
+  OS << "\t.type\t" << Type << ';';
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::endCOFFSymbolDef() {
+  OS << "\t.endef";
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitCOFFSafeSEH(MCSymbol const *Symbol) {
+  OS << "\t.safeseh\t";
+  Symbol->print(OS, MAI);
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitCOFFSymbolIndex(MCSymbol const *Symbol) {
+  OS << "\t.symidx\t";
+  Symbol->print(OS, MAI);
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitCOFFSectionIndex(MCSymbol const *Symbol) {
+  OS << "\t.secidx\t";
+  Symbol->print(OS, MAI);
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitCOFFSecRel32(MCSymbol const *Symbol,
+                                        uint64_t Offset) {
+  OS << "\t.secrel32\t";
+  Symbol->print(OS, MAI);
+  if (Offset != 0)
+    OS << '+' << Offset;
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitCOFFImgRel32(MCSymbol const *Symbol,
+                                        int64_t Offset) {
+  OS << "\t.rva\t";
+  Symbol->print(OS, MAI);
+  if (Offset > 0)
+    OS << '+' << Offset;
+  else if (Offset < 0)
+    OS << '-' << -Offset;
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitCOFFSecNumber(MCSymbol const *Symbol) {
+  OS << "\t.secnum\t";
+  Symbol->print(OS, MAI);
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitCOFFSecOffset(MCSymbol const *Symbol) {
+  OS << "\t.secoffset\t";
+  Symbol->print(OS, MAI);
+  EmitEOL();
+}
+
+// We need an XCOFF-specific version of this directive as the AIX syntax
+// requires a QualName argument identifying the csect name and storage mapping
+// class to appear before the alignment if we are specifying it.
+void MCGNUAsmStreamer::emitXCOFFLocalCommonSymbol(MCSymbol *LabelSym,
+                                                  uint64_t Size,
+                                                  MCSymbol *CsectSym,
+                                                  Align Alignment) {
+  assert(MAI->getLCOMMDirectiveAlignmentType() == LCOMM::Log2Alignment &&
+         "We only support writing log base-2 alignment format with XCOFF.");
+
+  OS << "\t.lcomm\t";
+  LabelSym->print(OS, MAI);
+  OS << ',' << Size << ',';
+  CsectSym->print(OS, MAI);
+  OS << ',' << Log2(Alignment);
+
+  EmitEOL();
+
+  // Print symbol's rename (original name contains invalid character(s)) if
+  // there is one.
+  auto *XSym = static_cast<MCSymbolXCOFF *>(CsectSym);
+  if (XSym->hasRename())
+    emitXCOFFRenameDirective(XSym, XSym->getSymbolTableName());
+}
+
+void MCGNUAsmStreamer::emitXCOFFSymbolLinkageWithVisibility(
+    MCSymbol *Symbol, MCSymbolAttr Linkage, MCSymbolAttr Visibility) {
+  auto &Sym = static_cast<MCSymbolXCOFF &>(*Symbol);
+  switch (Linkage) {
+  case MCSA_Global:
+    OS << MAI->getGlobalDirective();
+    break;
+  case MCSA_Weak:
+    OS << MAI->getWeakDirective();
+    break;
+  case MCSA_Extern:
+    OS << "\t.extern\t";
+    break;
+  case MCSA_LGlobal:
+    OS << "\t.lglobl\t";
+    break;
+  default:
+    report_fatal_error("unhandled linkage type");
+  }
+
+  Symbol->print(OS, MAI);
+
+  switch (Visibility) {
+  case MCSA_Invalid:
+    // Nothing to do.
+    break;
+  case MCSA_Hidden:
+    OS << ",hidden";
+    break;
+  case MCSA_Protected:
+    OS << ",protected";
+    break;
+  case MCSA_Exported:
+    OS << ",exported";
+    break;
+  default:
+    report_fatal_error("unexpected value for Visibility type");
+  }
+  EmitEOL();
+
+  // Print symbol's rename (original name contains invalid character(s)) if
+  // there is one.
+  if (Sym.hasRename())
+    emitXCOFFRenameDirective(&Sym, Sym.getSymbolTableName());
+}
+
+void MCGNUAsmStreamer::emitXCOFFRenameDirective(const MCSymbol *Name,
+                                                StringRef Rename) {
+  OS << "\t.rename\t";
+  Name->print(OS, MAI);
+  const char DQ = '"';
+  OS << ',' << DQ;
+  for (char C : Rename) {
+    // To escape a double quote character, the character should be doubled.
+    if (C == DQ)
+      OS << DQ;
+    OS << C;
+  }
+  OS << DQ;
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitXCOFFRefDirective(const MCSymbol *Symbol) {
+  OS << "\t.ref ";
+  Symbol->print(OS, MAI);
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitXCOFFExceptDirective(const MCSymbol *Symbol,
+                                                const MCSymbol *Trap,
+                                                unsigned Lang, unsigned Reason,
+                                                unsigned FunctionSize,
+                                                bool hasDebug) {
+  OS << "\t.except\t";
+  Symbol->print(OS, MAI);
+  OS << ", " << Lang << ", " << Reason;
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitXCOFFCInfoSym(StringRef Name, StringRef Metadata) {
+  const char InfoDirective[] = "\t.info ";
+  const char *Separator = ", ";
+  constexpr int WordSize = sizeof(uint32_t);
+
+  // Start by emitting the .info pseudo-op and C_INFO symbol name.
+  OS << InfoDirective;
+  PrintQuotedString(Name, OS);
+  OS << Separator;
+
+  size_t MetadataSize = Metadata.size();
+
+  // Emit the 4-byte length of the metadata.
+  OS << format_hex(MetadataSize, 10) << Separator;
+
+  // Nothing left to do if there's no metadata.
+  if (MetadataSize == 0) {
+    EmitEOL();
+    return;
+  }
+
+  // Metadata needs to be padded out to an even word size when generating
+  // assembly because the .info pseudo-op can only generate words of data. We
+  // apply the same restriction to the object case for consistency, however the
+  // linker doesn't require padding, so it will only save bytes specified by the
+  // length and discard any padding.
+  uint32_t PaddedSize = alignTo(MetadataSize, WordSize);
+  uint32_t PaddingSize = PaddedSize - MetadataSize;
+
+  // Write out the payload a word at a time.
+  //
+  // The assembler has a limit on the number of operands in an expression,
+  // so we need multiple .info pseudo-ops. We choose a small number of words
+  // per pseudo-op to keep the assembly readable.
+  constexpr int WordsPerDirective = 5;
+  // Force emitting a new directive to keep the first directive purely about the
+  // name and size of the note.
+  int WordsBeforeNextDirective = 0;
+  auto PrintWord = [&](const uint8_t *WordPtr) {
+    if (WordsBeforeNextDirective-- == 0) {
+      EmitEOL();
+      OS << InfoDirective;
+      WordsBeforeNextDirective = WordsPerDirective;
+    }
+    OS << Separator;
+    uint32_t Word = llvm::support::endian::read32be(WordPtr);
+    OS << format_hex(Word, 10);
+  };
+
+  size_t Index = 0;
+  for (; Index + WordSize <= MetadataSize; Index += WordSize)
+    PrintWord(reinterpret_cast<const uint8_t *>(Metadata.data()) + Index);
+
+  // If there is padding, then we have at least one byte of payload left
+  // to emit.
+  if (PaddingSize) {
+    assert(PaddedSize - Index == WordSize);
+    std::array<uint8_t, WordSize> LastWord = {0};
+    ::memcpy(LastWord.data(), Metadata.data() + Index, MetadataSize - Index);
+    PrintWord(LastWord.data());
+  }
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitELFSize(MCSymbol *Symbol, const MCExpr *Value) {
+  assert(MAI->hasDotTypeDotSizeDirective());
+  OS << "\t.size\t";
+  Symbol->print(OS, MAI);
+  OS << ", ";
+  MAI->printExpr(OS, *Value);
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
+                                        Align ByteAlignment) {
+  OS << "\t.comm\t";
+  Symbol->print(OS, MAI);
+  OS << ',' << Size;
+
+  if (MAI->getCOMMDirectiveAlignmentIsInBytes())
+    OS << ',' << ByteAlignment.value();
+  else
+    OS << ',' << Log2(ByteAlignment);
+  EmitEOL();
+
+  // Print symbol's rename (original name contains invalid character(s)) if
+  // there is one.
+  if (getContext().isXCOFF()) {
+    auto *XSym = static_cast<MCSymbolXCOFF *>(Symbol);
+    if (XSym && XSym->hasRename())
+      emitXCOFFRenameDirective(XSym, XSym->getSymbolTableName());
+  }
+}
+
+void MCGNUAsmStreamer::emitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size,
+                                             Align ByteAlign) {
+  OS << "\t.lcomm\t";
+  Symbol->print(OS, MAI);
+  OS << ',' << Size;
+
+  if (ByteAlign > 1) {
+    switch (MAI->getLCOMMDirectiveAlignmentType()) {
+    case LCOMM::NoAlignment:
+      llvm_unreachable("alignment not supported on .lcomm!");
+    case LCOMM::ByteAlignment:
+      OS << ',' << ByteAlign.value();
+      break;
+    case LCOMM::Log2Alignment:
+      OS << ',' << Log2(ByteAlign);
+      break;
+    }
+  }
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitZerofill(MCSection *Section, MCSymbol *Symbol,
+                                    uint64_t Size, Align ByteAlignment,
+                                    SMLoc Loc) {
+  if (Symbol)
+    Symbol->setFragment(&Section->getDummyFragment());
+
+  // Note: a .zerofill directive does not switch sections.
+  OS << ".zerofill ";
+
+  assert(getContext().getObjectFileType() == MCContext::IsMachO &&
+         ".zerofill is a Mach-O specific directive");
+  // This is a mach-o specific directive.
+
+  const MCSectionMachO *MOSection = ((const MCSectionMachO*)Section);
+  OS << MOSection->getSegmentName() << "," << MOSection->getName();
+
+  if (Symbol) {
+    OS << ',';
+    Symbol->print(OS, MAI);
+    OS << ',' << Size;
+    OS << ',' << Log2(ByteAlignment);
+  }
+  EmitEOL();
+}
+
+// .tbss sym, size, align
+// This depends that the symbol has already been mangled from the original,
+// e.g. _a.
+void MCGNUAsmStreamer::emitTBSSSymbol(MCSection *Section, MCSymbol *Symbol,
+                                      uint64_t Size, Align ByteAlignment) {
+  Symbol->setFragment(&Section->getDummyFragment());
+
+  // Instead of using the Section we'll just use the shortcut.
+
+  assert(getContext().getObjectFileType() == MCContext::IsMachO &&
+         ".zerofill is a Mach-O specific directive");
+  // This is a mach-o specific directive and section.
+
+  OS << ".tbss ";
+  Symbol->print(OS, MAI);
+  OS << ", " << Size;
+
+  // Output align if we have it.  We default to 1 so don't bother printing
+  // that.
+  if (ByteAlignment > 1)
+    OS << ", " << Log2(ByteAlignment);
+
+  EmitEOL();
+}
+
+static inline bool isPrintableString(StringRef Data) {
+  const auto BeginPtr = Data.begin(), EndPtr = Data.end();
+  for (const unsigned char C : make_range(BeginPtr, EndPtr - 1)) {
+    if (!isPrint(C))
+      return false;
+  }
+  return isPrint(Data.back()) || Data.back() == 0;
+}
+
+static inline char toOctal(int X) { return (X&7)+'0'; }
+
+static void PrintByteList(StringRef Data, raw_ostream &OS,
+                          MCAsmInfo::AsmCharLiteralSyntax ACLS) {
+  assert(!Data.empty() && "Cannot generate an empty list.");
+  const auto printCharacterInOctal = [&OS](unsigned char C) {
+    OS << '0';
+    OS << toOctal(C >> 6);
+    OS << toOctal(C >> 3);
+    OS << toOctal(C >> 0);
+  };
+  const auto printOneCharacterFor = [printCharacterInOctal](
+                                        auto printOnePrintingCharacter) {
+    return [printCharacterInOctal, printOnePrintingCharacter](unsigned char C) {
+      if (isPrint(C)) {
+        printOnePrintingCharacter(static_cast<char>(C));
+        return;
+      }
+      printCharacterInOctal(C);
+    };
+  };
+  const auto printCharacterList = [Data, &OS](const auto &printOneCharacter) {
+    const auto BeginPtr = Data.begin(), EndPtr = Data.end();
+    for (const unsigned char C : make_range(BeginPtr, EndPtr - 1)) {
+      printOneCharacter(C);
+      OS << ',';
+    }
+    printOneCharacter(*(EndPtr - 1));
+  };
+  switch (ACLS) {
+  case MCAsmInfo::ACLS_Unknown:
+    printCharacterList(printCharacterInOctal);
+    return;
+  case MCAsmInfo::ACLS_SingleQuotePrefix:
+    printCharacterList(printOneCharacterFor([&OS](char C) {
+      const char AsmCharLitBuf[2] = {'\'', C};
+      OS << StringRef(AsmCharLitBuf, sizeof(AsmCharLitBuf));
+    }));
+    return;
+  }
+  llvm_unreachable("Invalid AsmCharLiteralSyntax value!");
+}
+
+void MCGNUAsmStreamer::PrintQuotedString(StringRef Data,
+                                         raw_ostream &OS) const {
+  OS << '"';
+
+  if (MAI->isAIX()) {
+    for (unsigned char C : Data) {
+      if (C == '"')
+        OS << "\"\"";
+      else
+        OS << (char)C;
+    }
+  } else {
+    for (unsigned char C : Data) {
+      if (C == '"' || C == '\\') {
+        OS << '\\' << (char)C;
+        continue;
+      }
+
+      if (isPrint(C)) {
+        OS << (char)C;
+        continue;
+      }
+
+      switch (C) {
+      case '\b':
+        OS << "\\b";
+        break;
+      case '\f':
+        OS << "\\f";
+        break;
+      case '\n':
+        OS << "\\n";
+        break;
+      case '\r':
+        OS << "\\r";
+        break;
+      case '\t':
+        OS << "\\t";
+        break;
+      default:
+        OS << '\\';
+        OS << toOctal(C >> 6);
+        OS << toOctal(C >> 3);
+        OS << toOctal(C >> 0);
+        break;
+      }
+    }
+  }
+
+  OS << '"';
+}
+
+void MCGNUAsmStreamer::emitBytes(StringRef Data) {
+  assert(getCurrentSectionOnly() &&
+         "Cannot emit contents before setting section!");
+  if (Data.empty()) return;
+
+  const auto emitAsString = [this](StringRef Data) {
+    if (MAI->isAIX()) {
+      if (isPrintableString(Data)) {
+        // For target with DoubleQuoteString constants, .string and .byte are
+        // used as replacement of .asciz and .ascii.
+        if (Data.back() == 0) {
+          OS << "\t.string\t";
+          Data = Data.substr(0, Data.size() - 1);
+        } else {
+          OS << "\t.byte\t";
+        }
+        PrintQuotedString(Data, OS);
+      } else {
+        OS << "\t.byte\t";
+        PrintByteList(Data, OS, MAI->characterLiteralSyntax());
+      }
+      EmitEOL();
+      return true;
+    }
+
+    // If the data ends with 0 and the target supports .asciz, use it, otherwise
+    // use .ascii or a byte-list directive
+    if (MAI->getAscizDirective() && Data.back() == 0) {
+      OS << MAI->getAscizDirective();
+      Data = Data.substr(0, Data.size() - 1);
+    } else if (LLVM_LIKELY(MAI->getAsciiDirective())) {
+      OS << MAI->getAsciiDirective();
+    } else {
+      return false;
+    }
+
+    PrintQuotedString(Data, OS);
+    EmitEOL();
+    return true;
+  };
+
+  if (Data.size() != 1 && emitAsString(Data))
+    return;
+
+  // Only single byte is provided or no ascii, asciz, or byte-list directives
+  // are applicable. Emit as vector of individual 8bits data elements.
+  if (MCTargetStreamer *TS = getTargetStreamer()) {
+    TS->emitRawBytes(Data);
+    return;
+  }
+  const char *Directive = MAI->getData8bitsDirective();
+  for (const unsigned char C : Data.bytes()) {
+    OS << Directive << (unsigned)C;
+    EmitEOL();
+  }
+}
+
+void MCGNUAsmStreamer::emitBinaryData(StringRef Data) {
+  // This is binary data. Print it in a grid of hex bytes for readability.
+  const size_t Cols = 4;
+  for (size_t I = 0, EI = alignTo(Data.size(), Cols); I < EI; I += Cols) {
+    size_t J = I, EJ = std::min(I + Cols, Data.size());
+    assert(EJ > 0);
+    OS << MAI->getData8bitsDirective();
+    for (; J < EJ - 1; ++J)
+      OS << format("0x%02x", uint8_t(Data[J])) << ", ";
+    OS << format("0x%02x", uint8_t(Data[J]));
+    EmitEOL();
+  }
+}
+
+void MCGNUAsmStreamer::emitIntValue(uint64_t Value, unsigned Size) {
+  emitValue(MCConstantExpr::create(Value, getContext()), Size);
+}
+
+void MCGNUAsmStreamer::emitIntValueInHex(uint64_t Value, unsigned Size) {
+  emitValue(MCConstantExpr::create(Value, getContext(), true), Size);
+}
+
+void MCGNUAsmStreamer::emitIntValueInHexWithPadding(uint64_t Value,
+                                                    unsigned Size) {
+  emitValue(MCConstantExpr::create(Value, getContext(), true, Size), Size);
+}
+
+void MCGNUAsmStreamer::emitValueImpl(const MCExpr *Value, unsigned Size,
+                                     SMLoc Loc) {
+  assert(Size <= 8 && "Invalid size");
+  assert(getCurrentSectionOnly() &&
+         "Cannot emit contents before setting section!");
+  const char *Directive = nullptr;
+  switch (Size) {
+  default: break;
+  case 1: Directive = MAI->getData8bitsDirective();  break;
+  case 2: Directive = MAI->getData16bitsDirective(); break;
+  case 4: Directive = MAI->getData32bitsDirective(); break;
+  case 8: Directive = MAI->getData64bitsDirective(); break;
+  }
+
+  if (!Directive) {
+    int64_t IntValue;
+    if (!Value->evaluateAsAbsolute(IntValue))
+      report_fatal_error("Don't know how to emit this value.");
+
+    // We couldn't handle the requested integer size so we fallback by breaking
+    // the request down into several, smaller, integers.
+    // Since sizes greater or equal to "Size" are invalid, we use the greatest
+    // power of 2 that is less than "Size" as our largest piece of granularity.
+    bool IsLittleEndian = MAI->isLittleEndian();
+    for (unsigned Emitted = 0; Emitted != Size;) {
+      unsigned Remaining = Size - Emitted;
+      // The size of our partial emission must be a power of two less than
+      // Size.
+      unsigned EmissionSize = llvm::bit_floor(std::min(Remaining, Size - 1));
+      // Calculate the byte offset of our partial emission taking into account
+      // the endianness of the target.
+      unsigned ByteOffset =
+          IsLittleEndian ? Emitted : (Remaining - EmissionSize);
+      uint64_t ValueToEmit = IntValue >> (ByteOffset * 8);
+      // We truncate our partial emission to fit within the bounds of the
+      // emission domain.  This produces nicer output and silences potential
+      // truncation warnings when round tripping through another assembler.
+      uint64_t Shift = 64 - EmissionSize * 8;
+      assert(Shift < static_cast<uint64_t>(
+                         std::numeric_limits<unsigned long long>::digits) &&
+             "undefined behavior");
+      ValueToEmit &= ~0ULL >> Shift;
+      emitIntValue(ValueToEmit, EmissionSize);
+      Emitted += EmissionSize;
+    }
+    return;
+  }
+
+  assert(Directive && "Invalid size for machine code value!");
+  OS << Directive;
+  if (MCTargetStreamer *TS = getTargetStreamer()) {
+    TS->emitValue(Value);
+  } else {
+    MAI->printExpr(OS, *Value);
+    EmitEOL();
+  }
+}
+
+void MCGNUAsmStreamer::emitULEB128Value(const MCExpr *Value) {
+  int64_t IntValue;
+  if (Value->evaluateAsAbsolute(IntValue)) {
+    emitULEB128IntValue(IntValue);
+    return;
+  }
+  OS << "\t.uleb128 ";
+  MAI->printExpr(OS, *Value);
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitSLEB128Value(const MCExpr *Value) {
+  int64_t IntValue;
+  if (Value->evaluateAsAbsolute(IntValue)) {
+    emitSLEB128IntValue(IntValue);
+    return;
+  }
+  OS << "\t.sleb128 ";
+  MAI->printExpr(OS, *Value);
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitFill(const MCExpr &NumBytes, uint64_t FillValue,
+                                SMLoc Loc) {
+  int64_t IntNumBytes;
+  const bool IsAbsolute = NumBytes.evaluateAsAbsolute(IntNumBytes);
+  if (IsAbsolute && IntNumBytes == 0)
+    return;
+
+  if (const char *ZeroDirective = MAI->getZeroDirective()) {
+    if (!MAI->isAIX() || FillValue == 0) {
+      // FIXME: Emit location directives
+      OS << ZeroDirective;
+      MAI->printExpr(OS, NumBytes);
+      if (FillValue != 0)
+        OS << ',' << (int)FillValue;
+      EmitEOL();
+    } else {
+      if (!IsAbsolute)
+        report_fatal_error(
+            "Cannot emit non-absolute expression lengths of fill.");
+      for (int i = 0; i < IntNumBytes; ++i) {
+        OS << MAI->getData8bitsDirective() << (int)FillValue;
+        EmitEOL();
+      }
+    }
+    return;
+  }
+
+  MCStreamer::emitFill(NumBytes, FillValue);
+}
+
+void MCGNUAsmStreamer::emitFill(const MCExpr &NumValues, int64_t Size,
+                                int64_t Expr, SMLoc Loc) {
+  // FIXME: Emit location directives
+  OS << "\t.fill\t";
+  MAI->printExpr(OS, NumValues);
+  OS << ", " << Size << ", 0x";
+  OS.write_hex(truncateToSize(Expr, 4));
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitAlignmentDirective(uint64_t ByteAlignment,
+                                              std::optional<int64_t> Value,
+                                              unsigned ValueSize,
+                                              unsigned MaxBytesToEmit) {
+  if (MAI->isAIX()) {
+    if (!isPowerOf2_64(ByteAlignment))
+      report_fatal_error("Only power-of-two alignments are supported "
+                         "with .align.");
+    OS << "\t.align\t";
+    OS << Log2_64(ByteAlignment);
+    EmitEOL();
+    return;
+  }
+
+  // Some assemblers don't support non-power of two alignments, so we always
+  // emit alignments as a power of two if possible.
+  if (isPowerOf2_64(ByteAlignment)) {
+    switch (ValueSize) {
+    default:
+      llvm_unreachable("Invalid size for machine code value!");
+    case 1:
+      OS << "\t.p2align\t";
+      break;
+    case 2:
+      OS << ".p2alignw ";
+      break;
+    case 4:
+      OS << ".p2alignl ";
+      break;
+    case 8:
+      llvm_unreachable("Unsupported alignment size!");
+    }
+
+    OS << Log2_64(ByteAlignment);
+
+    if (Value.has_value() || MaxBytesToEmit) {
+      if (Value.has_value()) {
+        OS << ", 0x";
+        OS.write_hex(truncateToSize(*Value, ValueSize));
+      } else {
+        OS << ", ";
+      }
+
+      if (MaxBytesToEmit)
+        OS << ", " << MaxBytesToEmit;
+    }
+    EmitEOL();
+    return;
+  }
+
+  // Non-power of two alignment.  This is not widely supported by assemblers.
+  // FIXME: Parameterize this based on MAI.
+  switch (ValueSize) {
+  default: llvm_unreachable("Invalid size for machine code value!");
+  case 1: OS << ".balign";  break;
+  case 2: OS << ".balignw"; break;
+  case 4: OS << ".balignl"; break;
+  case 8: llvm_unreachable("Unsupported alignment size!");
+  }
+
+  OS << ' ' << ByteAlignment;
+  if (Value.has_value())
+    OS << ", " << truncateToSize(*Value, ValueSize);
+  else if (MaxBytesToEmit)
+    OS << ", ";
+  if (MaxBytesToEmit)
+    OS << ", " << MaxBytesToEmit;
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitValueToAlignment(Align Alignment, int64_t Fill,
+                                            uint8_t FillLen,
+                                            unsigned MaxBytesToEmit) {
+  emitAlignmentDirective(Alignment.value(), Fill, FillLen, MaxBytesToEmit);
+}
+
+void MCGNUAsmStreamer::emitCodeAlignment(Align Alignment,
+                                         const MCSubtargetInfo *STI,
+                                         unsigned MaxBytesToEmit) {
+  // Emit with a text fill value.
+  if (MAI->getTextAlignFillValue())
+    emitAlignmentDirective(Alignment.value(), MAI->getTextAlignFillValue(), 1,
+                           MaxBytesToEmit);
+  else
+    emitAlignmentDirective(Alignment.value(), std::nullopt, 1, MaxBytesToEmit);
+}
+
+void MCGNUAsmStreamer::emitPrefAlign(Align Alignment) {
+  OS << "\t.prefalign\t" << Alignment.value();
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitValueToOffset(const MCExpr *Offset,
+                                         unsigned char Value, SMLoc Loc) {
+  // FIXME: Verify that Offset is associated with the current section.
+  OS << ".org ";
+  MAI->printExpr(OS, *Offset);
+  OS << ", " << (unsigned)Value;
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitFileDirective(StringRef Filename) {
+  assert(MAI->hasSingleParameterDotFile());
+  OS << "\t.file\t";
+  PrintQuotedString(Filename, OS);
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitFileDirective(StringRef Filename,
+                                         StringRef CompilerVersion,
+                                         StringRef TimeStamp,
+                                         StringRef Description) {
+  assert(MAI->isAIX());
+  OS << "\t.file\t";
+  PrintQuotedString(Filename, OS);
+  bool useTimeStamp = !TimeStamp.empty();
+  bool useCompilerVersion = !CompilerVersion.empty();
+  bool useDescription = !Description.empty();
+  if (useTimeStamp || useCompilerVersion || useDescription) {
+    OS << ",";
+    if (useTimeStamp)
+      PrintQuotedString(TimeStamp, OS);
+    if (useCompilerVersion || useDescription) {
+      OS << ",";
+      if (useCompilerVersion)
+        PrintQuotedString(CompilerVersion, OS);
+      if (useDescription) {
+        OS << ",";
+        PrintQuotedString(Description, OS);
+      }
+    }
+  }
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::printDwarfFileDirective(
+    unsigned FileNo, StringRef Directory, StringRef Filename,
+    std::optional<MD5::MD5Result> Checksum, std::optional<StringRef> Source,
+    bool UseDwarfDirectory, raw_svector_ostream &OS) const {
+  SmallString<128> FullPathName;
+
+  if (!UseDwarfDirectory && !Directory.empty()) {
+    if (sys::path::is_absolute(Filename))
+      Directory = "";
+    else {
+      FullPathName = Directory;
+      sys::path::append(FullPathName, Filename);
+      Directory = "";
+      Filename = FullPathName;
+    }
+  }
+
+  OS << "\t.file\t" << FileNo << ' ';
+  if (!Directory.empty()) {
+    PrintQuotedString(Directory, OS);
+    OS << ' ';
+  }
+  PrintQuotedString(Filename, OS);
+  if (Checksum)
+    OS << " md5 0x" << Checksum->digest();
+  if (Source) {
+    OS << " source ";
+    PrintQuotedString(*Source, OS);
+  }
+}
+
+Expected<unsigned> MCGNUAsmStreamer::tryEmitDwarfFileDirective(
+    unsigned FileNo, StringRef Directory, StringRef Filename,
+    std::optional<MD5::MD5Result> Checksum, std::optional<StringRef> Source,
+    unsigned CUID) {
+  assert(CUID == 0 && "multiple CUs not supported by MCGNUAsmStreamer");
+
+  MCDwarfLineTable &Table = getContext().getMCDwarfLineTable(CUID);
+  unsigned NumFiles = Table.getMCDwarfFiles().size();
+  Expected<unsigned> FileNoOrErr =
+      Table.tryGetFile(Directory, Filename, Checksum, Source,
+                       getContext().getDwarfVersion(), FileNo);
+  if (!FileNoOrErr)
+    return FileNoOrErr.takeError();
+  FileNo = FileNoOrErr.get();
+
+  // Return early if this file is already emitted before or if target doesn't
+  // support .file directive.
+  if (NumFiles == Table.getMCDwarfFiles().size() || MAI->isAIX())
+    return FileNo;
+
+  SmallString<128> Str;
+  raw_svector_ostream OS1(Str);
+  printDwarfFileDirective(FileNo, Directory, Filename, Checksum, Source,
+                          UseDwarfDirectory, OS1);
+
+  if (MCTargetStreamer *TS = getTargetStreamer())
+    TS->emitDwarfFileDirective(OS1.str());
+  else
+    emitRawText(OS1.str());
+
+  return FileNo;
+}
+
+void MCGNUAsmStreamer::emitDwarfFile0Directive(
+    StringRef Directory, StringRef Filename,
+    std::optional<MD5::MD5Result> Checksum, std::optional<StringRef> Source,
+    unsigned CUID) {
+  assert(CUID == 0);
+  // .file 0 is new for DWARF v5.
+  if (getContext().getDwarfVersion() < 5)
+    return;
+  // Inform MCDwarf about the root file.
+  getContext().setMCLineTableRootFile(CUID, Directory, Filename, Checksum,
+                                      Source);
+
+  // Target doesn't support .loc/.file directives, return early.
+  if (MAI->isAIX())
+    return;
+
+  SmallString<128> Str;
+  raw_svector_ostream OS1(Str);
+  printDwarfFileDirective(0, Directory, Filename, Checksum, Source,
+                          UseDwarfDirectory, OS1);
+
+  if (MCTargetStreamer *TS = getTargetStreamer())
+    TS->emitDwarfFileDirective(OS1.str());
+  else
+    emitRawText(OS1.str());
+}
+
+/// Helper to emit common .loc directive flags, isa, and discriminator.
+void MCGNUAsmStreamer::emitDwarfLocDirectiveFlags(unsigned Flags, unsigned Isa,
+                                                  unsigned Discriminator) {
+  if (!MAI->supportsExtendedDwarfLocDirective())
+    return;
+
+  if (Flags & DWARF2_FLAG_BASIC_BLOCK)
+    OS << " basic_block";
+  if (Flags & DWARF2_FLAG_PROLOGUE_END)
+    OS << " prologue_end";
+  if (Flags & DWARF2_FLAG_EPILOGUE_BEGIN)
+    OS << " epilogue_begin";
+
+  const unsigned OldFlags = getContext().getCurrentDwarfLoc().getFlags();
+  if ((Flags & DWARF2_FLAG_IS_STMT) != (OldFlags & DWARF2_FLAG_IS_STMT)) {
+    OS << " is_stmt ";
+    OS << ((Flags & DWARF2_FLAG_IS_STMT) ? "1" : "0");
+  }
+
+  if (Isa)
+    OS << " isa " << Isa;
+  if (Discriminator)
+    OS << " discriminator " << Discriminator;
+}
+
+/// Helper to emit the common suffix of .loc directives.
+void MCGNUAsmStreamer::emitDwarfLocDirectiveSuffix(
+    unsigned FileNo, unsigned Line, unsigned Column, unsigned Flags,
+    unsigned Isa, unsigned Discriminator, StringRef FileName,
+    StringRef Comment) {
+  // Emit flags, isa, and discriminator.
+  emitDwarfLocDirectiveFlags(Flags, Isa, Discriminator);
+
+  // Emit verbose comment if enabled.
+  if (IsVerboseAsm) {
+    OS.PadToColumn(MAI->getCommentColumn());
+    OS << MAI->getCommentString() << ' ';
+    if (Comment.empty())
+      OS << FileName << ':' << Line << ':' << Column;
+    else
+      OS << Comment;
+  }
+
+  // Emit end of line and update the baseclass state.
+  EmitEOL();
+  MCStreamer::emitDwarfLocDirective(FileNo, Line, Column, Flags, Isa,
+                                    Discriminator, FileName, Comment);
+}
+
+void MCGNUAsmStreamer::emitDwarfLocDirective(unsigned FileNo, unsigned Line,
+                                             unsigned Column, unsigned Flags,
+                                             unsigned Isa,
+                                             unsigned Discriminator,
+                                             StringRef FileName,
+                                             StringRef Comment) {
+  // If target doesn't support .loc/.file directive, we need to record the lines
+  // same way like we do in object mode.
+  if (MAI->isAIX()) {
+    // In case we see two .loc directives in a row, make sure the
+    // first one gets a line entry.
+    MCDwarfLineEntry::make(this, getCurrentSectionOnly());
+    this->MCStreamer::emitDwarfLocDirective(FileNo, Line, Column, Flags, Isa,
+                                            Discriminator, FileName, Comment);
+    return;
+  }
+
+  // Emit the basic .loc directive.
+  OS << "\t.loc\t" << FileNo << " " << Line << " " << Column;
+
+  // Emit common suffix (flags, comment, EOL, parent call).
+  emitDwarfLocDirectiveSuffix(FileNo, Line, Column, Flags, Isa, Discriminator,
+                              FileName, Comment);
+}
+
+/// This is same as emitDwarfLocDirective, except also emits inlined function
+/// and inlined callsite information.
+void MCGNUAsmStreamer::emitDwarfLocDirectiveWithInlinedAt(
+    unsigned FileNo, unsigned Line, unsigned Column, unsigned FileIA,
+    unsigned LineIA, unsigned ColIA, const MCSymbol *Sym, unsigned Flags,
+    unsigned Isa, unsigned Discriminator, StringRef FileName,
+    StringRef Comment) {
+  // Emit the basic .loc directive with NVPTX-specific extensions.
+  OS << "\t.loc\t" << FileNo << " " << Line << " " << Column;
+  OS << ", function_name " << *Sym;
+  OS << ", inlined_at " << FileIA << " " << LineIA << " " << ColIA;
+
+  // Emit common suffix (flags, comment, EOL, parent call).
+  emitDwarfLocDirectiveSuffix(FileNo, Line, Column, Flags, Isa, Discriminator,
+                              FileName, Comment);
+}
+
+void MCGNUAsmStreamer::emitDwarfLocLabelDirective(SMLoc Loc, StringRef Name) {
+  MCStreamer::emitDwarfLocLabelDirective(Loc, Name);
+  OS << ".loc_label\t" << Name;
+  EmitEOL();
+}
+
+MCSymbol *MCGNUAsmStreamer::getDwarfLineTableSymbol(unsigned CUID) {
+  // Always use the zeroth line table, since asm syntax only supports one line
+  // table for now.
+  return MCStreamer::getDwarfLineTableSymbol(0);
+}
+
+bool MCGNUAsmStreamer::emitCVFileDirective(unsigned FileNo, StringRef Filename,
+                                           ArrayRef<uint8_t> Checksum,
+                                           unsigned ChecksumKind) {
+  if (!getContext().getCVContext().addFile(*this, FileNo, Filename, Checksum,
+                                           ChecksumKind))
+    return false;
+
+  OS << "\t.cv_file\t" << FileNo << ' ';
+  PrintQuotedString(Filename, OS);
+
+  if (!ChecksumKind) {
+    EmitEOL();
+    return true;
+  }
+
+  OS << ' ';
+  PrintQuotedString(toHex(Checksum), OS);
+  OS << ' ' << ChecksumKind;
+
+  EmitEOL();
+  return true;
+}
+
+bool MCGNUAsmStreamer::emitCVFuncIdDirective(unsigned FuncId) {
+  OS << "\t.cv_func_id " << FuncId << '\n';
+  return MCStreamer::emitCVFuncIdDirective(FuncId);
+}
+
+bool MCGNUAsmStreamer::emitCVInlineSiteIdDirective(unsigned FunctionId,
+                                                   unsigned IAFunc,
+                                                   unsigned IAFile,
+                                                   unsigned IALine,
+                                                   unsigned IACol, SMLoc Loc) {
+  OS << "\t.cv_inline_site_id " << FunctionId << " within " << IAFunc
+     << " inlined_at " << IAFile << ' ' << IALine << ' ' << IACol << '\n';
+  return MCStreamer::emitCVInlineSiteIdDirective(FunctionId, IAFunc, IAFile,
+                                                 IALine, IACol, Loc);
+}
+
+void MCGNUAsmStreamer::emitCVLocDirective(unsigned FunctionId, unsigned FileNo,
+                                          unsigned Line, unsigned Column,
+                                          bool PrologueEnd, bool IsStmt,
+                                          StringRef FileName, SMLoc Loc) {
+  // Validate the directive.
+  if (!checkCVLocSection(FunctionId, FileNo, Loc))
+    return;
+
+  OS << "\t.cv_loc\t" << FunctionId << " " << FileNo << " " << Line << " "
+     << Column;
+  if (PrologueEnd)
+    OS << " prologue_end";
+
+  if (IsStmt)
+    OS << " is_stmt 1";
+
+  if (IsVerboseAsm) {
+    OS.PadToColumn(MAI->getCommentColumn());
+    OS << MAI->getCommentString() << ' ' << FileName << ':' << Line << ':'
+       << Column;
+  }
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitCVLinetableDirective(unsigned FunctionId,
+                                                const MCSymbol *FnStart,
+                                                const MCSymbol *FnEnd) {
+  OS << "\t.cv_linetable\t" << FunctionId << ", ";
+  FnStart->print(OS, MAI);
+  OS << ", ";
+  FnEnd->print(OS, MAI);
+  EmitEOL();
+  this->MCStreamer::emitCVLinetableDirective(FunctionId, FnStart, FnEnd);
+}
+
+void MCGNUAsmStreamer::emitCVInlineLinetableDirective(
+    unsigned PrimaryFunctionId, unsigned SourceFileId, unsigned SourceLineNum,
+    const MCSymbol *FnStartSym, const MCSymbol *FnEndSym) {
+  OS << "\t.cv_inline_linetable\t" << PrimaryFunctionId << ' ' << SourceFileId
+     << ' ' << SourceLineNum << ' ';
+  FnStartSym->print(OS, MAI);
+  OS << ' ';
+  FnEndSym->print(OS, MAI);
+  EmitEOL();
+  this->MCStreamer::emitCVInlineLinetableDirective(
+      PrimaryFunctionId, SourceFileId, SourceLineNum, FnStartSym, FnEndSym);
+}
+
+void MCGNUAsmStreamer::PrintCVDefRangePrefix(
+    ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges) {
+  OS << "\t.cv_def_range\t";
+  for (std::pair<const MCSymbol *, const MCSymbol *> Range : Ranges) {
+    OS << ' ';
+    Range.first->print(OS, MAI);
+    OS << ' ';
+    Range.second->print(OS, MAI);
+  }
+}
+
+void MCGNUAsmStreamer::emitCVDefRangeDirective(
+    ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,
+    codeview::DefRangeRegisterRelHeader DRHdr) {
+  PrintCVDefRangePrefix(Ranges);
+  OS << ", reg_rel, ";
+  OS << DRHdr.Register << ", " << DRHdr.Flags << ", "
+     << DRHdr.BasePointerOffset;
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitCVDefRangeDirective(
+    ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,
+    codeview::DefRangeSubfieldRegisterHeader DRHdr) {
+  PrintCVDefRangePrefix(Ranges);
+  OS << ", subfield_reg, ";
+  OS << DRHdr.Register << ", " << DRHdr.OffsetInParent;
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitCVDefRangeDirective(
+    ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,
+    codeview::DefRangeRegisterHeader DRHdr) {
+  PrintCVDefRangePrefix(Ranges);
+  OS << ", reg, ";
+  OS << DRHdr.Register;
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitCVDefRangeDirective(
+    ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,
+    codeview::DefRangeFramePointerRelHeader DRHdr) {
+  PrintCVDefRangePrefix(Ranges);
+  OS << ", frame_ptr_rel, ";
+  OS << DRHdr.Offset;
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitCVStringTableDirective() {
+  OS << "\t.cv_stringtable";
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitCVFileChecksumsDirective() {
+  OS << "\t.cv_filechecksums";
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitCVFileChecksumOffsetDirective(unsigned FileNo) {
+  OS << "\t.cv_filechecksumoffset\t" << FileNo;
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitCVFPOData(const MCSymbol *ProcSym, SMLoc L) {
+  OS << "\t.cv_fpo_data\t";
+  ProcSym->print(OS, MAI);
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitIdent(StringRef IdentString) {
+  assert(MAI->hasIdentDirective() && ".ident directive not supported");
+  OS << "\t.ident\t";
+  PrintQuotedString(IdentString, OS);
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitCFISections(bool EH, bool Debug, bool SFrame) {
+  MCStreamer::emitCFISections(EH, Debug, SFrame);
+  OS << "\t.cfi_sections ";
+  bool C = false;
+  if (EH) {
+    OS << ".eh_frame";
+    C = true;
+  }
+  if (Debug) {
+    if (C)
+      OS << ", ";
+    OS << ".debug_frame";
+    C = true;
+  }
+  if (SFrame) {
+    if (C)
+      OS << ", ";
+    OS << ".sframe";
+  }
+
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitCFIStartProcImpl(MCDwarfFrameInfo &Frame) {
+  OS << "\t.cfi_startproc";
+  if (Frame.IsSimple)
+    OS << " simple";
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitCFIEndProcImpl(MCDwarfFrameInfo &Frame) {
+  MCStreamer::emitCFIEndProcImpl(Frame);
+  OS << "\t.cfi_endproc";
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::EmitRegisterName(int64_t Register) {
+  if (!MAI->useDwarfRegNumForCFI()) {
+    // User .cfi_* directives can use arbitrary DWARF register numbers, not
+    // just ones that map to LLVM register numbers and have known names.
+    // Fall back to using the original number directly if no name is known.
+    const MCRegisterInfo *MRI = getContext().getRegisterInfo();
+    if (std::optional<MCRegister> LLVMRegister =
+            MRI->getLLVMRegNum(Register, true)) {
+      InstPrinter->printRegName(OS, *LLVMRegister);
+      return;
+    }
+  }
+  OS << Register;
+}
+
+void MCGNUAsmStreamer::emitCFIDefCfa(int64_t Register, int64_t Offset,
+                                     SMLoc Loc) {
+  MCStreamer::emitCFIDefCfa(Register, Offset, Loc);
+  OS << "\t.cfi_def_cfa ";
+  EmitRegisterName(Register);
+  OS << ", " << Offset;
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitCFIDefCfaOffset(int64_t Offset, SMLoc Loc) {
+  MCStreamer::emitCFIDefCfaOffset(Offset, Loc);
+  OS << "\t.cfi_def_cfa_offset " << Offset;
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitCFILLVMDefAspaceCfa(int64_t Register, int64_t Offset,
+                                               int64_t AddressSpace,
+                                               SMLoc Loc) {
+  MCStreamer::emitCFILLVMDefAspaceCfa(Register, Offset, AddressSpace, Loc);
+  OS << "\t.cfi_llvm_def_aspace_cfa ";
+  EmitRegisterName(Register);
+  OS << ", " << Offset;
+  OS << ", " << AddressSpace;
+  EmitEOL();
+}
+
+static void PrintCFIEscape(llvm::formatted_raw_ostream &OS, StringRef Values) {
+  OS << "\t.cfi_escape ";
+  if (!Values.empty()) {
+    size_t e = Values.size() - 1;
+    for (size_t i = 0; i < e; ++i)
+      OS << format("0x%02x", uint8_t(Values[i])) << ", ";
+    OS << format("0x%02x", uint8_t(Values[e]));
+  }
+}
+
+void MCGNUAsmStreamer::emitCFIEscape(StringRef Values, SMLoc Loc) {
+  MCStreamer::emitCFIEscape(Values, Loc);
+  PrintCFIEscape(OS, Values);
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitCFIGnuArgsSize(int64_t Size, SMLoc Loc) {
+  MCStreamer::emitCFIGnuArgsSize(Size, Loc);
+
+  uint8_t Buffer[16] = { dwarf::DW_CFA_GNU_args_size };
+  unsigned Len = encodeULEB128(Size, Buffer + 1) + 1;
+
+  PrintCFIEscape(OS, StringRef((const char *)&Buffer[0], Len));
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitCFIDefCfaRegister(int64_t Register, SMLoc Loc) {
+  MCStreamer::emitCFIDefCfaRegister(Register, Loc);
+  OS << "\t.cfi_def_cfa_register ";
+  EmitRegisterName(Register);
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitCFIOffset(int64_t Register, int64_t Offset,
+                                     SMLoc Loc) {
+  MCStreamer::emitCFIOffset(Register, Offset, Loc);
+  OS << "\t.cfi_offset ";
+  EmitRegisterName(Register);
+  OS << ", " << Offset;
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitCFIPersonality(const MCSymbol *Sym,
+                                          unsigned Encoding) {
+  MCStreamer::emitCFIPersonality(Sym, Encoding);
+  OS << "\t.cfi_personality " << Encoding << ", ";
+  Sym->print(OS, MAI);
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitCFILsda(const MCSymbol *Sym, unsigned Encoding) {
+  MCStreamer::emitCFILsda(Sym, Encoding);
+  OS << "\t.cfi_lsda " << Encoding << ", ";
+  Sym->print(OS, MAI);
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitCFIRememberState(SMLoc Loc) {
+  MCStreamer::emitCFIRememberState(Loc);
+  OS << "\t.cfi_remember_state";
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitCFIRestoreState(SMLoc Loc) {
+  MCStreamer::emitCFIRestoreState(Loc);
+  OS << "\t.cfi_restore_state";
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitCFIRestore(int64_t Register, SMLoc Loc) {
+  MCStreamer::emitCFIRestore(Register, Loc);
+  OS << "\t.cfi_restore ";
+  EmitRegisterName(Register);
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitCFISameValue(int64_t Register, SMLoc Loc) {
+  MCStreamer::emitCFISameValue(Register, Loc);
+  OS << "\t.cfi_same_value ";
+  EmitRegisterName(Register);
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitCFIRelOffset(int64_t Register, int64_t Offset,
+                                        SMLoc Loc) {
+  MCStreamer::emitCFIRelOffset(Register, Offset, Loc);
+  OS << "\t.cfi_rel_offset ";
+  EmitRegisterName(Register);
+  OS << ", " << Offset;
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitCFIAdjustCfaOffset(int64_t Adjustment, SMLoc Loc) {
+  MCStreamer::emitCFIAdjustCfaOffset(Adjustment, Loc);
+  OS << "\t.cfi_adjust_cfa_offset " << Adjustment;
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitCFISignalFrame() {
+  MCStreamer::emitCFISignalFrame();
+  OS << "\t.cfi_signal_frame";
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitCFIUndefined(int64_t Register, SMLoc Loc) {
+  MCStreamer::emitCFIUndefined(Register, Loc);
+  OS << "\t.cfi_undefined ";
+  EmitRegisterName(Register);
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitCFIRegister(int64_t Register1, int64_t Register2,
+                                       SMLoc Loc) {
+  MCStreamer::emitCFIRegister(Register1, Register2, Loc);
+  OS << "\t.cfi_register ";
+  EmitRegisterName(Register1);
+  OS << ", ";
+  EmitRegisterName(Register2);
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitCFIWindowSave(SMLoc Loc) {
+  MCStreamer::emitCFIWindowSave(Loc);
+  OS << "\t.cfi_window_save";
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitCFINegateRAState(SMLoc Loc) {
+  MCStreamer::emitCFINegateRAState(Loc);
+  OS << "\t.cfi_negate_ra_state";
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitCFINegateRAStateWithPC(SMLoc Loc) {
+  MCStreamer::emitCFINegateRAStateWithPC(Loc);
+  OS << "\t.cfi_negate_ra_state_with_pc";
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitCFIReturnColumn(int64_t Register) {
+  MCStreamer::emitCFIReturnColumn(Register);
+  OS << "\t.cfi_return_column ";
+  EmitRegisterName(Register);
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitCFILabelDirective(SMLoc Loc, StringRef Name) {
+  MCStreamer::emitCFILabelDirective(Loc, Name);
+  OS << "\t.cfi_label " << Name;
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitCFIBKeyFrame() {
+  MCStreamer::emitCFIBKeyFrame();
+  OS << "\t.cfi_b_key_frame";
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitCFIMTETaggedFrame() {
+  MCStreamer::emitCFIMTETaggedFrame();
+  OS << "\t.cfi_mte_tagged_frame";
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitCFIValOffset(int64_t Register, int64_t Offset,
+                                        SMLoc Loc) {
+  MCStreamer::emitCFIValOffset(Register, Offset, Loc);
+  OS << "\t.cfi_val_offset ";
+  EmitRegisterName(Register);
+  OS << ", " << Offset;
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitWinCFIStartProc(const MCSymbol *Symbol, SMLoc Loc) {
+  MCStreamer::emitWinCFIStartProc(Symbol, Loc);
+
+  OS << ".seh_proc ";
+  Symbol->print(OS, MAI);
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitWinCFIEndProc(SMLoc Loc) {
+  MCStreamer::emitWinCFIEndProc(Loc);
+
+  OS << "\t.seh_endproc";
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitWinCFIFuncletOrFuncEnd(SMLoc Loc) {
+  MCStreamer::emitWinCFIFuncletOrFuncEnd(Loc);
+
+  OS << "\t.seh_endfunclet";
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitWinCFISplitChained(SMLoc Loc) {
+  MCStreamer::emitWinCFISplitChained(Loc);
+
+  OS << "\t.seh_splitchained";
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitWinEHHandler(const MCSymbol *Sym, bool Unwind,
+                                        bool Except, SMLoc Loc) {
+  MCStreamer::emitWinEHHandler(Sym, Unwind, Except, Loc);
+
+  OS << "\t.seh_handler ";
+  Sym->print(OS, MAI);
+  char Marker = '@';
+  const Triple &T = getContext().getTargetTriple();
+  if (T.getArch() == Triple::arm || T.getArch() == Triple::thumb)
+    Marker = '%';
+  if (Unwind)
+    OS << ", " << Marker << "unwind";
+  if (Except)
+    OS << ", " << Marker << "except";
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitWinEHHandlerData(SMLoc Loc) {
+  MCStreamer::emitWinEHHandlerData(Loc);
+
+  // Switch sections. Don't call switchSection directly, because that will
+  // cause the section switch to be visible in the emitted assembly.
+  // We only do this so the section switch that terminates the handler
+  // data block is visible.
+  WinEH::FrameInfo *CurFrame = getCurrentWinFrameInfo();
+
+  // Do nothing if no frame is open. MCStreamer should've already reported an
+  // error.
+  if (!CurFrame)
+    return;
+
+  MCSection *TextSec = &CurFrame->Function->getSection();
+  MCSection *XData = getAssociatedXDataSection(TextSec);
+  switchSectionNoPrint(XData);
+
+  OS << "\t.seh_handlerdata";
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitWinCFIPushReg(MCRegister Register, SMLoc Loc) {
+  MCStreamer::emitWinCFIPushReg(Register, Loc);
+
+  OS << "\t.seh_pushreg ";
+  InstPrinter->printRegName(OS, Register);
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitWinCFISetFrame(MCRegister Register, unsigned Offset,
+                                          SMLoc Loc) {
+  MCStreamer::emitWinCFISetFrame(Register, Offset, Loc);
+
+  OS << "\t.seh_setframe ";
+  InstPrinter->printRegName(OS, Register);
+  OS << ", " << Offset;
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitWinCFIAllocStack(unsigned Size, SMLoc Loc) {
+  MCStreamer::emitWinCFIAllocStack(Size, Loc);
+
+  OS << "\t.seh_stackalloc " << Size;
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitWinCFISaveReg(MCRegister Register, unsigned Offset,
+                                         SMLoc Loc) {
+  MCStreamer::emitWinCFISaveReg(Register, Offset, Loc);
+
+  OS << "\t.seh_savereg ";
+  InstPrinter->printRegName(OS, Register);
+  OS << ", " << Offset;
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitWinCFISaveXMM(MCRegister Register, unsigned Offset,
+                                         SMLoc Loc) {
+  MCStreamer::emitWinCFISaveXMM(Register, Offset, Loc);
+
+  OS << "\t.seh_savexmm ";
+  InstPrinter->printRegName(OS, Register);
+  OS << ", " << Offset;
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitWinCFIPushFrame(bool Code, SMLoc Loc) {
+  MCStreamer::emitWinCFIPushFrame(Code, Loc);
+
+  OS << "\t.seh_pushframe";
+  if (Code)
+    OS << " @code";
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitWinCFIEndProlog(SMLoc Loc) {
+  MCStreamer::emitWinCFIEndProlog(Loc);
+
+  OS << "\t.seh_endprologue";
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitWinCFIBeginEpilogue(SMLoc Loc) {
+  MCStreamer::emitWinCFIBeginEpilogue(Loc);
+
+  OS << "\t.seh_startepilogue";
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitWinCFIEndEpilogue(SMLoc Loc) {
+  MCStreamer::emitWinCFIEndEpilogue(Loc);
+
+  OS << "\t.seh_endepilogue";
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitWinCFIUnwindV2Start(SMLoc Loc) {
+  MCStreamer::emitWinCFIUnwindV2Start(Loc);
+
+  OS << "\t.seh_unwindv2start";
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitWinCFIUnwindVersion(uint8_t Version, SMLoc Loc) {
+  MCStreamer::emitWinCFIUnwindVersion(Version, Loc);
+
+  OS << "\t.seh_unwindversion " << (unsigned)Version;
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitCGProfileEntry(const MCSymbolRefExpr *From,
+                                          const MCSymbolRefExpr *To,
+                                          uint64_t Count) {
+  OS << "\t.cg_profile ";
+  From->getSymbol().print(OS, MAI);
+  OS << ", ";
+  To->getSymbol().print(OS, MAI);
+  OS << ", " << Count;
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitInstruction(const MCInst &Inst,
+                                       const MCSubtargetInfo &STI) {
+  if (LFIRewriter && LFIRewriter->rewriteInst(Inst, *this, STI))
+    return;
+
+  if (CurFrag) {
+    MCSection *Sec = getCurrentSectionOnly();
+    Sec->setHasInstructions(true);
+  }
+
+  if (MAI->isAIX() && CurFrag)
+    // Now that a machine instruction has been assembled into this section, make
+    // a line entry for any .loc directive that has been seen.
+    MCDwarfLineEntry::make(this, getCurrentSectionOnly());
+
+  // Show the encoding in a comment if we have a code emitter.
+  addEncodingComment(Inst, STI);
+
+  // Show the MCInst if enabled.
+  if (ShowInst) {
+    Inst.dump_pretty(getCommentOS(), InstPrinter.get(), "\n ", &getContext());
+    getCommentOS() << "\n";
+  }
+
+  if(getTargetStreamer())
+    getTargetStreamer()->prettyPrintAsm(*InstPrinter, 0, Inst, STI, OS);
+  else
+    InstPrinter->printInst(&Inst, 0, "", STI, OS);
+
+  StringRef Comments = CommentToEmit;
+  if (Comments.size() && Comments.back() != '\n')
+    getCommentOS() << "\n";
+
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitPseudoProbe(
+    uint64_t Guid, uint64_t Index, uint64_t Type, uint64_t Attr,
+    uint64_t Discriminator, const MCPseudoProbeInlineStack &InlineStack,
+    MCSymbol *FnSym) {
+  OS << "\t.pseudoprobe\t" << Guid << " " << Index << " " << Type << " " << Attr;
+  if (Discriminator)
+    OS << " " << Discriminator;
+  // Emit inline stack like
+  //  @ GUIDmain:3 @ GUIDCaller:1 @ GUIDDirectCaller:11
+  for (const auto &Site : InlineStack)
+    OS << " @ " << std::get<0>(Site) << ":" << std::get<1>(Site);
+
+  OS << " ";
+  FnSym->print(OS, MAI);
+
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitRelocDirective(const MCExpr &Offset, StringRef Name,
+                                          const MCExpr *Expr, SMLoc) {
+  OS << "\t.reloc ";
+  MAI->printExpr(OS, Offset);
+  OS << ", " << Name;
+  if (Expr) {
+    OS << ", ";
+    MAI->printExpr(OS, *Expr);
+  }
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitAddrsig() {
+  OS << "\t.addrsig";
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::emitAddrsigSym(const MCSymbol *Sym) {
+  OS << "\t.addrsig_sym ";
+  Sym->print(OS, MAI);
+  EmitEOL();
+}
+
+/// EmitRawText - If this file is backed by an assembly streamer, this dumps
+/// the specified string in the output .s file.  This capability is
+/// indicated by the hasRawTextSupport() predicate.
+void MCGNUAsmStreamer::emitRawTextImpl(StringRef String) {
+  String.consume_back("\n");
+  OS << String;
+  EmitEOL();
+}
+
+void MCGNUAsmStreamer::finishImpl() {
+  // If we are generating dwarf for assembly source files dump out the sections.
+  if (getContext().getGenDwarfForAssembly())
+    MCGenDwarfInfo::Emit(this);
+
+  // Now it is time to emit debug line sections if target doesn't support .loc
+  // and .line directives.
+  if (MAI->isAIX()) {
+    MCDwarfLineTable::emit(this, getAssembler().getDWARFLinetableParams());
+    return;
+  }
+
+  // Emit the label for the line table, if requested - since the rest of the
+  // line table will be defined by .loc/.file directives, and not emitted
+  // directly, the label is the only work required here.
+  const auto &Tables = getContext().getMCDwarfLineTables();
+  if (!Tables.empty()) {
+    assert(Tables.size() == 1 && "asm output only supports one line table");
+    if (auto *Label = Tables.begin()->second.getLabel()) {
+      switchSection(getContext().getObjectFileInfo()->getDwarfLineSection(), 0);
+      emitLabel(Label);
+    }
+  }
+}
+
+void MCGNUAsmStreamer::emitDwarfUnitLength(uint64_t Length,
+                                           const Twine &Comment) {
+  // If the assembler on some target fills in the DWARF unit length, we
+  // don't want to emit the length in the compiler. For example, the AIX
+  // assembler requires the assembly file with the unit length omitted from
+  // the debug section headers. In such cases, any label we placed occurs
+  // after the implied length field. We need to adjust the reference here
+  // to account for the offset introduced by the inserted length field.
+  if (MAI->isAIX())
+    return;
+  MCStreamer::emitDwarfUnitLength(Length, Comment);
+}
+
+MCSymbol *MCGNUAsmStreamer::emitDwarfUnitLength(const Twine &Prefix,
+                                                const Twine &Comment) {
+  // If the assembler on some target fills in the DWARF unit length, we
+  // don't want to emit the length in the compiler. For example, the AIX
+  // assembler requires the assembly file with the unit length omitted from
+  // the debug section headers. In such cases, any label we placed occurs
+  // after the implied length field. We need to adjust the reference here
+  // to account for the offset introduced by the inserted length field.
+  if (MAI->isAIX())
+    return getContext().createTempSymbol(Prefix + "_end");
+  return MCStreamer::emitDwarfUnitLength(Prefix, Comment);
+}
+
+void MCGNUAsmStreamer::emitDwarfLineStartLabel(MCSymbol *StartSym) {
+  // If the assembler on some target fills in the DWARF unit length, we
+  // don't want to emit the length in the compiler. For example, the AIX
+  // assembler requires the assembly file with the unit length omitted from
+  // the debug section headers. In such cases, any label we placed occurs
+  // after the implied length field. We need to adjust the reference here
+  // to account for the offset introduced by the inserted length field.
+  MCContext &Ctx = getContext();
+  if (MAI->isAIX()) {
+    MCSymbol *DebugLineSymTmp = Ctx.createTempSymbol("debug_line_");
+    // Emit the symbol which does not contain the unit length field.
+    emitLabel(DebugLineSymTmp);
+
+    // Adjust the outer reference to account for the offset introduced by the
+    // inserted length field.
+    unsigned LengthFieldSize =
+        dwarf::getUnitLengthFieldByteSize(Ctx.getDwarfFormat());
+    const MCExpr *EntrySize = MCConstantExpr::create(LengthFieldSize, Ctx);
+    const MCExpr *OuterSym = MCBinaryExpr::createSub(
+        MCSymbolRefExpr::create(DebugLineSymTmp, Ctx), EntrySize, Ctx);
+
+    emitAssignment(StartSym, OuterSym);
+    return;
+  }
+  MCStreamer::emitDwarfLineStartLabel(StartSym);
+}
+
+void MCGNUAsmStreamer::emitDwarfLineEndEntry(MCSection *Section,
+                                             MCSymbol *LastLabel,
+                                             MCSymbol *EndLabel) {
+  // If the targets write the raw debug line data for assembly output (We can
+  // not switch to Section and add the end symbol there for assembly output)
+  // we currently use the .text end label as any section end. This will not
+  // impact the debugability as we will jump to the caller of the last function
+  // in the section before we come into the .text end address.
+  assert(MAI->isAIX() &&
+         ".loc should not be generated together with raw data!");
+
+  MCContext &Ctx = getContext();
+
+  // FIXME: use section end symbol as end of the Section. We need to consider
+  // the explicit sections and -ffunction-sections when we try to generate or
+  // find section end symbol for the Section.
+  MCSection *TextSection = Ctx.getObjectFileInfo()->getTextSection();
+  assert(TextSection->hasEnded() && ".text section is not end!");
+
+  if (!EndLabel)
+    EndLabel = TextSection->getEndSymbol(Ctx);
+  const MCAsmInfo *AsmInfo = Ctx.getAsmInfo();
+  emitDwarfAdvanceLineAddr(INT64_MAX, LastLabel, EndLabel,
+                           AsmInfo->getCodePointerSize());
+}
+
+// Generate DWARF line sections for assembly mode without .loc/.file
+void MCGNUAsmStreamer::emitDwarfAdvanceLineAddr(int64_t LineDelta,
+                                                const MCSymbol *LastLabel,
+                                                const MCSymbol *Label,
+                                                unsigned PointerSize) {
+  assert(MAI->isAIX() &&
+         ".loc/.file don't need raw data in debug line section!");
+
+  // Set to new address.
+  AddComment("Set address to " + Label->getName());
+  emitIntValue(dwarf::DW_LNS_extended_op, 1);
+  emitULEB128IntValue(PointerSize + 1);
+  emitIntValue(dwarf::DW_LNE_set_address, 1);
+  emitSymbolValue(Label, PointerSize);
+
+  if (!LastLabel) {
+    // Emit the sequence for the LineDelta (from 1) and a zero address delta.
+    AddComment("Start sequence");
+    MCDwarfLineAddr::Emit(this, MCDwarfLineTableParams(), LineDelta, 0);
+    return;
+  }
+
+  // INT64_MAX is a signal of the end of the section. Emit DW_LNE_end_sequence
+  // for the end of the section.
+  if (LineDelta == INT64_MAX) {
+    AddComment("End sequence");
+    emitIntValue(dwarf::DW_LNS_extended_op, 1);
+    emitULEB128IntValue(1);
+    emitIntValue(dwarf::DW_LNE_end_sequence, 1);
+    return;
+  }
+
+  // Advance line.
+  AddComment("Advance line " + Twine(LineDelta));
+  emitIntValue(dwarf::DW_LNS_advance_line, 1);
+  emitSLEB128IntValue(LineDelta);
+  emitIntValue(dwarf::DW_LNS_copy, 1);
+}
+
+MCStreamer *llvm::createAsmStreamer(MCContext &Context,
+                                    std::unique_ptr<formatted_raw_ostream> OS,
+                                    std::unique_ptr<MCInstPrinter> IP,
+                                    std::unique_ptr<MCCodeEmitter> CE,
+                                    std::unique_ptr<MCAsmBackend> MAB) {
+  return new MCGNUAsmStreamer(Context, std::move(OS), std::move(IP), std::move(CE),
+                           std::move(MAB));
+}
diff --git a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZHLASMAsmStreamer.h b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZHLASMAsmStreamer.h
index 42d49b77d06d8..56f922bf3b442 100644
--- a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZHLASMAsmStreamer.h
+++ b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZHLASMAsmStreamer.h
@@ -16,7 +16,7 @@
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/MC/MCAsmBackend.h"
-#include "llvm/MC/MCAsmBaseStreamer.h"
+#include "llvm/MC/MCAsmStreamer.h"
 #include "llvm/MC/MCAsmInfo.h"
 #include "llvm/MC/MCAssembler.h"
 #include "llvm/MC/MCCodeEmitter.h"
@@ -31,7 +31,7 @@
 namespace llvm {
 class MCSymbolGOFF;
 
-class SystemZHLASMAsmStreamer final : public MCAsmBaseStreamer {
+class SystemZHLASMAsmStreamer final : public MCAsmStreamer {
   constexpr static size_t InstLimit = 80;
   constexpr static size_t ContIndicatorColumn = 72;
   constexpr static size_t ContStartColumn = 15;
@@ -50,7 +50,7 @@ class SystemZHLASMAsmStreamer final : public MCAsmBaseStreamer {
                           std::unique_ptr<MCInstPrinter> Printer,
                           std::unique_ptr<MCCodeEmitter> Emitter,
                           std::unique_ptr<MCAsmBackend> AsmBackend)
-      : MCAsmBaseStreamer(Context, std::move(Emitter), std::move(AsmBackend)),
+      : MCAsmStreamer(Context, std::move(Emitter), std::move(AsmBackend)),
         FOSOwner(std::move(OS)), FOS(*FOSOwner), OS(Str),
         MAI(Context.getAsmInfo()), InstPrinter(std::move(Printer)) {
     assert(InstPrinter);



More information about the llvm-branch-commits mailing list