Explorar o código

Adding options for dxc
- Update command line options of dxc
(Qstrip_debug, Qstrip_priv, Qstrip_rootsignature, setrootsignature, getprivate, setprivate)
- Add IDxcContainerBuilder API and its implementation
- Resolve lifetime of dxil.dll on dxcompiler.dll to guarantee access of memory generated from dxil.dll

Young Kim %!s(int64=8) %!d(string=hai) anos
pai
achega
5a916c56d9

+ 10 - 0
include/dxc/HLSL/DxilContainer.h

@@ -384,6 +384,16 @@ inline char * PartKindToCharArray(uint32_t partKind, _Out_writes_(5) char* pText
   return pText;
 }
 
+inline size_t GetOffsetTableSize(uint32_t partCount) {
+  return sizeof(uint32_t) * partCount;
+}
+// Compute total size of the dxil container from parts information
+inline size_t GetDxilContainerSizeFromParts(uint32_t partCount, uint32_t partsSize) {
+  return partsSize + (uint32_t)sizeof(DxilContainerHeader) +
+         GetOffsetTableSize(partCount) +
+         (uint32_t)sizeof(DxilPartHeader) * partCount;
+}
+
 } // namespace hlsl
 
 #endif // __DXC_CONTAINER__

+ 6 - 0
include/dxc/Support/ErrorCodes.h

@@ -77,3 +77,9 @@
 
 // 0x80AA0010 - Error parsing DDI signature.
 #define DXC_E_INCORRECT_DDI_SIGNATURE                 DXC_MAKE_HRESULT(DXC_SEVERITY_ERROR,FACILITY_DXC,(0x0010))
+
+// 0x80AA0011 - Duplicate part exists in dxil container.
+#define DXC_E_DUPLICATE_PART                          DXC_MAKE_HRESULT(DXC_SEVERITY_ERROR,FACILITY_DXC,(0x0011))
+
+// 0x80AA0012 - Error finding part in dxil container.
+#define DXC_E_MISSING_PART                            DXC_MAKE_HRESULT(DXC_SEVERITY_ERROR,FACILITY_DXC,(0x0012))

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

@@ -94,6 +94,7 @@ public:
   llvm::StringRef ExternalFn;   // OPT_external_fn
   llvm::StringRef ExternalLib;  // OPT_external_lib
   llvm::StringRef ExtractRootSignatureFile; // OPT_extractrootsignature
+  llvm::StringRef ExtractPrivateFile; // OPT_getprivate
   llvm::StringRef ForceRootSigVer; // OPT_force_rootsig_ver
   llvm::StringRef InputFile; // OPT_INPUT
   llvm::StringRef OutputHeader; // OPT_Fh
@@ -102,6 +103,8 @@ public:
   llvm::StringRef Preprocess; // OPT_P
   llvm::StringRef TargetProfile; // OPT_target_profile
   llvm::StringRef VariableName; // OPT_Vn
+  llvm::StringRef PrivateSource; // OPT_setprivate
+  llvm::StringRef RootSignatureSource; // OPT_setrootsignature
 
   bool AllResourcesBound; // OPT_all_resources_bound
   bool AstDump; // OPT_ast_dump
@@ -132,6 +135,10 @@ public:
   bool NotUseLegacyCBufLoad;  // OPT_not_use_legacy_cbuf_load
   bool DisplayIncludeProcess; // OPT__vi
   bool RecompileFromBinary; // OPT _Recompile (Recompiling the DXBC binary file not .hlsl file)
+  bool StripDebug; // OPT Qstrip_debug
+  bool StripRootSignature; // OPT Qstrip_rootsignature
+  bool StripPrivate; // OPT Qstrip_priv
+  bool StripReflection; // OPT Qstrip_reflect
 };
 
 /// Use this class to capture, convert and handle the lifetime for the

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

@@ -273,17 +273,17 @@ def P : Separate<["-", "/"], "P">, Flags<[DriverOption]>, Group<hlslutil_Group>,
 
 def dumpbin : Flag<["-", "/"], "dumpbin">, Flags<[DriverOption]>, Group<hlslutil_Group>,
   HelpText<"Load a binary file rather than compiling">;
-def Qstrip_reflect : Flag<["-", "/"], "Qstrip_reflect">, Group<hlslutil_Group>,
+def Qstrip_reflect : Flag<["-", "/"], "Qstrip_reflect">, Flags<[DriverOption]>, Group<hlslutil_Group>,
   HelpText<"Strip reflection data from shader bytecode">;
-def Qstrip_debug : Flag<["-", "/"], "Qstrip_debug">, Group<hlslutil_Group>,
+def Qstrip_debug : Flag<["-", "/"], "Qstrip_debug">, Flags<[DriverOption]>, Group<hlslutil_Group>,
   HelpText<"Strip debug information from 4_0+ shader bytecode">;
-def Qstrip_priv : Flag<["-", "/"], "Qstrip_priv">, Group<hlslutil_Group>,
+def Qstrip_priv : Flag<["-", "/"], "Qstrip_priv">, Flags<[DriverOption]>, Group<hlslutil_Group>,
   HelpText<"Strip private data from shader bytecode">;
 
-def Qstrip_rootsignature : Flag<["-", "/"], "Qstrip_rootsignature">,     Group<hlslutil_Group>, HelpText<"Strip root signature data from shader bytecode">;
-def setrootsignature     : JoinedOrSeparate<["-", "/"], "setrootsignature">,     MetaVarName<"<file>">, Group<hlslutil_Group>, HelpText<"Attach root signature to shader bytecode">;
-def extractrootsignature : JoinedOrSeparate<["-", "/"], "extractrootsignature">, MetaVarName<"<file>">, Group<hlslutil_Group>, HelpText<"Extract root signature from shader bytecode">;
-def verifyrootsignature  : JoinedOrSeparate<["-", "/"], "verifyrootsignature">,  MetaVarName<"<file>">, Group<hlslutil_Group>, HelpText<"Verify shader bytecode with root signature">;
+def Qstrip_rootsignature : Flag<["-", "/"], "Qstrip_rootsignature">, Flags<[DriverOption]>, Group<hlslutil_Group>, HelpText<"Strip root signature data from shader bytecode">;
+def setrootsignature     : JoinedOrSeparate<["-", "/"], "setrootsignature">,     MetaVarName<"<file>">, Flags<[DriverOption]>, Group<hlslutil_Group>, HelpText<"Attach root signature to shader bytecode">;
+def extractrootsignature : JoinedOrSeparate<["-", "/"], "extractrootsignature">, MetaVarName<"<file>">, Flags<[DriverOption]>, Group<hlslutil_Group>, HelpText<"Extract root signature from shader bytecode">;
+def verifyrootsignature  : JoinedOrSeparate<["-", "/"], "verifyrootsignature">,  MetaVarName<"<file>">, Flags<[DriverOption]>, Group<hlslutil_Group>, HelpText<"Verify shader bytecode with root signature">;
 def force_rootsig_ver    : JoinedOrSeparate<["-", "/"], "force_rootsig_ver">,    Flags<[CoreOption]>, MetaVarName<"<profile>">, Group<hlslcomp_Group>, HelpText<"force root signature version (rootsig_1_1 if omitted)">;
 
 def shtemplate : JoinedOrSeparate<["-", "/"], "shtemplate">, MetaVarName<"<file>">, Group<hlslcomp_Group>,
