[clang] [llvm] [Driver][DirectX] Add `/Qembed_debug` and `/Fd` flags (PR #204166)
Ilia Kuklin via cfe-commits
cfe-commits at lists.llvm.org
Fri Jun 19 04:18:17 PDT 2026
https://github.com/kuilpd updated https://github.com/llvm/llvm-project/pull/204166
>From a6ae624e191ae5ea4592ab690edb8fe83d47d55b Mon Sep 17 00:00:00 2001
From: Ilia Kuklin <kuklin.iy at mail.ru>
Date: Sat, 6 Jun 2026 02:49:05 +0500
Subject: [PATCH 1/5] [Driver][DirectX] Add /Qembed_debug and /Fd flags
---
.../clang/Basic/DiagnosticDriverKinds.td | 10 +++
clang/include/clang/Options/Options.td | 27 ++++---
clang/lib/Driver/ToolChains/Clang.cpp | 19 +++++
clang/test/Driver/dxc_debug.hlsl | 14 +++-
llvm/include/llvm/MC/MCDXContainerWriter.h | 1 +
llvm/lib/MC/MCDXContainerWriter.cpp | 14 ++++
.../lib/Target/DirectX/DXContainerGlobals.cpp | 70 ++++++++-----------
llvm/lib/Target/DirectX/DXContainerPDB.cpp | 3 +-
.../DirectX/DXILWriter/DXILWriterPass.cpp | 15 ++++
.../DirectX/ContainerData/ContainerFlags.ll | 38 ++++++++++
.../DebugName-default-output.test | 1 -
.../DebugName-user-directory.test | 2 +-
.../DebugName-user-specified.test | 9 +++
.../DirectX/ContainerData/DebugName.test | 22 ++++++
.../DirectX/ContainerData/PDBParts.test | 2 +-
.../DirectX/ContainerData/SourceInfo-Args.ll | 3 +-
.../ContainerData/SourceInfo-Compressed.ll | 3 +-
.../ContainerData/SourceInfo-Uncompressed.ll | 3 +-
llvm/test/CodeGen/DirectX/embed-ildb.ll | 9 +--
19 files changed, 201 insertions(+), 64 deletions(-)
create mode 100644 llvm/test/CodeGen/DirectX/ContainerData/ContainerFlags.ll
create mode 100644 llvm/test/CodeGen/DirectX/ContainerData/DebugName-user-specified.test
create mode 100644 llvm/test/CodeGen/DirectX/ContainerData/DebugName.test
diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td
index 8edac14f4972a..a642797e518e4 100644
--- a/clang/include/clang/Basic/DiagnosticDriverKinds.td
+++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td
@@ -883,6 +883,16 @@ def err_drv_dxc_Fre_requires_Fo_metal
: Error<"-Fre option requires -Fo option when targeting Metal">;
def err_drv_dxc_invalid_shader_hash
: Error<"cannot specify both /Zss and /Zsb">;
+def err_drv_no_debug_info_for_embed_debug
+ : Error<"must enable debug info with /Zi for /Qembed_debug">;
+def err_drv_no_debug_info_for_Fd
+ : Error<"/Fd specified, but no Debug Info was found in the shader; "
+ "please use the /Zi or /Zs switch to generate debug information "
+ "compiling this shader">;
+def warn_drv_dxc_no_output_for_debug
+ : Warning<"no output provided for debug - embedding PDB in shader "
+ "container; use /Qembed_debug to silence this warning">,
+ InGroup<DiagGroup<"default-embed-debug">>;
def err_drv_hlsl_unsupported_target : Error<
"HLSL code generation is unsupported for target '%0'">;
def err_drv_hlsl_bad_shader_required_in_target : Error<
diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td
index 919d46c449750..e2a14d364f457 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -9319,10 +9319,9 @@ def _SLASH_ZH_SHA1 : CLFlag<"ZH:SHA1">,
HelpText<"Use SHA1 for file checksums in debug info">,
Alias<gsrc_hash_EQ>, AliasArgs<["sha1"]>;
def _SLASH_ZH_SHA_256 : CLFlag<"ZH:SHA_256">,
- HelpText<"Use SHA256 for file checksums in debug info">,
- Alias<gsrc_hash_EQ>, AliasArgs<["sha256"]>;
-def _SLASH_Zi : CLFlag<"Zi", [CLOption, DXCOption]>, Alias<g_Flag>,
- HelpText<"Like /Z7">;
+ HelpText<"Use SHA256 for file checksums in debug info">,
+ Alias<gsrc_hash_EQ>,
+ AliasArgs<["sha256"]>;
def _SLASH_Zp : CLJoined<"Zp">,
HelpText<"Set default maximum struct packing alignment">,
Alias<fpack_struct_EQ>;
@@ -9666,6 +9665,18 @@ def dxc_Zss : DXCFlag<"Zss">,
HelpText<"Compute Shader Hash considering source information">;
def dxc_Zsb : DXCFlag<"Zsb">,
HelpText<"Compute Shader Hash considering only output binary">;
+def dxc_Fd
+ : DXCJoinedOrSeparate<"Fd">,
+ HelpText<"Write debug information to the given file, or automatically "
+ "named file in directory when ending in '/'">;
+def dxc_Qembed_debug
+ : DXCFlag<"Qembed_debug">,
+ HelpText<"Embed PDB in shader container (must be used with /Zi)">;
+def dxc_Zi : Option<["/", "-"], "Zi", KIND_FLAG>,
+ Group<dxc_Group>,
+ Alias<g_Flag>,
+ Visibility<[CLOption, DXCOption]>,
+ HelpText<"Enable debug information">;
def dxil_validator_version : Option<["/", "-"], "validator-version", KIND_SEPARATE>,
Group<dxc_Group>, Flags<[HelpHidden]>,
Visibility<[DXCOption, ClangOption, CC1Option]>,
@@ -9760,11 +9771,9 @@ def spirv_validator_path_EQ : Joined<["--"], "spirv-val-path=">, Group<dxc_Group
HelpText<"SPIRV validator installation path">;
def dxc_disable_validation : DXCFlag<"Vd">,
HelpText<"Disable validation">;
-def dxc_gis : DXCFlag<"Gis">,
- HelpText<"Enable IEEE strict mode (equivalent to -ffp-model=strict)">;
-def : Option<["/", "-"], "Qembed_debug", KIND_FLAG>, Group<dxc_Group>,
- Flags<[Ignored]>, Visibility<[DXCOption]>,
- HelpText<"Embed PDB in shader container (ignored)">;
+def dxc_gis
+ : DXCFlag<"Gis">,
+ HelpText<"Enable IEEE strict mode (equivalent to -ffp-model=strict)">;
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 323417e294d5a..b3b8280de3006 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -3854,6 +3854,25 @@ static void RenderHLSLOptions(const Driver &D, const ArgList &Args,
}
if (Arg *A = Args.getLastArg(options::OPT_dxc_Zsb))
A->claim(); // /Zsb is the default behavior, no need to forward it to llc.
+ bool Zi = Args.hasArg(options::OPT_g_Flag);
+ bool Qembed_debug = Args.hasArg(options::OPT_dxc_Qembed_debug);
+ Arg *Fd = Args.getLastArg(options::OPT_dxc_Fd);
+ if (Zi && !Fd && !Qembed_debug) {
+ D.Diag(diag::warn_drv_dxc_no_output_for_debug);
+ Qembed_debug = true;
+ }
+ if (Qembed_debug && !Zi)
+ D.Diag(diag::err_drv_no_debug_info_for_embed_debug);
+ if (Fd && !Zi)
+ D.Diag(diag::err_drv_no_debug_info_for_Fd);
+ if (Qembed_debug) {
+ CmdArgs.push_back("-mllvm");
+ CmdArgs.push_back("--dx-embed-debug");
+ }
+ if (Fd) {
+ CmdArgs.push_back("-mllvm");
+ CmdArgs.push_back(Args.MakeArgString("--dx-Fd=" + Twine(Fd->getValue())));
+ }
}
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 1a6c26c80750b..d90be0bb5bad2 100644
--- a/clang/test/Driver/dxc_debug.hlsl
+++ b/clang/test/Driver/dxc_debug.hlsl
@@ -1,8 +1,10 @@
// RUN: %clang_dxc -Tlib_6_7 -### -g %s 2>&1 | FileCheck %s --check-prefix=CHECK,CHECK-CMD
// 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 /Qembed_debug %s 2>&1 | FileCheck %s -check-prefixes=CHECK,CHECK-EMBED
// 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 -Qembed_debug %s 2>&1 | FileCheck %s -check-prefixes=CHECK,CHECK-EMBED
+// RUN: %clang_dxc -Tlib_6_7 -### -Zi /Fd %t.pdb %s 2>&1 | FileCheck %s -check-prefixes=CHECK,CHECK-FD
+// RUN: %clang_dxc -Tlib_6_7 -### -Zi -Fd=%t.pdb %s 2>&1 | FileCheck %s -check-prefixes=CHECK,CHECK-FD
// 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 -gcodeview %s 2>&1 | FileCheck %s -check-prefixes=CHECK,CHECK-CV
// RUN: %clang_dxc -Tlib_6_7 -### -Zi -gdwarf %s 2>&1 | FileCheck %s -check-prefixes=CHECK,CHECK-DWARF
@@ -15,11 +17,19 @@
// Make sure dwarf-version is 4.
// CHECK-DWARF-SAME: -dwarf-version=4
// Check that the flags are converted to their llc equivalents.
+// CHECK-EMBED-SAME: --dx-embed-debug
+// CHECK-FD-SAME: --dx-Fd=
// CHECK-ZSS-SAME: -dx-Zss
// Make sure dxc command line arguments are passed to clang invocation.
// CHECK-SAME: -fdx-record-command-line
// CHECK-CMD-SAME: --driver-mode=dxc -T lib_6_7 -### -g {{.*}}dxc_debug.hlsl
// Check errors and warnings
+// RUN: %clang_dxc -Tlib_6_7 -### /Zi %s 2>&1 | FileCheck %s --check-prefix=WARN-EMBED
+// WARN-EMBED: warning: no output provided for debug - embedding PDB in shader container
+// RUN: not %clang_dxc -Tlib_6_7 -### /Qembed_debug %s 2>&1 | FileCheck %s --check-prefix=ERROR-NODBG0
+// ERROR-NODBG0: error: must enable debug info with /Zi for /Qembed_debug
+// RUN: not %clang_dxc -Tlib_6_7 -### /Fd %t.pdb %s 2>&1 | FileCheck %s --check-prefix=ERROR-NODBG1
+// ERROR-NODBG1: error: /Fd specified, but no Debug Info was found in the shader
// RUN: not %clang_dxc -Tlib_6_7 -### -Zss -Zsb %s 2>&1 | FileCheck %s --check-prefix=CHECK-ZSS-ZSB
// CHECK-ZSS-ZSB: cannot specify both /Zss and /Zsb
diff --git a/llvm/include/llvm/MC/MCDXContainerWriter.h b/llvm/include/llvm/MC/MCDXContainerWriter.h
index 8bc6d31eb25d0..1df38b6ff906b 100644
--- a/llvm/include/llvm/MC/MCDXContainerWriter.h
+++ b/llvm/include/llvm/MC/MCDXContainerWriter.h
@@ -73,6 +73,7 @@ class LLVM_ABI DXContainerObjectWriter final : public MCDXContainerBaseWriter,
protected:
ArrayRef<MCDXContainerPart> collectParts() override;
+ bool shouldSkipSection(StringRef SectionName, size_t SectionSize) override;
public:
DXContainerObjectWriter(std::unique_ptr<MCDXContainerTargetWriter> MOTW,
diff --git a/llvm/lib/MC/MCDXContainerWriter.cpp b/llvm/lib/MC/MCDXContainerWriter.cpp
index de973f2667da3..994b90fbcb66b 100644
--- a/llvm/lib/MC/MCDXContainerWriter.cpp
+++ b/llvm/lib/MC/MCDXContainerWriter.cpp
@@ -13,9 +13,13 @@
#include "llvm/MC/MCSection.h"
#include "llvm/MC/MCValue.h"
#include "llvm/Support/Alignment.h"
+#include "llvm/Support/CommandLine.h"
using namespace llvm;
+cl::opt<bool> EmbedDebug("dx-embed-debug",
+ cl::desc("Embed PDB in shader container"));
+
MCDXContainerTargetWriter::~MCDXContainerTargetWriter() = default;
MCDXContainerBaseWriter::~MCDXContainerBaseWriter() = default;
@@ -132,6 +136,16 @@ ArrayRef<MCDXContainerPart> DXContainerObjectWriter::collectParts() {
return Parts;
}
+bool DXContainerObjectWriter::shouldSkipSection(StringRef SectionName,
+ size_t SectionSize) {
+ // Do not write ILDB part if we're not embedding it.
+ if (!EmbedDebug && SectionName == "ILDB")
+ return true;
+ if (SectionName == "SRCI")
+ return true;
+ return MCDXContainerBaseWriter::shouldSkipSection(SectionName, SectionSize);
+}
+
uint64_t DXContainerObjectWriter::writeObject() {
write(W.OS, getContext().getTargetTriple());
clearParts();
diff --git a/llvm/lib/Target/DirectX/DXContainerGlobals.cpp b/llvm/lib/Target/DirectX/DXContainerGlobals.cpp
index 5a03b1854c9d7..16facaf13b96b 100644
--- a/llvm/lib/Target/DirectX/DXContainerGlobals.cpp
+++ b/llvm/lib/Target/DirectX/DXContainerGlobals.cpp
@@ -41,15 +41,11 @@ using namespace llvm::mcdxbc;
static cl::opt<bool> ShaderHashDependsOnSource(
"dx-Zss", cl::desc("Compute Shader Hash considering source information"));
-static cl::opt<std::string>
- PdbFileName("dx-pdb-file",
- cl::desc("Specify the PDB output file path for DirectX target"),
- cl::value_desc("filename"));
-static cl::opt<std::string> PdbOutputDir(
- "dx-pdb-dir",
- cl::desc("Specify the PDB output directory for DirectX target. The file "
- "name is derived from the shader hash"),
- cl::value_desc("directory"));
+cl::opt<std::string> PdbDebugPath(
+ "dx-Fd",
+ cl::desc("Write debug information to the given file, or automatically "
+ "named file in directory when ending in '/'"),
+ cl::value_desc("filename"));
namespace {
class DXContainerGlobals : public llvm::ModulePass {
@@ -148,9 +144,9 @@ void DXContainerGlobals::computeShaderHashAndDebugName(
}
Digest.update(DXILConstant->getRawDataValues());
- MD5::MD5Result Result = Digest.final();
+ MD5::MD5Result MD5 = Digest.final();
- memcpy(reinterpret_cast<void *>(&HashData.Digest), Result.data(), 16);
+ memcpy(reinterpret_cast<void *>(&HashData.Digest), MD5.data(), 16);
if (sys::IsBigEndianHost)
HashData.swapBytes();
StringRef Data(reinterpret_cast<char *>(&HashData), sizeof(dxbc::ShaderHash));
@@ -160,47 +156,41 @@ void DXContainerGlobals::computeShaderHashAndDebugName(
Globals.emplace_back(
buildContainerGlobal(M, ModuleConstant, "dx.hash", "HASH"));
- // Emit ILDN part in debug info mode.
- // DXIL bitcode hash is used, which corresponds to DXC behavior with
- // `/Zi /Qembed_debug /Zsb` flags.
if (M.debug_compile_units().empty())
return;
- if (!PdbFileName.empty() && !PdbOutputDir.empty())
- report_fatal_error(
- "--dx-pdb-file and --dx-pdb-dir are mutually exclusive options");
-
SmallString<40> DebugNameStr;
- Digest.stringifyResult(Result, 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;
+ }
- mcdxbc::DebugName DebugName;
- if (PdbFileName.empty()) {
- // Use the MD5 hash as the file name.
- Digest.stringifyResult(Result, DebugNameStr);
- DebugNameStr += ".pdb";
- } else {
- // Use user-provided PDB file name.
- DebugNameStr = PdbFileName;
+ // 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)),
+ "dx.pdb.hash", ModuleHashSectionName));
}
- DebugName.setFilename(DebugNameStr);
-
- SmallString<256> AbsoluteDebugName(PdbOutputDir);
- sys::path::append(AbsoluteDebugName, DebugNameStr);
+ // Emit ILDN part in debug info mode.
+ mcdxbc::DebugName DebugName;
+ DebugName.setFilename(DebugNameStr);
SmallString<64> ILDNData;
raw_svector_ostream OS(ILDNData);
DebugName.write(OS);
addSection(M, Globals, ILDNData, "dx.ildn", "ILDN");
-
- // TODO: Do not create PDB in embedded mode.
- // 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)),
- "dx.pdb.hash", ModuleHashSectionName));
}
GlobalVariable *DXContainerGlobals::buildContainerGlobal(
diff --git a/llvm/lib/Target/DirectX/DXContainerPDB.cpp b/llvm/lib/Target/DirectX/DXContainerPDB.cpp
index 9a0933af4c165..5d0d04a9646b4 100644
--- a/llvm/lib/Target/DirectX/DXContainerPDB.cpp
+++ b/llvm/lib/Target/DirectX/DXContainerPDB.cpp
@@ -145,7 +145,8 @@ bool DXContainerPDB::runOnModule(Module &M) {
// Write PDB file.
codeview::GUID IgnoredOutGuid;
if (Error Err = Builder.commit(DebugFileName, &IgnoredOutGuid))
- reportFatalUsageError(std::move(Err));
+ reportFatalUsageError(
+ formatv("Couldn't write to PDB file: {0}", toString(std::move(Err))));
reset();
diff --git a/llvm/lib/Target/DirectX/DXILWriter/DXILWriterPass.cpp b/llvm/lib/Target/DirectX/DXILWriter/DXILWriterPass.cpp
index e78e6775403fa..9bbb87327d749 100644
--- a/llvm/lib/Target/DirectX/DXILWriter/DXILWriterPass.cpp
+++ b/llvm/lib/Target/DirectX/DXILWriter/DXILWriterPass.cpp
@@ -35,6 +35,9 @@
using namespace llvm;
using namespace llvm::dxil;
+extern cl::opt<bool> EmbedDebug;
+extern cl::opt<std::string> PdbDebugPath;
+
namespace {
class WriteDXILPass : public llvm::ModulePass {
raw_ostream &OS; // raw_ostream to print on
@@ -227,6 +230,18 @@ class EmbedDXILPass : public llvm::ModulePass {
legalizeLifetimeIntrinsics(M);
bool HasDebugInfo = !M.debug_compile_units().empty();
+
+ // Enable EmbedDebug if there is debug info, but it is not being written
+ // to a PDB file.
+ if (HasDebugInfo && !EmbedDebug && 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");
+
std::string ILDBData;
if (HasDebugInfo) {
// Write DXIL with debug info to ILDB part.
diff --git a/llvm/test/CodeGen/DirectX/ContainerData/ContainerFlags.ll b/llvm/test/CodeGen/DirectX/ContainerData/ContainerFlags.ll
new file mode 100644
index 0000000000000..36eb5b0b1b8e3
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/ContainerData/ContainerFlags.ll
@@ -0,0 +1,38 @@
+;; Check that --dx-embed-debug is enabled by default when debug info is present
+; RUN: llc %S/Inputs/SourceInfo.ll --filetype=obj -o %t.cso
+; RUN: obj2yaml %t.cso | FileCheck %s --check-prefix=DEFAULT-EMBED
+; DEFAULT-EMBED: Parts:
+; DEFAULT-EMBED: - Name: ILDB
+; DEFAULT-EMBED: - Name: ILDN
+
+;; Check that debug info is not embedded if only the PDB ouput is specified
+; RUN: llc %S/Inputs/SourceInfo.ll --filetype=obj --dx-Fd=%t.pdb -o %t.cso
+; RUN: obj2yaml %t.cso | FileCheck %s --check-prefix=NO-EMBED
+; NO-EMBED: Parts:
+; NO-EMBED-NOT: - Name: ILDB
+; NO-EMBED: - Name: ILDN
+
+;; Check that debug info is both embedded and output to the PDB
+;; if both options are specified
+; RUN: llc %S/Inputs/SourceInfo.ll --filetype=obj --dx-embed-debug --dx-Fd=%t.pdb -o %t.cso
+; RUN: obj2yaml %t.cso | FileCheck %s --check-prefix=EMBED
+; EMBED: Parts:
+; EMBED: - Name: ILDB
+; EMBED: - Name: ILDN
+; RUN: llvm-pdbutil pdb2yaml --dxcontainer %t.pdb | FileCheck %s --check-prefix=PDB
+; Check that PDB file contains only debug-info relevant parts.
+; PDB: Parts:
+; PDB-DAG: - Name: ILDB
+; PDB-DAG: - Name: ILDN
+
+;; Check errors when trying to output debug info with no debug info present
+; RUN: not llc %s --filetype=obj --dx-embed-debug -o %t.cso 2>&1 | FileCheck %s --check-prefix=ERROR-NODBG
+; ERROR-NODBG: Missing debug info for embedding into the container
+; RUN: not llc %s --filetype=obj --dx-Fd=%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
+
+target triple = "dxil-unknown-shadermodel6.5-library"
+
+define i32 @foo(i32 %a) {
+ ret i32 %a
+}
diff --git a/llvm/test/CodeGen/DirectX/ContainerData/DebugName-default-output.test b/llvm/test/CodeGen/DirectX/ContainerData/DebugName-default-output.test
index 3914a3250df7d..abaee2ac5b3b3 100644
--- a/llvm/test/CodeGen/DirectX/ContainerData/DebugName-default-output.test
+++ b/llvm/test/CodeGen/DirectX/ContainerData/DebugName-default-output.test
@@ -3,7 +3,6 @@ RUN: llvm-objcopy --dump-section=DXIL=%t0.bc %t.dxbc
RUN: %md5sum %t0.bc >%t0.bc.md5
RUN: obj2yaml %t.dxbc >%t.yaml
RUN: cat %t.yaml %t0.bc.md5 | FileCheck %s
-RUN: %python %S/Inputs/check_pdb_exists.py "" "%t0.bc.md5"
CHECK-NOT: - Name: PDBN
CHECK-NOT: - Name: PDBH
diff --git a/llvm/test/CodeGen/DirectX/ContainerData/DebugName-user-directory.test b/llvm/test/CodeGen/DirectX/ContainerData/DebugName-user-directory.test
index 3a6fb6c0476f2..f380fe6458b8f 100644
--- a/llvm/test/CodeGen/DirectX/ContainerData/DebugName-user-directory.test
+++ b/llvm/test/CodeGen/DirectX/ContainerData/DebugName-user-directory.test
@@ -1,5 +1,5 @@
RUN: rm -rf %t && mkdir %t
-RUN: llc %S/Inputs/SourceInfo.ll --filetype=obj -o %t.dxbc --dx-pdb-dir=%t
+RUN: llc %S/Inputs/SourceInfo.ll --filetype=obj -o %t.dxbc --dx-Fd=%t/
RUN: llvm-objcopy --dump-section=DXIL=%t0.bc %t.dxbc
RUN: %md5sum %t0.bc >%t0.bc.md5
RUN: obj2yaml %t.dxbc >%t.yaml
diff --git a/llvm/test/CodeGen/DirectX/ContainerData/DebugName-user-specified.test b/llvm/test/CodeGen/DirectX/ContainerData/DebugName-user-specified.test
new file mode 100644
index 0000000000000..a2a8a3d1d79e9
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/ContainerData/DebugName-user-specified.test
@@ -0,0 +1,9 @@
+RUN: rm -rf %t && mkdir %t
+RUN: llc %S/Inputs/SourceInfo.ll --filetype=obj -o - --dx-Fd=%t/ofile.pdb | obj2yaml | FileCheck %s
+RUN: test -f %t/ofile.pdb
+
+CHECK: - Name: ILDN
+CHECK: DebugName:
+CHECK-NEXT: Flags: 0
+CHECK-NEXT: NameLength: {{.*}}
+CHECK-NEXT: DebugName: {{.*[/\]+}}ofile.pdb
diff --git a/llvm/test/CodeGen/DirectX/ContainerData/DebugName.test b/llvm/test/CodeGen/DirectX/ContainerData/DebugName.test
new file mode 100644
index 0000000000000..d2462aec17e6b
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/ContainerData/DebugName.test
@@ -0,0 +1,22 @@
+# Check that debug name and hashed are passed to DXContainerPDBPass, but
+# not emitted into output file (checked with --implicit-check-not arguments).
+RUN: opt %S/Inputs/SourceInfo.ll -dxil-embed -dxil-globals --dx-Fd=%t.pdb -S -o - \
+RUN: | FileCheck %s --check-prefix=BC
+BC: @dx.pdb.name
+BC: @dx.pdb.hash
+
+# Check that ILDN debug name is calculated from DXIL by default.
+RUN: llc %S/Inputs/SourceInfo.ll --filetype=obj -o %t.dxbc
+RUN: llvm-objcopy --dump-section=DXIL=%t0.bc %t.dxbc
+RUN: %md5sum %t0.bc >%t0.bc.md5
+RUN: obj2yaml %t.dxbc >%t.yaml
+RUN: cat %t.yaml %t0.bc.md5 | FileCheck %s --implicit-check-not PDBN --implicit-check-not PDBH
+
+CHECK: - Name: ILDN
+CHECK-NEXT: Size: 44
+CHECK-NEXT: DebugName:
+CHECK-NEXT: Flags: 0
+CHECK-NEXT: NameLength: 36
+CHECK-NEXT: DebugName: [[MD5:[0-9a-f]+]].pdb
+CHECK: ...
+CHECK-NEXT: [[MD5]]
diff --git a/llvm/test/CodeGen/DirectX/ContainerData/PDBParts.test b/llvm/test/CodeGen/DirectX/ContainerData/PDBParts.test
index 8fc7f5adb4e9c..9964bb87585ab 100644
--- a/llvm/test/CodeGen/DirectX/ContainerData/PDBParts.test
+++ b/llvm/test/CodeGen/DirectX/ContainerData/PDBParts.test
@@ -1,5 +1,5 @@
RUN: rm -rf %t && mkdir %t
-RUN: llc %S/Inputs/SourceInfo.ll --filetype=obj -o %t.dxbc --dx-pdb-file=%t/parts.pdb
+RUN: llc %S/Inputs/SourceInfo.ll --filetype=obj -o %t.dxbc --dx-Fd=%t/parts.pdb
RUN: llvm-pdbutil pdb2yaml --dxcontainer %t/parts.pdb | FileCheck %s
# Check that debug-related container parts are emitted into companion PDB file.
diff --git a/llvm/test/CodeGen/DirectX/ContainerData/SourceInfo-Args.ll b/llvm/test/CodeGen/DirectX/ContainerData/SourceInfo-Args.ll
index 9b22812e212df..299136e3ac1de 100644
--- a/llvm/test/CodeGen/DirectX/ContainerData/SourceInfo-Args.ll
+++ b/llvm/test/CodeGen/DirectX/ContainerData/SourceInfo-Args.ll
@@ -1,4 +1,5 @@
-; RUN: llc %S/Inputs/SourceInfo.ll --filetype=obj -o - | obj2yaml | FileCheck %s --check-prefix=DXC
+; RUN: llc %S/Inputs/SourceInfo.ll --filetype=obj --dx-Fd=%t.pdb -o /dev/null
+; RUN: llvm-pdbutil pdb2yaml --dxcontainer %t.pdb | FileCheck %s --check-prefix=DXC
; DXC: - Name: SRCI
; DXC: SourceInfo:
diff --git a/llvm/test/CodeGen/DirectX/ContainerData/SourceInfo-Compressed.ll b/llvm/test/CodeGen/DirectX/ContainerData/SourceInfo-Compressed.ll
index 1d7e39fb77ff2..5ee7255788c8c 100644
--- a/llvm/test/CodeGen/DirectX/ContainerData/SourceInfo-Compressed.ll
+++ b/llvm/test/CodeGen/DirectX/ContainerData/SourceInfo-Compressed.ll
@@ -1,5 +1,6 @@
; RUN: opt %S/Inputs/SourceInfo.ll -dxil-embed -dxil-globals -S -o - | FileCheck %s
-; RUN: llc %S/Inputs/SourceInfo.ll --filetype=obj -o - | obj2yaml | FileCheck %s --check-prefix=DXC
+; RUN: llc %S/Inputs/SourceInfo.ll --filetype=obj --dx-Fd=%t.pdb -o /dev/null
+; RUN: llvm-pdbutil pdb2yaml --dxcontainer %t.pdb | FileCheck %s --check-prefix=DXC
; REQUIRES: zlib
; CHECK: @dx.srci = private constant [348 x i8] c"{{.*}}", section "SRCI", align 4
diff --git a/llvm/test/CodeGen/DirectX/ContainerData/SourceInfo-Uncompressed.ll b/llvm/test/CodeGen/DirectX/ContainerData/SourceInfo-Uncompressed.ll
index df42386f1c418..6ced1580812b1 100644
--- a/llvm/test/CodeGen/DirectX/ContainerData/SourceInfo-Uncompressed.ll
+++ b/llvm/test/CodeGen/DirectX/ContainerData/SourceInfo-Uncompressed.ll
@@ -1,5 +1,6 @@
; RUN: opt %S/Inputs/SourceInfo.ll -compress-srci=none -dxil-embed -dxil-globals -S -o - | FileCheck %s
-; RUN: llc %S/Inputs/SourceInfo.ll -compress-srci=none --filetype=obj -o - | obj2yaml | FileCheck %s --check-prefix=DXC
+; RUN: llc %S/Inputs/SourceInfo.ll -compress-srci=none --filetype=obj --dx-Fd=%t.pdb -o /dev/null
+; RUN: llvm-pdbutil pdb2yaml --dxcontainer %t.pdb | FileCheck %s --check-prefix=DXC
; CHECK: @dx.srci = private constant [416 x i8] c"{{.*}}", section "SRCI", align 4
diff --git a/llvm/test/CodeGen/DirectX/embed-ildb.ll b/llvm/test/CodeGen/DirectX/embed-ildb.ll
index 5f1b17e0e1e56..84bdad2b39e08 100644
--- a/llvm/test/CodeGen/DirectX/embed-ildb.ll
+++ b/llvm/test/CodeGen/DirectX/embed-ildb.ll
@@ -1,6 +1,6 @@
; RUN: rm -f %t.pdb
; RUN: opt %s -dxil-embed -dxil-globals -S -o - | FileCheck %s
-; RUN: llc %s --filetype=obj -o %t.bc --dx-pdb-file=%t.pdb
+; RUN: llc %s --filetype=obj --dx-embed-debug -o %t.bc --dx-Fd=%t.pdb
; RUN: obj2yaml %t.bc | FileCheck %s --check-prefix=YAML
; RUN: llvm-objcopy --dump-section=ILDB=%t.ildb %t.bc
; RUN: llvm-objcopy --dump-section=DXIL=%t.dxil %t.bc
@@ -40,11 +40,11 @@ define i32 @add(i32 %a, i32 %b) {
!7 = !{!"hlsl.hlsl"}
!8 = !{!"-T", !"lib_6_5", !"-g", !"hlsl.hlsl"}
-; Check that DXIL, ILDB and SRCI parts are emitted as a GV and used by the compiler.
+
+; Check that DXIL and ILDB parts are emitted as a GV and used by the compiler.
; CHECK: @dx.ildb = private constant [[BC_TYPE:\[[0-9]+ x i8\]]] c"BC\C0\DE{{[^"]+}}", section "ILDB", align 4
; CHECK: @dx.dxil = private constant [[BC_TYPE:\[[0-9]+ x i8\]]] c"BC\C0\DE{{[^"]+}}", section "DXIL", align 4
-; CHECK: @dx.srci = private constant {{\[[0-9]+ x i8\]}}
; CHECK: @llvm.compiler.used = appending global {{\[[0-9]+ x ptr\]}} [ptr @dx.ildb, ptr @dx.dxil
; This is using regex matches on some sizes, offsets and fields. These are all
@@ -89,9 +89,6 @@ define i32 @add(i32 %a, i32 %b) {
; YAML-NEXT: DXILSize: [[#DXILSIZE - 24]]
; YAML-NEXT: DXIL: [ 0x42, 0x43, 0xC0, 0xDE,
-; Check that despite dx.source is stripped from DXIL, SRCI is still emitted:
-; YAML: - Name: SRCI
-
; Check that ILDB has the debug info, and DXIL does not:
; ILDB-DIS: define i32 @add(i32 %a, i32 %b)
>From 616f7719ee59a6093a72358266b46c83c1d3b04a Mon Sep 17 00:00:00 2001
From: Ilia Kuklin <ikuklin at accesssoftek.com>
Date: Wed, 17 Jun 2026 04:27:11 +0500
Subject: [PATCH 2/5] Use c_str for formatv
---
llvm/lib/Target/DirectX/DXContainerPDB.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/llvm/lib/Target/DirectX/DXContainerPDB.cpp b/llvm/lib/Target/DirectX/DXContainerPDB.cpp
index 5d0d04a9646b4..824bc001dd0d3 100644
--- a/llvm/lib/Target/DirectX/DXContainerPDB.cpp
+++ b/llvm/lib/Target/DirectX/DXContainerPDB.cpp
@@ -145,8 +145,8 @@ bool DXContainerPDB::runOnModule(Module &M) {
// Write PDB file.
codeview::GUID IgnoredOutGuid;
if (Error Err = Builder.commit(DebugFileName, &IgnoredOutGuid))
- reportFatalUsageError(
- formatv("Couldn't write to PDB file: {0}", toString(std::move(Err))));
+ reportFatalUsageError(formatv("Couldn't write to PDB file: {0}",
+ toString(std::move(Err)).c_str()));
reset();
>From de2ad3562e0f5a50b0fd2a790e66137af171d6e7 Mon Sep 17 00:00:00 2001
From: Ilia Kuklin <ikuklin at accesssoftek.com>
Date: Wed, 17 Jun 2026 21:19:13 +0500
Subject: [PATCH 3/5] Use Twine in error message
---
llvm/lib/Target/DirectX/DXContainerPDB.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/llvm/lib/Target/DirectX/DXContainerPDB.cpp b/llvm/lib/Target/DirectX/DXContainerPDB.cpp
index 824bc001dd0d3..49fb9f4b290fb 100644
--- a/llvm/lib/Target/DirectX/DXContainerPDB.cpp
+++ b/llvm/lib/Target/DirectX/DXContainerPDB.cpp
@@ -145,8 +145,8 @@ bool DXContainerPDB::runOnModule(Module &M) {
// Write PDB file.
codeview::GUID IgnoredOutGuid;
if (Error Err = Builder.commit(DebugFileName, &IgnoredOutGuid))
- reportFatalUsageError(formatv("Couldn't write to PDB file: {0}",
- toString(std::move(Err)).c_str()));
+ reportFatalUsageError("Couldn't write to PDB file: " +
+ Twine(toString(std::move(Err))));
reset();
>From 8179e4a95c0f14357e812369dcdf15b9e4a17186 Mon Sep 17 00:00:00 2001
From: Ilia Kuklin <ikuklin at accesssoftek.com>
Date: Fri, 19 Jun 2026 15:42:05 +0500
Subject: [PATCH 4/5] Adjust Options.td
---
clang/include/clang/Options/Options.td | 31 +++++++++++---------------
1 file changed, 13 insertions(+), 18 deletions(-)
diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td
index e2a14d364f457..ceb430029aba1 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -9319,9 +9319,10 @@ def _SLASH_ZH_SHA1 : CLFlag<"ZH:SHA1">,
HelpText<"Use SHA1 for file checksums in debug info">,
Alias<gsrc_hash_EQ>, AliasArgs<["sha1"]>;
def _SLASH_ZH_SHA_256 : CLFlag<"ZH:SHA_256">,
- HelpText<"Use SHA256 for file checksums in debug info">,
- Alias<gsrc_hash_EQ>,
- AliasArgs<["sha256"]>;
+ HelpText<"Use SHA256 for file checksums in debug info">,
+ Alias<gsrc_hash_EQ>, AliasArgs<["sha256"]>;
+def _SLASH_Zi : CLFlag<"Zi", [CLOption, DXCOption]>, Alias<g_Flag>,
+ HelpText<"Enable debug information">;
def _SLASH_Zp : CLJoined<"Zp">,
HelpText<"Set default maximum struct packing alignment">,
Alias<fpack_struct_EQ>;
@@ -9661,22 +9662,14 @@ def dxc_Fc : DXCJoinedOrSeparate<"Fc">,
HelpText<"Output assembly listing file">;
def dxc_Frs : DXCJoinedOrSeparate<"Frs">,
HelpText<"Output additional root signature object file">;
-def dxc_Zss : DXCFlag<"Zss">,
- HelpText<"Compute Shader Hash considering source information">;
-def dxc_Zsb : DXCFlag<"Zsb">,
- HelpText<"Compute Shader Hash considering only output binary">;
def dxc_Fd
: DXCJoinedOrSeparate<"Fd">,
HelpText<"Write debug information to the given file, or automatically "
"named file in directory when ending in '/'">;
-def dxc_Qembed_debug
- : DXCFlag<"Qembed_debug">,
- HelpText<"Embed PDB in shader container (must be used with /Zi)">;
-def dxc_Zi : Option<["/", "-"], "Zi", KIND_FLAG>,
- Group<dxc_Group>,
- Alias<g_Flag>,
- Visibility<[CLOption, DXCOption]>,
- HelpText<"Enable debug information">;
+def dxc_Zss : DXCFlag<"Zss">,
+ HelpText<"Compute Shader Hash considering source information">;
+def dxc_Zsb : DXCFlag<"Zsb">,
+ HelpText<"Compute Shader Hash considering only output binary">;
def dxil_validator_version : Option<["/", "-"], "validator-version", KIND_SEPARATE>,
Group<dxc_Group>, Flags<[HelpHidden]>,
Visibility<[DXCOption, ClangOption, CC1Option]>,
@@ -9771,9 +9764,11 @@ def spirv_validator_path_EQ : Joined<["--"], "spirv-val-path=">, Group<dxc_Group
HelpText<"SPIRV validator installation path">;
def dxc_disable_validation : DXCFlag<"Vd">,
HelpText<"Disable validation">;
-def dxc_gis
- : DXCFlag<"Gis">,
- HelpText<"Enable IEEE strict mode (equivalent to -ffp-model=strict)">;
+def dxc_gis : DXCFlag<"Gis">,
+ HelpText<"Enable IEEE strict mode (equivalent to -ffp-model=strict)">;
+def dxc_Qembed_debug
+ : DXCFlag<"Qembed_debug">,
+ HelpText<"Embed PDB in shader container (must be used with /Zi)">;
def spirv : DXCFlag<"spirv">,
HelpText<"Generate SPIR-V code">;
def metal : DXCFlag<"metal">, HelpText<"Generate Metal library">;
>From a5dc61c04e2661580a8cb9195ef394299b624ef7 Mon Sep 17 00:00:00 2001
From: Ilia Kuklin <ikuklin at accesssoftek.com>
Date: Fri, 19 Jun 2026 16:08:21 +0500
Subject: [PATCH 5/5] Rename local Zi to HasDebug
---
clang/lib/Driver/ToolChains/Clang.cpp | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index b3b8280de3006..1a4f4fcec2c9a 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -3854,16 +3854,16 @@ static void RenderHLSLOptions(const Driver &D, const ArgList &Args,
}
if (Arg *A = Args.getLastArg(options::OPT_dxc_Zsb))
A->claim(); // /Zsb is the default behavior, no need to forward it to llc.
- bool Zi = Args.hasArg(options::OPT_g_Flag);
+ bool HasDebug = Args.hasArg(options::OPT_g_Flag);
bool Qembed_debug = Args.hasArg(options::OPT_dxc_Qembed_debug);
Arg *Fd = Args.getLastArg(options::OPT_dxc_Fd);
- if (Zi && !Fd && !Qembed_debug) {
+ if (HasDebug && !Fd && !Qembed_debug) {
D.Diag(diag::warn_drv_dxc_no_output_for_debug);
Qembed_debug = true;
}
- if (Qembed_debug && !Zi)
+ if (Qembed_debug && !HasDebug)
D.Diag(diag::err_drv_no_debug_info_for_embed_debug);
- if (Fd && !Zi)
+ if (Fd && !HasDebug)
D.Diag(diag::err_drv_no_debug_info_for_Fd);
if (Qembed_debug) {
CmdArgs.push_back("-mllvm");
More information about the cfe-commits
mailing list