[clang] [llvm] [DirectX][Driver] Add /Qpdb_in_private flag support (PR #204903)
Vladislav Dzhidzhoev via cfe-commits
cfe-commits at lists.llvm.org
Tue Jul 21 07:26:50 PDT 2026
https://github.com/dzhidzhoev updated https://github.com/llvm/llvm-project/pull/204903
>From e34a3f8f7a51800478189b89eab5a5e3e148d40a Mon Sep 17 00:00:00 2001
From: Vladislav Dzhidzhoev <vdzhidzhoev at accesssoftek.com>
Date: Tue, 16 Jun 2026 05:43:51 +0200
Subject: [PATCH 1/2] [clang][Driver][DirectX] Add /Zs flag support
When DXC is called with `/Zs` flag, it emits "slim" debug info.
It means that ILDB section is omitted from the main DXContainer
output and from the output PDB file.
This patch reimplements similar behavior in llc and Clang.
`/Zs` flag has completely different meaning for clang-cl driver. It is an
alias for `-fsyntax-only` there.
`/Zs` flag description in TableGen was generalized, so as not to trigger
`-fsyntax-only` or `-g`. Thus, Driver checks for `-fsyntax-only` were
replaced with `isSyntaxOnly()` helper function calls.
---
llvm/include/llvm/MC/MCDXContainerWriter.h | 6 +-----
llvm/lib/MC/MCDXContainerWriter.cpp | 12 +++++++++++
.../DirectX/DXILWriter/DXILWriterPass.cpp | 7 +++++--
.../DirectX/ContainerData/ContainerFlags.ll | 20 +++++++++++++++++++
4 files changed, 38 insertions(+), 7 deletions(-)
diff --git a/llvm/include/llvm/MC/MCDXContainerWriter.h b/llvm/include/llvm/MC/MCDXContainerWriter.h
index 1df38b6ff906b..8461bb5f1e1b5 100644
--- a/llvm/include/llvm/MC/MCDXContainerWriter.h
+++ b/llvm/include/llvm/MC/MCDXContainerWriter.h
@@ -49,11 +49,7 @@ class LLVM_ABI MCDXContainerBaseWriter {
llvm_unreachable("Unimplemented");
}
- virtual bool shouldSkipSection(StringRef SectionName, size_t SectionSize) {
- // Skip empty and auxiliary sections.
- return SectionSize == 0 || SectionName == PdbFileNameSectionName ||
- SectionName == ModuleHashSectionName;
- }
+ virtual bool shouldSkipSection(StringRef SectionName, size_t SectionSize);
public:
MCDXContainerBaseWriter() {}
diff --git a/llvm/lib/MC/MCDXContainerWriter.cpp b/llvm/lib/MC/MCDXContainerWriter.cpp
index 99d4394eebaea..d15086e101fb3 100644
--- a/llvm/lib/MC/MCDXContainerWriter.cpp
+++ b/llvm/lib/MC/MCDXContainerWriter.cpp
@@ -22,11 +22,23 @@ cl::opt<bool> EmbedDebug("dx-embed-debug",
cl::opt<bool>
StripDebug("dx-strip-debug",
cl::desc("Strip debug information from shader bytecode"));
+cl::opt<bool> SlimDebug("dx-slim-debug",
+ cl::desc("Generate slim PDB without ILDB part"));
MCDXContainerTargetWriter::~MCDXContainerTargetWriter() = default;
MCDXContainerBaseWriter::~MCDXContainerBaseWriter() = default;
+bool MCDXContainerBaseWriter::shouldSkipSection(StringRef SectionName,
+ size_t SectionSize) {
+ // Skip empty and auxiliary sections.
+ if (SectionSize == 0 || SectionName == PdbFileNameSectionName ||
+ SectionName == ModuleHashSectionName)
+ return true;
+ // Slim debug omits ILDB from all DXContainer outputs.
+ return SlimDebug && SectionName == "ILDB";
+}
+
void MCDXContainerBaseWriter::write(raw_ostream &OS, const Triple &TT) {
ArrayRef<MCDXContainerPart> Parts = collectParts();
diff --git a/llvm/lib/Target/DirectX/DXILWriter/DXILWriterPass.cpp b/llvm/lib/Target/DirectX/DXILWriter/DXILWriterPass.cpp
index 442ea1131beb9..f8e7e7b7b790d 100644
--- a/llvm/lib/Target/DirectX/DXILWriter/DXILWriterPass.cpp
+++ b/llvm/lib/Target/DirectX/DXILWriter/DXILWriterPass.cpp
@@ -47,6 +47,7 @@ cl::opt<bool> SourceInDebugModule(
"dx-source-in-debug-module",
cl::desc("Embed source code into debug module on DirectX target"),
cl::init(false));
+extern cl::opt<bool> SlimDebug;
namespace {
class WriteDXILPass : public llvm::ModulePass {
@@ -242,17 +243,19 @@ class EmbedDXILPass : public llvm::ModulePass {
bool HasDebugInfo = !M.debug_compile_units().empty();
+ if (SlimDebug && EmbedDebug)
+ reportFatalUsageError("/Qembed_debug is not compatible with /Zs");
+
// If both StripDebug and EmbedDebug are specified, StripDebug is ignored.
if (StripDebug && EmbedDebug)
StripDebug = false;
// Enable EmbedDebug if there is debug info, but it is not being stripped
// or written to a PDB file.
- if (HasDebugInfo && !StripDebug && !EmbedDebug && PdbDebugPath.empty())
+ if (HasDebugInfo && !StripDebug && !SlimDebug && PdbDebugPath.empty())
EmbedDebug = true;
if (!HasDebugInfo && EmbedDebug)
reportFatalUsageError(
"Missing debug info for embedding into the container");
- // TODO: move this check to DXContainerPDB.cpp when /Zs is implemented.
if (!HasDebugInfo && !PdbDebugPath.empty())
reportFatalUsageError("Missing debug info for writing to the PDB file");
diff --git a/llvm/test/CodeGen/DirectX/ContainerData/ContainerFlags.ll b/llvm/test/CodeGen/DirectX/ContainerData/ContainerFlags.ll
index 4ea070951dd1e..9dd4fca06cb60 100644
--- a/llvm/test/CodeGen/DirectX/ContainerData/ContainerFlags.ll
+++ b/llvm/test/CodeGen/DirectX/ContainerData/ContainerFlags.ll
@@ -44,6 +44,26 @@
; RUN: not llc %s --filetype=obj --dx-pdb-path=%t.pdb -o %t.cso 2>&1 | FileCheck %s --check-prefix=ERROR-NODBG-PDB
; ERROR-NODBG-PDB: Missing debug info for writing to the PDB file
+;; Check that slim debug (-dx-slim-debug) omits ILDB from container and companion PDB
+; RUN: llc %S/Inputs/SourceInfo.ll --filetype=obj -dx-slim-debug --dx-pdb-path=%t.pdb -o %t.cso
+; RUN: obj2yaml %t.cso | FileCheck %s --check-prefix=SLIM --implicit-check-not=ILDB
+; RUN: llvm-pdbutil pdb2yaml --dxcontainer %t.pdb | FileCheck %s --check-prefix=SLIM --implicit-check-not=ILDB
+
+; SLIM: Parts:
+; SLIM: - Name: HASH
+; SLIM: - Name: ILDN
+
+;; Check that /Zss can still hash from ILDB when /Zs omits it from output
+; RUN: llc %S/Inputs/SourceInfo.ll --filetype=obj -dx-slim-debug -dx-Zss -o %t.slim.cso
+; RUN: obj2yaml %t.slim.cso | FileCheck %s --check-prefix=SLIM-ZSS --implicit-check-not=ILDB
+; SLIM-ZSS: - Name: HASH
+; SLIM-ZSS: Hash:
+; SLIM-ZSS: IncludesSource: true
+
+;; Check that slim debug and embed debug are mutually exclusive
+; RUN: not llc %S/Inputs/SourceInfo.ll --filetype=obj -dx-slim-debug --dx-embed-debug -o /dev/null 2>&1 | FileCheck %s --check-prefix=ERROR-ZS-EMBED
+; ERROR-ZS-EMBED: /Qembed_debug is not compatible with /Zs
+
target triple = "dxil-unknown-shadermodel6.5-library"
define i32 @foo(i32 %a) {
>From 3712c8df2af8a04dcb4df08027a0fdd000a12453 Mon Sep 17 00:00:00 2001
From: Vladislav Dzhidzhoev <vdzhidzhoev at accesssoftek.com>
Date: Sat, 20 Jun 2026 03:59:00 +0200
Subject: [PATCH 2/2] [DirectX][Driver] Add /Qpdb_in_private flag support
In DXC, when `/Qpdb_in_private` flag is specified, debug info PDB is
emitted into PRIV part of the output DXContainer (as well as
into separate PDB file, if it was requested).
This patch reimplements similar behavior in llc and Clang.
---
clang/include/clang/Options/Options.td | 3 +
clang/lib/Driver/ToolChains/Clang.cpp | 4 +
clang/test/Driver/dxc_debug.hlsl | 2 +
clang/test/Driver/dxc_section_emission.hlsl | 11 +++
llvm/lib/MC/MCDXContainerWriter.cpp | 22 +++--
.../lib/Target/DirectX/DXContainerGlobals.cpp | 34 ++++----
llvm/lib/Target/DirectX/DXContainerPDB.cpp | 46 +++++++++-
.../ContainerData/PdbInPrivate-no-fd.test | 17 ++++
.../ContainerData/PdbInPrivate-no-flag.test | 5 ++
.../ContainerData/PdbInPrivate-no-pdbname.ll | 10 +++
.../DirectX/ContainerData/PdbInPrivate.ll | 18 ++++
.../DirectX/ContainerData/PdbInPrivate.test | 33 ++++++++
llvm/unittests/MC/CMakeLists.txt | 2 +
llvm/unittests/MC/DXContainerWriterTest.cpp | 83 +++++++++++++++++++
14 files changed, 267 insertions(+), 23 deletions(-)
create mode 100644 llvm/test/CodeGen/DirectX/ContainerData/PdbInPrivate-no-fd.test
create mode 100644 llvm/test/CodeGen/DirectX/ContainerData/PdbInPrivate-no-flag.test
create mode 100644 llvm/test/CodeGen/DirectX/ContainerData/PdbInPrivate-no-pdbname.ll
create mode 100644 llvm/test/CodeGen/DirectX/ContainerData/PdbInPrivate.ll
create mode 100644 llvm/test/CodeGen/DirectX/ContainerData/PdbInPrivate.test
create mode 100644 llvm/unittests/MC/DXContainerWriterTest.cpp
diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td
index c306179a084d3..669b6e64725c9 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -9923,6 +9923,9 @@ def dxc_gis : DXCFlag<"Gis">,
def : Option<["/", "-"], "Qembed_debug", KIND_FLAG>, Group<dxc_Group>,
Flags<[Ignored]>, Visibility<[DXCOption]>,
HelpText<"Embed PDB in shader container (ignored)">;
+def dxc_Qpdb_in_private : DXCFlag<"Qpdb_in_private">,
+ Flags<[HelpHidden]>,
+ HelpText<"Store PDB in private user data">;
def spirv : DXCFlag<"spirv">,
HelpText<"Generate SPIR-V code">;
def metal : DXCFlag<"metal">, HelpText<"Generate Metal library">;
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index 10a1c0e8dec3f..1178f625d1172 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -4003,6 +4003,10 @@ static void RenderHLSLOptions(const Driver &D, const ArgList &Args,
CmdArgs.push_back("-mllvm");
CmdArgs.push_back("--dx-strip-debug");
}
+ if (Args.hasArg(options::OPT_dxc_Qpdb_in_private)) {
+ CmdArgs.push_back("-mllvm");
+ CmdArgs.push_back("--dx-pdb-in-private");
+ }
}
static void RenderOpenACCOptions(const Driver &D, const ArgList &Args,
diff --git a/clang/test/Driver/dxc_debug.hlsl b/clang/test/Driver/dxc_debug.hlsl
index 90a02f1d1c1c4..b4a491fa6e1b1 100644
--- a/clang/test/Driver/dxc_debug.hlsl
+++ b/clang/test/Driver/dxc_debug.hlsl
@@ -3,6 +3,7 @@
// RUN: %clang_dxc -Tlib_6_7 -### /Zi /Qembed_debug %s 2>&1 | FileCheck %s
// RUN: %clang_dxc -Tlib_6_7 -### -Zi %s 2>&1 | FileCheck %s
// RUN: %clang_dxc -Tlib_6_7 -### -Zi -Qembed_debug %s 2>&1 | FileCheck %s
+// RUN: %clang_dxc -Tlib_6_7 -### /Zi /Qpdb_in_private %s 2>&1 | FileCheck %s -check-prefixes=CHECK,CHECK-PRIV
// RUN: %clang_dxc -Tlib_6_7 -### -Zi -Zss %s 2>&1 | FileCheck %s --check-prefix=CHECK,CHECK-ZSS
// RUN: %clang_dxc -Tlib_6_7 -### /Zi -Qsource_in_debug_module %s 2>&1 | FileCheck %s --check-prefix=CHECK,CHECK-SIDM
// RUN: %clang_dxc -Tlib_6_7 -### -Zi -Qstrip_debug %s 2>&1 | FileCheck %s --check-prefix=CHECK,CHECK-STRIP
@@ -17,6 +18,7 @@
// Make sure dwarf-version is 4.
// CHECK-DWARF-SAME: -dwarf-version=4
// Check that the flags are converted to their llc equivalents.
+// CHECK-PRIV-SAME: --dx-pdb-in-private
// CHECK-ZSS-SAME: -dx-Zss
// CHECK-SIDM-SAME: --dx-source-in-debug-module
// CHECK-STRIP-SAME: --dx-strip-debug
diff --git a/clang/test/Driver/dxc_section_emission.hlsl b/clang/test/Driver/dxc_section_emission.hlsl
index b27232f6b7d27..be8081e884c78 100644
--- a/clang/test/Driver/dxc_section_emission.hlsl
+++ b/clang/test/Driver/dxc_section_emission.hlsl
@@ -22,4 +22,15 @@
// CHECK: - Name: ILDN
+// Check that /Qpdb_in_private emits a PRIV part in the output container.
+// RUN: %clang_dxc -Tlib_6_7 /Fo %t-priv.dxbc /Zi /Qpdb_in_private %s 2>&1
+// RUN: obj2yaml %t-priv.dxbc | FileCheck %s --check-prefix=CHECK-PRIV
+
+// Without /Qpdb_in_private, PRIV is not emitted.
+// RUN: %clang_dxc -Tlib_6_7 /Fo %t-no-priv.dxbc /Zi %s 2>&1
+// RUN: obj2yaml %t-no-priv.dxbc | FileCheck %s --check-prefix=CHECK-NO-PRIV
+
+// CHECK-PRIV: - Name: PRIV
+// CHECK-NO-PRIV-NOT: - Name: PRIV
+
[numthreads(1, 1, 1)] void main() {}
diff --git a/llvm/lib/MC/MCDXContainerWriter.cpp b/llvm/lib/MC/MCDXContainerWriter.cpp
index d15086e101fb3..1bbdf52920900 100644
--- a/llvm/lib/MC/MCDXContainerWriter.cpp
+++ b/llvm/lib/MC/MCDXContainerWriter.cpp
@@ -49,14 +49,22 @@ void MCDXContainerBaseWriter::write(raw_ostream &OS, const Triple &TT) {
// 16 part offsets gives us a little room for growth.
llvm::SmallVector<uint64_t, 16> PartOffsets;
uint64_t PartOffset = 0;
+ bool HasPrivate = false;
for (const MCDXContainerPart &Part : Parts) {
+ if (HasPrivate)
+ reportFatalInternalError(
+ "PRIV must be the last section in a DXContainer");
+ if (Part.Name == "PRIV")
+ HasPrivate = true;
+
uint64_t SectionSize = Part.Data.size();
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));
+ if (!HasPrivate)
+ PartOffset = alignTo(PartOffset, Align(4ul));
// The DXIL part also writes a program header, so we need to include its
// size when computing the offset for a part after the DXIL part.
if (dxbc::isProgramPart(Part.Name))
@@ -96,8 +104,10 @@ void MCDXContainerBaseWriter::write(raw_ostream &OS, const Triple &TT) {
if (dxbc::isProgramPart(Part.Name))
PartSize += sizeof(dxbc::ProgramHeader);
- // DXContainer parts should be 4-byte aligned.
- PartSize = alignTo(PartSize, Align(4));
+ // DXContainer part should be 4-byte aligned, unless it is PRIV part.
+ bool IsPrivate = Part.Name == "PRIV";
+ if (!IsPrivate)
+ PartSize = alignTo(PartSize, Align(4));
W.write<uint32_t>(static_cast<uint32_t>(PartSize));
if (dxbc::isProgramPart(Part.Name)) {
dxbc::ProgramHeader Header;
@@ -127,8 +137,10 @@ void MCDXContainerBaseWriter::write(raw_ostream &OS, const Triple &TT) {
sizeof(dxbc::ProgramHeader)));
}
W.write<char>(Part.Data);
- unsigned Size = W.OS.tell() - Start;
- W.OS.write_zeros(offsetToAlignment(Size, Align(4)));
+ if (!IsPrivate) {
+ unsigned Size = W.OS.tell() - Start;
+ W.OS.write_zeros(offsetToAlignment(Size, Align(4)));
+ }
}
}
diff --git a/llvm/lib/Target/DirectX/DXContainerGlobals.cpp b/llvm/lib/Target/DirectX/DXContainerGlobals.cpp
index f9cf43e67f1fb..1753b3e3f3a1a 100644
--- a/llvm/lib/Target/DirectX/DXContainerGlobals.cpp
+++ b/llvm/lib/Target/DirectX/DXContainerGlobals.cpp
@@ -43,6 +43,8 @@ static cl::opt<bool> ShaderHashDependsOnSource(
"dx-Zss", cl::desc("Compute Shader Hash considering source information"));
extern cl::opt<std::string> PdbDebugPath;
extern cl::opt<bool> SourceInDebugModule;
+cl::opt<bool> PdbInPrivate("dx-pdb-in-private",
+ cl::desc("Store PDB in private user data"));
namespace {
class DXContainerGlobals : public llvm::ModulePass {
@@ -159,22 +161,26 @@ void DXContainerGlobals::computeShaderHashAndDebugName(
SmallString<40> DebugNameStr;
Digest.stringifyResult(MD5, DebugNameStr);
DebugNameStr += ".pdb";
- if (!PdbDebugPath.empty()) {
- StringRef DebugFile = PdbDebugPath.getValue();
- SmallString<256> AbsoluteDebugName;
- if (sys::path::is_separator(DebugFile.back())) {
- // If /Fd was specified as a directory, put the MD5.pdb file there.
- AbsoluteDebugName = DebugFile;
- sys::path::append(AbsoluteDebugName, DebugNameStr);
- } else {
- // Otherwise, use /Fd value as a user-provided PDB file name.
- DebugNameStr = DebugFile;
- AbsoluteDebugName = DebugNameStr;
+ if (!PdbDebugPath.empty() || PdbInPrivate) {
+ if (!PdbDebugPath.empty()) {
+ StringRef DebugFile = PdbDebugPath.getValue();
+ SmallString<256> AbsoluteDebugName;
+ if (sys::path::is_separator(DebugFile.back())) {
+ // If PDB output path was specified as a directory, put the MD5.pdb file
+ // there.
+ AbsoluteDebugName = DebugFile;
+ sys::path::append(AbsoluteDebugName, DebugNameStr);
+ } else {
+ // Otherwise, use PDB output path as a user-provided PDB file name.
+ DebugNameStr = DebugFile;
+ AbsoluteDebugName = DebugNameStr;
+ }
+
+ // Pass PDB name to DXContainerPDBPass via PDBNAME section.
+ addSection(M, Globals, AbsoluteDebugName, "dx.pdb.name",
+ PdbFileNameSectionName);
}
- // Pass PDB name to DXContainerPDBPass via PDBNAME section.
- addSection(M, Globals, AbsoluteDebugName, "dx.pdb.name",
- PdbFileNameSectionName);
// Pass module hash to DXContainerPDBPass.
Globals.emplace_back(buildContainerGlobal(
M, ConstantDataArray::get(M.getContext(), ArrayRef(HashData.Digest)),
diff --git a/llvm/lib/Target/DirectX/DXContainerPDB.cpp b/llvm/lib/Target/DirectX/DXContainerPDB.cpp
index dc3c05376b2c1..13f57baaaa032 100644
--- a/llvm/lib/Target/DirectX/DXContainerPDB.cpp
+++ b/llvm/lib/Target/DirectX/DXContainerPDB.cpp
@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "DirectX.h"
+#include "llvm/ADT/ScopeExit.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/BinaryFormat/DXContainer.h"
#include "llvm/DebugInfo/CodeView/GUID.h"
@@ -17,10 +18,15 @@
#include "llvm/IR/Module.h"
#include "llvm/MC/MCDXContainerWriter.h"
#include "llvm/Pass.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/FileSystem.h"
#include "llvm/Support/IOSandbox.h"
+#include "llvm/Transforms/Utils/ModuleUtils.h"
using namespace llvm;
+extern cl::opt<bool> PdbInPrivate;
+
namespace {
class DXContainerPDB : public ModulePass, MCDXContainerBaseWriter {
@@ -85,10 +91,22 @@ ArrayRef<MCDXContainerPart> DXContainerPDB::collectParts() {
return Parts;
}
+static GlobalVariable *createPrivateDataGlobal(Module &M, StringRef Data) {
+ Constant *Content =
+ ConstantDataArray::getString(M.getContext(), Data, /*AddNull*/ false);
+ auto *GV =
+ new GlobalVariable(M, Content->getType(), true,
+ GlobalValue::PrivateLinkage, Content, "dx.priv");
+ GV->setSection("PRIV");
+ GV->setAlignment(Align(1));
+ return GV;
+}
+
bool DXContainerPDB::runOnModule(Module &M) {
+ llvm::scope_exit Cleanup([&]() { reset(); });
this->M = &M;
- StringRef DebugFileName;
+ SmallString<128> DebugFileName;
ArrayRef<char> ModuleHash;
for (const GlobalVariable &GV : M.globals()) {
if (GV.getSection() == PdbFileNameSectionName) {
@@ -102,11 +120,23 @@ bool DXContainerPDB::runOnModule(Module &M) {
}
// PDB emission was not requested.
- if (DebugFileName.empty())
+ if (DebugFileName.empty() && !PdbInPrivate)
return false;
if (ModuleHash.empty())
report_fatal_error("Module hash for PDB not found");
+ bool DeleteAfterRead = false;
+ if (DebugFileName.empty()) {
+ if (std::error_code EC =
+ sys::fs::createTemporaryFile("dxil", "pdb", DebugFileName))
+ reportFatalInternalError("Failed to create temporary PDB file");
+ DeleteAfterRead = true;
+ }
+ llvm::scope_exit FileCleanup([&]() {
+ if (DeleteAfterRead)
+ sys::fs::remove(DebugFileName);
+ });
+
BumpPtrAllocator Allocator;
pdb::PDBFileBuilder Builder(Allocator);
@@ -151,9 +181,17 @@ bool DXContainerPDB::runOnModule(Module &M) {
reportFatalUsageError("Couldn't write to PDB file: " +
Twine(toString(std::move(Err))));
- reset();
+ if (!PdbInPrivate)
+ return false;
+
+ ErrorOr<std::unique_ptr<MemoryBuffer>> Buf = MemoryBuffer::getFile(
+ DebugFileName, /*IsText=*/false, /*RequiresNullTerminator=*/false);
+ if (!Buf)
+ reportFatalInternalError("Failed to read PDB for PRIV embedding");
+
+ appendToCompilerUsed(M, createPrivateDataGlobal(M, (*Buf)->getBuffer()));
- return false;
+ return true;
}
char DXContainerPDB::ID = 0;
diff --git a/llvm/test/CodeGen/DirectX/ContainerData/PdbInPrivate-no-fd.test b/llvm/test/CodeGen/DirectX/ContainerData/PdbInPrivate-no-fd.test
new file mode 100644
index 0000000000000..c7e5cf3e340e2
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/ContainerData/PdbInPrivate-no-fd.test
@@ -0,0 +1,17 @@
+## Check that --dx-pdb-in-private generates a PDB in PRIV without --dx-pdb-path.
+
+# RUN: llc %S/Inputs/SourceInfo.ll --filetype=obj -o %t.dxbc --dx-pdb-in-private
+# RUN: obj2yaml %t.dxbc | FileCheck %s
+# RUN: llvm-objcopy --dump-section=PRIV=%t.priv %t.dxbc
+# RUN: llvm-pdbutil pdb2yaml --dxcontainer %t.priv | FileCheck %s --check-prefix=PDB
+
+# CHECK: - Name: PRIV
+# CHECK-NEXT: Size:
+
+# PDB: PartCount: 5
+# PDB: Parts:
+# PDB-DAG: - Name: ILDB
+# PDB-DAG: - Name: HASH
+# PDB-DAG: - Name: ILDN
+# PDB-DAG: - Name: VERS
+# PDB-DAG: - Name: SRCI
diff --git a/llvm/test/CodeGen/DirectX/ContainerData/PdbInPrivate-no-flag.test b/llvm/test/CodeGen/DirectX/ContainerData/PdbInPrivate-no-flag.test
new file mode 100644
index 0000000000000..4a185ed7842dd
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/ContainerData/PdbInPrivate-no-flag.test
@@ -0,0 +1,5 @@
+## Check that PRIV is not emitted unless --dx-pdb-in-private is specified.
+
+# RUN: llc %S/Inputs/SourceInfo.ll --filetype=obj -o - | obj2yaml | FileCheck %s --implicit-check-not='PRIV'
+
+# CHECK: - Name: DXIL
diff --git a/llvm/test/CodeGen/DirectX/ContainerData/PdbInPrivate-no-pdbname.ll b/llvm/test/CodeGen/DirectX/ContainerData/PdbInPrivate-no-pdbname.ll
new file mode 100644
index 0000000000000..f07d19416b267
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/ContainerData/PdbInPrivate-no-pdbname.ll
@@ -0,0 +1,10 @@
+;; Check that dxil-pdb can emit PRIV using a temporary PDB when PDBNAME is absent.
+; RUN: opt %s -dxil-pdb --dx-pdb-in-private -S -o - | FileCheck %s
+
+;; CHECK: @dx.priv = private constant {{.*}} section "PRIV"
+
+target triple = "dxilv1.3-pc-shadermodel6.3-library"
+
+ at dx.ildb = private constant [4 x i8] c"BC\C0\DE", section "ILDB", align 4
+ at dx.pdb.hash = private constant [16 x i8] c"dummymodulehash!", section "PDBHASH", align 4
+ at llvm.compiler.used = appending global [2 x ptr] [ptr @dx.ildb, ptr @dx.pdb.hash], section "llvm.metadata"
diff --git a/llvm/test/CodeGen/DirectX/ContainerData/PdbInPrivate.ll b/llvm/test/CodeGen/DirectX/ContainerData/PdbInPrivate.ll
new file mode 100644
index 0000000000000..7edc3fd8918d1
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/ContainerData/PdbInPrivate.ll
@@ -0,0 +1,18 @@
+; RUN: opt %s -dxil-pdb --dx-pdb-in-private -S -o - | FileCheck %s --check-prefix=CHECK-IR
+; RUN: opt %s -dxil-pdb --dx-pdb-in-private -o /dev/null
+; RUN: llvm-pdbutil pdb2yaml --dxcontainer PdbInPrivateTest.pdb | FileCheck %s --check-prefix=CHECK-PDB
+
+;; Check that dxil-pdb pass emits a PRIV global when --dx-pdb-in-private is set.
+; CHECK-IR: @dx.priv = private constant {{.*}} section "PRIV"
+
+; Check that the companion PDB file is still written when PDBNAME is present.
+; CHECK-PDB: PartCount: 1
+; CHECK-PDB: Parts:
+; CHECK-PDB: - Name: ILDB
+
+target triple = "dxilv1.3-pc-shadermodel6.3-library"
+
+ at dx.ildb = private constant [4 x i8] c"BC\C0\DE", section "ILDB", align 4
+ at dx.pdb.name = private constant [20 x i8] c"PdbInPrivateTest.pdb", section "PDBNAME", align 4
+ at dx.pdb.hash = private constant [16 x i8] c"dummymodulehash!", section "PDBHASH", align 4
+ at llvm.compiler.used = appending global [3 x ptr] [ptr @dx.ildb, ptr @dx.pdb.name, ptr @dx.pdb.hash], section "llvm.metadata"
diff --git a/llvm/test/CodeGen/DirectX/ContainerData/PdbInPrivate.test b/llvm/test/CodeGen/DirectX/ContainerData/PdbInPrivate.test
new file mode 100644
index 0000000000000..7c370ea0da02a
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/ContainerData/PdbInPrivate.test
@@ -0,0 +1,33 @@
+## Check that --dx-pdb-in-private stores the generated PDB in the PRIV part.
+
+## File: --dx-pdb-path specifies the PDB output path.
+
+# RUN: llc %S/Inputs/SourceInfo.ll --filetype=obj -o %t.dxbc --dx-pdb-in-private --dx-pdb-path=%t.pdb
+# RUN: obj2yaml %t.dxbc | FileCheck %s
+# RUN: llvm-objcopy --dump-section=PRIV=%t.priv %t.dxbc
+# RUN: diff %t.pdb %t.priv
+# RUN: llvm-pdbutil pdb2yaml --dxcontainer %t.priv | FileCheck %s --check-prefix=PDB
+
+## Directory: --dx-pdb-path ending in '/' writes <md5>.pdb under that directory.
+
+# RUN: rm -rf %t.dir && mkdir %t.dir
+# RUN: llc %S/Inputs/SourceInfo.ll --filetype=obj -o %t.dir.dxbc --dx-pdb-in-private --dx-pdb-path=%t.dir/
+# RUN: obj2yaml %t.dir.dxbc | FileCheck %s
+# RUN: llvm-objcopy --dump-section=PRIV=%t.dir.priv %t.dir.dxbc
+# RUN: llvm-objcopy --dump-section=DXIL=%t.dir.bc %t.dir.dxbc
+# RUN: %md5sum %t.dir.bc >%t.dir.bc.md5
+# RUN: %python %S/Inputs/check_pdb_exists.py %t.dir %t.dir.bc.md5
+# RUN: cat %t.dir/*.pdb > %t.dir.pdb
+# RUN: diff %t.dir.pdb %t.dir.priv
+# RUN: llvm-pdbutil pdb2yaml --dxcontainer %t.dir.priv | FileCheck %s --check-prefix=PDB
+
+# CHECK: - Name: PRIV
+# CHECK-NEXT: Size:
+
+# PDB: PartCount: 5
+# PDB: Parts:
+# PDB-DAG: - Name: ILDB
+# PDB-DAG: - Name: HASH
+# PDB-DAG: - Name: ILDN
+# PDB-DAG: - Name: VERS
+# PDB-DAG: - Name: SRCI
diff --git a/llvm/unittests/MC/CMakeLists.txt b/llvm/unittests/MC/CMakeLists.txt
index 4958396c731b8..789fdb1722197 100644
--- a/llvm/unittests/MC/CMakeLists.txt
+++ b/llvm/unittests/MC/CMakeLists.txt
@@ -6,6 +6,7 @@ endforeach()
set(LLVM_LINK_COMPONENTS
${LLVM_TARGETS_TO_BUILD}
+ BinaryFormat
DebugInfoDWARF
MC
MCDisassembler
@@ -19,6 +20,7 @@ add_llvm_unittest(MCTests
DwarfDebugFrameCIE.cpp
DwarfLineTables.cpp
DwarfLineTableHeaders.cpp
+ DXContainerWriterTest.cpp
MCInstPrinter.cpp
StringTableBuilderTest.cpp
TargetRegistry.cpp
diff --git a/llvm/unittests/MC/DXContainerWriterTest.cpp b/llvm/unittests/MC/DXContainerWriterTest.cpp
new file mode 100644
index 0000000000000..3641e873dbf4f
--- /dev/null
+++ b/llvm/unittests/MC/DXContainerWriterTest.cpp
@@ -0,0 +1,83 @@
+//===- DXContainerWriterTest.cpp - MCDXContainerWriter tests --------------===//
+//
+// 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/Object/DXContainer.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/MemoryBufferRef.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/TargetParser/Triple.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+using namespace llvm::object;
+
+namespace {
+
+class TestDXContainerWriter : public MCDXContainerBaseWriter {
+ SmallVector<SmallString<8>> PartNames;
+ SmallVector<SmallString<32>> PartData;
+ SmallVector<MCDXContainerPart> Parts;
+
+protected:
+ ArrayRef<MCDXContainerPart> collectParts() override { return Parts; }
+
+public:
+ void addPart(StringRef Name, ArrayRef<uint8_t> Data) {
+ PartNames.emplace_back(Name);
+ PartData.emplace_back(Data.begin(), Data.end());
+ Parts.push_back({PartNames.back(), PartData.back()});
+ }
+};
+
+static Triple getTestTriple() {
+ return Triple("dxilv1.3-pc-shadermodel6.3-library");
+}
+
+static std::string writeContainer(TestDXContainerWriter &Writer) {
+ std::string Buffer;
+ raw_string_ostream OS(Buffer);
+ Writer.write(OS, getTestTriple());
+ return Buffer;
+}
+
+static DXContainer parseContainer(StringRef Buffer) {
+ return llvm::cantFail(DXContainer::create(MemoryBufferRef(Buffer, "")));
+}
+
+TEST(MCDXContainerWriterTest, PrivUnaligned) {
+ TestDXContainerWriter Writer;
+ const uint8_t PrivData[] = {0xDE, 0xAD, 0xBE, 0xEF, 0x42};
+ Writer.addPart("PRIV", PrivData);
+
+ std::string Buffer = writeContainer(Writer);
+ DXContainer C = parseContainer(Buffer);
+
+ EXPECT_EQ(C.getHeader().PartCount, 1u);
+ EXPECT_EQ(C.getHeader().FileSize, 49u);
+ EXPECT_EQ(C.getData().size(), 49u);
+
+ ASSERT_TRUE(C.getPrivateData());
+ EXPECT_EQ(C.getPrivateData()->size(), 5u);
+ EXPECT_EQ(
+ *C.getPrivateData(),
+ StringRef(reinterpret_cast<const char *>(PrivData), sizeof(PrivData)));
+}
+
+TEST(MCDXContainerWriterTest, PrivMustBeLast) {
+ TestDXContainerWriter Writer;
+ const uint8_t PrivData[] = {0x42};
+ const uint8_t DxilData[] = {0xBC, 0xC0, 0xDE, 0x00};
+ Writer.addPart("PRIV", PrivData);
+ Writer.addPart("DXIL", DxilData);
+
+ EXPECT_DEATH(writeContainer(Writer),
+ "PRIV must be the last section in a DXContainer");
+}
+
+} // namespace
More information about the cfe-commits
mailing list