@@ -299,9 +299,9 @@ def enable_unbounded_descriptor_tables : Flag<["-", "/"], "enable_unbounded_desc
 def all_resources_bound : Flag<["-", "/"], "all_resources_bound">, Flags<[CoreOption]>, Group<hlslcomp_Group>,
   HelpText<"Enables agressive flattening">;
 
-def setprivate : JoinedOrSeparate<["-", "/"], "setprivate">, MetaVarName<"<file>">, Group<hlslutil_Group>,
+def setprivate : JoinedOrSeparate<["-", "/"], "setprivate">, Flags<[DriverOption]>, MetaVarName<"<file>">, Group<hlslutil_Group>,
   HelpText<"Private data to add to compiled shader blob">;
-def getprivate : JoinedOrSeparate<["-", "/"], "getprivate">, MetaVarName<"<file>">, Group<hlslutil_Group>,
+def getprivate : JoinedOrSeparate<["-", "/"], "getprivate">, Flags<[DriverOption]>, MetaVarName<"<file>">, Group<hlslutil_Group>,
   HelpText<"Save private data from shader blob">;
 
 def nologo : Flag<["-", "/"], "nologo">, Group<hlslcore_Group>,

+ 11 - 1
include/dxc/Support/dxcapi.use.h

@@ -62,9 +62,13 @@ public:
 
   template <typename TInterface>
   HRESULT CreateInstance(REFCLSID clsid, _Outptr_ TInterface** pResult) {
+    return CreateInstance(clsid, __uuidof(TInterface), (IUnknown**)pResult);
+  }
+
+  HRESULT CreateInstance(REFCLSID clsid, REFIID riid, _Outptr_ IUnknown **pResult) {
     if (pResult == nullptr) return E_POINTER;
     if (m_dll == nullptr) return E_FAIL;
-    HRESULT hr = m_createFn(clsid, __uuidof(TInterface), (LPVOID*)pResult);
+    HRESULT hr = m_createFn(clsid, riid, (LPVOID*)pResult);
     return hr;
   }
 
@@ -79,6 +83,12 @@ public:
       m_dll = nullptr;
     }
   }
+
+  HMODULE Detach() {
+    HMODULE module = m_dll;
+    m_dll = nullptr;
+    return module;
+  }
 };
 
 inline DxcDefine GetDefine(_In_ LPCWSTR name, LPCWSTR value) {

+ 15 - 0
include/dxc/dxcapi.h

@@ -175,6 +175,14 @@ IDxcValidator : public IUnknown {
     ) = 0;
 };
 
