فهرست منبع

[spirv] Add mechanism for fine-grained control of debug info (#1518)

Added a new command-line option: -fspv-debug=<category>, where
category can be file, source, line, and tool, to give developers
fine-grained control of what debug information they want in
the generated SPIR-V code.
Lei Zhang 7 سال پیش
والد
کامیت
81b3451b4a

+ 19 - 0
docs/SPIR-V.rst

@@ -451,6 +451,9 @@ let the compiler emit the following additional debug information:
 * Full path of the main source file using ``OpSource``
 * Full path of the main source file using ``OpSource``
 * Preprocessed source code using ``OpSource`` and ``OpSourceContinued``
 * Preprocessed source code using ``OpSource`` and ``OpSourceContinued``
 * Line information for certain instructions using ``OpLine`` (WIP)
 * Line information for certain instructions using ``OpLine`` (WIP)
+* DXC Git commit hash using ``OpModuleProcessed`` (requires Vulkan 1.1)
+* DXC command-line options used to compile the shader using ``OpModuleProcessed``
+  (requires Vulkan 1.1)
 
 
 We chose to embed preprocessed source code instead of original source code to
 We chose to embed preprocessed source code instead of original source code to
 avoid pulling in lots of contents unrelated to the current entry point, and
 avoid pulling in lots of contents unrelated to the current entry point, and
@@ -464,6 +467,19 @@ preprocessing the source code, and the second time is for feeding the
 preprocessed source code as input for a whole compilation. So using ``-Zi``
 preprocessed source code as input for a whole compilation. So using ``-Zi``
 means performance penality.
 means performance penality.
 
 
+If you want to have fine-grained control over the categories of emitted debug
+information, you can use ``-fspv-debug=``. It accepts:
+
+* ``file``: for emitting full path of the main source file
+* ``source``: for emitting preprocessed source code (turns on ``file`` implicitly)
+* ``line``: for emitting line information (turns on ``source`` implicitly)
+* ``tool``: for emitting DXC Git commit hash and command-line options
+
+``-fspv-debug=`` overrules ``-Zi``. And you can provide multiple instances of
+``-fspv-debug=``. For example, you can use ``-fspv-debug=file -fspv-debug=tool``
+to turn on emitting file path and DXC information; source code and line
+information will not be emitted.
+
 Reflection
 Reflection
 ----------
 ----------
 
 
@@ -2877,6 +2893,9 @@ codegen for Vulkan:
   location number according to alphabetical order or declaration order. See
   location number according to alphabetical order or declaration order. See
   `HLSL semantic and Vulkan Location`_ for more details.
   `HLSL semantic and Vulkan Location`_ for more details.
 - ``-fspv-reflect``: Emits additional SPIR-V instructions to aid reflection.
 - ``-fspv-reflect``: Emits additional SPIR-V instructions to aid reflection.
+- ``-fspv-debug=<category>``: Controls what category of debug information
+  should be emitted. Accepted values are ``file``, ``source``, ``line``, and
+  ``tool``. See `Debugging`_ for more details.
 - ``-fspv-extension=<extension>``: Only allows using ``<extension>`` in CodeGen.
 - ``-fspv-extension=<extension>``: Only allows using ``<extension>`` in CodeGen.
   If you want to allow multiple extensions, provide more than one such option. If you
   If you want to allow multiple extensions, provide more than one such option. If you
   want to allow *all* KHR extensions, use ``-fspv-extension=KHR``.
   want to allow *all* KHR extensions, use ``-fspv-extension=KHR``.

+ 4 - 0
include/dxc/Support/HLSLOptions.h

@@ -167,6 +167,10 @@ public:
   bool VkUseDxLayout;                      // OPT_fvk_use_dx_layout
   bool VkUseDxLayout;                      // OPT_fvk_use_dx_layout
   bool SpvEnableReflect;                   // OPT_fspv_reflect
   bool SpvEnableReflect;                   // OPT_fspv_reflect
   bool VkNoWarnIgnoredFeatures;            // OPT_Wno_vk_ignored_features
   bool VkNoWarnIgnoredFeatures;            // OPT_Wno_vk_ignored_features
+  bool SpvDebugFile;                       // OPT_fspv_debug
+  bool SpvDebugSource;                     // OPT_fspv_debug
+  bool SpvDebugLine;                       // OPT_fspv_debug
+  bool SpvDebugTool;                       // OPT_fspv_debug
   llvm::StringRef VkStageIoOrder;          // OPT_fvk_stage_io_order
   llvm::StringRef VkStageIoOrder;          // OPT_fvk_stage_io_order
   llvm::SmallVector<int32_t, 4> VkBShift;  // OPT_fvk_b_shift
   llvm::SmallVector<int32_t, 4> VkBShift;  // OPT_fvk_b_shift
   llvm::SmallVector<int32_t, 4> VkTShift;  // OPT_fvk_t_shift
   llvm::SmallVector<int32_t, 4> VkTShift;  // OPT_fvk_t_shift

+ 2 - 0
include/dxc/Support/HLSLOptions.td

@@ -259,6 +259,8 @@ def fvk_use_dx_layout: Flag<["-"], "fvk-use-dx-layout">, Group<spirv_Group>, Fla
   HelpText<"Use DirectX memory layout for Vulkan resources">;
   HelpText<"Use DirectX memory layout for Vulkan resources">;
 def fspv_reflect: Flag<["-"], "fspv-reflect">, Group<spirv_Group>, Flags<[CoreOption, DriverOption]>,
 def fspv_reflect: Flag<["-"], "fspv-reflect">, Group<spirv_Group>, Flags<[CoreOption, DriverOption]>,
   HelpText<"Emit additional SPIR-V instructions to aid reflection">;
   HelpText<"Emit additional SPIR-V instructions to aid reflection">;
+def fspv_debug_EQ : Joined<["-"], "fspv-debug=">, Group<spirv_Group>, Flags<[CoreOption, DriverOption]>,
+  HelpText<"Specify whitelist of debug info category (file -> source -> line, tool)">;
 def fspv_extension_EQ : Joined<["-"], "fspv-extension=">, Group<spirv_Group>, Flags<[CoreOption, DriverOption]>,
 def fspv_extension_EQ : Joined<["-"], "fspv-extension=">, Group<spirv_Group>, Flags<[CoreOption, DriverOption]>,
   HelpText<"Specify SPIR-V extension permitted to use">;
   HelpText<"Specify SPIR-V extension permitted to use">;
 def fspv_target_env_EQ : Joined<["-"], "fspv-target-env=">, Group<spirv_Group>, Flags<[CoreOption, DriverOption]>,
 def fspv_target_env_EQ : Joined<["-"], "fspv-target-env=">, Group<spirv_Group>, Flags<[CoreOption, DriverOption]>,

+ 28 - 1
lib/DxcSupport/HLSLOptions.cpp

@@ -556,7 +556,7 @@ int ReadDxcOpts(const OptTable *optionTable, unsigned flagsToInclude,
 
 
   // SPIRV Change Starts
   // SPIRV Change Starts
 #ifdef ENABLE_SPIRV_CODEGEN
 #ifdef ENABLE_SPIRV_CODEGEN
-  const bool genSpirv = opts.GenSPIRV = Args.hasFlag(OPT_spirv, OPT_INVALID, false);
+  opts.GenSPIRV = Args.hasFlag(OPT_spirv, OPT_INVALID, false);
   opts.VkInvertY = Args.hasFlag(OPT_fvk_invert_y, OPT_INVALID, false);
   opts.VkInvertY = Args.hasFlag(OPT_fvk_invert_y, OPT_INVALID, false);
   opts.VkInvertW = Args.hasFlag(OPT_fvk_use_dx_position_w, OPT_INVALID, false);
   opts.VkInvertW = Args.hasFlag(OPT_fvk_use_dx_position_w, OPT_INVALID, false);
   opts.VkUseGlLayout = Args.hasFlag(OPT_fvk_use_gl_layout, OPT_INVALID, false);
   opts.VkUseGlLayout = Args.hasFlag(OPT_fvk_use_gl_layout, OPT_INVALID, false);
@@ -583,6 +583,32 @@ int ReadDxcOpts(const OptTable *optionTable, unsigned flagsToInclude,
     opts.SpvExtensions.push_back(A->getValue());
     opts.SpvExtensions.push_back(A->getValue());
   }
   }
 
 
+  opts.SpvDebugFile = opts.SpvDebugSource = false;
+  opts.SpvDebugLine = opts.SpvDebugTool = false;
+  if (Args.hasArg(OPT_fspv_debug_EQ)) {
+    opts.DebugInfo = true;
+    for (const Arg *A : Args.filtered(OPT_fspv_debug_EQ)) {
+      const llvm::StringRef v = A->getValue();
+      if (v == "file") {
+        opts.SpvDebugFile = true;
+      } else if (v == "source") {
+        opts.SpvDebugFile = opts.SpvDebugSource = true;
+      } else if (v == "line") {
+        opts.SpvDebugFile = opts.SpvDebugSource = true;
+        opts.SpvDebugLine = true;
+      } else if (v == "tool") {
+        opts.SpvDebugTool = true;
+      } else {
+        errors << "unknown SPIR-V debug info control parameter: " << v;
+        return 1;
+      }
+    }
+  } else if (opts.DebugInfo) {
+    // By default turn on all categories
+    opts.SpvDebugFile = opts.SpvDebugSource = true;
+    opts.SpvDebugLine = opts.SpvDebugTool = true;
+  }
+
   opts.SpvTargetEnv = Args.getLastArgValue(OPT_fspv_target_env_EQ, "vulkan1.0");
   opts.SpvTargetEnv = Args.getLastArgValue(OPT_fspv_target_env_EQ, "vulkan1.0");
 
 
   // Handle -Oconfig=<comma-separated-list> option.
   // Handle -Oconfig=<comma-separated-list> option.
@@ -611,6 +637,7 @@ int ReadDxcOpts(const OptTable *optionTable, unsigned flagsToInclude,
       Args.hasFlag(OPT_fspv_reflect, OPT_INVALID, false) ||
       Args.hasFlag(OPT_fspv_reflect, OPT_INVALID, false) ||
       Args.hasFlag(OPT_Wno_vk_ignored_features, OPT_INVALID, false) ||
       Args.hasFlag(OPT_Wno_vk_ignored_features, OPT_INVALID, false) ||
       !Args.getLastArgValue(OPT_fvk_stage_io_order_EQ).empty() ||
       !Args.getLastArgValue(OPT_fvk_stage_io_order_EQ).empty() ||
+      !Args.getLastArgValue(OPT_fspv_debug_EQ).empty() ||
       !Args.getLastArgValue(OPT_fspv_extension_EQ).empty() ||
       !Args.getLastArgValue(OPT_fspv_extension_EQ).empty() ||
       !Args.getLastArgValue(OPT_fspv_target_env_EQ).empty() ||
       !Args.getLastArgValue(OPT_fspv_target_env_EQ).empty() ||
       !Args.getLastArgValue(OPT_Oconfig).empty() ||
       !Args.getLastArgValue(OPT_Oconfig).empty() ||

+ 6 - 2
tools/clang/include/clang/SPIRV/EmitSPIRVOptions.h

@@ -41,7 +41,10 @@ struct EmitSPIRVOptions {
   bool useDxLayout;
   bool useDxLayout;
   bool enable16BitTypes;
   bool enable16BitTypes;
   bool enableReflect;
   bool enableReflect;
-  bool enableDebugInfo;
+  bool debugInfoFile;
+  bool debugInfoSource;
+  bool debugInfoLine;
+  bool debugInfoTool;
   bool noWarnIgnoredFeatures;
   bool noWarnIgnoredFeatures;
   llvm::StringRef stageIoOrder;
   llvm::StringRef stageIoOrder;
   llvm::SmallVector<int32_t, 4> bShift;
   llvm::SmallVector<int32_t, 4> bShift;
@@ -55,10 +58,11 @@ struct EmitSPIRVOptions {
   spirv::LayoutRule tBufferLayoutRule;
   spirv::LayoutRule tBufferLayoutRule;
   spirv::LayoutRule sBufferLayoutRule;
   spirv::LayoutRule sBufferLayoutRule;
   llvm::SmallVector<llvm::StringRef, 4> optConfig;
   llvm::SmallVector<llvm::StringRef, 4> optConfig;
+
   // String representation of all command line options.
   // String representation of all command line options.
   std::string clOptions;
   std::string clOptions;
 
 
-  // Initializes dependent fields appropriately
+  /// Initializes dependent fields appropriately
   void Initialize();
   void Initialize();
 };
 };
 } // end namespace clang
 } // end namespace clang

