Jelajahi Sumber

Made -Zs the flag for slim PDB. Added -Qpdb_in_private. (#3541)

Adam Yang 4 tahun lalu
induk
melakukan
65996610c9

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

@@ -172,9 +172,9 @@ public:
   bool RecompileFromBinary = false; // OPT _Recompile (Recompiling the DXBC binary file not .hlsl file)
   bool StripDebug = false; // OPT Qstrip_debug
   bool EmbedDebug = false; // OPT Qembed_debug
-  bool SourceInDebugModule = false; // OPT Qsource_in_debug_module
+  bool SourceInDebugModule = false; // OPT Zs
   bool SourceOnlyDebug = false; // OPT Qsource_only_debug
-  bool FullDebug = false; // OPT Qfull_debug
+  bool PdbInPrivate = false; // OPT Qpdb_in_private
   bool StripRootSignature = false; // OPT_Qstrip_rootsignature
   bool StripPrivate = false; // OPT_Qstrip_priv
   bool StripReflection = false; // OPT_Qstrip_reflect
@@ -210,7 +210,8 @@ public:
   bool IsLibraryProfile();
 
   // Helpers to clarify interpretation of flags for behavior in implementation
-  bool IsDebugInfoEnabled();    // Zi
+  bool GenerateFullDebugInfo(); // Zi
+  bool GeneratePDB();           // Zi or Zs
   bool EmbedDebugInfo();        // Qembed_debug
   bool EmbedPDBName();          // Zi or Fd
   bool DebugFileIsDirectory();  // Fd ends in '\\'

+ 3 - 3
include/dxc/Support/HLSLOptions.td

@@ -411,10 +411,10 @@ def Qstrip_priv : Flag<["-", "/"], "Qstrip_priv">, Flags<[DriverOption]>, Group<
   HelpText<"Strip private data from shader bytecode  (must be used with /Fo <file>)">;
 def Qsource_in_debug_module : Flag<["-", "/"], "Qsource_in_debug_module">, Flags<[CoreOption, HelpHidden]>, Group<hlslutil_Group>,
   HelpText<"Generate old PDB format.">;
-def Qsource_only_debug : Flag<["-", "/"], "Qsource_only_debug">, Flags<[CoreOption, HelpHidden]>, Group<hlslutil_Group>,
+def Zs : Flag<["-", "/"], "Zs">, Flags<[CoreOption]>, Group<hlslutil_Group>,
   HelpText<"Generate small PDB with just sources and compile options.">;
-def Qfull_debug : Flag<["-", "/"], "Qfull_debug">, Flags<[CoreOption, HelpHidden]>, Group<hlslutil_Group>,
-  HelpText<"Generate full debug info for PDB.">;
+def Qpdb_in_private : Flag<["-", "/"], "Qpdb_in_private">, Flags<[CoreOption, HelpHidden]>, Group<hlslutil_Group>,
+  HelpText<"Store PDB in private user data.">;
 
 def Qstrip_rootsignature : Flag<["-", "/"], "Qstrip_rootsignature">, Flags<[CoreOption, DriverOption]>, Group<hlslutil_Group>, HelpText<"Strip root signature data from shader bytecode  (must be used with /Fo <file>)">;
 def setrootsignature     : JoinedOrSeparate<["-", "/"], "setrootsignature">,     MetaVarName<"<file>">, Flags<[CoreOption, DriverOption]>, Group<hlslutil_Group>, HelpText<"Attach root signature to shader bytecode">;

+ 13 - 9
lib/DxcSupport/HLSLOptions.cpp

@@ -138,16 +138,20 @@ bool DxcOpts::IsLibraryProfile() {
   return TargetProfile.startswith("lib_");
 }
 
-bool DxcOpts::IsDebugInfoEnabled() {
+bool DxcOpts::GenerateFullDebugInfo() {
   return DebugInfo;
 }
 
+bool DxcOpts::GeneratePDB() {
+  return DebugInfo || SourceOnlyDebug;
+}
+
 bool DxcOpts::EmbedDebugInfo() {
   return EmbedDebug;
 }
 
 bool DxcOpts::EmbedPDBName() {
-  return IsDebugInfoEnabled() || !DebugFile.empty();
+  return GeneratePDB() || !DebugFile.empty();
 }
 
 bool DxcOpts::DebugFileIsDirectory() {
@@ -626,8 +630,8 @@ int ReadDxcOpts(const OptTable *optionTable, unsigned flagsToInclude,
   opts.StripDebug = Args.hasFlag(OPT_Qstrip_debug, OPT_INVALID, false);
   opts.EmbedDebug = Args.hasFlag(OPT_Qembed_debug, OPT_INVALID, false);
   opts.SourceInDebugModule = Args.hasFlag(OPT_Qsource_in_debug_module, OPT_INVALID, false);
-  opts.SourceOnlyDebug = Args.hasFlag(OPT_Qsource_only_debug, OPT_INVALID, false);
-  opts.FullDebug = Args.hasFlag(OPT_Qfull_debug, OPT_INVALID, false);
+  opts.SourceOnlyDebug = Args.hasFlag(OPT_Zs, OPT_INVALID, false);
+  opts.PdbInPrivate = Args.hasFlag(OPT_Qpdb_in_private, OPT_INVALID, false);
   opts.StripRootSignature = Args.hasFlag(OPT_Qstrip_rootsignature, OPT_INVALID, false);
   opts.StripPrivate = Args.hasFlag(OPT_Qstrip_priv, OPT_INVALID, false);
   opts.StripReflection = Args.hasFlag(OPT_Qstrip_reflect, OPT_INVALID, false);
@@ -922,13 +926,13 @@ int ReadDxcOpts(const OptTable *optionTable, unsigned flagsToInclude,
     return 1;
   }
 
-  if (opts.FullDebug && opts.SourceOnlyDebug) {
-    errors << "Cannot specify both /Qfull_debug and /Qsource_only_debug";
+  if (opts.DebugInfo && opts.SourceOnlyDebug) {
+    errors << "Cannot specify both /Zi and /Zs";
     return 1;
   }
 
   if (opts.SourceInDebugModule && opts.SourceOnlyDebug) {
-    errors << "Cannot specify both /Qsource_in_debug_module and /Qsource_only_debug";
+    errors << "Cannot specify both /Qsource_in_debug_module and /Zs";
     return 1;
   }
 
@@ -939,8 +943,8 @@ int ReadDxcOpts(const OptTable *optionTable, unsigned flagsToInclude,
     return 1;
   }
 
-  if (opts.DebugNameForSource && !opts.DebugInfo) {
-    errors << "/Zss requires debug info (/Zi)";
+  if (opts.DebugNameForSource && (!opts.DebugInfo && !opts.SourceOnlyDebug)) {
+    errors << "/Zss requires debug info (/Zi or /Zs)";
     return 1;
   }
 

+ 2 - 2
tools/clang/tools/dxclib/dxc.cpp

@@ -293,9 +293,9 @@ int DxcContext::ActOnBlob(IDxcBlob *pBlob, IDxcBlob *pDebugBlob, LPCWSTR pDebugB
 
   // Extract and write the PDB/debug information.
   if (!m_Opts.DebugFile.empty()) {
-    IFTBOOLMSG(m_Opts.DebugInfo, E_INVALIDARG, "/Fd specified, but no Debug Info was "
+    IFTBOOLMSG(m_Opts.GeneratePDB(), E_INVALIDARG, "/Fd specified, but no Debug Info was "
       "found in the shader, please use the "
-      "/Zi switch to generate debug "
+      "/Zi or /Zs switch to generate debug "
       "information compiling this shader.");
     if (pDebugBlob != nullptr) {
       IFTBOOLMSG(pDebugBlobName && *pDebugBlobName, E_INVALIDARG,

+ 41 - 29
tools/clang/tools/dxcompiler/dxcompilerobj.cpp

@@ -161,11 +161,10 @@ struct CompilerVersionPartWriter {
 };
 
 static HRESULT CreateContainerForPDB(IMalloc *pMalloc,
-  llvm::Module *pModule,
   IDxcBlob *pOldContainer,
   IDxcBlob *pDebugBlob, IDxcVersionInfo *pVersionInfo,
   const hlsl::DxilSourceInfo *pSourceInfo,
-  AbstractMemoryStream *pReflectionStream, const uint32_t reflectionSizeInBytes,
+  AbstractMemoryStream *pReflectionStream,
   IDxcBlob **ppNewContaner)
 {
   // If the pContainer is not a valid container, give up.
@@ -244,15 +243,18 @@ static HRESULT CreateContainerForPDB(IMalloc *pMalloc,
   }
 
   if (pReflectionStream) {
+    const hlsl::DxilPartHeader *pReflectionPartHeader =
+      (const hlsl::DxilPartHeader *)pReflectionStream->GetPtr();
     Part NewPart(
       hlsl::DFCC_ShaderStatistics,
-      reflectionSizeInBytes,
-      [&pReflectionStream, pModule](IStream *pStream) {
-        hlsl::WriteProgramPart(pModule->GetOrCreateDxilModule().GetShaderModel(), pReflectionStream, pStream);
+      pReflectionPartHeader->PartSize,
+      [pReflectionPartHeader](IStream *pStream) {
+        ULONG uBytesWritten = 0;
+        pStream->Write(pReflectionPartHeader+1, pReflectionPartHeader->PartSize, &uBytesWritten);
         return S_OK;
       }
     );
-    AddPart(NewPart, reflectionSizeInBytes);
+    AddPart(NewPart, pReflectionPartHeader->PartSize);
   }
 
   CompilerVersionPartWriter versionWriter;
@@ -733,7 +735,8 @@ public:
       // Setup a compiler instance.
       raw_stream_ostream outStream(pOutputStream.p);
       llvm::LLVMContext llvmContext; // LLVMContext should outlive CompilerInstance
-      std::unique_ptr<llvm::Module> compiledModule;
+      std::unique_ptr<llvm::Module> debugModule;
+      CComPtr<AbstractMemoryStream> pReflectionStream;
       CompilerInstance compiler;
       std::unique_ptr<TextDiagnosticPrinter> diagPrinter =
           llvm::make_unique<TextDiagnosticPrinter>(w, &compiler.getDiagnosticOpts());
@@ -945,7 +948,6 @@ public:
         // Do not create a container when there is only a a high-level representation in the module.
         if (compileOK && !opts.CodeGenHighLevel) {
           HRESULT valHR = S_OK;
-          CComPtr<AbstractMemoryStream> pReflectionStream;
           CComPtr<AbstractMemoryStream> pRootSigStream;
           IFT(CreateMemoryStream(DxcGetThreadMallocNoRef(), &pReflectionStream));
           IFT(CreateMemoryStream(DxcGetThreadMallocNoRef(), &pRootSigStream));
@@ -953,11 +955,13 @@ public:
           std::unique_ptr<llvm::Module> serializeModule( action.takeModule() );
 
           // Clone and save the copy.
-          compiledModule.reset(llvm::CloneModule(serializeModule.get()));
+          if (opts.GenerateFullDebugInfo()) {
+            debugModule.reset(llvm::CloneModule(serializeModule.get()));
+          }
 
           dxcutil::AssembleInputs inputs(
                 std::move(serializeModule), pOutputBlob, m_pMalloc, SerializeFlags,
-                pOutputStream, opts.IsDebugInfoEnabled(),
+                pOutputStream, opts.GenerateFullDebugInfo(),
                 opts.GetPDBName(), &compiler.getDiagnostics(),
                 &ShaderHashContent, pReflectionStream, pRootSigStream);
 
@@ -1025,7 +1029,7 @@ public:
 
       bool hasErrorOccurred = compiler.getDiagnostics().hasErrorOccurred();
 
-      bool writePDB = opts.IsDebugInfoEnabled() && produceFullContainer;
+      bool writePDB = opts.GeneratePDB() && produceFullContainer;
 
       // SPIRV change starts
 #if defined(ENABLE_SPIRV_CODEGEN)
@@ -1035,14 +1039,7 @@ public:
 
       if (!hasErrorOccurred && writePDB) {
         CComPtr<IDxcBlob> pStrippedContainer;
-
         {
-          // Version info to store in the PDB
-          IDxcVersionInfo *pVersionInfo = nullptr;
-          if (opts.IsDebugInfoEnabled()) { // Only put version info if embedding debug
-            pVersionInfo = static_cast<IDxcVersionInfo *>(this);
-          }
-
           // Create the shader source information for PDB
           hlsl::SourceInfoWriter debugSourceInfoWriter;
           const hlsl::DxilSourceInfo *pSourceInfo = nullptr;
@@ -1051,36 +1048,32 @@ public:
             pSourceInfo = debugSourceInfoWriter.GetPart();
           }
 
-          CComPtr<AbstractMemoryStream> pReflectionStream;
-          uint32_t reflectionSizeInBytes = 0;
-
           CComPtr<IDxcBlob> pDebugProgramBlob;
+          CComPtr<AbstractMemoryStream> pReflectionInPdb;
           // Don't include the debug part if using source only PDB
           if (opts.SourceOnlyDebug) {
             assert(pSourceInfo);
-            hlsl::ReEmitLatestReflectionData(compiledModule.get());
-            hlsl::StripAndCreateReflectionStream(compiledModule.get(), &reflectionSizeInBytes, &pReflectionStream);
+            pReflectionInPdb = pReflectionStream;
           }
           else {
             if (!opts.SourceInDebugModule) {
               // Strip out the source related metadata
-              compiledModule->GetOrCreateDxilModule()
+              debugModule->GetOrCreateDxilModule()
                 .StripShaderSourcesAndCompileOptions(/* bReplaceWithDummyData */ true);
             }
             CComPtr<AbstractMemoryStream> pDebugBlobStorage;
             IFT(CreateMemoryStream(DxcGetThreadMallocNoRef(), &pDebugBlobStorage));
             raw_stream_ostream outStream(pDebugBlobStorage.p);
-            WriteBitcodeToFile(compiledModule.get(), outStream, true);
+            WriteBitcodeToFile(debugModule.get(), outStream, true);
             outStream.flush();
             IFT(pDebugBlobStorage.QueryInterface(&pDebugProgramBlob));
           }
 
           IFT(CreateContainerForPDB(
             m_pMalloc,
-            compiledModule.get(),
             pOutputBlob, pDebugProgramBlob,
             static_cast<IDxcVersionInfo *>(this), pSourceInfo,
-            pReflectionStream, reflectionSizeInBytes,
+            pReflectionInPdb,
             &pStrippedContainer));
         }
 
@@ -1088,7 +1081,26 @@ public:
         CComPtr<IDxcBlob> pPdbBlob;
         IFT(hlsl::pdb::WriteDxilPDB(m_pMalloc, pStrippedContainer, ShaderHashContent.Digest, &pPdbBlob));
         IFT(pResult->SetOutputObject(DXC_OUT_PDB, pPdbBlob));
-      }
+
+        // If option Qpdb_in_private given, add the PDB to the DXC_OUT_OBJECT container output as a
+        // DFCC_PrivateData part.
+        if (opts.PdbInPrivate) {
+          CComPtr<IDxcBlobEncoding> pContainerBlob;
+          hlsl::DxcCreateBlobWithEncodingFromPinned(pOutputBlob->GetBufferPointer(), pOutputBlob->GetBufferSize(), CP_ACP, &pContainerBlob);
+
+          CComPtr<IDxcContainerBuilder> pContainerBuilder;
+          DxcCreateInstance2(this->m_pMalloc, CLSID_DxcContainerBuilder, IID_PPV_ARGS(&pContainerBuilder));
+          IFT(pContainerBuilder->Load(pOutputBlob));
+          IFT(pContainerBuilder->AddPart(hlsl::DFCC_PrivateData, pPdbBlob));
+
+          CComPtr<IDxcOperationResult> pReserializeResult;
+          IFT(pContainerBuilder->SerializeContainer(&pReserializeResult));
+
+          CComPtr<IDxcBlob> pNewOutput;
+          IFT(pReserializeResult->GetResult(&pNewOutput));
+          pOutputBlob = pNewOutput;
+        } // PDB in private
+      } // Write PDB
 
       IFT(primaryOutput.SetObject(pOutputBlob, opts.DefaultTextCodePage));
       IFT(pResult->SetOutput(primaryOutput));
@@ -1216,7 +1228,7 @@ public:
 
     compiler.getFrontendOpts().Inputs.push_back(FrontendInputFile(pMainFile, IK_HLSL));
     // Setup debug information.
-    if (Opts.IsDebugInfoEnabled()) {
+    if (Opts.GenerateFullDebugInfo()) {
       CodeGenOptions &CGOpts = compiler.getCodeGenOpts();
       // HLSL Change - begin
       CGOpts.setDebugInfo(CodeGenOptions::FullDebugInfo);

+ 2 - 2
tools/clang/tools/dxcompiler/dxcpdbutils.cpp

@@ -748,11 +748,11 @@ public:
 
     std::vector<const WCHAR *> new_args;
     for (unsigned i = 0; i < m_Args.size(); i++) {
-      if (m_Args[i] == L"/Qsource_only_debug" || m_Args[i] == L"-Qsource_only_debug")
+      if (m_Args[i] == L"/Zs" || m_Args[i] == L"-Zs")
         continue;
       new_args.push_back(m_Args[i].c_str());
     }
-    new_args.push_back(L"-Qfull_debug");
+    new_args.push_back(L"-Zi");
 
     assert(m_MainFileName.size());
     if (m_MainFileName.size())

+ 62 - 8
tools/clang/unittests/HLSL/CompilerTest.cpp

@@ -128,6 +128,7 @@ public:
   TEST_METHOD(CompileWhenWorksThenAddRemovePrivate)
   TEST_METHOD(CompileThenAddCustomDebugName)
   TEST_METHOD(CompileThenTestPdbUtils)
+  TEST_METHOD(CompileThenTestPdbInPrivate)
   TEST_METHOD(CompileThenTestPdbUtilsStripped)
   TEST_METHOD(CompileThenTestPdbUtilsEmptyEntry)
   TEST_METHOD(CompileThenTestPdbUtilsRelativePath)
@@ -1288,8 +1289,8 @@ static void VerifyPdbUtil(dxc::DxcDllSupport &dllSupport,
     auto ReplaceDebugFlagPair = [](const std::vector<std::pair<const WCHAR *, const WCHAR *> > &List) -> std::vector<std::pair<const WCHAR *, const WCHAR *> > {
       std::vector<std::pair<const WCHAR *, const WCHAR *> > ret;
       for (unsigned i = 0; i < List.size(); i++) {
-        if (!wcscmp(List[i].first, L"/Qsource_only_debug") || !wcscmp(List[i].first, L"-Qsource_only_debug"))
-          ret.push_back(std::pair<const WCHAR *, const WCHAR *>(L"-Qfull_debug", nullptr));
+        if (!wcscmp(List[i].first, L"/Zs") || !wcscmp(List[i].first, L"-Zs"))
+          ret.push_back(std::pair<const WCHAR *, const WCHAR *>(L"-Zi", nullptr));
         else
           ret.push_back(List[i]);
       }
@@ -1453,7 +1454,6 @@ void CompilerTest::TestPdbUtils(bool bSlim, bool bSourceInDebugModule, bool bStr
     }
   };
 
-  AddArg(L"-Zi", nullptr, false);
   AddArg(L"-Od", nullptr, false);
   AddArg(L"-flegacy-macro-expansion", nullptr, false);
 
@@ -1468,7 +1468,10 @@ void CompilerTest::TestPdbUtils(bool bSlim, bool bSourceInDebugModule, bool bStr
     AddArg(L"-Qsource_in_debug_module", nullptr, false);
   }
   if (bSlim) {
-    AddArg(L"-Qsource_only_debug", nullptr, false);
+    AddArg(L"-Zs", nullptr, false);
+  }
+  else {
+    AddArg(L"-Zi", nullptr, false);
   }
 
   AddArg(L"-D", L"THIS_IS_A_DEFINE=HELLO", true);
@@ -1543,13 +1546,65 @@ void CompilerTest::TestPdbUtils(bool bSlim, bool bSourceInDebugModule, bool bStr
 }
 
 TEST_F(CompilerTest, CompileThenTestPdbUtils) {
+  TestPdbUtils(/*bSlim*/true,  /*bSourceInDebugModule*/false, /*strip*/true);  // Slim PDB, where source info is stored in its own part, and debug module is NOT present
+
   TestPdbUtils(/*bSlim*/false, /*bSourceInDebugModule*/true,  /*strip*/false);  // Old PDB format, where source info is embedded in the module
   TestPdbUtils(/*bSlim*/false, /*bSourceInDebugModule*/false, /*strip*/false);  // Full PDB, where source info is stored in its own part, and a debug module which is present
-  TestPdbUtils(/*bSlim*/true,  /*bSourceInDebugModule*/false, /*strip*/false);  // Slim PDB, where source info is stored in its own part, and a debug module which is NOT present
 
   TestPdbUtils(/*bSlim*/false, /*bSourceInDebugModule*/true,  /*strip*/true);  // Legacy PDB, where source info is embedded in the module
   TestPdbUtils(/*bSlim*/false, /*bSourceInDebugModule*/false, /*strip*/true);  // Full PDB, where source info is stored in its own part, and debug module is present
-  TestPdbUtils(/*bSlim*/true,  /*bSourceInDebugModule*/false, /*strip*/true);  // Slim PDB, where source info is stored in its own part, and debug module is NOT present
+}
+
+TEST_F(CompilerTest, CompileThenTestPdbInPrivate) {
+  CComPtr<IDxcCompiler> pCompiler;
+  VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
+
+  std::string main_source = R"x(
+      cbuffer MyCbuffer : register(b1) {
+        float4 my_cbuf_foo;
+      }
+
+      [RootSignature("CBV(b1)")]
+      float4 main() : SV_Target {
+        return my_cbuf_foo;
+      }
+  )x";
+
+  CComPtr<IDxcUtils> pUtils;
+  VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcUtils, &pUtils));
+
+  CComPtr<IDxcBlobEncoding> pSource;
+  VERIFY_SUCCEEDED(pUtils->CreateBlobFromPinned(main_source.c_str(), main_source.size(), CP_UTF8, &pSource));
+
+  const WCHAR *args[] = {
+    L"/Zs",
+    L"/Qpdb_in_private",
+  };
+
+  CComPtr<IDxcOperationResult> pOpResult;
+  VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"hlsl.hlsl", L"main", L"ps_6_0", args, _countof(args), nullptr, 0, nullptr, &pOpResult));
+
+  CComPtr<IDxcResult> pResult;
+  VERIFY_SUCCEEDED(pOpResult.QueryInterface(&pResult));
+
+  CComPtr<IDxcBlob> pShader;
+  VERIFY_SUCCEEDED(pResult->GetOutput(DXC_OUT_OBJECT, IID_PPV_ARGS(&pShader), nullptr));
+
+  CComPtr<IDxcContainerReflection> pRefl;
+  VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcContainerReflection, &pRefl));
+  VERIFY_SUCCEEDED(pRefl->Load(pShader));
+
+  UINT32 uIndex = 0;
+  VERIFY_SUCCEEDED(pRefl->FindFirstPartKind(hlsl::DFCC_PrivateData, &uIndex));
+
+  CComPtr<IDxcBlob> pPdbBlob;
+  VERIFY_SUCCEEDED(pResult->GetOutput(DXC_OUT_PDB, IID_PPV_ARGS(&pPdbBlob), nullptr));
+
+  CComPtr<IDxcBlob> pPrivatePdbBlob;
+  VERIFY_SUCCEEDED(pRefl->GetPartContent(uIndex, &pPrivatePdbBlob));
+
+  VERIFY_ARE_EQUAL(pPdbBlob->GetBufferSize(), pPrivatePdbBlob->GetBufferSize());
+  VERIFY_ARE_EQUAL(0, memcmp(pPdbBlob->GetBufferPointer(), pPrivatePdbBlob->GetBufferPointer(), pPdbBlob->GetBufferSize()));
 }
 
 TEST_F(CompilerTest, CompileThenTestPdbUtilsRelativePath) {
@@ -1575,8 +1630,7 @@ TEST_F(CompilerTest, CompileThenTestPdbUtilsRelativePath) {
 
   std::vector<const WCHAR *> args;
   args.push_back(L"/Tps_6_0");
-  args.push_back(L"/Zi");
-  args.push_back(L"/Qsource_only_debug");
+  args.push_back(L"/Zs");
   args.push_back(L"shaders/Shader.hlsl");
 
   CComPtr<TestIncludeHandler> pInclude;

+ 6 - 0
utils/hct/hcttestcmds.cmd

@@ -51,6 +51,12 @@ rem Should have debug name, and debug info should be stripped from module
 call :check_file log find "shader debug name: smoke.hlsl.d" find-not "DICompileUnit"
 if %Failed% neq 0 goto :failed
 
+set testname=/Fd plus /Zs
+call :run dxc.exe /T ps_6_0 "%testfiles%\smoke.hlsl" /Zs /Fd smoke.hlsl.pdb /Fo smoke.hlsl.Fd.dxo
+call :check_file smoke.hlsl.pdb del
+call :check_file smoke.hlsl.Fd.dxo
+if %Failed% neq 0 goto :failed
+
 rem del .pdb file if exists
 del %CD%\*.pdb 1>nul 2>nul