[llvm] 3adc908 - [DirectX][MC] Add MC support for DXContainer

Chris Bieneman via llvm-commits llvm-commits at lists.llvm.org
Fri Jun 17 19:23:29 PDT 2022


Author: Chris Bieneman
Date: 2022-06-17T21:19:32-05:00
New Revision: 3adc908b26857f8d3e1e8aed46c1102edc0244e1

URL: https://github.com/llvm/llvm-project/commit/3adc908b26857f8d3e1e8aed46c1102edc0244e1
DIFF: https://github.com/llvm/llvm-project/commit/3adc908b26857f8d3e1e8aed46c1102edc0244e1.diff

LOG: [DirectX][MC] Add MC support for DXContainer

DXContainer files resemble traditional object files in that they are
comprised of parts which resemble sections. Adding DXContainer as an
object file format in the MC layer will allow emitting DXContainer
objects through the normal object emission pipeline.

Differential Revision: https://reviews.llvm.org/D127165

Added: 
    llvm/include/llvm/MC/MCDXContainerStreamer.h
    llvm/include/llvm/MC/MCDXContainerWriter.h
    llvm/include/llvm/MC/MCSectionDXContainer.h
    llvm/lib/MC/MCDXContainerStreamer.cpp
    llvm/lib/MC/MCDXContainerWriter.cpp
    llvm/lib/MC/MCSectionDXContainer.cpp

Modified: 
    llvm/include/llvm/MC/MCContext.h
    llvm/include/llvm/MC/MCObjectFileInfo.h
    llvm/include/llvm/MC/MCSection.h
    llvm/include/llvm/MC/TargetRegistry.h
    llvm/lib/MC/CMakeLists.txt
    llvm/lib/MC/MCAsmBackend.cpp
    llvm/lib/MC/MCContext.cpp
    llvm/lib/MC/MCObjectFileInfo.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/MC/MCContext.h b/llvm/include/llvm/MC/MCContext.h
index c3a4e57fdd753..d996e3ff66e58 100644
--- a/llvm/include/llvm/MC/MCContext.h
+++ b/llvm/include/llvm/MC/MCContext.h
@@ -49,6 +49,7 @@ class MCObjectFileInfo;
 class MCRegisterInfo;
 class MCSection;
 class MCSectionCOFF;
+class MCSectionDXContainer;
 class MCSectionELF;
 class MCSectionGOFF;
 class MCSectionMachO;