+ 7 - 13
tools/clang/include/clang/SPIRV/Structure.h

@@ -26,6 +26,7 @@
 
 
 #include "spirv/unified1/spirv.hpp11"
 #include "spirv/unified1/spirv.hpp11"
 #include "clang/SPIRV/Constant.h"
 #include "clang/SPIRV/Constant.h"
+#include "clang/SPIRV/EmitSPIRVOptions.h"
 #include "clang/SPIRV/InstBuilder.h"
 #include "clang/SPIRV/InstBuilder.h"
 #include "clang/SPIRV/Type.h"
 #include "clang/SPIRV/Type.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/ArrayRef.h"
@@ -272,7 +273,7 @@ struct TypeIdPair {
 class SPIRVModule {
 class SPIRVModule {
 public:
 public:
   /// \brief Default constructs an empty SPIR-V module.
   /// \brief Default constructs an empty SPIR-V module.
-  inline SPIRVModule();
+  inline SPIRVModule(const EmitSPIRVOptions &options);
 
 
   // Disable copy constructor/assignment
   // Disable copy constructor/assignment
   SPIRVModule(const SPIRVModule &) = delete;
   SPIRVModule(const SPIRVModule &) = delete;
@@ -293,13 +294,10 @@ public:
   /// destructive; the module will be consumed and cleared after calling it.
   /// destructive; the module will be consumed and cleared after calling it.
   void take(InstBuilder *builder);
   void take(InstBuilder *builder);
 
 
-  inline void useVulkan1p1();
   /// \brief Sets the id bound to the given bound.
   /// \brief Sets the id bound to the given bound.
   inline void setBound(uint32_t newBound);
   inline void setBound(uint32_t newBound);
 
 
   /// \brief Sets the string representation of the command line options.
   /// \brief Sets the string representation of the command line options.
-  inline void setClOptions(llvm::StringRef opts);
-
   inline void addCapability(spv::Capability);
   inline void addCapability(spv::Capability);
   inline void addExtension(llvm::StringRef extension);
   inline void addExtension(llvm::StringRef extension);
   inline void addExtInstSet(uint32_t setId, llvm::StringRef extInstSet);
   inline void addExtInstSet(uint32_t setId, llvm::StringRef extInstSet);
@@ -331,7 +329,8 @@ public:
   inline uint32_t getExtInstSetId(llvm::StringRef setName);
   inline uint32_t getExtInstSetId(llvm::StringRef setName);
 
 
 private:
 private:
-  bool isVulkan1p1;
+  const EmitSPIRVOptions &spirvOptions;
+
   Header header; ///< SPIR-V module header.
   Header header; ///< SPIR-V module header.
   llvm::SetVector<spv::Capability> capabilities;
   llvm::SetVector<spv::Capability> capabilities;
   llvm::SetVector<std::string> extensions;
   llvm::SetVector<std::string> extensions;
@@ -458,16 +457,11 @@ TypeIdPair::TypeIdPair(const Type &ty, uint32_t id) : type(ty), resultId(id) {}
 
 
 // === Module inline implementations ===
 // === Module inline implementations ===
 
 
-SPIRVModule::SPIRVModule()
-    : isVulkan1p1(false), addressingModel(llvm::None), memoryModel(llvm::None),
-      shaderModelVersion(0), sourceFileNameId(0) {}
+SPIRVModule::SPIRVModule(const EmitSPIRVOptions &options)
+    : spirvOptions(options), addressingModel(llvm::None),
+      memoryModel(llvm::None), shaderModelVersion(0), sourceFileNameId(0) {}
 
 
-void SPIRVModule::useVulkan1p1() {
-  isVulkan1p1 = true;
-  header.version = 0x00010300u;
-}
 void SPIRVModule::setBound(uint32_t newBound) { header.bound = newBound; }
 void SPIRVModule::setBound(uint32_t newBound) { header.bound = newBound; }
-void SPIRVModule::setClOptions(llvm::StringRef opts) { clOptions = opts; }
 
 
 void SPIRVModule::addCapability(spv::Capability cap) {
 void SPIRVModule::addCapability(spv::Capability cap) {
   capabilities.insert(cap);
   capabilities.insert(cap);

+ 4 - 12
tools/clang/lib/SPIRV/ModuleBuilder.cpp

@@ -10,7 +10,7 @@
 #include "clang/SPIRV/ModuleBuilder.h"
 #include "clang/SPIRV/ModuleBuilder.h"
 
 
 #include "TypeTranslator.h"
 #include "TypeTranslator.h"
-#include "spirv/unified1//spirv.hpp11"
+#include "spirv/unified1/spirv.hpp11"
 #include "clang/SPIRV/BitwiseCast.h"
 #include "clang/SPIRV/BitwiseCast.h"
 #include "clang/SPIRV/InstBuilder.h"
 #include "clang/SPIRV/InstBuilder.h"
 
 
@@ -19,20 +19,12 @@ namespace spirv {
 
 
 ModuleBuilder::ModuleBuilder(SPIRVContext *C, FeatureManager *features,
 ModuleBuilder::ModuleBuilder(SPIRVContext *C, FeatureManager *features,
                              const EmitSPIRVOptions &opts)
                              const EmitSPIRVOptions &opts)
-    : theContext(*C), featureManager(features), spirvOptions(opts), theModule(),
-      theFunction(nullptr), insertPoint(nullptr), instBuilder(nullptr),
-      glslExtSetId(0) {
+    : theContext(*C), featureManager(features), spirvOptions(opts),
+      theModule(opts), theFunction(nullptr), insertPoint(nullptr),
+      instBuilder(nullptr), glslExtSetId(0) {
   instBuilder.setConsumer([this](std::vector<uint32_t> &&words) {
   instBuilder.setConsumer([this](std::vector<uint32_t> &&words) {
     this->constructSite = std::move(words);
     this->constructSite = std::move(words);
   });
   });
-
-  // Set the SPIR-V version and the command line options that were used to
-  // generate this module, if needed.
-  if (featureManager && featureManager->getTargetEnv() == SPV_ENV_VULKAN_1_1) {
-    theModule.useVulkan1p1();
-    if (spirvOptions.enableDebugInfo)
-      theModule.setClOptions(opts.clOptions);
-  }
 }
 }
 
 
 std::vector<uint32_t> ModuleBuilder::takeModule() {
 std::vector<uint32_t> ModuleBuilder::takeModule() {

+ 2 - 2
tools/clang/lib/SPIRV/SPIRVEmitter.cpp

@@ -623,7 +623,7 @@ SPIRVEmitter::SPIRVEmitter(CompilerInstance &ci, EmitSPIRVOptions &options)
 
 
   // Set debug info
   // Set debug info
   const auto &inputFiles = ci.getFrontendOpts().Inputs;
   const auto &inputFiles = ci.getFrontendOpts().Inputs;
-  if (options.enableDebugInfo && !inputFiles.empty()) {
+  if (options.debugInfoFile && !inputFiles.empty()) {
     // File name
     // File name
     mainSourceFileId = theContext.takeNextId();
     mainSourceFileId = theContext.takeNextId();
     theBuilder.setSourceFileName(mainSourceFileId,
     theBuilder.setSourceFileName(mainSourceFileId,
@@ -9999,7 +9999,7 @@ uint32_t SPIRVEmitter::extractVecFromVec4(uint32_t fromId,
 }
 }
 
 
 void SPIRVEmitter::emitDebugLine(SourceLocation loc) {
 void SPIRVEmitter::emitDebugLine(SourceLocation loc) {
-  if (spirvOptions.enableDebugInfo && mainSourceFileId != 0) {
+  if (spirvOptions.debugInfoLine && mainSourceFileId != 0) {
     auto floc = FullSourceLoc(loc, theCompilerInstance.getSourceManager());
     auto floc = FullSourceLoc(loc, theCompilerInstance.getSourceManager());
     theBuilder.debugLine(mainSourceFileId, floc.getSpellingLineNumber(),
     theBuilder.debugLine(mainSourceFileId, floc.getSpellingLineNumber(),
                          floc.getSpellingColumnNumber());
                          floc.getSpellingColumnNumber());

+ 26 - 15
tools/clang/lib/SPIRV/Structure.cpp

@@ -288,6 +288,8 @@ void SPIRVModule::take(InstBuilder *builder) {
 
 
   // Order matters here.
   // Order matters here.
 
 
+  if (spirvOptions.targetEnv == "vulkan1.1")
+    header.version = 0x00010300u;
   header.collect(consumer);
   header.collect(consumer);
 
 
   for (auto &cap : capabilities) {
   for (auto &cap : capabilities) {
@@ -319,25 +321,34 @@ void SPIRVModule::take(InstBuilder *builder) {
 
 
   if (shaderModelVersion != 0) {
   if (shaderModelVersion != 0) {
     llvm::Optional<uint32_t> fileName = llvm::None;
     llvm::Optional<uint32_t> fileName = llvm::None;
-    if (!sourceFileName.empty() && sourceFileNameId) {
+
+    if (spirvOptions.debugInfoFile && !sourceFileName.empty() &&
+        sourceFileNameId) {
       builder->opString(sourceFileNameId, sourceFileName).x();
       builder->opString(sourceFileNameId, sourceFileName).x();
       fileName = sourceFileNameId;
       fileName = sourceFileNameId;
     }
     }
 
 
-    llvm::SmallVector<llvm::StringRef, 2> choppedSrcCode;
     llvm::Optional<llvm::StringRef> firstSnippet;
     llvm::Optional<llvm::StringRef> firstSnippet;
-    chopString(sourceFileContent, &choppedSrcCode);
-    if (!choppedSrcCode.empty()) {
-      firstSnippet = llvm::Optional<llvm::StringRef>(choppedSrcCode.front());
-    }
+    if (spirvOptions.debugInfoSource) {
+      llvm::SmallVector<llvm::StringRef, 2> choppedSrcCode;
+      chopString(sourceFileContent, &choppedSrcCode);
+      if (!choppedSrcCode.empty()) {
+        firstSnippet = llvm::Optional<llvm::StringRef>(choppedSrcCode.front());
+      }
 
 
-    builder
-        ->opSource(spv::SourceLanguage::HLSL, shaderModelVersion, fileName,
-                   firstSnippet)
-        .x();
+      builder
+          ->opSource(spv::SourceLanguage::HLSL, shaderModelVersion, fileName,
+                     firstSnippet)
+          .x();
 
 
-    for (uint32_t i = 1; i < choppedSrcCode.size(); ++i) {
-      builder->opSourceContinued(choppedSrcCode[i]).x();
+      for (uint32_t i = 1; i < choppedSrcCode.size(); ++i) {
+        builder->opSourceContinued(choppedSrcCode[i]).x();
+      }
+    } else {
+      builder
+          ->opSource(spv::SourceLanguage::HLSL, shaderModelVersion, fileName,
+                     firstSnippet)
+          .x();
     }
     }
   }
   }
 
 
@@ -362,7 +373,7 @@ void SPIRVModule::take(InstBuilder *builder) {
     }
     }
   }
   }
 
 
-  if (isVulkan1p1) {
+  if (spirvOptions.debugInfoTool && spirvOptions.targetEnv == "vulkan1.1") {
     // Emit OpModuleProcessed to indicate the commit information.
     // Emit OpModuleProcessed to indicate the commit information.
     std::string commitHash =
     std::string commitHash =
         std::string("dxc-commit-hash: ") + clang::getGitCommitHash();
         std::string("dxc-commit-hash: ") + clang::getGitCommitHash();
@@ -374,9 +385,9 @@ void SPIRVModule::take(InstBuilder *builder) {
 
 
     // Emit OpModuleProcessed to indicate the command line options that were
     // Emit OpModuleProcessed to indicate the command line options that were
     // used to generate this module.
     // used to generate this module.
-    if (!clOptions.empty()) {
+    if (!spirvOptions.clOptions.empty()) {
       // Using this format: "dxc-cl-option: XXXXXX"
       // Using this format: "dxc-cl-option: XXXXXX"
-      std::string clOptionStr = "dxc-cl-option:" + clOptions;
+      std::string clOptionStr = "dxc-cl-option:" + spirvOptions.clOptions;
       builder->opModuleProcessed(clOptionStr).x();
       builder->opModuleProcessed(clOptionStr).x();
     }
     }
   }
   }

+ 17 - 0
tools/clang/test/CodeGenSPIRV/spirv.debug.ctrl.file.hlsl

@@ -0,0 +1,17 @@
+// Run: %dxc -T ps_6_1 -E main -fspv-target-env=vulkan1.1 -fspv-debug=file -Zi
+
+// Have file path
+// CHECK:      [[file:%\d+]] = OpString
+// CHECK-SAME: spirv.debug.ctrl.file.hlsl
+// CHECK:      OpSource HLSL 610 [[file]]
+// No source code
+// CHECK-NOT:  float4 main(uint val
+// No tool
+// CHECK-NOT: OpModuleProcessed
+// No line
+// CHECK-NOT: OpLine
+
+float4 main(uint val : A) : SV_Target {
+  uint a = reversebits(val);
+  return a;
+}

+ 17 - 0
tools/clang/test/CodeGenSPIRV/spirv.debug.ctrl.line.hlsl

@@ -0,0 +1,17 @@
+// Run: %dxc -T ps_6_1 -E main -fspv-debug=line
+
+// Have file path
+// CHECK:      [[file:%\d+]] = OpString
+// CHECK-SAME: spirv.debug.ctrl.line.hlsl
+// CHECK:      OpSource HLSL 610 [[file]]
+// Have source code
+// CHECK:      float4 main(uint val
+// No tool
+// CHECK-NOT:  OpModuleProcessed
+// Have line
+// CHECK:      OpLine
+
+float4 main(uint val : A) : SV_Target {
+  uint a = reversebits(val);
+  return a;
+}

+ 17 - 0
tools/clang/test/CodeGenSPIRV/spirv.debug.ctrl.source.hlsl

@@ -0,0 +1,17 @@
+// Run: %dxc -T ps_6_1 -E main -fspv-target-env=vulkan1.1 -fspv-debug=source
+
+// Have file path
+// CHECK:      [[file:%\d+]] = OpString
+// CHECK-SAME: spirv.debug.ctrl.source.hlsl
+// CHECK:      OpSource HLSL 610 [[file]]
+// Have source code
+// CHECK:      float4 main(uint val
+// No tool
+// CHECK-NOT: OpModuleProcessed
+// No line
+// CHECK-NOT: OpLine
+
+float4 main(uint val : A) : SV_Target {
+  uint a = reversebits(val);
+  return a;
+}

+ 15 - 0
tools/clang/test/CodeGenSPIRV/spirv.debug.ctrl.tool.hlsl

@@ -0,0 +1,15 @@
+// Run: %dxc -T ps_6_1 -E main -fspv-target-env=vulkan1.1 -fspv-debug=tool -Zi
+
+// No file path
+// CHECK-NOT: OpString
+// No source code
+// CHECK-NOT: float4 main(uint val
+// Have tool
+// CHECK:     OpModuleProcessed
+// No line
+// CHECK-NOT: OpLine
+
+float4 main(uint val : A) : SV_Target {
+  uint a = reversebits(val);
+  return a;
+}

+ 8 - 0
tools/clang/test/CodeGenSPIRV/spirv.debug.ctrl.unknown.hlsl

@@ -0,0 +1,8 @@
+// Run: %dxc -T ps_6_1 -E main -fspv-debug=t
+
+float4 main(uint val : A) : SV_Target {
+  uint a = reversebits(val);
+  return a;
+}
+
+// CHECK: unknown SPIR-V debug info control parameter: t

+ 4 - 1
tools/clang/tools/dxcompiler/dxcompilerobj.cpp

@@ -529,7 +529,10 @@ public:
           spirvOpts.allowedExtensions = opts.SpvExtensions;
           spirvOpts.allowedExtensions = opts.SpvExtensions;
           spirvOpts.targetEnv = opts.SpvTargetEnv;
           spirvOpts.targetEnv = opts.SpvTargetEnv;
           spirvOpts.enable16BitTypes = opts.Enable16BitTypes;
           spirvOpts.enable16BitTypes = opts.Enable16BitTypes;
-          spirvOpts.enableDebugInfo = opts.DebugInfo;
+          spirvOpts.debugInfoFile = opts.SpvDebugFile;
+          spirvOpts.debugInfoSource = opts.SpvDebugSource;
+          spirvOpts.debugInfoLine = opts.SpvDebugLine;
+          spirvOpts.debugInfoTool = opts.SpvDebugTool;
           spirvOpts.optConfig = opts.SpvOconfig;
           spirvOpts.optConfig = opts.SpvOconfig;
 
 
           // Store a string representation of command line options.
           // Store a string representation of command line options.

+ 27 - 6
tools/clang/unittests/SPIRV/CodeGenSPIRVTest.cpp

@@ -1269,12 +1269,6 @@ TEST_F(FileTest, SpirvOptOconfigInvalidFlag) {
 }
 }
 TEST_F(FileTest, SpirvOptOconfig) { runFileTest("spirv.opt.cl.oconfig.hlsl"); }
 TEST_F(FileTest, SpirvOptOconfig) { runFileTest("spirv.opt.cl.oconfig.hlsl"); }
 
 
-// Test that command line options are exposed using OpModuleProcessed.
-TEST_F(FileTest, SpirvDebugClOption) {
-  useVulkan1p1();
-  runFileTest("spirv.debug.cl-option.hlsl");
-}
-
 // For shader stage input/output interface
 // For shader stage input/output interface
 // For semantic SV_Position, SV_ClipDistance, SV_CullDistance
 // For semantic SV_Position, SV_ClipDistance, SV_CullDistance
 TEST_F(FileTest, SpirvStageIOInterfaceVS) {
 TEST_F(FileTest, SpirvStageIOInterfaceVS) {
@@ -1356,6 +1350,33 @@ TEST_F(FileTest, SpirvDebugDxcCommitInfo) {
   runFileTest("spirv.debug.commit.hlsl");
   runFileTest("spirv.debug.commit.hlsl");
 }
 }
 
 
+// Test that command line options are exposed using OpModuleProcessed.
+TEST_F(FileTest, SpirvDebugClOption) {
+  useVulkan1p1();
+  runFileTest("spirv.debug.cl-option.hlsl");
+}
+
+TEST_F(FileTest, SpirvDebugControlFile) {
+  useVulkan1p1();
+  runFileTest("spirv.debug.ctrl.file.hlsl");
+}
+TEST_F(FileTest, SpirvDebugControlSource) {
+  useVulkan1p1();
+  runFileTest("spirv.debug.ctrl.source.hlsl");
+}
+TEST_F(FileTest, SpirvDebugControlLine) {
+  useVulkan1p1();
+  runFileTest("spirv.debug.ctrl.line.hlsl");
+}
+TEST_F(FileTest, SpirvDebugControlTool) {
+  useVulkan1p1();
+  runFileTest("spirv.debug.ctrl.tool.hlsl");
+}
+TEST_F(FileTest, SpirvDebugControlUnknown) {
+  useVulkan1p1();
+  runFileTest("spirv.debug.ctrl.unknown.hlsl", Expect::Failure);
+}
+
 TEST_F(FileTest, VulkanAttributeErrors) {
 TEST_F(FileTest, VulkanAttributeErrors) {
   runFileTest("vk.attribute.error.hlsl", Expect::Failure);
   runFileTest("vk.attribute.error.hlsl", Expect::Failure);
 }
 }

+ 4 - 4
tools/clang/unittests/SPIRV/StructureTest.cpp

@@ -107,12 +107,12 @@ TEST(Structure, AfterClearFunctionIsEmpty) {
 }
 }
 
 
 TEST(Structure, DefaultConstructedModuleIsEmpty) {
 TEST(Structure, DefaultConstructedModuleIsEmpty) {
-  auto m = SPIRVModule();
+  auto m = SPIRVModule({});
   EXPECT_TRUE(m.isEmpty());
   EXPECT_TRUE(m.isEmpty());
 }
 }
 
 
 TEST(Structure, AfterClearModuleIsEmpty) {
 TEST(Structure, AfterClearModuleIsEmpty) {
-  auto m = SPIRVModule();
+  auto m = SPIRVModule({});
   m.setBound(12);
   m.setBound(12);
   EXPECT_FALSE(m.isEmpty());
   EXPECT_FALSE(m.isEmpty());
   m.clear();
   m.clear();
@@ -121,7 +121,7 @@ TEST(Structure, AfterClearModuleIsEmpty) {
 
 
 TEST(Structure, TakeModuleHaveAllContents) {
 TEST(Structure, TakeModuleHaveAllContents) {
   SPIRVContext context;
   SPIRVContext context;
-  auto m = SPIRVModule();
+  auto m = SPIRVModule({});
 
 
   // Will fix up the bound later.
   // Will fix up the bound later.
   SimpleInstBuilder sib(0);
   SimpleInstBuilder sib(0);
@@ -226,7 +226,7 @@ TEST(Structure, TakeModuleHaveAllContents) {
 
 
 TEST(Structure, TakeModuleWithArrayAndConstantDependency) {
 TEST(Structure, TakeModuleWithArrayAndConstantDependency) {
   SPIRVContext context;
   SPIRVContext context;
-  auto m = SPIRVModule();
+  auto m = SPIRVModule({});
 
 
   // Will fix up the id bound later.
   // Will fix up the id bound later.
   SimpleInstBuilder sib(0);
   SimpleInstBuilder sib(0);