+struct __declspec(uuid("334b1f50-2292-4b35-99a1-25588d8c17fe"))
+IDxcContainerBuilder : public IUnknown {
+  virtual HRESULT STDMETHODCALLTYPE Load(_In_ IDxcBlob *pDxilContainerHeader) = 0;                // Loads DxilContainer to the builder
+  virtual HRESULT STDMETHODCALLTYPE AddPart(_In_ UINT32 fourCC, _In_ IDxcBlob *pSource) = 0;      // Part to add to the container
+  virtual HRESULT STDMETHODCALLTYPE RemovePart(_In_ UINT32 fourCC) = 0;                           // Remove the part with fourCC
+  virtual HRESULT STDMETHODCALLTYPE SerializeContainer(_Out_ IDxcOperationResult **ppResult) = 0; // Builds a container of the given container builder state
+};
+
 struct __declspec(uuid("091f7a26-1c1f-4948-904b-e6e3a8a771d5"))
 IDxcAssembler : public IUnknown {
   // Assemble dxil in ll or llvm bitcode to DXIL container.
@@ -278,4 +286,11 @@ __declspec(selectany) extern const GUID CLSID_DxcOptimizer = {
     {0x9b, 0x6b, 0xb1, 0x24, 0xe7, 0xa5, 0x20, 0x4c}
 };
 
+// {94134294-411f-4574-b4d0-8741e25240d2}
+__declspec(selectany) extern const GUID CLSID_DxcContainerBuilder = {
+  0x94134294,
+  0x411f,
+  0x4574,  
+  { 0xb4, 0xd0, 0x87, 0x41, 0xe2, 0x52, 0x40, 0xd2 }
+};
 #endif

+ 7 - 0
lib/DxcSupport/HLSLOptions.cpp

@@ -237,6 +237,7 @@ int ReadDxcOpts(const OptTable *optionTable, unsigned flagsToInclude,
   opts.AssemblyCode = Args.getLastArgValue(OPT_Fc);
   opts.DebugFile = Args.getLastArgValue(OPT_Fd);
   opts.ExtractRootSignatureFile = Args.getLastArgValue(OPT_extractrootsignature);
+  opts.ExtractPrivateFile = Args.getLastArgValue(OPT_getprivate);
   opts.OutputObject = Args.getLastArgValue(OPT_Fo);
   opts.OutputHeader = Args.getLastArgValue(OPT_Fh);
   opts.OutputWarningsFile = Args.getLastArgValue(OPT_Fe);
@@ -251,6 +252,8 @@ int ReadDxcOpts(const OptTable *optionTable, unsigned flagsToInclude,
   opts.VariableName = Args.getLastArgValue(OPT_Vn);
   opts.InputFile = Args.getLastArgValue(OPT_INPUT);
   opts.ForceRootSigVer = Args.getLastArgValue(OPT_force_rootsig_ver);
+  opts.PrivateSource = Args.getLastArgValue(OPT_setprivate);
+  opts.RootSignatureSource = Args.getLastArgValue(OPT_setrootsignature);
 
   if (!opts.ForceRootSigVer.empty() && opts.ForceRootSigVer != "rootsig_1_0" &&
       opts.ForceRootSigVer != "rootsig_1_1") {
@@ -291,6 +294,10 @@ int ReadDxcOpts(const OptTable *optionTable, unsigned flagsToInclude,
   opts.AvoidFlowControl = Args.hasFlag(OPT_Gfa, OPT_INVALID, false);
   opts.PreferFlowControl = Args.hasFlag(OPT_Gfp, OPT_INVALID, false);
   opts.RecompileFromBinary = Args.hasFlag(OPT_recompile, OPT_INVALID, false);
+  opts.StripDebug = Args.hasFlag(OPT_Qstrip_debug, 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);
   if (opts.DefaultColMajor && opts.DefaultRowMajor) {
     errors << "Cannot specify /Zpr and /Zpc together, use /? to get usage information";
     return 1;

+ 85 - 3
tools/clang/tools/dxc/dxc.cpp

@@ -83,6 +83,8 @@ private:
   DxcDllSupport &m_dxcSupport;
 
   void ActOnBlob(IDxcBlob *pBlob);
+  void UpdatePart(IDxcBlob *pBlob, IDxcBlob **ppResult);
+  bool UpdatePartRequired();
   void WriteHeader(IDxcBlobEncoding *pDisassembly, IDxcBlob *pCode,
                    llvm::Twine &pVariableName, LPCWSTR pPath);
   // TODO : Refactor two functions below. There are duplicate functions in DxcContext in dxa.cpp
@@ -131,6 +133,8 @@ static void WritePartToFile(IDxcBlob *pBlob, hlsl::DxilFourCC CC,
   }
 }
 
+// This function is called either after the compilation is done or /dumpbin option is provided
+// Performing options that are used to process dxil container.
 void DxcContext::ActOnBlob(IDxcBlob *pBlob) {
   // Text output.
   if (m_Opts.AstDump || m_Opts.OptDump) {
@@ -140,7 +144,9 @@ void DxcContext::ActOnBlob(IDxcBlob *pBlob) {
 
   // Write the output blob.
   if (!m_Opts.OutputObject.empty()) {
-    WriteBlobToFile(pBlob, m_Opts.OutputObject);
+    CComPtr<IDxcBlob> pResult;
+    UpdatePart(pBlob, &pResult);
+    WriteBlobToFile(pResult, m_Opts.OutputObject);
   }
 
   // Extract and write the PDB/debug information.
@@ -153,6 +159,11 @@ void DxcContext::ActOnBlob(IDxcBlob *pBlob) {
     WritePartToFile(pBlob, hlsl::DFCC_RootSignature, m_Opts.ExtractRootSignatureFile);
   }
 
+  // Extract and write private data.
+  if (!m_Opts.ExtractPrivateFile.empty()) {
+    WritePartToFile(pBlob, hlsl::DFCC_PrivateData, m_Opts.ExtractPrivateFile);
+  }
+
   // OutputObject suppresses console dump.
   bool needDisassembly = !m_Opts.OutputHeader.empty() ||
                          !m_Opts.AssemblyCode.empty() ||
@@ -178,6 +189,68 @@ void DxcContext::ActOnBlob(IDxcBlob *pBlob) {
   }
 }
 
+// Given a dxil container, update the dxil container by processing container specific options.
+void DxcContext::UpdatePart(IDxcBlob *pSource, IDxcBlob **ppResult) {
+  DXASSERT(pSource && ppResult, "otherwise blob cannot be updated");
+  if (!UpdatePartRequired()) {
+    *ppResult = pSource;
+    pSource->AddRef();
+    return;
+  }
+
+  CComPtr<IDxcContainerBuilder> pContainerBuilder;
+  CComPtr<IDxcBlob> pResult;
+  IFT(m_dxcSupport.CreateInstance(CLSID_DxcContainerBuilder, &pContainerBuilder));
+  
+  // Load original container and update blob for each given option
+  IFT(pContainerBuilder->Load(pSource));
+
+  // Update parts based on dxc options
+  if (m_Opts.StripDebug) {
+    IFT(pContainerBuilder->RemovePart(hlsl::DxilFourCC::DFCC_ShaderDebugInfoDXIL));
+  }
+  if (m_Opts.StripPrivate) {
+    IFT(pContainerBuilder->RemovePart(hlsl::DxilFourCC::DFCC_PrivateData));
+  }
+  if (m_Opts.StripRootSignature) {
+    IFT(pContainerBuilder->RemovePart(hlsl::DxilFourCC::DFCC_RootSignature));
+  }
+  if (!m_Opts.PrivateSource.empty()) {
+    CComPtr<IDxcBlobEncoding> privateBlob;
+    ReadFileIntoBlob(m_dxcSupport, StringRefUtf16(m_Opts.PrivateSource), &privateBlob);
+    IFT(pContainerBuilder->AddPart(hlsl::DxilFourCC::DFCC_PrivateData, privateBlob));
+  }
+  if (!m_Opts.RootSignatureSource.empty()) {
+    CComPtr<IDxcBlobEncoding> RootSignatureBlob;
+    ReadFileIntoBlob(m_dxcSupport, StringRefUtf16(m_Opts.RootSignatureSource), &RootSignatureBlob);
+    IFT(pContainerBuilder->AddPart(hlsl::DxilFourCC::DFCC_RootSignature, RootSignatureBlob));
+  }
+  
+  // Get the final blob from container builder
+  CComPtr<IDxcOperationResult> pBuilderResult;
+  IFT(pContainerBuilder->SerializeContainer(&pBuilderResult));
+  if (!m_Opts.OutputWarningsFile.empty()) {
+    CComPtr<IDxcBlobEncoding> pErrors;
+    IFT(pBuilderResult->GetErrorBuffer(&pErrors));
+    if (pErrors != nullptr) {
+      WriteBlobToFile(pErrors, m_Opts.OutputWarningsFile);
+    }
+  }
+  else {
+    WriteOperationErrorsToConsole(pBuilderResult, m_Opts.OutputWarnings);
+  }
+  HRESULT status;
+  IFT(pBuilderResult->GetStatus(&status));
+  IFT(status);
+  IFT(pBuilderResult->GetResult(ppResult));
+}
+
+bool DxcContext::UpdatePartRequired() {
+  return m_Opts.StripDebug || m_Opts.StripPrivate ||
+    m_Opts.StripRootSignature || !m_Opts.PrivateSource.empty() ||
+    !m_Opts.RootSignatureSource.empty();
+}
+
 class DxcIncludeHandlerForInjectedSources : public IDxcIncludeHandler {
 private:
   DXC_MICROCOM_REF_FIELD(m_dwRef)
@@ -663,8 +736,17 @@ int __cdecl wmain(int argc, const wchar_t **argv_) {
       Unicode::acp_char printBuffer[128]; // printBuffer is safe to treat as
                                           // UTF-8 because we use ASCII only errors
       if (msg == nullptr || *msg == '\0') {
-        sprintf_s(printBuffer, _countof(printBuffer),
-                  "Compilation failed - error code 0x%08x.\n", hlslException.hr);
+        if (hlslException.hr == DXC_E_DUPLICATE_PART) {
+          sprintf_s(printBuffer, _countof(printBuffer),
+                    "DXIL container already contains the given part.");
+        } else if (hlslException.hr == DXC_E_MISSING_PART) {
+          sprintf_s(printBuffer, _countof(printBuffer),
+                    "DXIL container does not contain the given part.");
+        }
+        else {
+          sprintf_s(printBuffer, _countof(printBuffer),
+            "Compilation failed - error code 0x%08x.\n", hlslException.hr);
+        }
         msg = printBuffer;
       }
 

+ 3 - 1
tools/clang/tools/dxcompiler/CMakeLists.txt

@@ -1,4 +1,4 @@
-# Copyright (C) Microsoft Corporation. All rights reserved.
+# Copyright (C) Microsoft Corporation. All rights reserved.
 # Licensed under the MIT license. See COPYRIGHT in the project root for full license information.
 find_package(DiaSDK REQUIRED) # Used for constants and declarations.
 
@@ -47,6 +47,8 @@ set(SOURCES
   DXCompiler.cpp
   DXCompiler.rc
   DXCompiler.def
+  dxillib.cpp
+  dxcontainerbuilder.cpp
   )
 
 set(LIBRARIES

+ 13 - 3
tools/clang/tools/dxcompiler/DXCompiler.cpp

@@ -14,10 +14,11 @@
 
 #include "dxc/Support/WinIncludes.h"
 #include "dxcetw.h"
+#include "dxillib.h"
 
 namespace hlsl { HRESULT SetupRegistryPassForHLSL(); }
 
-BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD Reason, LPVOID) {
+BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD Reason, LPVOID reserved) {
   BOOL result = TRUE;
   if (Reason == DLL_PROCESS_ATTACH) {
     EventRegisterMicrosoft_Windows_DXCompiler_API();
@@ -29,7 +30,10 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD Reason, LPVOID) {
     }
     else {
       hr = hlsl::SetupRegistryPassForHLSL();
-      if (FAILED(hr)) {
+      if (SUCCEEDED(hr)) {
+        DxilLibInitialize();
+      }
+      else {
         ::llvm::sys::fs::CleanupPerThreadFileSystem();
       }
     }
@@ -41,7 +45,13 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD Reason, LPVOID) {
     ::llvm::llvm_shutdown();
     DxcEtw_DXCompilerShutdown_Stop(S_OK);
     EventUnregisterMicrosoft_Windows_DXCompiler_API();
-  }
+    if (reserved == NULL) { // FreeLibrary has been called or the DLL load failed
+      DxilLibCleanup(DxilLibCleanUpType::UnloadLibrary);
+    }
+    else { // Process termination. We should not call FreeLibrary()
+      DxilLibCleanup(DxilLibCleanUpType::ProcessTermination);
+    }
+  } 
 
   return result;
 }

+ 4 - 0
tools/clang/tools/dxcompiler/dxcapi.cpp

@@ -26,6 +26,7 @@ HRESULT CreateDxcRewriter(_In_ REFIID riid, _Out_ LPVOID *ppv);
 HRESULT CreateDxcValidator(_In_ REFIID riid, _Out_ LPVOID *ppv);
 HRESULT CreateDxcAssembler(_In_ REFIID riid, _Out_ LPVOID *ppv);
 HRESULT CreateDxcOptimizer(_In_ REFIID riid, _Out_ LPVOID *ppv);
+HRESULT CreateDxcContainerBuilder(_In_ REFIID riid, _Out_ LPVOID *ppv);
 
 namespace hlsl {
 void CreateDxcContainerReflection(IDxcContainerReflection **ppResult);
@@ -89,6 +90,9 @@ DxcCreateInstance(_In_ REFCLSID   rclsid,
   else if (IsEqualCLSID(rclsid, CLSID_DxcContainerReflection)) {
     hr = CreateDxcContainerReflection(riid, ppv);
   }
+  else if (IsEqualCLSID(rclsid, CLSID_DxcContainerBuilder)) {
+    hr = CreateDxcContainerBuilder(riid, ppv);
+  }
   else {
     hr = REGDB_E_CLASSNOTREG;
   }

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

@@ -73,6 +73,7 @@
 #include "dxc/Support/DxcLangExtensionsHelper.h"
 #include "dxc/Support/HLSLOptions.h"
 #include "dxcetw.h"
+#include "dxillib.h"
 #include <algorithm>
 
 #define CP_UTF16 1200
@@ -2042,13 +2043,11 @@ public:
       // validator can be used as a fallback.
       bool needsValidation = !opts.CodeGenHighLevel && !opts.DisableValidation;
       bool internalValidator = false;
-      dxc::DxcDllSupport lib;
       CComPtr<IDxcValidator> pValidator;
       CComPtr<IDxcOperationResult> pValResult;
       if (needsValidation) {
-        if (SUCCEEDED(lib.InitializeForDll(L"dxil.dll", "DxcCreateInstance"))) {
-          // If the DLL is found but doesn't work, warn.
-          if (FAILED(lib.CreateInstance(CLSID_DxcValidator, &pValidator))) {
+        if (DxilLibIsEnabled()) {
+          if (FAILED(DxilLibCreateInstance(CLSID_DxcValidator, &pValidator))) {
             w << "Unable to create validator from dxil.dll, fallback to built-in.";
           }
         }

+ 210 - 0
tools/clang/tools/dxcompiler/dxcontainerbuilder.cpp

@@ -0,0 +1,210 @@
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// dxcontainerbuilder.cpp                                                    //
+// Copyright (C) Microsoft Corporation. All rights reserved.                 //
+// This file is distributed under the University of Illinois Open Source     //
+// License. See LICENSE.TXT for details.                                     //
+//                                                                           //
+// Implements the Dxil Container Builder                                     //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+#include "dxc/Support/WinIncludes.h"
+#include "dxc/dxcapi.h"
+#include "dxc/HLSL/DxilContainer.h"
+#include "dxc/Support/ErrorCodes.h"
+#include "dxc/Support/FileIOHelper.h"
+#include "dxc/Support/Global.h"
+#include "dxc/Support/microcom.h"
+#include "dxc/Support/dxcapi.impl.h"
+#include "dxillib.h"
+
+#include <algorithm>
+#include "llvm/ADT/SmallVector.h"
+
+using namespace hlsl;
+
+class DxcContainerBuilder : public IDxcContainerBuilder {
+public:
+  __override HRESULT STDMETHODCALLTYPE Load(_In_ IDxcBlob *pDxilContainerHeader); // Loads DxilContainer to the builder
+  __override HRESULT STDMETHODCALLTYPE AddPart(_In_ UINT32 fourCC, _In_ IDxcBlob *pSource); // Add the given part with fourCC
+  __override HRESULT STDMETHODCALLTYPE RemovePart(_In_ UINT32 fourCC);                // Remove the part with fourCC
+  __override HRESULT STDMETHODCALLTYPE SerializeContainer(_Out_ IDxcOperationResult **ppResult); // Builds a container of the given container builder state
+
+  DXC_MICROCOM_ADDREF_RELEASE_IMPL(m_dwRef)
+  HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject) {
+    return DoBasicQueryInterface<IDxcContainerBuilder>(this, riid, ppvObject);
+  }
+
+  DxcContainerBuilder(const char *warning) : m_dwRef(0), m_parts(), m_pContainer(), m_warning(warning) {}
+
+private:
+  DXC_MICROCOM_REF_FIELD(m_dwRef)
+
+  class DxilPart {
+  public:
+    UINT32 m_fourCC;
+    CComPtr<IDxcBlob> m_Blob;
+    DxilPart(UINT32 fourCC, IDxcBlob *pSource) : m_fourCC(fourCC), m_Blob(pSource) {}
+  };
+  typedef llvm::SmallVector<DxilPart, 8> PartList;
+
+  PartList m_parts;
+  CComPtr<IDxcBlob> m_pContainer; 
+  const char *m_warning;
+
+  UINT32 ComputeContainerSize();
+  HRESULT UpdateContainerHeader(AbstractMemoryStream *pStream, uint32_t containerSize);
+  HRESULT UpdateOffsetTable(AbstractMemoryStream *pStream);
+  HRESULT UpdateParts(AbstractMemoryStream *pStream);
+};
+
+HRESULT STDMETHODCALLTYPE DxcContainerBuilder::Load(_In_ IDxcBlob *pSource) {
+  try {
+    IFTBOOL(m_pContainer == nullptr && pSource != nullptr &&
+      IsDxilContainerLike(pSource->GetBufferPointer(),
+        pSource->GetBufferSize()),
+      E_INVALIDARG);
+    m_pContainer = pSource;
+    const DxilContainerHeader *pHeader = (DxilContainerHeader *)pSource->GetBufferPointer();
+    for (DxilPartIterator it = begin(pHeader), itEnd = end(pHeader); it != itEnd; ++it) {
+      const DxilPartHeader *pPartHeader = *it;
+      CComPtr<IDxcBlobEncoding> pBlob;
+      IFT(DxcCreateBlobWithEncodingFromPinned((const void *)(pPartHeader + 1), pPartHeader->PartSize, CP_UTF8, &pBlob));
+      PartList::iterator itPartList = std::find_if(m_parts.begin(), m_parts.end(), [&](DxilPart part) {
+        return part.m_fourCC == pPartHeader->PartFourCC;
+      });
+      IFTBOOL(itPartList == m_parts.end(), DXC_E_DUPLICATE_PART);
+      m_parts.emplace_back(DxilPart(pPartHeader->PartFourCC, pBlob));
+    }
+    return S_OK;
+  }
+  CATCH_CPP_RETURN_HRESULT();
+}
+
+
+HRESULT STDMETHODCALLTYPE DxcContainerBuilder::AddPart(_In_ UINT32 fourCC, _In_ IDxcBlob *pSource) {
+  try {
+    IFTBOOL(pSource != nullptr && !IsDxilContainerLike(pSource->GetBufferPointer(),
+      pSource->GetBufferSize()),
+      E_INVALIDARG);
+    // Only allow adding private data and root signature for now
+    IFTBOOL(fourCC == DxilFourCC::DFCC_RootSignature || fourCC == DxilFourCC::DFCC_PrivateData, E_INVALIDARG);
+    PartList::iterator it = std::find_if(m_parts.begin(), m_parts.end(), [&](DxilPart part) {
+      return part.m_fourCC == fourCC;
+    });
+    IFTBOOL(it == m_parts.end(), DXC_E_DUPLICATE_PART);
+    m_parts.emplace_back(DxilPart(fourCC, pSource));
+    return S_OK;
+  }
+  CATCH_CPP_RETURN_HRESULT();
+}
+
+HRESULT STDMETHODCALLTYPE DxcContainerBuilder::RemovePart(_In_ UINT32 fourCC) {
+  try {
+    IFTBOOL(fourCC == DxilFourCC::DFCC_ShaderDebugInfoDXIL ||
+                fourCC == DxilFourCC::DFCC_RootSignature ||
+                fourCC == DxilFourCC::DFCC_PrivateData,
+            E_INVALIDARG); // You can only remove debug info, rootsignature, or private data blob
+    PartList::iterator it =
+      std::find_if(m_parts.begin(), m_parts.end(),
+        [&](DxilPart part) { return part.m_fourCC == fourCC; });
+    IFTBOOL(it != m_parts.end(), DXC_E_MISSING_PART);
+    m_parts.erase(it);
+    return S_OK;
+  }
+  CATCH_CPP_RETURN_HRESULT();
+}
+
+HRESULT STDMETHODCALLTYPE DxcContainerBuilder::SerializeContainer(_Out_ IDxcOperationResult **ppResult) {
+  try {
+    // Allocate memory for new dxil container.
+    uint32_t ContainerSize = ComputeContainerSize();
+    CComPtr<IMalloc> pMalloc;
+    CComPtr<AbstractMemoryStream> pMemoryStream;
+    CComPtr<IDxcBlob> pResult;
+    IFT(CoGetMalloc(1, &pMalloc));
+    IFT(CreateMemoryStream(pMalloc, &pMemoryStream));
+    IFT(pMemoryStream->QueryInterface(&pResult));
+    IFT(pMemoryStream->Reserve(ContainerSize))
+    
+    // Update Dxil Container
+    IFT(UpdateContainerHeader(pMemoryStream, ContainerSize));
+
+    // Update offset Table
+    IFT(UpdateOffsetTable(pMemoryStream));
+    
+    // Update Parts
+    IFT(UpdateParts(pMemoryStream));
+
+    CComPtr<IDxcBlobEncoding> pError;
+    DxcCreateBlobWithEncodingOnHeapCopy(m_warning, strlen(m_warning), CP_UTF8, &pError);
+    DxcOperationResult::CreateFromResultErrorStatus(pResult, pError, S_OK, ppResult);
+    return S_OK;
+  }
+  CATCH_CPP_RETURN_HRESULT();
+}
+
+UINT32 DxcContainerBuilder::ComputeContainerSize() {
+  UINT32 partsSize = 0;
+  for (DxilPart part : m_parts) {
+    partsSize += part.m_Blob->GetBufferSize();
+  }
+  return GetDxilContainerSizeFromParts(m_parts.size(), partsSize);
+}
+
+HRESULT DxcContainerBuilder::UpdateContainerHeader(AbstractMemoryStream *pStream, uint32_t containerSize) {
+  DxilContainerHeader header;
+  InitDxilContainer(&header, m_parts.size(), containerSize);
+  ULONG cbWritten;
+  IFR(pStream->Write(&header, sizeof(DxilContainerHeader), &cbWritten));
+  if (cbWritten != sizeof(DxilContainerHeader)) {
+    return E_FAIL;
+  }
+  return S_OK;
+}
+
+HRESULT DxcContainerBuilder::UpdateOffsetTable(AbstractMemoryStream *pStream) {
+  UINT32 offset = sizeof(DxilContainerHeader) + GetOffsetTableSize(m_parts.size());
+  for (int i = 0; i < m_parts.size(); ++i) {
+    ULONG cbWritten;
+    IFR(pStream->Write(&offset, sizeof(UINT32), &cbWritten));
+    if (cbWritten != sizeof(UINT32)) { return E_FAIL; }
+    offset += sizeof(DxilPartHeader) + m_parts[i].m_Blob->GetBufferSize();
+  }
+  return S_OK;
+}
+
+HRESULT DxcContainerBuilder::UpdateParts(AbstractMemoryStream *pStream) {
+  for (int i = 0; i < m_parts.size(); ++i) {
+    ULONG cbWritten;
+    CComPtr<IDxcBlob> pBlob = m_parts[i].m_Blob;
+    // Write part header
+    DxilPartHeader partHeader = { m_parts[i].m_fourCC, (uint32_t) pBlob->GetBufferSize() };
+    IFR(pStream->Write(&partHeader, sizeof(DxilPartHeader), &cbWritten));
+    if (cbWritten != sizeof(DxilPartHeader)) { return E_FAIL; }
+    // Write part content
+    IFR(pStream->Write(pBlob->GetBufferPointer(), pBlob->GetBufferSize(), &cbWritten));
+    if (cbWritten != pBlob->GetBufferSize()) { return E_FAIL; }
+  }
+  return S_OK;
+}
+
+HRESULT CreateDxcContainerBuilder(_In_ REFIID riid, _Out_ LPVOID *ppv) {
+  // Call dxil.dll's containerbuilder 
+  const char *warning;
+  HRESULT hr = DxilLibCreateInstance(CLSID_DxcContainerBuilder, (IDxcContainerBuilder**)ppv);
+  if (FAILED(hr)) {
+    warning = "Unable to create container builder from dxil.dll, fallback to built-in.";
+  }
+  else {
+    return hr;
+  }
+
+  CComPtr<IDxcContainerBuilder> Result = new  (std::nothrow) DxcContainerBuilder(warning);
+  if (Result == nullptr) {
+    *ppv = nullptr;
+    return E_OUTOFMEMORY;
+  }
+  return Result->QueryInterface(riid, ppv);
+}

+ 68 - 0
tools/clang/tools/dxcompiler/dxillib.cpp

@@ -0,0 +1,68 @@
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// dxillib.cpp                                                               //
+// Copyright (C) Microsoft Corporation. All rights reserved.                 //
+// This file is distributed under the University of Illinois Open Source     //
+// License. See LICENSE.TXT for details.                                     //
+//                                                                           //
+// Provides access to dxil.dll                                               //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+#include "dxillib.h"
+#include "dxc/Support/Global.h" // For DXASSERT
+#include "dxc/Support/dxcapi.use.h"
+
+using namespace dxc;
+
+static DxcDllSupport g_DllSupport;
+static HRESULT g_DllLibResult = S_OK;
+static CRITICAL_SECTION cs;
+
+// Check if we can successfully get IDxcValidator from dxil.dll
+// This function is to prevent multiple attempts to load dxil.dll 
+HRESULT DxilLibInitialize() {
+  InitializeCriticalSection(&cs);
+  return S_OK;
+}
+
+HRESULT DxilLibCleanup(DxilLibCleanUpType type) {
+  HRESULT hr = S_OK;
+  if (type == DxilLibCleanUpType::ProcessTermination) {
+    g_DllSupport.Detach();
+  }
+  else if (type == DxilLibCleanUpType::UnloadLibrary) {
+    g_DllSupport.Cleanup();
+  }
+  else {
+    hr = E_INVALIDARG;
+  }
+  DeleteCriticalSection(&cs);
+  return hr;
+}
+
+// g_DllLibResult is S_OK by default, check again to see if dxil.dll is loaded
+// If we fail to load dxil.dll, set g_DllLibResult to E_FAIL so that we don't
+// have multiple attempts to load dxil.dll
+bool DxilLibIsEnabled() {
+  EnterCriticalSection(&cs);
+  if (SUCCEEDED(g_DllLibResult)) {
+    if (!g_DllSupport.IsEnabled()) {
+      g_DllLibResult = g_DllSupport.InitializeForDll(L"dxil.dll", "DxcCreateInstance");
+    }
+  }
+  LeaveCriticalSection(&cs);
+  return SUCCEEDED(g_DllLibResult);
+}
+
+
+HRESULT DxilLibCreateInstance(_In_ REFCLSID rclsid, _In_ REFIID riid, _In_ IUnknown **ppInterface) {
+  DXASSERT_NOMSG(ppInterface != nullptr);
+  HRESULT hr = E_FAIL;
+  if (DxilLibIsEnabled()) {
+    EnterCriticalSection(&cs);
+    hr = g_DllSupport.CreateInstance(rclsid, riid, ppInterface);
+    LeaveCriticalSection(&cs);
+  }
+  return hr;
+}

+ 42 - 0
tools/clang/tools/dxcompiler/dxillib.h

@@ -0,0 +1,42 @@
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// dxillib.h                                                                 //
+// Copyright (C) Microsoft Corporation. All rights reserved.                 //
+// This file is distributed under the University of Illinois Open Source     //
+// License. See LICENSE.TXT for details.                                     //
+//                                                                           //
+// Provides wrappers to handle calls to dxil.dll                             //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+#pragma once
+#ifndef __DXC_DXILLIB__
+#define __DXC_DXILLIB__
+
+#include "dxc/Support/WinIncludes.h"
+
+
+// Initialize Dxil library. 
+HRESULT DxilLibInitialize();
+
+// When dxcompiler is detached from process, 
+// we should not call FreeLibrary on process termination. 
+// So the caller has to specify if cleaning is from FreeLibrary or process termination
+enum class DxilLibCleanUpType {
+  UnloadLibrary,
+  ProcessTermination
+};
+
+HRESULT DxilLibCleanup(DxilLibCleanUpType type);
+
+// Check if can access dxil.dll
+bool DxilLibIsEnabled();
+
+HRESULT DxilLibCreateInstance(_In_ REFCLSID rclsid, _In_ REFIID riid, _In_ IUnknown **ppInterface);
+
+template <class TInterface>
+HRESULT DxilLibCreateInstance(_In_ REFCLSID rclsid, _In_ TInterface **ppInterface) {
+  return DxilLibCreateInstance(rclsid, __uuidof(TInterface), (IUnknown**) ppInterface);
+}
+
+#endif // __DXC_DXILLIB__

+ 139 - 0
tools/clang/unittests/HLSL/CompilerTest.cpp

@@ -274,6 +274,9 @@ public:
   TEST_METHOD(CompileWhenEmptyThenFails)
   TEST_METHOD(CompileWhenIncorrectThenFails)
   TEST_METHOD(CompileWhenWorksThenDisassembleWorks)
+  TEST_METHOD(CompileWhenDebugWorksThenStripDebug)
+  TEST_METHOD(CompileWhenWorksThenAddRemovePrivate)
+  TEST_METHOD(CompileWithRootSignatureThenStripRootSignature)
 
   TEST_METHOD(CompileWhenIncludeThenLoadInvoked)
   TEST_METHOD(CompileWhenIncludeThenLoadUsed)
@@ -775,6 +778,10 @@ public:
     return m_dllSupport.CreateInstance(CLSID_DxcCompiler, ppResult);
   }
 
+  HRESULT CreateContainerBuilder(IDxcContainerBuilder **ppResult) {
+    return m_dllSupport.CreateInstance(CLSID_DxcContainerBuilder, ppResult);
+  }
+
   template <typename T, typename TDefault, typename TIface>
   void WriteIfValue(TIface *pSymbol, std::wstringstream &o,
                     TDefault defaultValue, LPCWSTR valueLabel,
@@ -1337,6 +1344,138 @@ TEST_F(CompilerTest, CompileWhenWorksThenDisassembleWorks) {
   // WEX::Logging::Log::Comment(disassembleStringW.m_psz);
 }
 
+TEST_F(CompilerTest, CompileWhenDebugWorksThenStripDebug) {
+  CComPtr<IDxcCompiler> pCompiler;
+  CComPtr<IDxcOperationResult> pResult;
+  CComPtr<IDxcBlobEncoding> pSource;
+  CComPtr<IDxcBlob> pProgram;
+
+  VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
+  CreateBlobFromText("float4 main(float4 pos : SV_Position) : SV_Target {\r\n"
+                     "  float4 local = abs(pos);\r\n"
+                     "  return local;\r\n"
+                     "}",
+                     &pSource);
+  LPCWSTR args[] = {L"/Zi"};
+
+  VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"source.hlsl", L"main",
+                                      L"ps_6_0", args, _countof(args), nullptr,
+                                      0, nullptr, &pResult));
+  VERIFY_SUCCEEDED(pResult->GetResult(&pProgram));
+  // Check if it contains debug blob
+  hlsl::DxilContainerHeader *pHeader =
+      (hlsl::DxilContainerHeader *)(pProgram->GetBufferPointer());
+  hlsl::DxilPartHeader *pPartHeader = hlsl::GetDxilPartByType(
+      pHeader, hlsl::DxilFourCC::DFCC_ShaderDebugInfoDXIL);
+  VERIFY_IS_NOT_NULL(pPartHeader);
+  // Check debug info part does not exist after strip debug info
+
+  CComPtr<IDxcBlob> pNewProgram;
+  CComPtr<IDxcContainerBuilder> pBuilder;
+  VERIFY_SUCCEEDED(CreateContainerBuilder(&pBuilder));
+  VERIFY_SUCCEEDED(pBuilder->Load(pProgram));
+  VERIFY_SUCCEEDED(pBuilder->RemovePart(hlsl::DxilFourCC::DFCC_ShaderDebugInfoDXIL));
+  VERIFY_SUCCEEDED(pBuilder->SerializeContainer(&pResult));
+  VERIFY_SUCCEEDED(pResult->GetResult(&pNewProgram));
+  pHeader = (hlsl::DxilContainerHeader *)(pNewProgram->GetBufferPointer());
+  pPartHeader = hlsl::GetDxilPartByType(
+      pHeader, hlsl::DxilFourCC::DFCC_ShaderDebugInfoDXIL);
+  VERIFY_IS_NULL(pPartHeader);
+}
+
+TEST_F(CompilerTest, CompileWhenWorksThenAddRemovePrivate) {
+  CComPtr<IDxcCompiler> pCompiler;
+  CComPtr<IDxcOperationResult> pResult;
+  CComPtr<IDxcBlobEncoding> pSource;
+  CComPtr<IDxcBlob> pProgram;
+
+  VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
+  CreateBlobFromText("float4 main() : SV_Target {\r\n"
+                     "  return 0;\r\n"
+                     "}",
+                     &pSource);
+  VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"source.hlsl", L"main",
+                                      L"ps_6_0", nullptr, 0, nullptr, 0,
+                                      nullptr, &pResult));
+  VERIFY_SUCCEEDED(pResult->GetResult(&pProgram));
+  // Append private data blob
+  CComPtr<IDxcContainerBuilder> pBuilder;
+  VERIFY_SUCCEEDED(CreateContainerBuilder(&pBuilder));
+
+  std::string privateTxt("private data");
+  CComPtr<IDxcBlobEncoding> pPrivate;
+  CreateBlobFromText(privateTxt.c_str(), &pPrivate);
+  VERIFY_SUCCEEDED(pBuilder->Load(pProgram));
+  VERIFY_SUCCEEDED(pBuilder->AddPart(hlsl::DxilFourCC::DFCC_PrivateData, pPrivate));
+  VERIFY_SUCCEEDED(pBuilder->SerializeContainer(&pResult));
+
+  CComPtr<IDxcBlob> pNewProgram;
+  VERIFY_SUCCEEDED(pResult->GetResult(&pNewProgram));
+  hlsl::DxilContainerHeader *pContainerHeader =
+      (hlsl::DxilContainerHeader *)(pNewProgram->GetBufferPointer());
+  hlsl::DxilPartHeader *pPartHeader = hlsl::GetDxilPartByType(
+      pContainerHeader, hlsl::DxilFourCC::DFCC_PrivateData);
+  VERIFY_IS_NOT_NULL(pPartHeader);
+  // compare data
+  std::string privatePart((const char *)(pPartHeader + 1), privateTxt.size());
+  VERIFY_IS_TRUE(strcmp(privatePart.c_str(), privateTxt.c_str()) == 0);
+
+  // Remove private data blob
+  pBuilder.Release();
+  VERIFY_SUCCEEDED(CreateContainerBuilder(&pBuilder));
+  VERIFY_SUCCEEDED(pBuilder->Load(pNewProgram));
+  VERIFY_SUCCEEDED(pBuilder->RemovePart(hlsl::DxilFourCC::DFCC_PrivateData));
+  VERIFY_SUCCEEDED(pBuilder->SerializeContainer(&pResult));
+
+  pNewProgram.Release();
+  VERIFY_SUCCEEDED(pResult->GetResult(&pNewProgram));
+  pContainerHeader =
+    (hlsl::DxilContainerHeader *)(pNewProgram->GetBufferPointer());
+  pPartHeader = hlsl::GetDxilPartByType(
+    pContainerHeader, hlsl::DxilFourCC::DFCC_PrivateData);
+  VERIFY_IS_NULL(pPartHeader);
+}
+
+TEST_F(CompilerTest, CompileWithRootSignatureThenStripRootSignature) {
+  CComPtr<IDxcCompiler> pCompiler;
+  CComPtr<IDxcOperationResult> pResult;
+  CComPtr<IDxcBlobEncoding> pSource;
+  CComPtr<IDxcBlob> pProgram;
+  VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
+  CreateBlobFromText("[RootSignature(\"\")] \r\n"
+                     "float4 main(float a : A) : SV_Target {\r\n"
+                     "  return a;\r\n"
+                     "}",
+                     &pSource);
+  VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"source.hlsl", L"main",
+                                      L"ps_6_0", nullptr, 0, nullptr,
+                                      0, nullptr, &pResult));
+  VERIFY_IS_NOT_NULL(pResult);
+  HRESULT status;
+  VERIFY_SUCCEEDED(pResult->GetStatus(&status));
+  VERIFY_SUCCEEDED(status);
+  VERIFY_SUCCEEDED(pResult->GetResult(&pProgram));
+  VERIFY_IS_NOT_NULL(pProgram);
+  hlsl::DxilContainerHeader *pContainerHeader =
+      (hlsl::DxilContainerHeader *)(pProgram->GetBufferPointer());
+  hlsl::DxilPartHeader *pPartHeader = hlsl::GetDxilPartByType(
+      pContainerHeader, hlsl::DxilFourCC::DFCC_RootSignature);
+  VERIFY_IS_NOT_NULL(pPartHeader);
+  
+  // Remove root signature
+  CComPtr<IDxcBlob> pNewProgram;
+  CComPtr<IDxcContainerBuilder> pBuilder;
+  VERIFY_SUCCEEDED(CreateContainerBuilder(&pBuilder));
+  VERIFY_SUCCEEDED(pBuilder->Load(pProgram));
+  VERIFY_SUCCEEDED(pBuilder->RemovePart(hlsl::DxilFourCC::DFCC_RootSignature));
+  VERIFY_SUCCEEDED(pBuilder->SerializeContainer(&pResult));
+  VERIFY_SUCCEEDED(pResult->GetResult(&pNewProgram));
+  pContainerHeader = (hlsl::DxilContainerHeader *)(pNewProgram->GetBufferPointer());
+  pPartHeader = hlsl::GetDxilPartByType(pContainerHeader,
+                                        hlsl::DxilFourCC::DFCC_RootSignature);
+  VERIFY_IS_NULL(pPartHeader);
+}
+
 TEST_F(CompilerTest, CompileWhenIncludeThenLoadInvoked) {
   CComPtr<IDxcCompiler> pCompiler;
   CComPtr<IDxcOperationResult> pResult;

+ 51 - 2
utils/hct/hcttestcmds.cmd

@@ -59,7 +59,7 @@ if %errorlevel% neq 0 (
   exit /b 1
 )
 
-dxc.exe smoke.hlsl /D "semantic = SV_Position" /T vs_6_0 /Zi /Fo smoke.cso 1> nul
+dxc.exe smoke.hlsl /D "semantic = SV_Position" /T vs_6_0 /Zi /DDX12 /Fo smoke.cso 1> nul
 if %errorlevel% neq 0 (
   echo Failed to compile smoke.hlsl with command line defines
   exit /b 1
@@ -71,6 +71,49 @@ if %errorlevel% neq 0 (
   exit /b 1
 )
 
+dxc.exe smoke.cso /dumpbin /Qstrip_debug /Fo nodebug.cso 1>nul
+if %errorlevel% neq 0 (
+  echo Failed to strip debug part from DXIL container blob
+  exit /b 1
+)
+
+dxc.exe smoke.cso /dumpbin /Qstrip_rootsignature /Fo norootsignature.cso 1>nul
+if %errorlevel% neq 0 (
+  echo Failed to strip rootsignature from DXIL container blob
+  exit /b 1
+)
+
+echo private data > private.txt
+dxc.exe smoke.cso /dumpbin /setprivate private.txt /Fo private.cso 1>nul
+if %errorlevel% neq 0 (
+  echo Failed to set private data from DXIL container blob
+  exit /b 1
+)
+
+dxc.exe private.cso /dumpbin /Qstrip_priv /Fo noprivate.cso 1>nul
+if %errorlevel% neq 0 (
+  echo Failed to strip private data from DXIL container blob
+  exit /b 1
+)
+
+dxc.exe private.cso /dumpbin /getprivate private1.txt 1>nul
+if %errorlevel% neq 0 (
+  echo Failed to get private data from DXIL container blob
+  exit /b 1
+)
+
+FC smoke.cso noprivate.cso 1>nul
+if %errorlevel% neq 0 (
+  echo Appending and removing blob roundtrip failed.
+  exit /b 1
+)
+
+dxc.exe private.cso /Dumpbin /Qstrip_priv /Qstrip_debug /Qstrip_rootsignature /Fo noprivdebugroot.cso 1>nul
+if %errorlevel% neq 0 (
+  echo Failed to extract multiple parts from DXIL container blob
+  exit /b 1
+)
+
 echo Smoke test for dxc.exe shader model upgrade...
 dxc.exe /T ps_5_0 smoke.hlsl 1> nul
 if %errorlevel% neq 0 (
@@ -131,9 +174,15 @@ if %errorlevel% neq 0 (
   exit /b 1
 )
 
-
 rem Clean up.
 del %CD%\smoke.hlsl.h
 del %CD%\smoke.cso
+del %CD%\private.cso
+del %CD%\private.txt
+del %CD%\private1.txt
+del %CD%\noprivate.cso
+del %CD%\nodebug.cso
+del %CD%\noprivdebugroot.cso
+del %CD%\norootsignature.cso
 
 exit /b 0

+ 5 - 0
utils/hct/smoke.hlsl

@@ -1,6 +1,11 @@
 #ifndef semantic
 #define semantic SV_Target
 #endif
+#ifdef DX12
+#define RS ""
+[RootSignature ( RS )]
+#endif
+
 float4 main() : semantic
 {
   return 0;