ソースを参照

Add DxilD3DCompile and DxilD3DCompile2 as example of library use. (#402)

* Add DxilD3DCompile and DxilD3DCompile2 as examle of library use.
It will compile shader into library first, then link to generate the final dxil.
If there's include used, it will compile included file into seperate lib and link all lib together.
Xiang Li 8 年 前
コミット
114fd223d1

+ 1 - 1
include/dxc/dxctools.h

@@ -14,7 +14,7 @@
 
 #include <dxc/dxcapi.h>
 
-enum RewirterOptionMask {
+enum RewriterOptionMask {
   Default = 0,
   SkipFunctionBody = 1,
   SkipStatic = 2,

+ 10 - 5
include/llvm/Support/FileSystem.h

@@ -74,16 +74,21 @@ long msf_lseek(int fd, long offset, int origin);
 class AutoPerThreadSystem
 {
 private:
-  const std::error_code ec;
+  ::llvm::sys::fs::MSFileSystem* m_pOrigValue;
+  std::error_code ec;
 public:
-  AutoPerThreadSystem(_In_ ::llvm::sys::fs::MSFileSystem* value)
-    : ec(::llvm::sys::fs::SetCurrentThreadFileSystem(value))
-  {
+  AutoPerThreadSystem(_In_ ::llvm::sys::fs::MSFileSystem *value)
+      : m_pOrigValue(::llvm::sys::fs::GetCurrentThreadFileSystem()) {
+    SetCurrentThreadFileSystem(nullptr);
+    ec = ::llvm::sys::fs::SetCurrentThreadFileSystem(value);
   }
 
   ~AutoPerThreadSystem()
   {
-    if (!ec) {
+    if (m_pOrigValue) {
+      ::llvm::sys::fs::SetCurrentThreadFileSystem(nullptr);
+      ::llvm::sys::fs::SetCurrentThreadFileSystem(m_pOrigValue);
+    } else if (!ec) {
       ::llvm::sys::fs::SetCurrentThreadFileSystem(nullptr);
     }
   }

+ 5 - 0
tools/clang/test/CodeGenHLSL/batch_cmds.txt

@@ -0,0 +1,5 @@
+-E ps_main -T ps_6_0     lib_entries2.hlsl
+-E vs_main -T vs_6_0   lib_entries2.hlsl
+-E hs_main -T hs_6_0     lib_entries2.hlsl
+-E gs_main -T gs_6_0     lib_entries2.hlsl
+-E ds_main -T ds_6_0    lib_entries2.hlsl

+ 1 - 0
tools/clang/tools/CMakeLists.txt

@@ -31,4 +31,5 @@ add_subdirectory(dxopt)
 add_subdirectory(dxr)
 add_subdirectory(dxv)
 add_subdirectory(dotnetc)
+add_subdirectory(dxlib-sample)
 # HLSL Change Ends

+ 0 - 2
tools/clang/tools/dxcompiler/dxcompilerobj.cpp

@@ -9,8 +9,6 @@
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-//#include "clang/AST/ASTConsumer.h"
-//#include "clang/AST/ASTContext.h"
 #include "clang/Basic/Diagnostic.h"
 #include "clang/Basic/FileManager.h"
 #include "clang/Basic/SourceManager.h"

+ 35 - 0
tools/clang/tools/dxlib-sample/CMakeLists.txt

@@ -0,0 +1,35 @@
+# Copyright (C) Microsoft Corporation. All rights reserved.
+# This file is distributed under the University of Illinois Open Source License. See LICENSE.TXT for details.
+# Build a dxlib_sample.dll as a sample for library and link.
+
+set(SOURCES
+  dxlib_sample.cpp
+  dxlib_sample.def
+  )
+
+set( LLVM_LINK_COMPONENTS
+  ${LLVM_TARGETS_TO_BUILD}
+  analysis
+  ipa
+  dxcsupport
+  HLSL
+  Option     # option library
+  Support    # just for assert and raw streams
+  )
+
+add_clang_library(dxlib_sample SHARED ${SOURCES})
+
+target_link_libraries(dxlib_sample
+  PRIVATE
+  clangAST
+  clangCodeGen
+  clangSema
+  dxcompiler
+  )
+
+add_dependencies(dxlib_sample dxcompiler)
+
+set_target_properties(dxlib_sample
+  PROPERTIES
+  OUTPUT_NAME "dxlib_sample"
+  VERSION ${LIBCLANG_LIBRARY_VERSION})

+ 562 - 0
tools/clang/tools/dxlib-sample/dxlib_sample.cpp

@@ -0,0 +1,562 @@
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// dxlib_sample.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 compile function which compile shader to lib then link.        //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+#include "dxc/Support/WinIncludes.h"
+#include "dxc/Support/FileIOHelper.h"
+#include "dxc/Support/Global.h"
+#include "dxc/Support/Unicode.h"
+#include "dxc/Support/dxcapi.use.h"
+#include "dxc/Support/microcom.h"
+#include "dxc/dxcapi.h"
+#include "dxc/dxctools.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "llvm/Support/Path.h"
+
+using namespace hlsl;
+using namespace llvm;
+
+namespace {
+bool IsAbsoluteOrCurDirRelative(const Twine &T) {
+  if (llvm::sys::path::is_absolute(T)) {
+    return true;
+  }
+  if (T.isSingleStringRef()) {
+    StringRef r = T.getSingleStringRef();
+    if (r.size() < 2)
+      return false;
+    const char *pData = r.data();
+    return pData[0] == '.' && (pData[1] == '\\' || pData[1] == '/');
+  }
+  DXASSERT(false, "twine kind not supported");
+  return false;
+}
+/// Max number of included files (1:1 to their directories) or search
+/// directories. If programs include more than a handful, DxcArgsFileSystem will
+/// need to do better than linear scans. If this is fired,
+/// ERROR_OUT_OF_STRUCTURES will be returned by an attempt to open a file.
+static const size_t MaxIncludedFiles = 200;
+
+class IncludeToLibPreprocessor : public IDxcIncludeHandler {
+public:
+  DXC_MICROCOM_ADDREF_RELEASE_IMPL(m_dwRef)
+  virtual ~IncludeToLibPreprocessor() {}
+  HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject) {
+    return DoBasicQueryInterface<::IDxcIncludeHandler>(this, riid, ppvObject);
+  }
+
+  IncludeToLibPreprocessor(IDxcIncludeHandler *handler)
+      : m_dwRef(0), m_pIncludeHandler(handler) {
+    if (!m_dllSupport.IsEnabled())
+      m_dllSupport.Initialize();
+  }
+
+  __override HRESULT STDMETHODCALLTYPE LoadSource(
+      _In_ LPCWSTR pFilename, // Candidate filename.
+      _COM_Outptr_result_maybenull_ IDxcBlob **ppIncludeSource // Resultant
+                                                               // source object
+                                                               // for included
+                                                               // file, nullptr
+                                                               // if not found.
+  ) {
+    // Read file.
+    CComPtr<IDxcBlob> pIncludeSource;
+    IFT(m_pIncludeHandler->LoadSource(pFilename, &pIncludeSource));
+    // Preprocess the header to remove function body and static function/global.
+    if (SUCCEEDED(Preprocess(pIncludeSource, pFilename))) {
+      return hlsl::DxcCreateBlobOnHeapCopy(m_curHeaderContent.data(),
+                                           m_curHeaderContent.size(),
+                                           ppIncludeSource);
+    } else {
+      IFT(m_pIncludeHandler->LoadSource(pFilename, ppIncludeSource));
+      return E_FAIL;
+    }
+  }
+
+  void SetupDefines(const DxcDefine *pDefines, unsigned defineCount);
+  HRESULT Preprocess(IDxcBlob *pSource, LPCWSTR pFilename);
+
+  const std::vector<std::string> &GetHeaders() const { return m_headers; }
+
+private:
+  DXC_MICROCOM_REF_FIELD(m_dwRef)
+  IDxcIncludeHandler *m_pIncludeHandler;
+  // Vector to save headers.
+  std::string m_curHeaderContent;
+  // Processed header content.
+  std::vector<std::string> m_headers;
+  // Defines.
+  std::vector<std::wstring> m_defineStrs;
+  std::vector<DxcDefine> m_defines;
+
+  dxc::DxcDllSupport m_dllSupport;
+};
+
+void IncludeToLibPreprocessor::SetupDefines(const DxcDefine *pDefines,
+                                            unsigned defineCount) {
+  for (unsigned i = 0; i < defineCount; i++) {
+    const DxcDefine &define = pDefines[i];
+
+    m_defineStrs.emplace_back(define.Name);
+    DxcDefine tmpDefine;
+    tmpDefine.Name = m_defineStrs.back().c_str();
+    tmpDefine.Value = nullptr;
+    if (define.Value) {
+      m_defineStrs.emplace_back(define.Value);
+      tmpDefine.Value = m_defineStrs.back().c_str();
+    }
+    m_defines.emplace_back(tmpDefine);
+  }
+}
+
+HRESULT IncludeToLibPreprocessor::Preprocess(IDxcBlob *pSource,
+                                             LPCWSTR pFilename) {
+  CComPtr<IDxcBlobEncoding> pEncodingIncludeSource;
+  DxcCreateBlobWithEncodingSet(pSource, CP_UTF8, &pEncodingIncludeSource);
+
+  // Create header with no function body.
+  CComPtr<IDxcRewriter> pRewriter;
+  m_dllSupport.CreateInstance(CLSID_DxcRewriter, &pRewriter);
+
+  CComPtr<IDxcOperationResult> pRewriteResult;
+  IFT(pRewriter->RewriteUnchangedWithInclude(
+      pEncodingIncludeSource, pFilename, m_defines.data(), m_defines.size(),
+      this,
+      RewriterOptionMask::SkipFunctionBody | RewriterOptionMask::SkipStatic,
+      &pRewriteResult));
+
+  HRESULT status;
+  if (!SUCCEEDED(pRewriteResult->GetStatus(&status)) || !SUCCEEDED(status)) {
+    return E_FAIL;
+  };
+  // Append existing header.
+  std::string includeSource =
+      m_curHeaderContent + std::string((char *)pSource->GetBufferPointer(),
+                                       pSource->GetBufferSize());
+  m_headers.push_back(includeSource);
+
+  // Save the content of processed header.
+  CComPtr<IDxcBlob> result;
+  IFT(pRewriteResult->GetResult(&result));
+  // Update m_curHeaderContent.
+  m_curHeaderContent = std::string((char *)(result)->GetBufferPointer(),
+                                   (result)->GetBufferSize());
+  return S_OK;
+}
+} // namespace
+
+namespace {
+// Include handler which ignore all include.
+class EmptyIncludeHandler : public IDxcIncludeHandler {
+public:
+  DXC_MICROCOM_ADDREF_RELEASE_IMPL(m_dwRef)
+
+  HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject) {
+    return DoBasicQueryInterface<::IDxcIncludeHandler>(this, riid, ppvObject);
+  }
+
+  EmptyIncludeHandler() {}
+
+  __override HRESULT STDMETHODCALLTYPE LoadSource(
+      _In_ LPCWSTR pFilename, // Candidate filename.
+      _COM_Outptr_result_maybenull_ IDxcBlob **ppIncludeSource // Resultant
+                                                               // source object
+                                                               // for included
+                                                               // file, nullptr
+                                                               // if not found.
+  ) {
+    // Return empty source.
+    if (ppIncludeSource) {
+      return hlsl::DxcCreateBlobOnHeapCopy(" ", 1, ppIncludeSource);
+    } else {
+      return E_FAIL;
+    }
+  }
+
+private:
+  DXC_MICROCOM_REF_FIELD(m_dwRef)
+};
+} // namespace
+
+#include "clang/CodeGen/CodeGenAction.h"
+#include "clang/Frontend/FrontendOptions.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/Hashing.h"
+#include "llvm/IR/LLVMContext.h"
+#include <mutex>
+#include <shared_mutex>
+#include <unordered_map>
+namespace {
+
+struct KeyHash {
+  std::size_t operator()(const hash_code &k) const { return k; }
+};
+struct KeyEqual {
+  bool operator()(const hash_code &l, const hash_code &r) const {
+    return l == r;
+  }
+};
+
+struct CompileInput {
+  std::vector<DxcDefine> &defines;
+  std::vector<LPCWSTR> &arguments;
+};
+
+class LibCacheManager {
+public:
+  HRESULT AddLibBlob(IDxcBlob *pSource, CompileInput &compiler, size_t &hash,
+                     IDxcBlob **pResultLib,
+                     std::function<void(void)> compileFn);
+  bool GetLibBlob(IDxcBlob *pSource, CompileInput &compiler, size_t &hash,
+                  IDxcBlob **pResultLib);
+
+private:
+  hash_code GetHash(IDxcBlob *pSource, CompileInput &compiler);
+  using libCacheType =
+      std::unordered_map<hash_code, CComPtr<IDxcBlob>, KeyHash, KeyEqual>;
+  libCacheType m_libCache;
+  std::shared_mutex m_mutex;
+};
+
+hash_code LibCacheManager::GetHash(IDxcBlob *pSource, CompileInput &compiler) {
+  hash_code libHash = hash_value(
+      StringRef((char *)pSource->GetBufferPointer(), pSource->GetBufferSize()));
+  // Combine compile input.
+  for (auto &Arg : compiler.arguments) {
+    CW2A pUtf8Arg(Arg, CP_UTF8);
+    libHash = hash_combine(libHash, pUtf8Arg.m_psz);
+  }
+  for (auto &Define : compiler.defines) {
+    CW2A pUtf8Name(Define.Name, CP_UTF8);
+    libHash = hash_combine(libHash, pUtf8Name.m_psz);
+    if (Define.Value) {
+      CW2A pUtf8Value(Define.Value, CP_UTF8);
+      libHash = hash_combine(libHash, pUtf8Value.m_psz);
+    }
+  }
+  return libHash;
+}
+
+bool LibCacheManager::GetLibBlob(IDxcBlob *pSource, CompileInput &compiler,
+                                 size_t &hash, IDxcBlob **pResultLib) {
+  if (!pSource || !pResultLib) {
+    return false;
+  }
+  // Create hash from source.
+  hash_code libHash = GetHash(pSource, compiler);
+  hash = libHash;
+  // lock
+  std::shared_lock<std::shared_mutex> lk(m_mutex);
+
+  auto it = m_libCache.find(libHash);
+  if (it != m_libCache.end()) {
+    *pResultLib = it->second;
+    return true;
+  } else {
+    return false;
+  }
+}
+
+HRESULT
+LibCacheManager::AddLibBlob(IDxcBlob *pSource, CompileInput &compiler,
+                            size_t &hash, IDxcBlob **pResultLib,
+                            std::function<void(void)> compileFn) {
+  if (!pSource || !pResultLib) {
+    return E_FAIL;
+  }
+
+  std::unique_lock<std::shared_mutex> lk(m_mutex);
+
+  auto it = m_libCache.find(hash);
+  if (it != m_libCache.end()) {
+    *pResultLib = it->second;
+    return S_OK;
+  }
+
+  compileFn();
+
+  m_libCache[hash] = *pResultLib;
+
+  return S_OK;
+}
+
+LibCacheManager &GetLibCacheManager() {
+  static LibCacheManager g_LibCache;
+  return g_LibCache;
+}
+
+} // namespace
+
+#include "dxc/HLSL/DxilContainer.h"
+#include "dxc/Support/Global.h"
+#include "dxc/Support/WinIncludes.h"
+#include "dxc/dxcapi.h"
+
+#include <d3dcompiler.h>
+#include <string>
+#include <vector>
+
+HRESULT CreateLibrary(IDxcLibrary **pLibrary) {
+  return DxcCreateInstance(CLSID_DxcLibrary, __uuidof(IDxcLibrary),
+                           (void **)pLibrary);
+}
+
+HRESULT CreateCompiler(IDxcCompiler **ppCompiler) {
+  return DxcCreateInstance(CLSID_DxcCompiler, __uuidof(IDxcCompiler),
+                           (void **)ppCompiler);
+}
+
+HRESULT CreateLinker(IDxcLinker **ppLinker) {
+  return DxcCreateInstance(CLSID_DxcLinker, __uuidof(IDxcLinker),
+                           (void **)ppLinker);
+}
+
+HRESULT CreateContainerReflection(IDxcContainerReflection **ppReflection) {
+  return DxcCreateInstance(CLSID_DxcContainerReflection,
+                           __uuidof(IDxcContainerReflection),
+                           (void **)ppReflection);
+}
+
+HRESULT CompileToLib(IDxcBlob *pSource, std::vector<DxcDefine> &defines,
+                     IDxcIncludeHandler *pInclude,
+                     std::vector<LPCWSTR> &arguments, IDxcBlob **ppCode,
+                     IDxcBlob **ppErrorMsgs) {
+  CComPtr<IDxcCompiler> compiler;
+  CComPtr<IDxcOperationResult> operationResult;
+
+  IFR(CreateCompiler(&compiler));
+  IFR(compiler->Compile(pSource, L"input.hlsl", L"", L"lib_6_1",
+                        arguments.data(), (UINT)arguments.size(),
+                        defines.data(), (UINT)defines.size(), pInclude,
+                        &operationResult));
+  HRESULT hr;
+  operationResult->GetStatus(&hr);
+  if (SUCCEEDED(hr)) {
+    return operationResult->GetResult((IDxcBlob **)ppCode);
+  } else {
+    if (ppErrorMsgs)
+      operationResult->GetErrorBuffer((IDxcBlobEncoding **)ppErrorMsgs);
+    return hr;
+  }
+  return hr;
+}
+
+#include "dxc/HLSL/DxilLinker.h"
+HRESULT CompileFromBlob(IDxcBlobEncoding *pSource, LPCWSTR pSourceName,
+                        std::vector<DxcDefine> &defines,
+                        IDxcIncludeHandler *pInclude, LPCSTR pEntrypoint,
+                        LPCSTR pTarget, std::vector<LPCWSTR> &arguments,
+                        IDxcOperationResult **ppOperationResult) {
+  CComPtr<IDxcCompiler> compiler;
+  CComPtr<IDxcLinker> linker;
+
+  // Upconvert legacy targets
+  char Target[7] = "?s_6_0";
+  Target[6] = 0;
+  Target[0] = pTarget[0];
+
+  try {
+    CA2W pEntrypointW(pEntrypoint);
+    CA2W pTargetProfileW(Target);
+
+    // Preprocess.
+    CComPtr<IncludeToLibPreprocessor> preprocessor(
+        new IncludeToLibPreprocessor(pInclude));
+    preprocessor->SetupDefines(defines.data(), defines.size());
+
+    preprocessor->Preprocess(pSource, pSourceName);
+
+    CompileInput compilerInput{defines, arguments};
+
+    EmptyIncludeHandler emptyIncludeHandler;
+    EmptyIncludeHandler *pEmptyIncludeHandler = &emptyIncludeHandler;
+    LibCacheManager &libCache = GetLibCacheManager();
+    LLVMContext llvmContext;
+    IFR(CreateLinker(&linker));
+
+    const auto &headers = preprocessor->GetHeaders();
+    std::vector<std::wstring> hashStrList;
+    std::vector<LPCWSTR> hashList;
+    for (const auto &header : headers) {
+      CComPtr<IDxcBlob> pOutputBlob;
+      CComPtr<IDxcBlob> pSource;
+      IFT(DxcCreateBlobOnHeap(header.data(), header.size(), &pSource));
+      size_t hash;
+      if (!libCache.GetLibBlob(pSource, compilerInput, hash, &pOutputBlob)) {
+        // Cannot find existing blob, create from pSource.
+        IDxcBlob **ppCode = &pOutputBlob;
+
+        auto compileFn = [&]() {
+          IFT(CompileToLib(pSource, defines, pEmptyIncludeHandler, arguments,
+                           ppCode, nullptr));
+        };
+        libCache.AddLibBlob(pSource, compilerInput, hash, &pOutputBlob,
+                            compileFn);
+      }
+      pSource.Detach(); // Don't keep the ownership.
+      hashStrList.emplace_back(std::to_wstring(hash));
+      hashList.emplace_back(hashStrList.back().c_str());
+      linker->RegisterLibrary(hashList.back(), pOutputBlob);
+      pOutputBlob.Detach(); // Ownership is in libCache.
+    }
+    std::wstring wEntry = Unicode::UTF8ToUTF16StringOrThrow(pEntrypoint);
+    std::wstring wTarget = Unicode::UTF8ToUTF16StringOrThrow(pTarget);
+
+    // Link
+    return linker->Link(wEntry.c_str(), wTarget.c_str(), hashList.data(),
+                        hashList.size(), nullptr, 0, ppOperationResult);
+  } catch (const std::bad_alloc &) {
+    return E_OUTOFMEMORY;
+  } catch (const CAtlException &err) {
+    return err.m_hr;
+  }
+}
+
+HRESULT WINAPI DxilD3DCompile(LPCVOID pSrcData, SIZE_T SrcDataSize,
+                              LPCSTR pSourceName,
+                              const D3D_SHADER_MACRO *pDefines,
+                              IDxcIncludeHandler *pInclude, LPCSTR pEntrypoint,
+                              LPCSTR pTarget, UINT Flags1, UINT Flags2,
+                              ID3DBlob **ppCode, ID3DBlob **ppErrorMsgs) {
+  CComPtr<IDxcLibrary> library;
+  CComPtr<IDxcBlobEncoding> source;
+  CComPtr<IDxcOperationResult> operationResult;
+  *ppCode = nullptr;
+  if (ppErrorMsgs != nullptr)
+    *ppErrorMsgs = nullptr;
+
+  IFR(CreateLibrary(&library));
+  IFR(library->CreateBlobWithEncodingFromPinned((LPBYTE)pSrcData, SrcDataSize,
+                                                CP_ACP, &source));
+
+  HRESULT hr;
+  try {
+    CA2W pFileName(pSourceName);
+
+    std::vector<std::wstring> defineValues;
+    std::vector<DxcDefine> defines;
+    if (pDefines) {
+      CONST D3D_SHADER_MACRO *pCursor = pDefines;
+
+      // Convert to UTF-16.
+      while (pCursor->Name) {
+        defineValues.push_back(std::wstring(CA2W(pCursor->Name)));
+        if (pCursor->Definition)
+          defineValues.push_back(std::wstring(CA2W(pCursor->Definition)));
+        else
+          defineValues.push_back(std::wstring());
+        ++pCursor;
+      }
+
+      // Build up array.
+      pCursor = pDefines;
+      size_t i = 0;
+      while (pCursor->Name) {
+        defines.push_back(
+            DxcDefine{defineValues[i++].c_str(), defineValues[i++].c_str()});
+        ++pCursor;
+      }
+    }
+
+    std::vector<LPCWSTR> arguments;
+    // /Gec, /Ges Not implemented:
+    // if(Flags1 & D3DCOMPILE_ENABLE_BACKWARDS_COMPATIBILITY)
+    // arguments.push_back(L"/Gec");  if(Flags1 & D3DCOMPILE_ENABLE_STRICTNESS)
+    // arguments.push_back(L"/Ges");
+    if (Flags1 & D3DCOMPILE_IEEE_STRICTNESS)
+      arguments.push_back(L"/Gis");
+    if (Flags1 & D3DCOMPILE_OPTIMIZATION_LEVEL2) {
+      switch (Flags1 & D3DCOMPILE_OPTIMIZATION_LEVEL2) {
+      case D3DCOMPILE_OPTIMIZATION_LEVEL0:
+        arguments.push_back(L"/O0");
+        break;
+      case D3DCOMPILE_OPTIMIZATION_LEVEL2:
+        arguments.push_back(L"/O2");
+        break;
+      case D3DCOMPILE_OPTIMIZATION_LEVEL3:
+        arguments.push_back(L"/O3");
+        break;
+      }
+    }
+    // Currently, /Od turns off too many optimization passes, causing incorrect
+    // DXIL to be generated. Re-enable once /Od is implemented properly:
+    // if(Flags1 & D3DCOMPILE_SKIP_OPTIMIZATION) arguments.push_back(L"/Od");
+    if (Flags1 & D3DCOMPILE_DEBUG)
+      arguments.push_back(L"/Zi");
+    if (Flags1 & D3DCOMPILE_PACK_MATRIX_ROW_MAJOR)
+      arguments.push_back(L"/Zpr");
+    if (Flags1 & D3DCOMPILE_PACK_MATRIX_COLUMN_MAJOR)
+      arguments.push_back(L"/Zpc");
+    if (Flags1 & D3DCOMPILE_AVOID_FLOW_CONTROL)
+      arguments.push_back(L"/Gfa");
+    if (Flags1 & D3DCOMPILE_PREFER_FLOW_CONTROL)
+      arguments.push_back(L"/Gfp");
+    // We don't implement this:
+    // if(Flags1 & D3DCOMPILE_PARTIAL_PRECISION) arguments.push_back(L"/Gpp");
+    if (Flags1 & D3DCOMPILE_RESOURCES_MAY_ALIAS)
+      arguments.push_back(L"/res_may_alias");
+
+    CompileFromBlob(source, pFileName, defines, pInclude, pEntrypoint, pTarget,
+                    arguments, &operationResult);
+    operationResult->GetStatus(&hr);
+    if (SUCCEEDED(hr)) {
+      return operationResult->GetResult((IDxcBlob **)ppCode);
+    } else {
+      if (ppErrorMsgs)
+        operationResult->GetErrorBuffer((IDxcBlobEncoding **)ppErrorMsgs);
+      return hr;
+    }
+  } catch (const std::bad_alloc &) {
+    return E_OUTOFMEMORY;
+  } catch (const CAtlException &err) {
+    return err.m_hr;
+  }
+}
+
+HRESULT WINAPI DxilD3DCompile2(
+    LPCVOID pSrcData, SIZE_T SrcDataSize, LPCSTR pSourceName,
+    LPCSTR pEntrypoint, LPCSTR pTarget,
+    const DxcDefine *pDefines, // Array of defines
+    UINT32 defineCount,        // Number of defines
+    LPCWSTR *pArguments,       // Array of pointers to arguments
+    UINT32 argCount,           // Number of arguments
+    IDxcIncludeHandler *pInclude, IDxcOperationResult **ppOperationResult) {
+  CComPtr<IDxcLibrary> library;
+  CComPtr<IDxcBlobEncoding> source;
+
+  *ppOperationResult = nullptr;
+
+  IFR(CreateLibrary(&library));
+  IFR(library->CreateBlobWithEncodingFromPinned((LPBYTE)pSrcData, SrcDataSize,
+                                                CP_ACP, &source));
+
+  try {
+    CA2W pFileName(pSourceName);
+    std::vector<DxcDefine> defines(pDefines, pDefines + defineCount);
+    std::vector<LPCWSTR> arguments(pArguments, pArguments + argCount);
+    return CompileFromBlob(source, pFileName, defines, pInclude, pEntrypoint,
+                           pTarget, arguments, ppOperationResult);
+  } catch (const std::bad_alloc &) {
+    return E_OUTOFMEMORY;
+  } catch (const CAtlException &err) {
+    return err.m_hr;
+  }
+}
+
+BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD Reason, LPVOID) {
+  BOOL result = TRUE;
+  if (Reason == DLL_PROCESS_ATTACH) {
+    DisableThreadLibraryCalls(hinstDLL);
+  } else if (Reason == DLL_PROCESS_DETACH) {
+    // Nothing to clean-up.
+  }
+
+  return result;
+}

+ 5 - 0
tools/clang/tools/dxlib-sample/dxlib_sample.def

@@ -0,0 +1,5 @@
+LIBRARY dxlib_sample
+
+EXPORTS
+    DxilD3DCompile=DxilD3DCompile
+    DxilD3DCompile2=DxilD3DCompile2

+ 3 - 3
tools/clang/tools/libclang/dxcrewriteunused.cpp

@@ -384,8 +384,8 @@ HRESULT DoSimpleReWrite(_In_ DxcLangExtensionsHelper *pHelper,
   if (pWarnings != nullptr) *pWarnings = nullptr;
   if (pResult != nullptr) *pResult = nullptr;
 
-  bool bSkipFunctionBody = rewriteOption & RewirterOptionMask::SkipFunctionBody;
-  bool bSkipStatic = rewriteOption & RewirterOptionMask::SkipStatic;
+  bool bSkipFunctionBody = rewriteOption & RewriterOptionMask::SkipFunctionBody;
+  bool bSkipStatic = rewriteOption & RewriterOptionMask::SkipStatic;
 
   std::string s, warnings;
   raw_string_ostream o(s);
@@ -515,7 +515,7 @@ public:
       HRESULT status =
           DoSimpleReWrite(&m_langExtensionsHelper, fakeName, pRemap.get(),
                           defineCount > 0 ? definesStr.c_str() : nullptr,
-                          RewirterOptionMask::Default, &errors, &rewrite);
+                          RewriterOptionMask::Default, &errors, &rewrite);
 
       return DxcOperationResult::CreateFromUtf8Strings(errors, rewrite, status,
                                                        ppResult);

+ 1 - 0
tools/clang/unittests/CMakeLists.txt

@@ -38,6 +38,7 @@ endif (CLANG_INCLUDE_TESTS) # HLSL Change
 if (HLSL_INCLUDE_TESTS) 
   add_subdirectory(HLSL)
   add_subdirectory(HLSLHost)
+  add_subdirectory(dxc_batch)
 endif (HLSL_INCLUDE_TESTS)
 
 # HLSL Change Ends

+ 4 - 4
tools/clang/unittests/HLSL/RewriterTest.cpp

@@ -344,14 +344,14 @@ TEST_F(RewriterTest, RunIncludes) {
   VERIFY_IS_TRUE(RewriteCompareGoldInclude(
       L"rewriter\\includes.hlsl",
       L"rewriter\\correct_rewrites\\includes_gold.hlsl",
-      RewirterOptionMask::Default));
+      RewriterOptionMask::Default));
 }
 
 TEST_F(RewriterTest, RunNoFunctionBodyInclude) {
   VERIFY_IS_TRUE(RewriteCompareGoldInclude(
       L"rewriter\\includes.hlsl",
       L"rewriter\\correct_rewrites\\includes_gold_nobody.hlsl",
-      RewirterOptionMask::SkipFunctionBody));
+      RewriterOptionMask::SkipFunctionBody));
 }
 
 TEST_F(RewriterTest, RunStructMethods) {
@@ -483,7 +483,7 @@ TEST_F(RewriterTest, RunNoFunctionBody) {
   // Run rewrite no function body on the source code
   VERIFY_SUCCEEDED(pRewriter->RewriteUnchangedWithInclude(
       source.BlobEncoding, L"vector-assignments_noerr.hlsl", myDefines,
-      myDefinesCount, /*pIncludeHandler*/ nullptr, RewirterOptionMask::SkipFunctionBody,
+      myDefinesCount, /*pIncludeHandler*/ nullptr, RewriterOptionMask::SkipFunctionBody,
       &pRewriteResult));
 
   CComPtr<IDxcBlob> result;
@@ -513,7 +513,7 @@ TEST_F(RewriterTest, RunNoStatic) {
   VERIFY_SUCCEEDED(pRewriter->RewriteUnchangedWithInclude(
       source.BlobEncoding, L"attributes_noerr.hlsl", myDefines, myDefinesCount,
       /*pIncludeHandler*/ nullptr,
-      RewirterOptionMask::SkipFunctionBody | RewirterOptionMask::SkipStatic,
+      RewriterOptionMask::SkipFunctionBody | RewriterOptionMask::SkipStatic,
       &pRewriteResult));
 
   CComPtr<IDxcBlob> result;

+ 46 - 0
tools/clang/unittests/dxc_batch/CMakeLists.txt

@@ -0,0 +1,46 @@
+# Copyright (C) Microsoft Corporation. All rights reserved.
+# This file is distributed under the University of Illinois Open Source License. See LICENSE.TXT for details.
+# Builds dxc_batch.exe
+
+set( LLVM_LINK_COMPONENTS
+  ${LLVM_TARGETS_TO_BUILD}
+  analysis
+  ipa
+  dxcsupport
+  HLSL
+  Option     # option library
+  Support    # just for assert and raw streams
+  MSSupport  # for CreateMSFileSystemForDisk
+  )
+
+add_clang_executable(dxc_batch
+  dxc_batch.cpp
+  )
+
+target_link_libraries(dxc_batch
+  clangAST
+  clangCodeGen
+  clangSema
+  dxcompiler
+  dxlib_sample
+  )
+
+set_target_properties(dxc PROPERTIES VERSION ${CLANG_EXECUTABLE_VERSION})
+hlsl_update_product_ver("dxc_batch")
+
+include_directories(AFTER ${DIASDK_INCLUDE_DIRS})
+
+add_dependencies(dxc_batch dxcompiler dxlib_sample)
+
+if(UNIX)
+  set(CLANGXX_LINK_OR_COPY create_symlink)
+# Create a relative symlink
+  set(dxc_batch_binary "dxc_batch${CMAKE_EXECUTABLE_SUFFIX}")
+else()
+  set(CLANGXX_LINK_OR_COPY copy)
+  set(dxc_batch_binary "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${CMAKE_CFG_INTDIR}/dxc_batch${CMAKE_EXECUTABLE_SUFFIX}")
+endif()
+
+install(TARGETS dxc_batch
+  RUNTIME DESTINATION bin)
+

+ 930 - 0
tools/clang/unittests/dxc_batch/dxc_batch.cpp

@@ -0,0 +1,930 @@
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// dxc_bach.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 the entry point for the dxc_back console program.                //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+// dxc_batch is a fork of dxc showing how to build multiple shaders while
+// sharing library-fied intermediates
+
+#include "dxc/Support/Global.h"
+#include "dxc/Support/Unicode.h"
+#include "dxc/Support/WinIncludes.h"
+#include <string>
+#include <vector>
+
+#include "dxc/HLSL/DxilContainer.h"
+#include "dxc/HLSL/DxilRootSignature.h"
+#include "dxc/HLSL/DxilShaderModel.h"
+#include "dxc/Support/FileIOHelper.h"
+#include "dxc/Support/HLSLOptions.h"
+#include "dxc/Support/dxcapi.use.h"
+#include "dxc/Support/microcom.h"
+#include "dxc/dxcapi.h"
+#include "dxc/dxcapi.internal.h"
+#include "dxc/dxctools.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Option/OptTable.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <chrono>
+#include <comdef.h>
+#include <thread>
+#include <unordered_map>
+
+#include "llvm/Support//MSFileSystem.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+
+inline bool wcseq(LPCWSTR a, LPCWSTR b) {
+  return (a == nullptr && b == nullptr) ||
+         (a != nullptr && b != nullptr && wcscmp(a, b) == 0);
+}
+inline bool wcsieq(LPCWSTR a, LPCWSTR b) { return _wcsicmp(a, b) == 0; }
+
+using namespace dxc;
+using namespace llvm;
+using namespace llvm::opt;
+using namespace hlsl::options;
+
+extern HRESULT WINAPI DxilD3DCompile2(
+    LPCVOID pSrcData, SIZE_T SrcDataSize, LPCSTR pSourceName,
+    LPCSTR pEntrypoint, LPCSTR pTarget,
+    const DxcDefine *pDefines, // Array of defines
+    UINT32 defineCount,        // Number of defines
+    LPCWSTR *pArguments,       // Array of pointers to arguments
+    UINT32 argCount,           // Number of arguments
+    IDxcIncludeHandler *pInclude, IDxcOperationResult **ppOperationResult);
+
+class DxcContext {
+
+private:
+  DxcOpts &m_Opts;
+  DxcDllSupport &m_dxcSupport;
+
+  int ActOnBlob(IDxcBlob *pBlob);
+  int ActOnBlob(IDxcBlob *pBlob, IDxcBlob *pDebugBlob, LPCWSTR pDebugBlobName);
+  void UpdatePart(IDxcBlob *pBlob, IDxcBlob **ppResult);
+  bool UpdatePartRequired();
+  void WriteHeader(IDxcBlobEncoding *pDisassembly, IDxcBlob *pCode,
+                   llvm::Twine &pVariableName, LPCWSTR pPath);
+  HRESULT ReadFileIntoPartContent(hlsl::DxilFourCC fourCC, LPCWSTR fileName,
+                                  IDxcBlob **ppResult);
+
+  void ExtractRootSignature(IDxcBlob *pBlob, IDxcBlob **ppResult);
+  int VerifyRootSignature();
+
+public:
+  DxcContext(DxcOpts &Opts, DxcDllSupport &dxcSupport)
+      : m_Opts(Opts), m_dxcSupport(dxcSupport) {}
+
+  int Compile(llvm::StringRef path, bool bLibLink);
+  int DumpBinary();
+  void Preprocess();
+};
+
+static void PrintHlslException(const ::hlsl::Exception &hlslException,
+                               llvm::StringRef stage) {
+  printf("%s failed\n", stage.str().c_str());
+  try {
+    const char *msg = hlslException.what();
+    Unicode::acp_char
+        printBuffer[128]; // printBuffer is safe to treat as
+                          // UTF-8 because we use ASCII only errors
+    if (msg == nullptr || *msg == '\0') {
+      if (hlslException.hr == DXC_E_DUPLICATE_PART) {
+        sprintf_s(
+            printBuffer, _countof(printBuffer),
+            "dxc failed : DXIL container already contains the given part.");
+      } else if (hlslException.hr == DXC_E_MISSING_PART) {
+        sprintf_s(
+            printBuffer, _countof(printBuffer),
+            "dxc failed : DXIL container does not contain the given part.");
+      } else if (hlslException.hr == DXC_E_CONTAINER_INVALID) {
+        sprintf_s(printBuffer, _countof(printBuffer),
+                  "dxc failed : Invalid DXIL container.");
+      } else if (hlslException.hr == DXC_E_CONTAINER_MISSING_DXIL) {
+        sprintf_s(printBuffer, _countof(printBuffer),
+                  "dxc failed : DXIL container is missing DXIL part.");
+      } else if (hlslException.hr == DXC_E_CONTAINER_MISSING_DEBUG) {
+        sprintf_s(printBuffer, _countof(printBuffer),
+                  "dxc failed : DXIL container is missing Debug Info part.");
+      } else if (hlslException.hr == E_OUTOFMEMORY) {
+        sprintf_s(printBuffer, _countof(printBuffer),
+                  "dxc failed : Out of Memory.");
+      } else if (hlslException.hr == E_INVALIDARG) {
+        sprintf_s(printBuffer, _countof(printBuffer),
+                  "dxc failed : Invalid argument.");
+      } else {
+        sprintf_s(printBuffer, _countof(printBuffer),
+                  "dxc failed : error code 0x%08x.\n", hlslException.hr);
+      }
+      msg = printBuffer;
+    }
+
+    dxc::WriteUtf8ToConsoleSizeT(msg, strlen(msg), STD_ERROR_HANDLE);
+    printf("\n");
+  } catch (...) {
+    printf("  unable to retrieve error message.\n");
+  }
+}
+
+static int Compile(llvm::StringRef command, DxcDllSupport &dxcSupport,
+                   llvm::StringRef path, bool bLinkLib) {
+  const OptTable *optionTable = getHlslOptTable();
+  llvm::SmallVector<llvm::StringRef, 4> args;
+  command.split(args, " ");
+  if (!path.empty()) {
+    args.emplace_back("-I");
+    args.emplace_back(path);
+  }
+
+  MainArgs argStrings(args);
+  DxcOpts dxcOpts;
+
+  std::string errorString;
+  llvm::raw_string_ostream errorStream(errorString);
+  int optResult =
+      ReadDxcOpts(optionTable, DxcFlags, argStrings, dxcOpts, errorStream);
+  errorStream.flush();
+  if (errorString.size()) {
+    fprintf(stderr, "dxc failed : %s", errorString.data());
+  }
+  if (optResult != 0) {
+    return optResult;
+  }
+
+  int retVal = 0;
+  try {
+    DxcContext context(dxcOpts, dxcSupport);
+    // TODO: implement all other actions.
+    if (!dxcOpts.Preprocess.empty()) {
+      context.Preprocess();
+    } else if (dxcOpts.DumpBin) {
+      retVal = context.DumpBinary();
+    } else {
+      retVal = context.Compile(path, bLinkLib);
+    }
+  } catch (const ::hlsl::Exception &hlslException) {
+    PrintHlslException(hlslException, command.str().c_str());
+    return 1;
+  } catch (std::bad_alloc &) {
+    printf("%s failed - out of memory.\n", command.str().c_str());
+    return 1;
+  } catch (...) {
+    printf("%s failed - unknown error.\n", command.str().c_str());
+    return 1;
+  }
+  return retVal;
+}
+
+static void WriteBlobToFile(_In_opt_ IDxcBlob *pBlob, llvm::StringRef FName) {
+  ::dxc::WriteBlobToFile(pBlob, StringRefUtf16(FName));
+}
+
+static void WritePartToFile(IDxcBlob *pBlob, hlsl::DxilFourCC CC,
+                            llvm::StringRef FName) {
+  const hlsl::DxilContainerHeader *pContainer = hlsl::IsDxilContainerLike(
+      pBlob->GetBufferPointer(), pBlob->GetBufferSize());
+  if (!pContainer) {
+    throw hlsl::Exception(E_FAIL, "Unable to find required part in blob");
+  }
+  hlsl::DxilPartIsType pred(CC);
+  hlsl::DxilPartIterator it =
+      std::find_if(hlsl::begin(pContainer), hlsl::end(pContainer), pred);
+  if (it == hlsl::end(pContainer)) {
+    throw hlsl::Exception(E_FAIL, "Unable to find required part in blob");
+  }
+
+  const char *pData = hlsl::GetDxilPartData(*it);
+  DWORD dataLen = (*it)->PartSize;
+  StringRefUtf16 WideName(FName);
+  CHandle file(CreateFile2(WideName, GENERIC_WRITE, FILE_SHARE_READ,
+                           CREATE_ALWAYS, nullptr));
+  if (file == INVALID_HANDLE_VALUE) {
+    IFT_Data(HRESULT_FROM_WIN32(GetLastError()), WideName);
+  }
+  DWORD written;
+  if (FALSE == WriteFile(file, pData, dataLen, &written, nullptr)) {
+    IFT_Data(HRESULT_FROM_WIN32(GetLastError()), WideName);
+  }
+}
+
+// This function is called either after the compilation is done or /dumpbin
+// option is provided Performing options that are used to process dxil
+// container.
+int DxcContext::ActOnBlob(IDxcBlob *pBlob) {
+  return ActOnBlob(pBlob, nullptr, nullptr);
+}
+
+int DxcContext::ActOnBlob(IDxcBlob *pBlob, IDxcBlob *pDebugBlob,
+                          LPCWSTR pDebugBlobName) {
+  int retVal = 0;
+  // Text output.
+  if (m_Opts.AstDump || m_Opts.OptDump) {
+    WriteBlobToConsole(pBlob);
+    return retVal;
+  }
+
+  // Write the output blob.
+  if (!m_Opts.OutputObject.empty()) {
+    // For backward compatability: fxc requires /Fo for /extractrootsignature
+    if (!m_Opts.ExtractRootSignature) {
+      CComPtr<IDxcBlob> pResult;
+      UpdatePart(pBlob, &pResult);
+      WriteBlobToFile(pResult, m_Opts.OutputObject);
+    }
+  }
+
+  // Verify Root Signature
+  if (!m_Opts.VerifyRootSignatureSource.empty()) {
+    return VerifyRootSignature();
+  }
+
+  // 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 "
+               "found in the shader, please use the "
+               "/Zi switch to generate debug "
+               "information compiling this shader.");
+
+    if (pDebugBlob != nullptr) {
+      IFTBOOLMSG(pDebugBlobName && *pDebugBlobName, E_INVALIDARG,
+                 "/Fd was specified but no debug name was produced");
+      WriteBlobToFile(pDebugBlob, pDebugBlobName);
+    } else {
+      WritePartToFile(pBlob, hlsl::DFCC_ShaderDebugInfoDXIL, m_Opts.DebugFile);
+    }
+  }
+
+  // Extract and write root signature information.
+  if (m_Opts.ExtractRootSignature) {
+    CComPtr<IDxcBlob> pRootSignatureContainer;
+    ExtractRootSignature(pBlob, &pRootSignatureContainer);
+    WriteBlobToFile(pRootSignatureContainer, m_Opts.OutputObject);
+  }
+
+  // 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() ||
+      (m_Opts.OutputObject.empty() && m_Opts.DebugFile.empty() &&
+       m_Opts.ExtractPrivateFile.empty() &&
+       m_Opts.VerifyRootSignatureSource.empty() &&
+       !m_Opts.ExtractRootSignature);
+
+  if (!needDisassembly)
+    return retVal;
+
+  CComPtr<IDxcBlobEncoding> pDisassembleResult;
+
+  if (m_Opts.IsRootSignatureProfile()) {
+    // keep the same behavior as fxc, people may want to embed the root
+    // signatures in their code bases.
+    CComPtr<IDxcLibrary> pLibrary;
+    IFT(m_dxcSupport.CreateInstance(CLSID_DxcLibrary, &pLibrary));
+    std::string Message = "Disassembly failed";
+    IFT(pLibrary->CreateBlobWithEncodingOnHeapCopy(
+        (LPBYTE)&Message[0], Message.size(), CP_ACP, &pDisassembleResult));
+  } else {
+    CComPtr<IDxcCompiler> pCompiler;
+    IFT(m_dxcSupport.CreateInstance(CLSID_DxcCompiler, &pCompiler));
+    IFT(pCompiler->Disassemble(pBlob, &pDisassembleResult));
+  }
+
+  if (!m_Opts.OutputHeader.empty()) {
+    llvm::Twine varName = m_Opts.VariableName.empty()
+                              ? llvm::Twine("g_", m_Opts.EntryPoint)
+                              : m_Opts.VariableName;
+    WriteHeader(pDisassembleResult, pBlob, varName,
+                StringRefUtf16(m_Opts.OutputHeader));
+  } else if (!m_Opts.AssemblyCode.empty()) {
+    WriteBlobToFile(pDisassembleResult, m_Opts.AssemblyCode);
+  } else {
+    WriteBlobToConsole(pDisassembleResult);
+  }
+  return retVal;
+}
+
+// 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<IDxcBlob> privateBlob;
+    IFT(ReadFileIntoPartContent(hlsl::DxilFourCC::DFCC_PrivateData,
+                                StringRefUtf16(m_Opts.PrivateSource),
+                                &privateBlob));
+
+    // setprivate option can replace existing private part.
+    // Try removing the private data if exists
+    pContainerBuilder->RemovePart(hlsl::DxilFourCC::DFCC_PrivateData);
+    IFT(pContainerBuilder->AddPart(hlsl::DxilFourCC::DFCC_PrivateData,
+                                   privateBlob));
+  }
+  if (!m_Opts.RootSignatureSource.empty()) {
+    // set rootsignature assumes that the given input is a dxil container.
+    // We only want to add RTS0 part to the container builder.
+    CComPtr<IDxcBlob> RootSignatureBlob;
+    IFT(ReadFileIntoPartContent(hlsl::DxilFourCC::DFCC_RootSignature,
+                                StringRefUtf16(m_Opts.RootSignatureSource),
+                                &RootSignatureBlob));
+
+    // setrootsignature option can replace existing rootsignature part
+    // Try removing rootsignature if exists
+    pContainerBuilder->RemovePart(hlsl::DxilFourCC::DFCC_RootSignature);
+    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();
+}
+
+// This function reads the file from input file and constructs a blob with
+// fourCC parts Used for setprivate and setrootsignature option
+HRESULT DxcContext::ReadFileIntoPartContent(hlsl::DxilFourCC fourCC,
+                                            LPCWSTR fileName,
+                                            IDxcBlob **ppResult) {
+  DXASSERT(fourCC == hlsl::DxilFourCC::DFCC_PrivateData ||
+               fourCC == hlsl::DxilFourCC::DFCC_RootSignature,
+           "Otherwise we provided wrong part to read for updating part.");
+
+  // Read result, if it's private data, then return the blob
+  if (fourCC == hlsl::DxilFourCC::DFCC_PrivateData) {
+    CComPtr<IDxcBlobEncoding> pResult;
+    ReadFileIntoBlob(m_dxcSupport, fileName, &pResult);
+    *ppResult = pResult.Detach();
+  }
+
+  // If root signature, check if it's a dxil container that contains
+  // rootsignature part, then construct a blob of root signature part
+  if (fourCC == hlsl::DxilFourCC::DFCC_RootSignature) {
+    CComPtr<IDxcBlob> pResult;
+    CComHeapPtr<BYTE> pData;
+    DWORD dataSize;
+    hlsl::ReadBinaryFile(fileName, (void **)&pData, &dataSize);
+    DXASSERT(pData != nullptr,
+             "otherwise ReadBinaryFile should throw an exception");
+    hlsl::DxilContainerHeader *pHeader =
+        (hlsl::DxilContainerHeader *)pData.m_pData;
+    IFRBOOL(hlsl::IsDxilContainerLike(pHeader, pHeader->ContainerSizeInBytes),
+            E_INVALIDARG);
+    hlsl::DxilPartHeader *pPartHeader =
+        hlsl::GetDxilPartByType(pHeader, hlsl::DxilFourCC::DFCC_RootSignature);
+    IFRBOOL(pPartHeader != nullptr, E_INVALIDARG);
+    hlsl::DxcCreateBlobOnHeapCopy(hlsl::GetDxilPartData(pPartHeader),
+                                  pPartHeader->PartSize, &pResult);
+    *ppResult = pResult.Detach();
+  }
+  return S_OK;
+}
+
+// Constructs a dxil container builder with only root signature part.
+// Right now IDxcContainerBuilder assumes that we are building a full dxil
+// container, but we are building a container with only rootsignature part
+void DxcContext::ExtractRootSignature(IDxcBlob *pBlob, IDxcBlob **ppResult) {
+
+  DXASSERT_NOMSG(pBlob != nullptr && ppResult != nullptr);
+  const hlsl::DxilContainerHeader *pHeader =
+      (hlsl::DxilContainerHeader *)(pBlob->GetBufferPointer());
+  IFTBOOL(hlsl::IsValidDxilContainer(pHeader, pHeader->ContainerSizeInBytes),
+          DXC_E_CONTAINER_INVALID);
+  const hlsl::DxilPartHeader *pPartHeader =
+      hlsl::GetDxilPartByType(pHeader, hlsl::DxilFourCC::DFCC_RootSignature);
+  IFTBOOL(pPartHeader != nullptr, DXC_E_MISSING_PART);
+
+  // Get new header and allocate memory for new container
+  hlsl::DxilContainerHeader newHeader;
+  uint32_t containerSize =
+      hlsl::GetDxilContainerSizeFromParts(1, pPartHeader->PartSize);
+  hlsl::InitDxilContainer(&newHeader, 1, containerSize);
+  CComPtr<IMalloc> pMalloc;
+  CComPtr<hlsl::AbstractMemoryStream> pMemoryStream;
+  IFT(CoGetMalloc(1, &pMalloc));
+  IFT(hlsl::CreateMemoryStream(pMalloc, &pMemoryStream));
+  ULONG cbWritten;
+
+  // Write Container Header
+  IFT(pMemoryStream->Write(&newHeader, sizeof(hlsl::DxilContainerHeader),
+                           &cbWritten));
+  IFTBOOL(cbWritten == sizeof(hlsl::DxilContainerHeader), E_OUTOFMEMORY);
+
+  // Write Part Offset
+  uint32_t offset =
+      sizeof(hlsl::DxilContainerHeader) + hlsl::GetOffsetTableSize(1);
+  IFT(pMemoryStream->Write(&offset, sizeof(uint32_t), &cbWritten));
+  IFTBOOL(cbWritten == sizeof(uint32_t), E_OUTOFMEMORY);
+
+  // Write Root Signature Header
+  IFT(pMemoryStream->Write(pPartHeader, sizeof(hlsl::DxilPartHeader),
+                           &cbWritten));
+  IFTBOOL(cbWritten == sizeof(hlsl::DxilPartHeader), E_OUTOFMEMORY);
+  const char *partContent = hlsl::GetDxilPartData(pPartHeader);
+
+  // Write Root Signature Content
+  IFT(pMemoryStream->Write(partContent, pPartHeader->PartSize, &cbWritten));
+  IFTBOOL(cbWritten == pPartHeader->PartSize, E_OUTOFMEMORY);
+
+  // Return Result
+  CComPtr<IDxcBlob> pResult;
+  IFT(pMemoryStream->QueryInterface(&pResult));
+  *ppResult = pResult.Detach();
+}
+
+int DxcContext::VerifyRootSignature() {
+  // Get dxil container from file
+  CComPtr<IDxcBlobEncoding> pSource;
+  ReadFileIntoBlob(m_dxcSupport, StringRefUtf16(m_Opts.InputFile), &pSource);
+  hlsl::DxilContainerHeader *pSourceHeader =
+      (hlsl::DxilContainerHeader *)pSource->GetBufferPointer();
+  IFTBOOLMSG(hlsl::IsValidDxilContainer(pSourceHeader,
+                                        pSourceHeader->ContainerSizeInBytes),
+             E_INVALIDARG, "invalid DXIL container to verify.");
+
+  // Get rootsignature from file
+  CComPtr<IDxcBlob> pRootSignature;
+
+  IFTMSG(ReadFileIntoPartContent(
+             hlsl::DxilFourCC::DFCC_RootSignature,
+             StringRefUtf16(m_Opts.VerifyRootSignatureSource), &pRootSignature),
+         "invalid root signature to verify.");
+
+  // TODO : Right now we are just going to bild a new blob with updated root
+  // signature to verify root signature Since dxil container builder will verify
+  // on its behalf. This does unnecessary memory allocation. We can improve this
+  // later.
+  CComPtr<IDxcContainerBuilder> pContainerBuilder;
+  IFT(m_dxcSupport.CreateInstance(CLSID_DxcContainerBuilder,
+                                  &pContainerBuilder));
+  IFT(pContainerBuilder->Load(pSource));
+  // Try removing root signature if it already exists
+  pContainerBuilder->RemovePart(hlsl::DxilFourCC::DFCC_RootSignature);
+  IFT(pContainerBuilder->AddPart(hlsl::DxilFourCC::DFCC_RootSignature,
+                                 pRootSignature));
+  CComPtr<IDxcOperationResult> pOperationResult;
+  IFT(pContainerBuilder->SerializeContainer(&pOperationResult));
+  HRESULT status = E_FAIL;
+  CComPtr<IDxcBlob> pResult;
+  IFT(pOperationResult->GetStatus(&status));
+  if (FAILED(status)) {
+    if (!m_Opts.OutputWarningsFile.empty()) {
+      CComPtr<IDxcBlobEncoding> pErrors;
+      IFT(pOperationResult->GetErrorBuffer(&pErrors));
+      WriteBlobToFile(pErrors, m_Opts.OutputWarningsFile);
+    } else {
+      WriteOperationErrorsToConsole(pOperationResult, m_Opts.OutputWarnings);
+    }
+    return 1;
+  } else {
+    printf("root signature verification succeeded.");
+    return 0;
+  }
+}
+
+class DxcIncludeHandlerForInjectedSources : public IDxcIncludeHandler {
+private:
+  DXC_MICROCOM_REF_FIELD(m_dwRef)
+
+public:
+  DXC_MICROCOM_ADDREF_RELEASE_IMPL(m_dwRef)
+  DxcIncludeHandlerForInjectedSources() : m_dwRef(0){};
+  std::unordered_map<std::wstring, CComPtr<IDxcBlob>> includeFiles;
+
+  HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **ppvObject) {
+    return DoBasicQueryInterface<IDxcIncludeHandler>(this, iid, ppvObject);
+  }
+
+  HRESULT insertIncludeFile(_In_ LPCWSTR pFilename,
+                            _In_ IDxcBlobEncoding *pBlob, _In_ UINT32 dataLen) {
+    try {
+      includeFiles.try_emplace(std::wstring(pFilename), pBlob);
+    }
+    CATCH_CPP_RETURN_HRESULT()
+    return S_OK;
+  }
+
+  __override HRESULT STDMETHODCALLTYPE
+  LoadSource(_In_ LPCWSTR pFilename,
+             _COM_Outptr_result_maybenull_ IDxcBlob **ppIncludeSource) {
+    try {
+      *ppIncludeSource = includeFiles.at(std::wstring(pFilename));
+      (*ppIncludeSource)->AddRef();
+    }
+    CATCH_CPP_RETURN_HRESULT()
+    return S_OK;
+  }
+};
+
+int DxcContext::Compile(llvm::StringRef path, bool bLibLink) {
+  CComPtr<IDxcCompiler> pCompiler;
+  CComPtr<IDxcOperationResult> pCompileResult;
+  CComPtr<IDxcBlob> pDebugBlob;
+  std::wstring debugName;
+  {
+    CComPtr<IDxcBlobEncoding> pSource;
+
+    std::vector<std::wstring> argStrings;
+    CopyArgsToWStrings(m_Opts.Args, CoreOption, argStrings);
+
+    std::vector<LPCWSTR> args;
+    args.reserve(argStrings.size());
+    for (unsigned i = 0; i < argStrings.size(); i++) {
+      const std::wstring &a = argStrings[i];
+      if (a == L"-E" || a == L"-T") {
+        // Skip entry and profile in arg.
+        i++;
+        continue;
+      }
+      args.push_back(a.data());
+    }
+
+    CComPtr<IDxcLibrary> pLibrary;
+    IFT(m_dxcSupport.CreateInstance(CLSID_DxcLibrary, &pLibrary));
+    IFT(m_dxcSupport.CreateInstance(CLSID_DxcCompiler, &pCompiler));
+    if (path.empty()) {
+      ReadFileIntoBlob(m_dxcSupport, StringRefUtf16(m_Opts.InputFile),
+                       &pSource);
+    } else {
+      llvm::sys::fs::MSFileSystem *msfPtr;
+      IFT(CreateMSFileSystemForDisk(&msfPtr));
+      std::unique_ptr<::llvm::sys::fs::MSFileSystem> msf(msfPtr);
+
+      ::llvm::sys::fs::AutoPerThreadSystem pts(msf.get());
+      IFTLLVM(pts.error_code());
+
+      if (llvm::sys::fs::exists(m_Opts.InputFile)) {
+        ReadFileIntoBlob(m_dxcSupport, StringRefUtf16(m_Opts.InputFile),
+                         &pSource);
+      } else {
+        SmallString<128> pathStr(path.begin(), path.end());
+        llvm::sys::path::append(pathStr, m_Opts.InputFile.begin(),
+                                m_Opts.InputFile.end());
+        ReadFileIntoBlob(m_dxcSupport, StringRefUtf16(pathStr.str().str()),
+                         &pSource);
+      }
+    }
+    IFTARG(pSource->GetBufferSize() >= 4);
+
+    CComPtr<IDxcIncludeHandler> pIncludeHandler;
+    IFT(pLibrary->CreateIncludeHandler(&pIncludeHandler));
+
+    // Upgrade profile to 6.0 version from minimum recognized shader model
+    llvm::StringRef TargetProfile = m_Opts.TargetProfile;
+    const hlsl::ShaderModel *SM =
+        hlsl::ShaderModel::GetByName(m_Opts.TargetProfile.str().c_str());
+    if (SM->IsValid() && SM->GetMajor() < 6) {
+      TargetProfile = hlsl::ShaderModel::Get(SM->GetKind(), 6, 0)->GetName();
+    }
+
+    if (bLibLink) {
+      IFT(DxilD3DCompile2(pSource->GetBufferPointer(), pSource->GetBufferSize(),
+                          m_Opts.InputFile.str().c_str(),
+                          m_Opts.EntryPoint.str().c_str(),
+                          TargetProfile.str().c_str(), m_Opts.Defines.data(),
+                          m_Opts.Defines.size(), args.data(), args.size(),
+                          pIncludeHandler, &pCompileResult));
+    } else {
+      IFT(pCompiler->Compile(
+          pSource, StringRefUtf16(m_Opts.InputFile),
+          StringRefUtf16(m_Opts.EntryPoint), StringRefUtf16(TargetProfile),
+          args.data(), args.size(), m_Opts.Defines.data(),
+          m_Opts.Defines.size(), pIncludeHandler, &pCompileResult));
+    }
+  }
+
+  if (!m_Opts.OutputWarningsFile.empty()) {
+    CComPtr<IDxcBlobEncoding> pErrors;
+    IFT(pCompileResult->GetErrorBuffer(&pErrors));
+    WriteBlobToFile(pErrors, m_Opts.OutputWarningsFile);
+  } else {
+    WriteOperationErrorsToConsole(pCompileResult, m_Opts.OutputWarnings);
+  }
+
+  HRESULT status;
+  IFT(pCompileResult->GetStatus(&status));
+  if (SUCCEEDED(status) || m_Opts.AstDump || m_Opts.OptDump) {
+    CComPtr<IDxcBlob> pProgram;
+    IFT(pCompileResult->GetResult(&pProgram));
+    pCompiler.Release();
+    pCompileResult.Release();
+    if (pProgram.p != nullptr) {
+      ActOnBlob(pProgram.p, pDebugBlob, debugName.c_str());
+    }
+  }
+  return status;
+}
+
+int DxcContext::DumpBinary() {
+  CComPtr<IDxcBlobEncoding> pSource;
+  ReadFileIntoBlob(m_dxcSupport, StringRefUtf16(m_Opts.InputFile), &pSource);
+  return ActOnBlob(pSource.p);
+}
+
+void DxcContext::Preprocess() {
+  DXASSERT(!m_Opts.Preprocess.empty(),
+           "else option reading should have failed");
+  CComPtr<IDxcCompiler> pCompiler;
+  CComPtr<IDxcOperationResult> pPreprocessResult;
+  CComPtr<IDxcBlobEncoding> pSource;
+  std::vector<LPCWSTR> args;
+
+  CComPtr<IDxcLibrary> pLibrary;
+  CComPtr<IDxcIncludeHandler> pIncludeHandler;
+  IFT(m_dxcSupport.CreateInstance(CLSID_DxcLibrary, &pLibrary));
+  IFT(pLibrary->CreateIncludeHandler(&pIncludeHandler));
+
+  ReadFileIntoBlob(m_dxcSupport, StringRefUtf16(m_Opts.InputFile), &pSource);
+  IFT(m_dxcSupport.CreateInstance(CLSID_DxcCompiler, &pCompiler));
+  IFT(pCompiler->Preprocess(pSource, StringRefUtf16(m_Opts.InputFile),
+                            args.data(), args.size(), m_Opts.Defines.data(),
+                            m_Opts.Defines.size(), pIncludeHandler,
+                            &pPreprocessResult));
+  WriteOperationErrorsToConsole(pPreprocessResult, m_Opts.OutputWarnings);
+
+  HRESULT status;
+  IFT(pPreprocessResult->GetStatus(&status));
+  if (SUCCEEDED(status)) {
+    CComPtr<IDxcBlob> pProgram;
+    IFT(pPreprocessResult->GetResult(&pProgram));
+    WriteBlobToFile(pProgram, m_Opts.Preprocess);
+  }
+}
+
+static void WriteString(HANDLE hFile, _In_z_ LPCSTR value, LPCWSTR pFileName) {
+  DWORD written;
+  if (FALSE == WriteFile(hFile, value, strlen(value) * sizeof(value[0]),
+                         &written, nullptr))
+    IFT_Data(HRESULT_FROM_WIN32(GetLastError()), pFileName);
+}
+
+void DxcContext::WriteHeader(IDxcBlobEncoding *pDisassembly, IDxcBlob *pCode,
+                             llvm::Twine &pVariableName, LPCWSTR pFileName) {
+  CHandle file(CreateFile2(pFileName, GENERIC_WRITE, FILE_SHARE_READ,
+                           CREATE_ALWAYS, nullptr));
+  if (file == INVALID_HANDLE_VALUE) {
+    IFT_Data(HRESULT_FROM_WIN32(GetLastError()), pFileName);
+  }
+
+  {
+    std::string s;
+    llvm::raw_string_ostream OS(s);
+    // Note: with \r\n line endings, writing the disassembly could be a simple
+    // WriteBlobToHandle with a prior and following WriteString for #ifs
+    OS << "#if 0\r\n";
+    const uint8_t *pBytes = (const uint8_t *)pDisassembly->GetBufferPointer();
+    size_t len = pDisassembly->GetBufferSize();
+    s.reserve(len + len * 0.1f); // rough estimate
+    for (size_t i = 0; i < len; ++i) {
+      if (pBytes[i] == '\n')
+        OS << '\r';
+      OS << pBytes[i];
+    }
+    OS << "\r\n#endif\r\n";
+    OS.flush();
+    WriteString(file, s.c_str(), pFileName);
+  }
+
+  {
+    std::string s;
+    llvm::raw_string_ostream OS(s);
+    OS << "\r\nconst unsigned char " << pVariableName << "[] = {";
+    const uint8_t *pBytes = (const uint8_t *)pCode->GetBufferPointer();
+    size_t len = pCode->GetBufferSize();
+    s.reserve(100 + len * 6 + (len / 12) * 3); // rough estimate
+    for (size_t i = 0; i < len; ++i) {
+      if (i != 0)
+        OS << ',';
+      if ((i % 12) == 0)
+        OS << "\r\n ";
+      OS << " 0x";
+      if (pBytes[i] < 0x10)
+        OS << '0';
+      OS.write_hex(pBytes[i]);
+    }
+    OS << "\r\n};\r\n";
+    OS.flush();
+    WriteString(file, s.c_str(), pFileName);
+  }
+}
+
+class DxcBatchContext {
+public:
+  DxcBatchContext(DxcOpts &Opts, DxcDllSupport &dxcSupport)
+      : m_Opts(Opts), m_dxcSupport(dxcSupport) {}
+
+  int BatchCompile(bool bMultiThread, bool bLibLink);
+
+private:
+  DxcOpts &m_Opts;
+  DxcDllSupport &m_dxcSupport;
+};
+
+int DxcBatchContext::BatchCompile(bool bMultiThread, bool bLibLink) {
+  DxcOpts tmp_Opts;
+  // tmp_Opts = m_Opts;
+  m_Opts.InputFile;
+  SmallString<128> path(m_Opts.InputFile.begin(), m_Opts.InputFile.end());
+  llvm::sys::path::remove_filename(path);
+
+  CComPtr<IDxcBlobEncoding> pSource;
+  ReadFileIntoBlob(m_dxcSupport, StringRefUtf16(m_Opts.InputFile), &pSource);
+  llvm::StringRef source((char *)pSource->GetBufferPointer(),
+                         pSource->GetBufferSize());
+  llvm::SmallVector<llvm::StringRef, 4> commands;
+  source.split(commands, "\r\n");
+
+  if (bMultiThread) {
+    unsigned int threadNum = std::min<unsigned>(
+        std::thread::hardware_concurrency(), commands.size());
+    auto empty_fn = []() {};
+    std::vector<std::thread> threads(threadNum);
+    for (unsigned i = 0; i < threadNum; i++)
+      threads[i] = std::thread(empty_fn);
+
+    for (unsigned i = 0; i < commands.size(); i++) {
+      llvm::StringRef command = commands[i];
+      if (command.empty())
+        continue;
+      if (command.startswith("//"))
+        continue;
+
+      unsigned threadIdx = i % threadNum;
+      threads[threadIdx].join();
+
+      threads[threadIdx] = std::thread(
+          ::Compile, command, std::ref(m_dxcSupport), path.str(), bLibLink);
+    }
+    for (auto &th : threads)
+      th.join();
+  } else {
+    for (llvm::StringRef command : commands) {
+      if (command.empty())
+        continue;
+      if (command.startswith("//"))
+        continue;
+      llvm::SmallVector<llvm::StringRef, 4> args;
+      command.split(args, " ");
+      Compile(command, m_dxcSupport, path.str(), bLibLink);
+    }
+  }
+  return 0;
+}
+
+int __cdecl wmain(int argc, const wchar_t **argv_) {
+  const char *pStage = "Operation";
+  int retVal = 0;
+  try {
+    auto t_start = std::chrono::high_resolution_clock::now();
+
+    pStage = "Argument processing";
+    const char *kMultiThreadArg = "-multi-thread";
+    bool bMultiThread = false;
+    const char *kLibLinkArg = "-lib-link";
+    bool bLibLink = false;
+    // Parse command line options.
+    const OptTable *optionTable = getHlslOptTable();
+    MainArgs argStrings(argc, argv_);
+    llvm::ArrayRef<const char *> tmpArgStrings = argStrings.getArrayRef();
+    std::vector<std::string> args(tmpArgStrings.begin(), tmpArgStrings.end());
+    // Add target to avoid fail.
+    args.emplace_back("-T");
+    args.emplace_back("lib_6_1");
+
+    std::vector<StringRef> refArgs;
+    refArgs.reserve(args.size());
+    for (auto &arg : args) {
+      if (arg != kMultiThreadArg && arg != kLibLinkArg) {
+        refArgs.emplace_back(arg.c_str());
+      } else if (arg == kLibLinkArg) {
+        bLibLink = true;
+      } else {
+        bMultiThread = true;
+      }
+    }
+
+    MainArgs batchArgStrings(refArgs);
+
+    DxcOpts dxcOpts;
+    DxcDllSupport dxcSupport;
+
+    // Read options and check errors.
+    {
+      std::string errorString;
+      llvm::raw_string_ostream errorStream(errorString);
+      int optResult = ReadDxcOpts(optionTable, DxcFlags, batchArgStrings,
+                                  dxcOpts, errorStream);
+      // TODO: validate unused option for dxc_bach.
+      errorStream.flush();
+      if (errorString.size()) {
+        fprintf(stderr, "dxc failed : %s", errorString.data());
+      }
+      if (optResult != 0) {
+        return optResult;
+      }
+    }
+
+    // Handle help request, which overrides any other processing.
+    if (dxcOpts.ShowHelp) {
+      std::string helpString;
+      llvm::raw_string_ostream helpStream(helpString);
+      optionTable->PrintHelp(helpStream, "dxc_bach.exe", "HLSL Compiler");
+      helpStream << "multi-thread";
+      helpStream.flush();
+      dxc::WriteUtf8ToConsoleSizeT(helpString.data(), helpString.size());
+      return 0;
+    }
+
+    // Setup a helper DLL.
+    {
+      std::string dllErrorString;
+      llvm::raw_string_ostream dllErrorStream(dllErrorString);
+      int dllResult = SetupDxcDllSupport(dxcOpts, dxcSupport, dllErrorStream);
+      dllErrorStream.flush();
+      if (dllErrorString.size()) {
+        fprintf(stderr, "%s", dllErrorString.data());
+      }
+      if (dllResult)
+        return dllResult;
+    }
+
+    EnsureEnabled(dxcSupport);
+    DxcBatchContext context(dxcOpts, dxcSupport);
+    pStage = "BatchCompilation";
+    retVal = context.BatchCompile(bMultiThread, bLibLink);
+    {
+      auto t_end = std::chrono::high_resolution_clock::now();
+      double duration_ms =
+          std::chrono::duration<double, std::milli>(t_end - t_start).count();
+
+      fprintf(stderr, "duration: %f sec", duration_ms / 1000);
+    }
+  } catch (const ::hlsl::Exception &hlslException) {
+    PrintHlslException(hlslException, pStage);
+    return 1;
+  } catch (std::bad_alloc &) {
+    printf("%s failed - out of memory.\n", pStage);
+    return 1;
+  } catch (...) {
+    printf("%s failed - unknown error.\n", pStage);
+    return 1;
+  }
+  return retVal;
+}

