diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td index 025e8e7d7d76..c12aa193c345 100644 --- a/clang/include/clang/Options/Options.td +++ b/clang/include/clang/Options/Options.td @@ -9624,6 +9624,11 @@ def dxc_Fc : DXCJoinedOrSeparate<"Fc">, HelpText<"Output assembly listing file">; def dxc_Frs : DXCJoinedOrSeparate<"Frs">, HelpText<"Output additional root signature object file">; +def dxc_source_in_debug_module + : Option<["/", "-"], "Qsource_in_debug_module", KIND_FLAG>, + Group, + Visibility<[DXCOption]>, + HelpText<"Embed source code into debug module on DirectX target">; def dxil_validator_version : Option<["/", "-"], "validator-version", KIND_SEPARATE>, Group, Flags<[HelpHidden]>, Visibility<[DXCOption, ClangOption, CC1Option]>, diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 7657afb14f07..98b988008e10 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -3832,6 +3832,11 @@ static void RenderHLSLOptions(const ArgList &Args, ArgStringList &CmdArgs, if (!Args.hasArg(options::OPT_dxc_no_stdinc) && !Args.hasArg(options::OPT_nostdinc)) CmdArgs.push_back("-finclude-default-header"); + + if (Args.hasArg(options::OPT_dxc_source_in_debug_module)) { + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back("--dx-source-in-debug-module"); + } } static void RenderOpenACCOptions(const Driver &D, const ArgList &Args, diff --git a/clang/test/Driver/dxc_source_in_debug_module.hlsl b/clang/test/Driver/dxc_source_in_debug_module.hlsl new file mode 100644 index 000000000000..cb09518c049c --- /dev/null +++ b/clang/test/Driver/dxc_source_in_debug_module.hlsl @@ -0,0 +1,6 @@ +// RUN: %clang_dxc -Tlib_6_7 -### /Zi /Qsource_in_debug_module %s 2>&1 | FileCheck %s +// RUN: %clang_dxc -Tlib_6_7 -### /Zi -Qsource_in_debug_module %s 2>&1 | FileCheck %s +// RUN: %clang_dxc -Tlib_6_7 -### /Zi %s 2>&1 | FileCheck %s --check-prefix=NOFLAG + +// CHECK: "-mllvm" "--dx-source-in-debug-module" +// NOFLAG-NOT: --dx-source-in-debug-module diff --git a/llvm/lib/Target/DirectX/DXILTranslateMetadata.cpp b/llvm/lib/Target/DirectX/DXILTranslateMetadata.cpp index 49a20e2f7517..240d5814d33d 100644 --- a/llvm/lib/Target/DirectX/DXILTranslateMetadata.cpp +++ b/llvm/lib/Target/DirectX/DXILTranslateMetadata.cpp @@ -514,15 +514,18 @@ static void cleanModuleFlags(Module &M) { M.addModuleFlag(Flag.Behavior, Flag.Key->getString(), Flag.Val); } -using GlobalMDList = std::array; +using GlobalMDList = std::array; // The following are compatible with DXIL but not emit with clang, they can // be added when applicable: // dx.typeAnnotations, dx.viewIDState, dx.dxrPayloadAnnotations static GlobalMDList CompatibleNamedModuleMDs = { - "llvm.ident", "llvm.module.flags", "dx.resources", "dx.valver", - "dx.shaderModel", "dx.version", "dx.entryPoints", -}; + "llvm.ident", "llvm.module.flags", + "dx.resources", "dx.valver", + "dx.shaderModel", "dx.version", + "dx.entryPoints", "dx.source.contents", + "dx.source.defines", "dx.source.mainFileName", + "dx.source.args"}; static void translateGlobalMetadata(Module &M, DXILResourceMap &DRM, DXILResourceTypeMap &DRTM, diff --git a/llvm/lib/Target/DirectX/DXILWriter/DXILWriterPass.cpp b/llvm/lib/Target/DirectX/DXILWriter/DXILWriterPass.cpp index f74accc3b861..f06777aa8f47 100644 --- a/llvm/lib/Target/DirectX/DXILWriter/DXILWriterPass.cpp +++ b/llvm/lib/Target/DirectX/DXILWriter/DXILWriterPass.cpp @@ -28,11 +28,17 @@ #include "llvm/InitializePasses.h" #include "llvm/Pass.h" #include "llvm/Support/Alignment.h" +#include "llvm/Support/CommandLine.h" #include "llvm/Transforms/Utils/ModuleUtils.h" using namespace llvm; using namespace llvm::dxil; +static cl::opt SourceInDebugModule( + "dx-source-in-debug-module", + cl::desc("Embed source code into debug module on DirectX target"), + cl::init(false)); + namespace { class WriteDXILPass : public llvm::ModulePass { raw_ostream &OS; // raw_ostream to print on @@ -138,6 +144,16 @@ static void removeLifetimeIntrinsics(Module &M) { } } +static void replaceNamedMetadataArray(Module &M, StringRef Name, + ArrayRef NewOps) { + NamedMDNode *NMD = M.getNamedMetadata(Name); + if (!NMD) + return; + NMD->eraseFromParent(); + M.getOrInsertNamedMetadata(Name)->addOperand( + MDTuple::get(M.getContext(), NewOps)); +} + class EmbedDXILPass : public llvm::ModulePass { public: static char ID; // Pass identification, replacement for typeid @@ -155,6 +171,16 @@ class EmbedDXILPass : public llvm::ModulePass { // fail the Module Verifier if performed in an earlier pass legalizeLifetimeIntrinsics(M); + // Replace dx.source metadata nodes with stubs. + if (!SourceInDebugModule) { + LLVMContext &Ctx = M.getContext(); + MDString *EmptyString = MDString::get(Ctx, ""); + replaceNamedMetadataArray(M, "dx.source.contents", + {EmptyString, EmptyString}); + replaceNamedMetadataArray(M, "dx.source.defines", {}); + replaceNamedMetadataArray(M, "dx.source.mainFileName", {EmptyString}); + replaceNamedMetadataArray(M, "dx.source.args", {}); + } const auto DIMap = DXILDebugInfoPass::run(M); WriteDXILToFile(M, OS, DIMap); diff --git a/llvm/test/CodeGen/DirectX/ContainerData/SourceInfo-Strip.ll b/llvm/test/CodeGen/DirectX/ContainerData/SourceInfo-Strip.ll new file mode 100644 index 000000000000..6feea2b79a2e --- /dev/null +++ b/llvm/test/CodeGen/DirectX/ContainerData/SourceInfo-Strip.ll @@ -0,0 +1,56 @@ +; Compare source info emission with and without --dx-source-in-debug-module flag. + +; RUN: llc %s --filetype=obj -o %t.dxbc +; RUN: llvm-objcopy --dump-section=DXIL=%t.dxil.bc %t.dxbc +; RUN: llvm-dis %t.dxil.bc -o - | FileCheck %s --check-prefix=ILDB-DIS + +; RUN: llc %s --filetype=obj -o %t.dxbc --dx-source-in-debug-module +; RUN: llvm-objcopy --dump-section=DXIL=%t.dxil.bc %t.dxbc +; RUN: llvm-dis %t.dxil.bc -o - | FileCheck %s --check-prefix=ILDB-SOURCE-DIS + +; Without the flag, dx.source should be replaced with dummy metadata. +; ILDB-DIS: !dx.source.contents = !{![[CONTENTS:[0-9]+]]} +; ILDB-DIS: !dx.source.defines = !{![[EMPTY_ARR:[0-9]+]]} +; ILDB-DIS: !dx.source.mainFileName = !{![[MAIN:[0-9]+]]} +; ILDB-DIS: !dx.source.args = !{![[EMPTY_ARR]]} +; ILDB-DIS: ![[CONTENTS]] = !{!"", !""} +; ILDB-DIS: ![[EMPTY_ARR]] = !{} +; ILDB-DIS: ![[MAIN]] = !{!""} + +; With the flag, dx.source should be be preserved. +; ILDB-SOURCE-DIS: !dx.source.args = !{![[ARGS:[0-9]+]]} +; ILDB-SOURCE-DIS: !dx.source.contents = !{![[FILE1:[0-9]+]], ![[FILE2:[0-9]+]], ![[FILE3:[0-9]+]]} +; ILDB-SOURCE-DIS: !dx.source.mainFileName = !{![[MAIN:[0-9]+]]} +; ILDB-SOURCE-DIS: !dx.source.defines = !{![[DEFINES:[0-9]+]]} +; ILDB-SOURCE-DIS: ![[FILE1]] = !{!"C:\\dx-source-metadata.hlsl", +; ILDB-SOURCE-DIS: ![[FILE2]] = !{!"C:\\a.hlsl" +; ILDB-SOURCE-DIS: ![[FILE3]] = !{!"C:\\b.hlsl" +; ILDB-SOURCE-DIS: ![[MAIN]] = !{!"C:\\dx-source-metadata.hlsl"} +; ILDB-SOURCE-DIS: ![[DEFINES]] = !{!"USER_DEF0=42", !"USER_DEF1=43"} + +target triple = "dxilv1.3-pc-shadermodel6.3-library" + +define float @_Z3fooff(float %a, float %b) { +entry: + %add = fadd float %a, %b + ret float %add +} + +!llvm.dbg.cu = !{!4} +!llvm.module.flags = !{!6, !7} + +!dx.source.args = !{!0} +!dx.source.contents = !{!1, !2, !3} +!dx.source.mainFileName = !{!8} +!dx.source.defines = !{!9} + +!0 = !{!"-g", !"-Tlib_6_3", !"-DUSER_DEF0=42", !"-DUSER_DEF1=43", !"C:\\\\dx-source-metadata.hlsl"} +!1 = !{!"C:\\dx-source-metadata.hlsl", !"#include \22a.hlsl\22\0A#include \22b.hlsl\22\0A\0Afloat foo(float a, float b) {\0A return a + b;\0A}\0A"} +!2 = !{!"C:\\a.hlsl", !"#include \22b.hlsl\22\0A"} +!3 = !{!"C:\\b.hlsl", !"#include \0A"} +!4 = distinct !DICompileUnit(language: DW_LANG_C99, file: !5, emissionKind: FullDebug) +!5 = !DIFile(filename: "dx-source-metadata.hlsl", directory: "C:\\") +!6 = !{i32 2, !"Dwarf Version", i32 4} +!7 = !{i32 2, !"Debug Info Version", i32 3} +!8 = !{!"C:\\dx-source-metadata.hlsl"} +!9 = !{!"USER_DEF0=42", !"USER_DEF1=43"}