[DirectX] Add DirectX target object writer
authorChris Bieneman <chris.bieneman@me.com>
Mon, 6 Jun 2022 21:27:40 +0000 (16:27 -0500)
committerChris Bieneman <chris.bieneman@me.com>
Sat, 18 Jun 2022 02:33:08 +0000 (21:33 -0500)
This is the last piece to bring together writing DXContainer files
containing DXIL through the DirectX backend.

While this change only has one test, all of the tests under
llvm/test/tools/dxil-dis also exercise this code. With this change the
output object file type for the dxil target is now DXContainer. Each of
the existing tests will generate DXContainer files, and the dxil-dis
tests additionally verify that the DXContainers generated are
well-formed and can be parsed by the DirectXShaderCompiler tools.

Depends on D127153 and D127165

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

llvm/lib/Target/DirectX/DirectXSubtarget.cpp
llvm/lib/Target/DirectX/DirectXSubtarget.h
llvm/lib/Target/DirectX/DirectXTargetMachine.cpp
llvm/lib/Target/DirectX/MCTargetDesc/CMakeLists.txt
llvm/lib/Target/DirectX/MCTargetDesc/DirectXContainerObjectWriter.cpp [new file with mode: 0644]
llvm/lib/Target/DirectX/MCTargetDesc/DirectXContainerObjectWriter.h [new file with mode: 0644]
llvm/lib/Target/DirectX/MCTargetDesc/DirectXMCTargetDesc.cpp
llvm/test/CodeGen/DirectX/embed-dxil.ll

index 96023224f02897ca2700e026d57a09e6ce1f84d7..526b7d29fb13ed5d91e98a96b6c2c2c218709768 100644 (file)
@@ -24,4 +24,6 @@ using namespace llvm;
 
 DirectXSubtarget::DirectXSubtarget(const Triple &TT, StringRef CPU,
                                    StringRef FS, const DirectXTargetMachine &TM)
-    : DirectXGenSubtargetInfo(TT, CPU, CPU, FS), TL(TM, *this) {}
+    : DirectXGenSubtargetInfo(TT, CPU, CPU, FS), FL(*this), TL(TM, *this) {}
+
+void DirectXSubtarget::anchor() {}
index 8840c0e038fac93388e70070ad26622733c543fc..464d05a0e1ffef58be8c10385539f36b5213147b 100644 (file)
@@ -13,6 +13,8 @@
 #ifndef LLVM_DIRECTX_DIRECTXSUBTARGET_H
 #define LLVM_DIRECTX_DIRECTXSUBTARGET_H
 
+#include "DirectXFrameLowering.h"
+#include "DirectXInstrInfo.h"
 #include "DirectXTargetLowering.h"
 #include "llvm/CodeGen/TargetSubtargetInfo.h"
 #include "llvm/IR/DataLayout.h"