@@ -129,6 +130,7 @@ class MCContext {
   BumpPtrAllocator Allocator;
 
   SpecificBumpPtrAllocator<MCSectionCOFF> COFFAllocator;
+  SpecificBumpPtrAllocator<MCSectionDXContainer> DXCAllocator;
   SpecificBumpPtrAllocator<MCSectionELF> ELFAllocator;
   SpecificBumpPtrAllocator<MCSectionMachO> MachOAllocator;
   SpecificBumpPtrAllocator<MCSectionGOFF> GOFFAllocator;
@@ -343,6 +345,7 @@ class MCContext {
   std::map<std::string, MCSectionGOFF *> GOFFUniquingMap;
   std::map<WasmSectionKey, MCSectionWasm *> WasmUniquingMap;
   std::map<XCOFFSectionKey, MCSectionXCOFF *> XCOFFUniquingMap;
+  StringMap<MCSectionDXContainer *> DXCUniquingMap;
   StringMap<bool> RelSecNames;
 
   SpecificBumpPtrAllocator<MCSubtargetInfo> MCSubtargetAllocator;
@@ -660,6 +663,9 @@ class MCContext {
   MCSectionWasm *getWasmSection(const Twine &Section, SectionKind K,
                                 unsigned Flags, const MCSymbolWasm *Group,
                                 unsigned UniqueID, const char *BeginSymName);
+  
+  /// Get the section for the provided Section name
+  MCSectionDXContainer *getDXContainerSection(StringRef Section, SectionKind K);
 
   bool hasXCOFFSection(StringRef Section,
                        XCOFF::CsectProperties CsectProp) const;

diff  --git a/llvm/include/llvm/MC/MCDXContainerStreamer.h b/llvm/include/llvm/MC/MCDXContainerStreamer.h
new file mode 100644
index 0000000000000..ef1a95f71778b
--- /dev/null
+++ b/llvm/include/llvm/MC/MCDXContainerStreamer.h
@@ -0,0 +1,49 @@
+//===- MCDXContainerStreamer.h - MCDXContainerStreamer Interface ---*- 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
+//
+//===----------------------------------------------------------------------===//
+//
+// Overrides MCObjectStreamer to disable all unnecessary features with stubs.
+// The DXContainer format isn't a fully featured object format. It doesn't
+// support symbols, and initially it will not support instruction data since it
+// is used as a bitcode container for DXIL.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_MC_MCDXCONTAINERSTREAMER_H
+#define LLVM_MC_MCDXCONTAINERSTREAMER_H
+
+#include "llvm/MC/MCAsmBackend.h"
+#include "llvm/MC/MCCodeEmitter.h"
+#include "llvm/MC/MCObjectStreamer.h"
+#include "llvm/MC/MCObjectWriter.h"
+
+namespace llvm {
+class MCAssembler;
+class MCExpr;
+class MCInst;
+class raw_ostream;
+
+class MCDXContainerStreamer : public MCObjectStreamer {
+public:
+  MCDXContainerStreamer(MCContext &Context, std::unique_ptr<MCAsmBackend> TAB,
+                        std::unique_ptr<MCObjectWriter> OW,
+                        std::unique_ptr<MCCodeEmitter> Emitter)
+      : MCObjectStreamer(Context, std::move(TAB), std::move(OW),
+                         std::move(Emitter)) {}
+
+  bool emitSymbolAttribute(MCSymbol *, MCSymbolAttr) override { return false; }
+  void emitCommonSymbol(MCSymbol *, uint64_t, unsigned) override {}
+  void emitZerofill(MCSection *, MCSymbol *Symbol = nullptr, uint64_t Size = 0,
+                    unsigned ByteAlignment = 0, SMLoc Loc = SMLoc()) override {}
+
+private:
+  void emitInstToData(const MCInst &, const MCSubtargetInfo &) override;
+};
+
+} // end namespace llvm
+
+#endif // LLVM_MC_MCDXCONTAINERSTREAMER_H

diff  --git a/llvm/include/llvm/MC/MCDXContainerWriter.h b/llvm/include/llvm/MC/MCDXContainerWriter.h
new file mode 100644
index 0000000000000..8ecb86c8a16ff
--- /dev/null
+++ b/llvm/include/llvm/MC/MCDXContainerWriter.h
@@ -0,0 +1,45 @@
+//===- llvm/MC/MCDXContainerWriter.h - DXContainer Writer -*- 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_MC_MCDXCONTAINERWRITER_H
+#define LLVM_MC_MCDXCONTAINERWRITER_H
+
+#include "llvm/ADT/Triple.h"
+#include "llvm/MC/MCObjectWriter.h"
+
+namespace llvm {
+
+class raw_pwrite_stream;
+
+class MCDXContainerTargetWriter : public MCObjectTargetWriter {
+protected:
+  MCDXContainerTargetWriter() {}
+
+public:
+  virtual ~MCDXContainerTargetWriter();
+
+  Triple::ObjectFormatType getFormat() const override {
+    return Triple::DXContainer;
+  }
+  static bool classof(const MCObjectTargetWriter *W) {
+    return W->getFormat() == Triple::DXContainer;
+  }
+};
+
+/// Construct a new DXContainer writer instance.
+///
+/// \param MOTW - The target specific DXContainer writer subclass.
+/// \param OS - The stream to write to.
+/// \returns The constructed object writer.
+std::unique_ptr<MCObjectWriter>
+createDXContainerObjectWriter(std::unique_ptr<MCDXContainerTargetWriter> MOTW,
+                              raw_pwrite_stream &OS);
+
+} // end namespace llvm
+
+#endif // LLVM_MC_MCDXCONTAINERWRITER_H

diff  --git a/llvm/include/llvm/MC/MCObjectFileInfo.h b/llvm/include/llvm/MC/MCObjectFileInfo.h
index e4ae85e915316..ebc9b95d6d4e0 100644
--- a/llvm/include/llvm/MC/MCObjectFileInfo.h
+++ b/llvm/include/llvm/MC/MCObjectFileInfo.h
@@ -459,6 +459,7 @@ class MCObjectFileInfo {
   void initSPIRVMCObjectFileInfo(const Triple &T);
   void initWasmMCObjectFileInfo(const Triple &T);
   void initXCOFFMCObjectFileInfo(const Triple &T);
+  void initDXContainerObjectFileInfo(const Triple &T);
   MCSection *getDwarfComdatSection(const char *Name, uint64_t Hash) const;
 
 public:

diff  --git a/llvm/include/llvm/MC/MCSection.h b/llvm/include/llvm/MC/MCSection.h
index 46ccd9f85d9e0..2f7e17123c19d 100644
--- a/llvm/include/llvm/MC/MCSection.h
+++ b/llvm/include/llvm/MC/MCSection.h
@@ -48,6 +48,7 @@ class MCSection {
     SV_Wasm,
     SV_XCOFF,
     SV_SPIRV,
+    SV_DXContainer,
   };
 
   /// Express the state of bundle locked groups while emitting code.

diff  --git a/llvm/include/llvm/MC/MCSectionDXContainer.h b/llvm/include/llvm/MC/MCSectionDXContainer.h
new file mode 100644
index 0000000000000..014684a935295
--- /dev/null
+++ b/llvm/include/llvm/MC/MCSectionDXContainer.h
@@ -0,0 +1,38 @@
+//===- MCSectionDXContainer.h - DXContainer MC Sections ---------*- 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares the MCSectionDXContainer class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_MC_MCSECTIONDXCONTAINER_H
+#define LLVM_MC_MCSECTIONDXCONTAINER_H
+
+#include "llvm/MC/MCSection.h"
+#include "llvm/MC/SectionKind.h"
+
+namespace llvm {
+
+class MCSymbol;
+
+class MCSectionDXContainer final : public MCSection {
+  friend class MCContext;
+
+  MCSectionDXContainer(StringRef Name, SectionKind K, MCSymbol *Begin)
+      : MCSection(SV_DXContainer, Name, K, Begin) {}
+
+public:
+  void printSwitchToSection(const MCAsmInfo &, const Triple &, raw_ostream &,
+                            const MCExpr *) const override;
+  bool useCodeAlign() const override { return false; }
+  bool isVirtualSection() const override { return false; }
+};
+
+} // end namespace llvm
+
+#endif // LLVM_MC_MCSECTIONDXCONTAINER_H

diff  --git a/llvm/include/llvm/MC/TargetRegistry.h b/llvm/include/llvm/MC/TargetRegistry.h
index 0b1a0fec667ff..4ff358df4a343 100644
--- a/llvm/include/llvm/MC/TargetRegistry.h
+++ b/llvm/include/llvm/MC/TargetRegistry.h
@@ -114,6 +114,11 @@ MCStreamer *createSPIRVStreamer(MCContext &Ctx,
                                 std::unique_ptr<MCObjectWriter> &&OW,
                                 std::unique_ptr<MCCodeEmitter> &&CE,
                                 bool RelaxAll);
+MCStreamer *createDXContainerStreamer(MCContext &Ctx,
+                                      std::unique_ptr<MCAsmBackend> &&TAB,
+                                      std::unique_ptr<MCObjectWriter> &&OW,
+                                      std::unique_ptr<MCCodeEmitter> &&CE,
+                                      bool RelaxAll);
 
 MCRelocationInfo *createMCRelocationInfo(const Triple &TT, MCContext &Ctx);
 
@@ -211,6 +216,12 @@ class Target {
                       std::unique_ptr<MCAsmBackend> &&TAB,
                       std::unique_ptr<MCObjectWriter> &&OW,
                       std::unique_ptr<MCCodeEmitter> &&Emitter, bool RelaxAll);
+  
+  using DXContainerStreamerCtorTy =
+      MCStreamer *(*)(const Triple &T, MCContext &Ctx,
+                      std::unique_ptr<MCAsmBackend> &&TAB,
+                      std::unique_ptr<MCObjectWriter> &&OW,
+                      std::unique_ptr<MCCodeEmitter> &&Emitter, bool RelaxAll);
 
   using NullTargetStreamerCtorTy = MCTargetStreamer *(*)(MCStreamer &S);
   using AsmTargetStreamerCtorTy = MCTargetStreamer *(*)(
@@ -313,6 +324,7 @@ class Target {
   WasmStreamerCtorTy WasmStreamerCtorFn = nullptr;
   XCOFFStreamerCtorTy XCOFFStreamerCtorFn = nullptr;
   SPIRVStreamerCtorTy SPIRVStreamerCtorFn = nullptr;
+  DXContainerStreamerCtorTy DXContainerStreamerCtorFn = nullptr;
 
   /// Construction function for this target's null TargetStreamer, if
   /// registered (default = nullptr).
@@ -541,8 +553,6 @@ class Target {
     switch (T.getObjectFormat()) {
     case Triple::UnknownObjectFormat:
       llvm_unreachable("Unknown object format");
-    case Triple::DXContainer:
-      llvm_unreachable("DXContainer is unsupported through MC");
     case Triple::COFF:
       assert(T.isOSWindows() && "only Windows COFF is supported");
       S = COFFStreamerCtorFn(Ctx, std::move(TAB), std::move(OW),
@@ -593,6 +603,14 @@ class Target {
         S = createSPIRVStreamer(Ctx, std::move(TAB), std::move(OW),
                                 std::move(Emitter), RelaxAll);
       break;
+    case Triple::DXContainer:
+      if (DXContainerStreamerCtorFn)
+        S = DXContainerStreamerCtorFn(T, Ctx, std::move(TAB), std::move(OW),
+                              std::move(Emitter), RelaxAll);
+      else
+        S = createDXContainerStreamer(Ctx, std::move(TAB), std::move(OW),
+                                      std::move(Emitter), RelaxAll);
+      break;
     }
     if (ObjectTargetStreamerCtorFn)
       ObjectTargetStreamerCtorFn(*S, STI);
@@ -977,6 +995,10 @@ struct TargetRegistry {
     T.SPIRVStreamerCtorFn = Fn;
   }
 
+  static void RegisterDXContainerStreamer(Target &T, Target::DXContainerStreamerCtorTy Fn) {
+    T.DXContainerStreamerCtorFn = Fn;
+  }
+
   static void RegisterWasmStreamer(Target &T, Target::WasmStreamerCtorTy Fn) {
     T.WasmStreamerCtorFn = Fn;
   }

diff  --git a/llvm/lib/MC/CMakeLists.txt b/llvm/lib/MC/CMakeLists.txt
index bb245172fdc9a..8beab9b4aea9e 100644
--- a/llvm/lib/MC/CMakeLists.txt
+++ b/llvm/lib/MC/CMakeLists.txt
@@ -16,6 +16,8 @@ add_llvm_component_library(LLVMMC
   MCCodeView.cpp
   MCContext.cpp
   MCDwarf.cpp
+  MCDXContainerStreamer.cpp
+  MCDXContainerWriter.cpp
   MCELFObjectTargetWriter.cpp
   MCELFStreamer.cpp
   MCExpr.cpp
@@ -38,6 +40,7 @@ add_llvm_component_library(LLVMMC
   MCSchedule.cpp
   MCSection.cpp
   MCSectionCOFF.cpp
+  MCSectionDXContainer.cpp
   MCSectionELF.cpp
   MCSectionMachO.cpp
   MCSectionWasm.cpp

diff  --git a/llvm/lib/MC/MCAsmBackend.cpp b/llvm/lib/MC/MCAsmBackend.cpp
index df07f06205401..4ed9d8593336f 100644
--- a/llvm/lib/MC/MCAsmBackend.cpp
+++ b/llvm/lib/MC/MCAsmBackend.cpp
@@ -9,6 +9,7 @@
 #include "llvm/MC/MCAsmBackend.h"
 #include "llvm/ADT/None.h"
 #include "llvm/ADT/STLArrayExtras.h"
+#include "llvm/MC/MCDXContainerWriter.h"
 #include "llvm/MC/MCELFObjectWriter.h"
 #include "llvm/MC/MCFixupKindInfo.h"
 #include "llvm/MC/MCMachObjectWriter.h"
@@ -49,6 +50,9 @@ MCAsmBackend::createObjectWriter(raw_pwrite_stream &OS) const {
   case Triple::XCOFF:
     return createXCOFFObjectWriter(
         cast<MCXCOFFObjectTargetWriter>(std::move(TW)), OS);
+  case Triple::DXContainer:
+    return createDXContainerObjectWriter(
+        cast<MCDXContainerTargetWriter>(std::move(TW)), OS);
   default:
     llvm_unreachable("unexpected object format");
   }

diff  --git a/llvm/lib/MC/MCContext.cpp b/llvm/lib/MC/MCContext.cpp
index 52bf48b6d242b..1c0c711a4e3a0 100644
--- a/llvm/lib/MC/MCContext.cpp
+++ b/llvm/lib/MC/MCContext.cpp
@@ -26,6 +26,7 @@
 #include "llvm/MC/MCInst.h"
 #include "llvm/MC/MCLabel.h"
 #include "llvm/MC/MCSectionCOFF.h"
+#include "llvm/MC/MCSectionDXContainer.h"
 #include "llvm/MC/MCSectionELF.h"
 #include "llvm/MC/MCSectionGOFF.h"
 #include "llvm/MC/MCSectionMachO.h"
@@ -145,6 +146,7 @@ void MCContext::reset() {
 
   // Call the destructors so the fragments are freed
   COFFAllocator.DestroyAll();
+  DXCAllocator.DestroyAll();
   ELFAllocator.DestroyAll();
   GOFFAllocator.DestroyAll();
   MachOAllocator.DestroyAll();
@@ -176,6 +178,7 @@ void MCContext::reset() {
   COFFUniquingMap.clear();
   WasmUniquingMap.clear();
   XCOFFUniquingMap.clear();
+  DXCUniquingMap.clear();
 
   ELFEntrySizeMap.clear();
   ELFSeenGenericMergeableSections.clear();
@@ -838,6 +841,29 @@ MCSectionSPIRV *MCContext::getSPIRVSection() {
   return Result;
 }
 
+MCSectionDXContainer *MCContext::getDXContainerSection(StringRef Section,
+                                                       SectionKind K) {
+  // Do the lookup, if we have a hit, return it.
+  auto ItInsertedPair = DXCUniquingMap.try_emplace(Section);
+  if (!ItInsertedPair.second)
+    return ItInsertedPair.first->second;
+
+  auto MapIt = ItInsertedPair.first;
+  // Grab the name from the StringMap. Since the Section is going to keep a
+  // copy of this StringRef we need to make sure the underlying string stays
+  // alive as long as we need it.
+  StringRef Name = MapIt->first();
+  MapIt->second =
+      new (DXCAllocator.Allocate()) MCSectionDXContainer(Name, K, nullptr);
+
+  // The first fragment will store the header
+  auto *F = new MCDataFragment();
+  MapIt->second->getFragmentList().insert(MapIt->second->begin(), F);
+  F->setParent(MapIt->second);
+
+  return MapIt->second;
+}
+
 MCSubtargetInfo &MCContext::getSubtargetCopy(const MCSubtargetInfo &STI) {
   return *new (MCSubtargetAllocator.Allocate()) MCSubtargetInfo(STI);
 }

diff  --git a/llvm/lib/MC/MCDXContainerStreamer.cpp b/llvm/lib/MC/MCDXContainerStreamer.cpp
new file mode 100644
index 0000000000000..3cb452f3dfa55
--- /dev/null
+++ b/llvm/lib/MC/MCDXContainerStreamer.cpp
@@ -0,0 +1,31 @@
+//===- lib/MC/MCDXContainerStreamer.cpp - DXContainer Impl ----*- 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains the object streamer for DXContainer files.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/MC/MCDXContainerStreamer.h"
+#include "llvm/MC/MCAssembler.h"
+#include "llvm/MC/TargetRegistry.h"
+
+using namespace llvm;
+
+void MCDXContainerStreamer::emitInstToData(const MCInst &,
+                                           const MCSubtargetInfo &) {}
+
+MCStreamer *llvm::createDXContainerStreamer(
+    MCContext &Context, std::unique_ptr<MCAsmBackend> &&MAB,
+    std::unique_ptr<MCObjectWriter> &&OW, std::unique_ptr<MCCodeEmitter> &&CE,
+    bool RelaxAll) {
+  auto *S = new MCDXContainerStreamer(Context, std::move(MAB), std::move(OW),
+                                      std::move(CE));
+  if (RelaxAll)
+    S->getAssembler().setRelaxAll(true);
+  return S;
+}

diff  --git a/llvm/lib/MC/MCDXContainerWriter.cpp b/llvm/lib/MC/MCDXContainerWriter.cpp
new file mode 100644
index 0000000000000..db2cfa7ea6307
--- /dev/null
+++ b/llvm/lib/MC/MCDXContainerWriter.cpp
@@ -0,0 +1,143 @@
+//===- llvm/MC/MCDXContainerWriter.cpp - DXContainer Writer -----*- 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/MCDXContainerWriter.h"
+#include "llvm/BinaryFormat/DXContainer.h"
+#include "llvm/MC/MCAsmLayout.h"
+#include "llvm/MC/MCAssembler.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCSection.h"
+#include "llvm/MC/MCValue.h"
+#include "llvm/Support/Alignment.h"
+#include "llvm/Support/EndianStream.h"
+
+using namespace llvm;
+
+MCDXContainerTargetWriter::~MCDXContainerTargetWriter() {}
+
+namespace {
+class DXContainerObjectWriter : public MCObjectWriter {
+  ::support::endian::Writer W;
+
+  /// The target specific DXContainer writer instance.
+  std::unique_ptr<MCDXContainerTargetWriter> TargetObjectWriter;
+
+public:
+  DXContainerObjectWriter(std::unique_ptr<MCDXContainerTargetWriter> MOTW,
+                          raw_pwrite_stream &OS)
+      : W(OS, support::little), TargetObjectWriter(std::move(MOTW)) {}
+
+  ~DXContainerObjectWriter() override {}
+
+private:
+  void recordRelocation(MCAssembler &Asm, const MCAsmLayout &Layout,
+                        const MCFragment *Fragment, const MCFixup &Fixup,
+                        MCValue Target, uint64_t &FixedValue) override {}
+
+  void executePostLayoutBinding(MCAssembler &Asm,
+                                const MCAsmLayout &Layout) override {}
+
+  uint64_t writeObject(MCAssembler &Asm, const MCAsmLayout &Layout) override;
+};
+} // namespace
+
+uint64_t DXContainerObjectWriter::writeObject(MCAssembler &Asm,
+                                              const MCAsmLayout &Layout) {
+  // Start the file size as the header plus the size of the part offsets.
+  // Presently DXContainer files usually contain 7-10 parts. Reserving space for
+  // 16 part offsets gives us a little room for growth.
+  llvm::SmallVector<uint64_t, 16> PartOffsets;
+  uint64_t PartOffset = 0;
+  for (const MCSection &Sec : Asm) {
+    uint64_t SectionSize = Layout.getSectionAddressSize(&Sec);
+    // Skip empty sections.
+    if (SectionSize == 0)
+      continue;
+
+    assert(SectionSize < std::numeric_limits<uint32_t>::max() &&
+           "Section size too large for DXContainer");
+
+    PartOffsets.push_back(PartOffset);
+    PartOffset += sizeof(dxbc::PartHeader) + SectionSize;
+    PartOffset = alignTo(PartOffset, Align(4ul));
+  }
+  assert(PartOffset < std::numeric_limits<uint32_t>::max() &&
+         "Part data too large for DXContainer");
+
+  uint64_t PartStart =
+      sizeof(dxbc::Header) + (PartOffsets.size() * sizeof(uint32_t));
+  uint64_t FileSize = PartStart + PartOffset;
+  assert(FileSize < std::numeric_limits<uint32_t>::max() &&
+         "File size too large for DXContainer");
+
+  // Write the header.
+  W.write<char>({'D', 'X', 'B', 'C'});
+  // Write 16-bytes of 0's for the hash.
+  W.OS.write_zeros(16);
+  // Write 1.0 for file format version.
+  W.write<uint16_t>(1u);
+  W.write<uint16_t>(0u);
+  // Write the file size.
+  W.write<uint32_t>(static_cast<uint32_t>(FileSize));
+  // Write the number of parts.
+  W.write<uint32_t>(static_cast<uint32_t>(PartOffsets.size()));
+  // Write the offsets for the part headers for each part.
+  for (uint64_t Offset : PartOffsets)
+    W.write<uint32_t>(static_cast<uint32_t>(PartStart + Offset));
+
+  for (const MCSection &Sec : Asm) {
+    uint64_t SectionSize = Layout.getSectionAddressSize(&Sec);
+    // Skip empty sections.
+    if (SectionSize == 0)
+      continue;
+
+    unsigned Start = W.OS.tell();
+    // Write section header.
+    W.write<char>(ArrayRef<char>(Sec.getName().data(), 4));
+
+    uint64_t PartSize = SectionSize + sizeof(dxbc::PartHeader);
+
+    if (Sec.getName() == "DXIL")
+      PartSize += sizeof(dxbc::ProgramHeader);
+    // DXContainer parts should be 4-byte aligned.
+    PartSize = alignTo(PartSize, Align(4));
+    W.write<uint32_t>(static_cast<uint32_t>(PartSize));
+    if (Sec.getName() == "DXIL") {
+      dxbc::ProgramHeader Header;
+      bzero(reinterpret_cast<void *>(&Header), sizeof(dxbc::ProgramHeader));
+
+      const Triple &TT = Asm.getContext().getTargetTriple();
+      VersionTuple Version = TT.getOSVersion();
+      Header.MajorVersion = static_cast<uint8_t>(Version.getMajor());
+      if (Version.getMinor().hasValue())
+        Header.MinorVersion = static_cast<uint8_t>(*Version.getMinor());
+      if (TT.hasEnvironment())
+        Header.ShaderKind =
+            static_cast<uint16_t>(TT.getEnvironment() - Triple::Pixel);
+
+      // The program header's size field is in 32-bit words.
+      Header.Size = (SectionSize + sizeof(dxbc::ProgramHeader) + 3) / 4;
+      memcpy(Header.Bitcode.Magic, "DXIL", 4);
+      Header.Bitcode.Offset = sizeof(dxbc::BitcodeHeader);
+      Header.Bitcode.Size = SectionSize;
+      if (sys::IsBigEndianHost)
+        Header.swapBytes();
+      W.write<char>(ArrayRef<char>(reinterpret_cast<char *>(&Header),
+                                   sizeof(dxbc::ProgramHeader)));
+    }
+    Asm.writeSectionData(W.OS, &Sec, Layout);
+    unsigned Size = W.OS.tell() - Start;
+    W.OS.write_zeros(offsetToAlignment(Size, Align(4)));
+  }
+  return 0;
+}
+
+std::unique_ptr<MCObjectWriter> llvm::createDXContainerObjectWriter(
+    std::unique_ptr<MCDXContainerTargetWriter> MOTW, raw_pwrite_stream &OS) {
+  return std::make_unique<DXContainerObjectWriter>(std::move(MOTW), OS);
+}

diff  --git a/llvm/lib/MC/MCObjectFileInfo.cpp b/llvm/lib/MC/MCObjectFileInfo.cpp
index bb39e5aaad7f4..d6fe952c0c1d8 100644
--- a/llvm/lib/MC/MCObjectFileInfo.cpp
+++ b/llvm/lib/MC/MCObjectFileInfo.cpp
@@ -16,6 +16,7 @@
 #include "llvm/MC/MCContext.h"
 #include "llvm/MC/MCSection.h"
 #include "llvm/MC/MCSectionCOFF.h"
+#include "llvm/MC/MCSectionDXContainer.h"
 #include "llvm/MC/MCSectionELF.h"
 #include "llvm/MC/MCSectionGOFF.h"
 #include "llvm/MC/MCSectionMachO.h"
@@ -1019,6 +1020,11 @@ void MCObjectFileInfo::initXCOFFMCObjectFileInfo(const Triple &T) {
       /* MultiSymbolsAllowed */ true, ".dwmac", XCOFF::SSUBTYP_DWMAC);
 }
 
+void MCObjectFileInfo::initDXContainerObjectFileInfo(const Triple &T) {
+  // At the moment the DXBC section should end up empty.
+  TextSection = Ctx->getDXContainerSection("DXBC", SectionKind::getText());
+}
+
 MCObjectFileInfo::~MCObjectFileInfo() = default;
 
 void MCObjectFileInfo::initMCObjectFileInfo(MCContext &MCCtx, bool PIC,
@@ -1067,6 +1073,7 @@ void MCObjectFileInfo::initMCObjectFileInfo(MCContext &MCCtx, bool PIC,
     initXCOFFMCObjectFileInfo(TheTriple);
     break;
   case MCContext::IsDXContainer:
+    initDXContainerObjectFileInfo(TheTriple);
     break;
   }
 }

diff  --git a/llvm/lib/MC/MCSectionDXContainer.cpp b/llvm/lib/MC/MCSectionDXContainer.cpp
new file mode 100644
index 0000000000000..065b506c21ce3
--- /dev/null
+++ b/llvm/lib/MC/MCSectionDXContainer.cpp
@@ -0,0 +1,15 @@
+//===- lib/MC/MCSectionDXContainer.cpp - DXContainer Section --------------===//
+//
+// 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/MCSectionDXContainer.h"
+
+using namespace llvm;
+
+void MCSectionDXContainer::printSwitchToSection(const MCAsmInfo &,
+                                                const Triple &, raw_ostream &,
+                                                const MCExpr *) const {}


        


More information about the llvm-commits mailing list