+ 1 - 1
utils/hct/hcttest.cmd

@@ -172,7 +172,7 @@ if "%TEST_CLEAN%"=="1" (
 if not exist %TEST_DIR%\. (mkdir %TEST_DIR%)
 
 echo Copying binaries to test to %TEST_DIR%:
-call %HCT_DIR%\hctcopy.cmd %BIN_DIR% %TEST_DIR% dxa.exe dxc.exe dxexp.exe dxopt.exe dxr.exe dxv.exe clang-hlsl-tests.dll dxcompiler.dll d3dcompiler_dxc_bridge.dll
+call %HCT_DIR%\hctcopy.cmd %BIN_DIR% %TEST_DIR% dxa.exe dxc.exe dxexp.exe dxopt.exe dxr.exe dxv.exe clang-hlsl-tests.dll dxcompiler.dll d3dcompiler_dxc_bridge.dll dxc_batch.exe dxlib_sample.dll
 if errorlevel 1 exit /b 1
 
 rem Begin SPIRV change

+ 16 - 0
utils/hct/hcttestcmds.cmd

@@ -502,6 +502,22 @@ if %errorlevel% neq 0 (
   exit /b 1
 )
 
+dxc_batch.exe -lib-link  -multi-thread "%2"\..\CodeGenHLSL\batch_cmds.txt 1>nul
+if %errorlevel% neq 0 (
+  echo Failed to run dxc_batch -lib-link  -multi-thread
+  call :cleanup 2>nul
+  exit /b 1
+)
+
+dxc_batch.exe -multi-thread "%2"\..\CodeGenHLSL\batch_cmds.txt 1>nul
+if %errorlevel% neq 0 (
+  echo Failed to run dxc_batch -multi-thread
+  call :cleanup 2>nul
+  exit /b 1
+)
+
+
+
 call :cleanup
 exit /b 0