@@ -26,7 +28,11 @@ namespace llvm {
 class DirectXTargetMachine;
 
 class DirectXSubtarget : public DirectXGenSubtargetInfo {
+  DirectXFrameLowering FL;
   DirectXTargetLowering TL;
+  DirectXInstrInfo InstrInfo;
+
+  virtual void anchor(); // virtual anchor method
 
 public:
   DirectXSubtarget(const Triple &TT, StringRef CPU, StringRef FS,
@@ -39,6 +45,10 @@ public:
   const DirectXTargetLowering *getTargetLowering() const override {
     return &TL;
   }
+
+  const DirectXFrameLowering *getFrameLowering() const override { return &FL; }
+
+  const DirectXInstrInfo *getInstrInfo() const override { return &InstrInfo; }
 };
 
 } // end namespace llvm
index 91d9ebb3d6960965e742a5837cb344fa6544ee44..44bef80ea6fb859ce695eb4f64099a5c452df36e 100644 (file)
 #include "DirectXSubtarget.h"
 #include "DirectXTargetTransformInfo.h"
 #include "TargetInfo/DirectXTargetInfo.h"
+#include "llvm/CodeGen/MachineModuleInfo.h"
 #include "llvm/CodeGen/Passes.h"
 #include "llvm/CodeGen/TargetPassConfig.h"
 #include "llvm/IR/IRPrintingPasses.h"
 #include "llvm/IR/LegacyPassManager.h"
+#include "llvm/MC/MCSectionDXContainer.h"
 #include "llvm/MC/SectionKind.h"
 #include "llvm/MC/TargetRegistry.h"
 #include "llvm/Support/CodeGen.h"
@@ -45,7 +47,7 @@ public:
 
   MCSection *getExplicitSectionGlobal(const GlobalObject *GO, SectionKind Kind,
                                       const TargetMachine &TM) const override {
-    llvm_unreachable("Not supported!");
+    return getContext().getDXContainerSection(GO->getSection(), Kind);
   }
 
 protected:
@@ -79,7 +81,9 @@ DirectXTargetMachine::DirectXTargetMachine(const Target &T, const Triple &TT,
                         TT, CPU, FS, Options, Reloc::Static, CodeModel::Small,
                         OL),
       TLOF(std::make_unique<DXILTargetObjectFile>()),
-      Subtarget(std::make_unique<DirectXSubtarget>(TT, CPU, FS, *this)) {}
+      Subtarget(std::make_unique<DirectXSubtarget>(TT, CPU, FS, *this)) {
+  initAsmInfo();
+}
 
 DirectXTargetMachine::~DirectXTargetMachine() {}
 
@@ -90,16 +94,23 @@ bool DirectXTargetMachine::addPassesToEmitFile(
   PM.add(createDXILOpLoweringLegacyPass());
   PM.add(createDXILPrepareModulePass());
   PM.add(createDXILTranslateMetadataPass());
+  if (TargetPassConfig::willCompleteCodeGenPipeline()) {
+    PM.add(createDXILEmbedderPass());
+  }
   switch (FileType) {
   case CGFT_AssemblyFile:
-    if (TargetPassConfig::willCompleteCodeGenPipeline()) {
-      PM.add(createDXILEmbedderPass());
-    }
     PM.add(createPrintModulePass(Out, "", true));
     break;
   case CGFT_ObjectFile:
-    // TODO: Use MC Object streamer to write DXContainer
-    PM.add(createDXILWriterPass(Out));
+    if (TargetPassConfig::willCompleteCodeGenPipeline()) {
+      if (!MMIWP)
+        MMIWP = new MachineModuleInfoWrapperPass(this);
+      PM.add(MMIWP);
+      if (addAsmPrinter(PM, Out, DwoOut, FileType,
+                        MMIWP->getMMI().getContext()))
+        return true;
+    } else
+      PM.add(createDXILWriterPass(Out));
     break;
   case CGFT_Null:
     break;
index 7ffa93a1faded6b0550a9acb3b806dfc69b142ee..392fb99b490cfcd3e56f382788817aca6620983c 100644 (file)
@@ -1,4 +1,5 @@
 add_llvm_component_library(LLVMDirectXDesc
+  DirectXContainerObjectWriter.cpp
   DirectXMCTargetDesc.cpp
 
   LINK_COMPONENTS
diff --git a/llvm/lib/Target/DirectX/MCTargetDesc/DirectXContainerObjectWriter.cpp b/llvm/lib/Target/DirectX/MCTargetDesc/DirectXContainerObjectWriter.cpp
new file mode 100644 (file)
index 0000000..78ccbc4
--- /dev/null
@@ -0,0 +1,28 @@
+//===-- DirectXContainerObjectWriter.cpp - DX object 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains DXContainer object writers for the DirectX backend.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DirectXContainerObjectWriter.h"
+#include "llvm/MC/MCDXContainerWriter.h"
+
+using namespace llvm;
+
+namespace {
+class DirectXContainerObjectWriter : public MCDXContainerTargetWriter {
+public:
+  DirectXContainerObjectWriter() : MCDXContainerTargetWriter() {}
+};
+} // namespace
+
+std::unique_ptr<MCObjectTargetWriter>
+llvm::createDXContainerTargetObjectWriter() {
+  return std::make_unique<DirectXContainerObjectWriter>();
+}
diff --git a/llvm/lib/Target/DirectX/MCTargetDesc/DirectXContainerObjectWriter.h b/llvm/lib/Target/DirectX/MCTargetDesc/DirectXContainerObjectWriter.h
new file mode 100644 (file)
index 0000000..a6fbdc8
--- /dev/null
@@ -0,0 +1,24 @@
+//===-- DirectXContainerObjectWriter.h - DX object 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains DXContainer object writers for the DirectX backend.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DIRECTX_DIRECTXCONTAINEROBJECTWRITER_H
+#define LLVM_DIRECTX_DIRECTXCONTAINEROBJECTWRITER_H
+
+#include "llvm/MC/MCObjectWriter.h"
+
+namespace llvm {
+
+std::unique_ptr<MCObjectTargetWriter> createDXContainerTargetObjectWriter();
+
+}
+
+#endif // LLVM_DIRECTX_DIRECTXCONTAINEROBJECTWRITER_H
index be690b728705758e73cadc827c6b8acc44af7cfc..0c97ab62a37b56814266faf322d11f927d8ff117 100644 (file)
 ///
 //===----------------------------------------------------------------------===//
 
+#include "DirectXMCTargetDesc.h"
+#include "DirectXContainerObjectWriter.h"
+#include "TargetInfo/DirectXTargetInfo.h"
 #include "llvm/ADT/Triple.h"
+#include "llvm/MC/LaneBitmask.h"
 #include "llvm/MC/MCAsmBackend.h"
+#include "llvm/MC/MCAsmInfo.h"
 #include "llvm/MC/MCCodeEmitter.h"
+#include "llvm/MC/MCDXContainerWriter.h"
+#include "llvm/MC/MCInstPrinter.h"
 #include "llvm/MC/MCInstrInfo.h"
+#include "llvm/MC/MCRegisterInfo.h"
 #include "llvm/MC/MCSchedule.h"
 #include "llvm/MC/MCSubtargetInfo.h"
+#include "llvm/MC/TargetRegistry.h"
 #include "llvm/Support/Compiler.h"
+#include <memory>
 
 using namespace llvm;
 
+#define GET_INSTRINFO_MC_DESC
+#define GET_INSTRINFO_MC_HELPERS
+#include "DirectXGenInstrInfo.inc"
+
 #define GET_SUBTARGETINFO_MC_DESC
 #include "DirectXGenSubtargetInfo.inc"
 
-extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeDirectXTargetMC() {}
+#define GET_REGINFO_MC_DESC
+#include "DirectXGenRegisterInfo.inc"
+
+namespace {
+
+// DXILInstPrinter is a null stub because DXIL instructions aren't printed.
+class DXILInstPrinter : public MCInstPrinter {
+public:
+  DXILInstPrinter(const MCAsmInfo &MAI, const MCInstrInfo &MII,
+                  const MCRegisterInfo &MRI)
+      : MCInstPrinter(MAI, MII, MRI) {}
+
+  void printInst(const MCInst *MI, uint64_t Address, StringRef Annot,
+                 const MCSubtargetInfo &STI, raw_ostream &O) override {}
+
+  std::pair<const char *, uint64_t> getMnemonic(const MCInst *MI) override {
+    return std::make_pair<const char *, uint64_t>("", 0ull);
+  }
+
+private:
+};
+
+class DXILMCCodeEmitter : public MCCodeEmitter {
+public:
+  DXILMCCodeEmitter() {}
+
+  void encodeInstruction(const MCInst &MI, raw_ostream &OS,
+                         SmallVectorImpl<MCFixup> &Fixups,
+                         const MCSubtargetInfo &STI) const override {}
+};
+
+class DXILAsmBackend : public MCAsmBackend {
+
+public:
+  DXILAsmBackend(const MCSubtargetInfo &STI) : MCAsmBackend(support::little) {}
+  ~DXILAsmBackend() override = default;
+
+  void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
+                  const MCValue &Target, MutableArrayRef<char> Data,
+                  uint64_t Value, bool IsResolved,
+                  const MCSubtargetInfo *STI) const override {}
+
+  std::unique_ptr<MCObjectTargetWriter>
+  createObjectTargetWriter() const override {
+    return createDXContainerTargetObjectWriter();
+  }
+
+  unsigned getNumFixupKinds() const override { return 0; }
+
+  bool writeNopData(raw_ostream &OS, uint64_t Count,
+                    const MCSubtargetInfo *STI) const override {
+    return true;
+  }
+
+  bool fixupNeedsRelaxation(const MCFixup &Fixup, uint64_t Value,
+                            const MCRelaxableFragment *DF,
+                            const MCAsmLayout &Layout) const override {
+    return true;
+  }
+};
+
+class DirectXMCAsmInfo : public MCAsmInfo {
+public:
+  explicit DirectXMCAsmInfo(const Triple &TT, const MCTargetOptions &Options)
+      : MCAsmInfo() {}
+};
+
+} // namespace
+
+static MCInstPrinter *createDXILMCInstPrinter(const Triple &T,
+                                              unsigned SyntaxVariant,
+                                              const MCAsmInfo &MAI,
+                                              const MCInstrInfo &MII,
+                                              const MCRegisterInfo &MRI) {
+  if (SyntaxVariant == 0)
+    return new DXILInstPrinter(MAI, MII, MRI);
+  return nullptr;
+}
+
+MCCodeEmitter *createDXILMCCodeEmitter(const MCInstrInfo &MCII,
+                                       MCContext &Ctx) {
+  return new DXILMCCodeEmitter();
+}
+
+MCAsmBackend *createDXILMCAsmBackend(const Target &T,
+                                     const MCSubtargetInfo &STI,
+                                     const MCRegisterInfo &MRI,
+                                     const MCTargetOptions &Options) {
+  return new DXILAsmBackend(STI);
+}
+
+static MCSubtargetInfo *
+createDirectXMCSubtargetInfo(const Triple &TT, StringRef CPU, StringRef FS) {
+  return createDirectXMCSubtargetInfoImpl(TT, CPU, /*TuneCPU*/ CPU, FS);
+}
+
+static MCRegisterInfo *createDirectXMCRegisterInfo(const Triple &Triple) {
+  return new MCRegisterInfo();
+}
+
+static MCInstrInfo *createDirectXMCInstrInfo() { return new MCInstrInfo(); }
+
+extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeDirectXTargetMC() {
+  Target &T = getTheDirectXTarget();
+  RegisterMCAsmInfo<DirectXMCAsmInfo> X(T);
+  TargetRegistry::RegisterMCInstrInfo(T, createDirectXMCInstrInfo);
+  TargetRegistry::RegisterMCInstPrinter(T, createDXILMCInstPrinter);
+  TargetRegistry::RegisterMCRegInfo(T, createDirectXMCRegisterInfo);
+  TargetRegistry::RegisterMCSubtargetInfo(T, createDirectXMCSubtargetInfo);
+  TargetRegistry::RegisterMCCodeEmitter(T, createDXILMCCodeEmitter);
+  TargetRegistry::RegisterMCAsmBackend(T, createDXILMCAsmBackend);
+}
index f56fefede7fce2a1e84c6590d7161aabc994b640..c84bd2cac26982fa4d72ae2ab7217d7c4e9ebec8 100644 (file)
@@ -1,6 +1,7 @@
 ; RUN: llc %s --filetype=asm -o - | FileCheck %s
 ; RUN: opt %s -dxil-embed -S -o - | FileCheck %s
-target triple = "dxil-unknown-unknown"
+; RUN: llc %s --filetype=obj -o - | obj2yaml | FileCheck %s --check-prefix=DXC
+target triple = "dxil-unknown-shadermodel6.5-library"
 
 define i32 @add(i32 %a, i32 %b) {
   %sum = add i32 %a, %b
@@ -9,3 +10,34 @@ define i32 @add(i32 %a, i32 %b) {
 
 ; CHECK: @dx.dxil = private constant [[BC_TYPE:\[[0-9]+ x i8\]]] c"BC\C0\DE{{[^"]+}}", section "DXIL", align 4
 ; CHECK: @llvm.compiler.used = appending global [1 x ptr] [ptr @dx.dxil], section "llvm.metadata"
+
+; This is using regex matches on some sizes, offsets and fields. These are all
+; going to change as the DirectX backend continues to evolve and implement more
+; features. Rather than extending this test to cover those future features, this
+; test's matches are extremely fuzzy so that it won't break.
+
+; DXC: --- !dxcontainer
+; DXC-NEXT: Header:
+; DXC-NEXT:   Hash:            [ 0x0, 0x0, 0x0,
+; DXC:   Version:
+; DXC-NEXT:     Major:           1
+; DXC-NEXT:     Minor:           0
+; DXC-NEXT:   FileSize:        [[#]]
+; DXC-NEXT:   PartCount:       [[#]]
+; DXC-NEXT:   PartOffsets:     [ {{[0-9, ]+}} ]
+; DXC-NEXT: Parts:
+
+; In verifying the DXIL part, this test captures the size of the part, and
+; derives the program header and dxil size fields from the part's size.
+
+; DXC:   - Name:            DXIL
+; DXC-NEXT:     Size:            [[#SIZE:]]
+; DXC-NEXT:     Program:
+; DXC-NEXT:       MajorVersion:    6
+; DXC-NEXT:       MinorVersion:    5
+; DXC-NEXT:       ShaderKind:      6
+; DXC-NEXT:       Size:            [[#div(SIZE,4) - 2]]
+; DXC-NEXT:       DXILMajorVersion: [[#]]
+; DXC-NEXT:       DXILMinorVersion: [[#]]
+; DXC-NEXT:       DXILSize:        [[#SIZE - 32]]
+; DXC-NEXT:       DXIL:            [ 0x42, 0x43, 0xC0, 0xDE,