Browse Source

Merged PR 63: Support D3D12LibraryReflection, add tests, fix reflection bugs, fix MSFileSystem usage issue

- Support ID3DLibraryReflection
- Fix CB init that was putting a pointer to stack in var desc
- Reflection dumper for testing, add tests, fix more empty struct breaks
- Fix problems with MSFileSystem used from independent locations
- Skip structured buffers when setting usage, since it's not gathered
- RDAT Assembly: Avoid adding duplicate strings to string table
- DxilRuntimeReflection: avoid possibility of wstring::data() invalidation
Tex Riddell 7 years ago
parent
commit
f0513781bd
28 changed files with 2150 additions and 100 deletions
  1. 2 1
      include/dxc/HLSL/DxilRuntimeReflection.h
  2. 4 3
      include/dxc/HLSL/DxilRuntimeReflection.inl
  3. 3 0
      include/llvm/Support/FileSystem.h
  4. 11 5
      lib/HLSL/DxilContainerAssembler.cpp
  5. 413 50
      lib/HLSL/DxilContainerReflection.cpp
  6. 65 18
      lib/Support/Windows/MSFileSystem.inc.cpp
  7. 51 0
      tools/clang/test/CodeGenHLSL/quick-test/d3dreflect/anon_struct.hlsl
  8. 41 0
      tools/clang/test/CodeGenHLSL/quick-test/d3dreflect/cb_array.hlsl
  9. 42 0
      tools/clang/test/CodeGenHLSL/quick-test/d3dreflect/cbuffer_default_val.hlsl
  10. 62 0
      tools/clang/test/CodeGenHLSL/quick-test/d3dreflect/empty_struct2.hlsl
  11. 245 0
      tools/clang/test/CodeGenHLSL/quick-test/d3dreflect/reflect-lib-1.hlsl
  12. 30 0
      tools/clang/test/CodeGenHLSL/quick-test/d3dreflect/structured_buffer_getdim_stride.hlsl
  13. 3 0
      tools/clang/tools/driver/driver.cpp
  14. 12 4
      tools/clang/tools/dxcompiler/dxcdisassembler.cpp
  15. 3 0
      tools/clang/tools/dxl/dxl.cpp
  16. 5 0
      tools/clang/tools/dxopt/dxopt.cpp
  17. 1 0
      tools/clang/unittests/HLSL/CMakeLists.txt
  18. 621 0
      tools/clang/unittests/HLSL/D3DReflectionDumper.cpp
  19. 118 0
      tools/clang/unittests/HLSL/D3DReflectionDumper.h
  20. 3 0
      tools/clang/unittests/HLSL/DxcTestUtils.h
  21. 307 0
      tools/clang/unittests/HLSL/DxilContainerTest.cpp
  22. 9 1
      tools/clang/unittests/HLSL/DxilModuleTest.cpp
  23. 0 18
      tools/clang/unittests/HLSL/FileCheckForTest.cpp
  24. 90 0
      tools/clang/unittests/HLSL/FileCheckerTest.cpp
  25. 4 0
      tools/clang/unittests/HLSL/VerifierTest.cpp
  26. 3 0
      tools/clang/unittests/dxc_batch/dxc_batch.cpp
  27. 1 0
      tools/clang/utils/TableGen/TableGen.cpp
  28. 1 0
      utils/TableGen/TableGen.cpp

+ 2 - 1
include/dxc/HLSL/DxilRuntimeReflection.h

@@ -12,6 +12,7 @@
 #include <windows.h>
 #include <unordered_map>
 #include <vector>
+#include <memory>
 #include "DxilConstants.h"
 
 namespace hlsl {
@@ -388,7 +389,7 @@ typedef struct DXIL_LIBRARY_DESC {
 
 class DxilRuntimeReflection {
 private:
-  typedef std::unordered_map<const char *, std::wstring> StringMap;
+  typedef std::unordered_map<const char *, std::unique_ptr<wchar_t[]>> StringMap;
   typedef std::vector<DXIL_RESOURCE> ResourceList;
   typedef std::vector<DXIL_RESOURCE *> ResourceRefList;
   typedef std::vector<DXIL_FUNCTION> FunctionList;

+ 4 - 3
include/dxc/HLSL/DxilRuntimeReflection.inl

@@ -81,9 +81,10 @@ void DxilRuntimeReflection::AddString(const char *ptr) {
     int size = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, ptr, -1,
                                      nullptr, 0);
     if (size != 0) {
-      m_StringMap[ptr] = std::wstring(size, '\0');
+      auto pNew = std::make_unique<wchar_t[]>(size);
       ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, ptr, -1,
-                            &(m_StringMap[ptr][0]), size);
+                            pNew.get(), size);
+      m_StringMap[ptr] = std::move(pNew);
     }
   }
 }
@@ -92,7 +93,7 @@ const wchar_t *DxilRuntimeReflection::GetWideString(const char *ptr) {
   if (m_StringMap.find(ptr) == m_StringMap.end()) {
     AddString(ptr);
   }
-  return m_StringMap.at(ptr).data();
+  return m_StringMap.at(ptr).get();
 }
 
 bool DxilRuntimeReflection::InitFromRDAT(const void *pRDAT) {

+ 3 - 0
include/llvm/Support/FileSystem.h

@@ -53,8 +53,11 @@ namespace fs {
 class MSFileSystem;
 typedef _Inout_ MSFileSystem* MSFileSystemRef;
 
+std::error_code GetFileSystemTlsStatus() throw();
+
 std::error_code SetupPerThreadFileSystem() throw();
 void CleanupPerThreadFileSystem() throw();
+struct AutoCleanupPerThreadFileSystem { ~AutoCleanupPerThreadFileSystem() { CleanupPerThreadFileSystem(); } };
 
 /// <summary>Gets a reference to the file system installed for the current thread (possibly NULL).</summary>
 /// <remarks>In practice, consumers of the library should always install a file system.</remarks>

+ 11 - 5
lib/HLSL/DxilContainerAssembler.cpp

@@ -751,19 +751,25 @@ public:
 
 class StringTable : public RDATPart {
 private:
+  StringMap<uint32_t> m_StringMap;
   SmallVector<char, 256> m_StringBuffer;
   uint32_t curIndex;
 public:
-  StringTable() : m_StringBuffer(), curIndex(0) {}
+  StringTable() : m_StringMap(), m_StringBuffer(), curIndex(0) {}
   // returns the offset of the name inserted
   uint32_t Insert(StringRef name) {
-    for (auto iter = name.begin(), End = name.end(); iter != End; ++iter) {
-        m_StringBuffer.push_back(*iter);
-    }
+    // Don't add duplicate strings
+    auto found = m_StringMap.find(name);
+    if (found != m_StringMap.end())
+      return found->second;
+    m_StringMap[name] = curIndex;
+
+    m_StringBuffer.reserve(m_StringBuffer.size() + name.size() + 1);
+    m_StringBuffer.append(name.begin(), name.end());
     m_StringBuffer.push_back('\0');
 
     uint32_t prevIndex = curIndex;
-    curIndex += name.size() + 1;
+    curIndex += (uint32_t)name.size() + 1;
     return prevIndex;
   }
   RuntimeDataPartType GetType() const { return RuntimeDataPartType::String; }

+ 413 - 50
lib/HLSL/DxilContainerReflection.cpp

@@ -24,8 +24,10 @@
 #include "dxc/Support/FileIOHelper.h"
 #include "dxc/Support/dxcapi.impl.h"
 #include "dxc/HLSL/DxilRuntimeReflection.inl"
+#include "dxc/HLSL/DxilFunctionProps.h"
 
 #include <unordered_set>
+#include "llvm/ADT/SetVector.h"
 
 #include "dxc/dxcapi.h"
 
@@ -69,39 +71,60 @@ public:
 
 class CShaderReflectionConstantBuffer;
 class CShaderReflectionType;
-class DxilShaderReflection : public ID3D12ShaderReflection {
-private:
-  DXC_MICROCOM_TM_REF_FIELDS()
+
+enum class PublicAPI { D3D12 = 0, D3D11_47 = 1, D3D11_43 = 2 };
+
+class DxilModuleReflection {
+public:
   CComPtr<IDxcBlob> m_pContainer;
   LLVMContext Context;
   std::unique_ptr<Module> m_pModule; // Must come after LLVMContext, otherwise unique_ptr will over-delete.
   DxilModule *m_pDxilModule = nullptr;
-  std::vector<CShaderReflectionConstantBuffer>    m_CBs;
+  std::vector<std::unique_ptr<CShaderReflectionConstantBuffer>>    m_CBs;
   std::vector<D3D12_SHADER_INPUT_BIND_DESC>       m_Resources;
+  std::vector<std::unique_ptr<CShaderReflectionType>> m_Types;
+  void CreateReflectionObjects();
+  void CreateReflectionObjectForResource(DxilResourceBase *R);
+
+  HRESULT LoadModule(IDxcBlob *pBlob, const DxilPartHeader *pPart);
+
+  // Common code
+  ID3D12ShaderReflectionConstantBuffer* _GetConstantBufferByIndex(UINT Index);
+  ID3D12ShaderReflectionConstantBuffer* _GetConstantBufferByName(LPCSTR Name);
+
+  HRESULT _GetResourceBindingDesc(UINT ResourceIndex,
+                                  _Out_ D3D12_SHADER_INPUT_BIND_DESC *pDesc,
+                                  PublicAPI api = PublicAPI::D3D12);
+
+  ID3D12ShaderReflectionVariable* _GetVariableByName(LPCSTR Name);
+
+  HRESULT _GetResourceBindingDescByName(LPCSTR Name,
+                                        D3D12_SHADER_INPUT_BIND_DESC *pDesc,
+                                        PublicAPI api = PublicAPI::D3D12);
+};
+
+class DxilShaderReflection : public DxilModuleReflection, public ID3D12ShaderReflection {
+private:
+  DXC_MICROCOM_TM_REF_FIELDS()
   std::vector<D3D12_SIGNATURE_PARAMETER_DESC>     m_InputSignature;
   std::vector<D3D12_SIGNATURE_PARAMETER_DESC>     m_OutputSignature;
   std::vector<D3D12_SIGNATURE_PARAMETER_DESC>     m_PatchConstantSignature;
   std::vector<std::unique_ptr<char[]>>            m_UpperCaseNames;
-  std::vector<std::unique_ptr<CShaderReflectionType>> m_Types;
-  void CreateReflectionObjects();
   void SetCBufferUsage();
-  void CreateReflectionObjectForResource(DxilResourceBase *R);
   void CreateReflectionObjectsForSignature(
       const DxilSignature &Sig,
       std::vector<D3D12_SIGNATURE_PARAMETER_DESC> &Descs);
   LPCSTR CreateUpperCase(LPCSTR pValue);
   void MarkUsedSignatureElements();
 public:
-  enum class PublicAPI { D3D12 = 0, D3D11_47 = 1, D3D11_43 = 2 };
   PublicAPI m_PublicAPI;
   void SetPublicAPI(PublicAPI value) { m_PublicAPI = value; }
   static PublicAPI IIDToAPI(REFIID iid) {
-    DxilShaderReflection::PublicAPI api =
-        DxilShaderReflection::PublicAPI::D3D12;
+    PublicAPI api = PublicAPI::D3D12;
     if (IsEqualIID(IID_ID3D11ShaderReflection_43, iid))
-      api = DxilShaderReflection::PublicAPI::D3D11_43;
+      api = PublicAPI::D3D11_43;
     else if (IsEqualIID(IID_ID3D11ShaderReflection_47, iid))
-      api = DxilShaderReflection::PublicAPI::D3D11_47;
+      api = PublicAPI::D3D11_47;
     return api;
   }
   DXC_MICROCOM_TM_ADDREF_RELEASE_IMPL()
@@ -163,6 +186,34 @@ public:
   STDMETHODIMP_(UINT64) GetRequiresFlags(THIS);
 };
 
+class CFunctionReflection;
+class DxilLibraryReflection : public DxilModuleReflection, public ID3D12LibraryReflection {
+private:
+  DXC_MICROCOM_TM_REF_FIELDS()
+
+  typedef MapVector<StringRef, std::unique_ptr<CFunctionReflection> > FunctionMap;
+  typedef DenseMap<const Function*, CFunctionReflection*> FunctionsByPtr;
+  FunctionMap m_FunctionMap;
+  FunctionsByPtr m_FunctionsByPtr;
+
+  void AddResourceUseToFunctions(DxilResourceBase &resource, unsigned resIndex);
+  void AddResourceDependencies();
+
+public:
+  DXC_MICROCOM_TM_ADDREF_RELEASE_IMPL()
+  DXC_MICROCOM_TM_CTOR(DxilLibraryReflection)
+  HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **ppvObject) {
+    return DoBasicQueryInterface<ID3D12LibraryReflection>(this, iid, ppvObject);
+  }
+
+  HRESULT Load(IDxcBlob *pBlob, const DxilPartHeader *pPart);
+
+  // ID3D12LibraryReflection
+  STDMETHOD(GetDesc)(THIS_ _Out_ D3D12_LIBRARY_DESC * pDesc);
+
+  STDMETHOD_(ID3D12FunctionReflection *, GetFunctionByIndex)(THIS_ _In_ INT FunctionIndex);
+};
+
 _Use_decl_annotations_
 HRESULT DxilContainerReflection::Load(IDxcBlob *pContainer) {
   if (pContainer == nullptr) {
@@ -245,13 +296,28 @@ HRESULT DxilContainerReflection::GetPartReflection(UINT32 idx, REFIID iid, void
   
   DxcThreadMalloc TM(m_pMalloc);
   HRESULT hr = S_OK;
-  CComPtr<DxilShaderReflection> pReflection = DxilShaderReflection::Alloc(m_pMalloc);
-  IFCOOM(pReflection.p);
-  DxilShaderReflection::PublicAPI api = DxilShaderReflection::IIDToAPI(iid);
-  pReflection->SetPublicAPI(api);
+  const DxilProgramHeader *pProgramHeader =
+    reinterpret_cast<const DxilProgramHeader*>(GetDxilPartData(pPart));
+  if (!IsValidDxilProgramHeader(pProgramHeader, pPart->PartSize)) {
+    return E_INVALIDARG;
+  }
+
+  DXIL::ShaderKind SK = GetVersionShaderType(pProgramHeader->ProgramVersion);
+  if (SK == DXIL::ShaderKind::Library) {
+    CComPtr<DxilLibraryReflection> pReflection = DxilLibraryReflection::Alloc(m_pMalloc);
+    IFCOOM(pReflection.p);
+    IFC(pReflection->Load(m_container, pPart));
+    IFC(pReflection.p->QueryInterface(iid, ppvObject));
+  } else {
+    CComPtr<DxilShaderReflection> pReflection = DxilShaderReflection::Alloc(m_pMalloc);
+    IFCOOM(pReflection.p);
+    PublicAPI api = DxilShaderReflection::IIDToAPI(iid);
+    pReflection->SetPublicAPI(api);
+
+    IFC(pReflection->Load(m_container, pPart));
+    IFC(pReflection.p->QueryInterface(iid, ppvObject));
+  }
 
-  IFC(pReflection->Load(m_container, pPart));
-  IFC(pReflection.p->QueryInterface(iid, ppvObject));
 Cleanup:
   return hr;
 }
@@ -411,6 +477,30 @@ class CInvalidSRConstantBuffer : public ID3D12ShaderReflectionConstantBuffer {
 };
 static CInvalidSRConstantBuffer g_InvalidSRConstantBuffer;
 
+class CInvalidFunctionParameter : public ID3D12FunctionParameterReflection {
+  STDMETHOD(GetDesc)(THIS_ _Out_ D3D12_PARAMETER_DESC * pDesc) { return E_FAIL; }
+};
+CInvalidFunctionParameter g_InvalidFunctionParameter;
+
+class CInvalidFunction : public ID3D12FunctionReflection {
+  STDMETHOD(GetDesc)(THIS_ _Out_ D3D12_FUNCTION_DESC * pDesc) { return E_FAIL; }
+
+  STDMETHOD_(ID3D12ShaderReflectionConstantBuffer *, GetConstantBufferByIndex)(THIS_ _In_ UINT BufferIndex) { return &g_InvalidSRConstantBuffer; }
+  STDMETHOD_(ID3D12ShaderReflectionConstantBuffer *, GetConstantBufferByName)(THIS_ _In_ LPCSTR Name) { return &g_InvalidSRConstantBuffer; }
+
+  STDMETHOD(GetResourceBindingDesc)(THIS_ _In_ UINT ResourceIndex,
+    _Out_ D3D12_SHADER_INPUT_BIND_DESC * pDesc) { return E_FAIL; }
+
+  STDMETHOD_(ID3D12ShaderReflectionVariable *, GetVariableByName)(THIS_ _In_ LPCSTR Name) { return nullptr; }
+
+  STDMETHOD(GetResourceBindingDescByName)(THIS_ _In_ LPCSTR Name,
+    _Out_ D3D12_SHADER_INPUT_BIND_DESC * pDesc) { return E_FAIL; }
+
+  // Use D3D_RETURN_PARAMETER_INDEX to get description of the return value.
+  STDMETHOD_(ID3D12FunctionParameterReflection *, GetFunctionParameter)(THIS_ _In_ INT ParameterIndex) { return &g_InvalidFunctionParameter; }
+};
+CInvalidFunction g_InvalidFunction;
+
 void CShaderReflectionVariable::Initialize(
     CShaderReflectionConstantBuffer *pBuffer, D3D12_SHADER_VARIABLE_DESC *pDesc,
     CShaderReflectionType *pType, BYTE *pDefaultValue) {
@@ -832,13 +922,15 @@ HRESULT CShaderReflectionType::Initialize(
       name = name.ltrim("struct.");
       m_Name = name;
 
-      unsigned int fieldCount = type->getStructNumElements();
-
       // Fields may have annotations, and we need to look at these
       // in order to decode their types properly.
       DxilTypeSystem &typeSys = M.GetTypeSystem();
       DxilStructAnnotation *structAnnotation = typeSys.GetStructAnnotation(structType);
-      DXASSERT(structAnnotation, "else type system is missing annotations for user-defined struct");
+
+      // There is no annotation for empty structs
+      unsigned int fieldCount = 0;
+      if (structAnnotation)
+        fieldCount = type->getStructNumElements();
 
       // The DXBC reflection info computes `Columns` for a
       // `struct` type from the fields (see below)
@@ -1229,7 +1321,7 @@ static UINT ResourceToFlags(DxilResourceBase *RB) {
   return result;
 }
 
-void DxilShaderReflection::CreateReflectionObjectForResource(DxilResourceBase *RB) {
+void DxilModuleReflection::CreateReflectionObjectForResource(DxilResourceBase *RB) {
   DxilResourceBase::Class C = RB->GetClass();
   DxilResource *R =
       (C == DXIL::ResourceClass::UAV || C == DXIL::ResourceClass::SRV)
@@ -1386,7 +1478,10 @@ static void SetCBufVarUsage(CShaderReflectionConstantBuffer &cb,
 void DxilShaderReflection::SetCBufferUsage() {
   hlsl::OP *hlslOP = m_pDxilModule->GetOP();
   LLVMContext &Ctx = m_pDxilModule->GetCtx();
-  unsigned cbSize = m_CBs.size();
+
+  // Indexes >= cbuffer size from DxilModule are SRV or UAV structured buffers.
+  // We only collect usage for actual cbuffers, so don't go clearing usage on other buffers.
+  unsigned cbSize = std::min(m_CBs.size(), m_pDxilModule->GetCBuffers().size());
   std::vector< std::vector<unsigned> > cbufUsage(cbSize);
 
   Function *createHandle = hlslOP->GetOpFunc(DXIL::OpCode::CreateHandle, Type::getVoidTy(Ctx));
@@ -1408,38 +1503,36 @@ void DxilShaderReflection::SetCBufferUsage() {
   }
 
   for (unsigned i=0;i<cbSize;i++) {
-    SetCBufVarUsage(m_CBs[i], cbufUsage[i]);
+    SetCBufVarUsage(*m_CBs[i], cbufUsage[i]);
   }
 }
 
-void DxilShaderReflection::CreateReflectionObjects() {
+void DxilModuleReflection::CreateReflectionObjects() {
   DXASSERT_NOMSG(m_pDxilModule != nullptr);
 
   // Create constant buffers, resources and signatures.
   for (auto && cb : m_pDxilModule->GetCBuffers()) {
-    CShaderReflectionConstantBuffer rcb;
-    rcb.Initialize(*m_pDxilModule, *(cb.get()), m_Types);
-    m_CBs.push_back(std::move(rcb));
+    std::unique_ptr<CShaderReflectionConstantBuffer> rcb(new CShaderReflectionConstantBuffer());
+    rcb->Initialize(*m_pDxilModule, *(cb.get()), m_Types);
+    m_CBs.emplace_back(std::move(rcb));
   }
-  // Set cbuf usage.
-  SetCBufferUsage();
 
   // TODO: add tbuffers into m_CBs
   for (auto && uav : m_pDxilModule->GetUAVs()) {
     if (uav->GetKind() != DxilResource::Kind::StructuredBuffer) {
       continue;
     }
-    CShaderReflectionConstantBuffer rcb;
-    rcb.InitializeStructuredBuffer(*m_pDxilModule, *(uav.get()), m_Types);
-    m_CBs.push_back(std::move(rcb));
+    std::unique_ptr<CShaderReflectionConstantBuffer> rcb(new CShaderReflectionConstantBuffer());
+    rcb->InitializeStructuredBuffer(*m_pDxilModule, *(uav.get()), m_Types);
+    m_CBs.emplace_back(std::move(rcb));
   }
   for (auto && srv : m_pDxilModule->GetSRVs()) {
     if (srv->GetKind() != DxilResource::Kind::StructuredBuffer) {
       continue;
     }
-    CShaderReflectionConstantBuffer rcb;
-    rcb.InitializeStructuredBuffer(*m_pDxilModule, *(srv.get()), m_Types);
-    m_CBs.push_back(std::move(rcb));
+    std::unique_ptr<CShaderReflectionConstantBuffer> rcb(new CShaderReflectionConstantBuffer());
+    rcb->InitializeStructuredBuffer(*m_pDxilModule, *(srv.get()), m_Types);
+    m_CBs.emplace_back(std::move(rcb));
   }
 
   // Populate all resources.
@@ -1455,12 +1548,6 @@ void DxilShaderReflection::CreateReflectionObjects() {
   for (auto && uavRes : m_pDxilModule->GetUAVs()) {
     CreateReflectionObjectForResource(uavRes.get());
   }
-
-  // Populate input/output/patch constant signatures.
-  CreateReflectionObjectsForSignature(m_pDxilModule->GetInputSignature(), m_InputSignature);
-  CreateReflectionObjectsForSignature(m_pDxilModule->GetOutputSignature(), m_OutputSignature);
-  CreateReflectionObjectsForSignature(m_pDxilModule->GetPatchConstantSignature(), m_PatchConstantSignature);
-  MarkUsedSignatureElements();
 }
 
 static D3D_REGISTER_COMPONENT_TYPE CompTypeToRegisterComponentType(CompType CT) {
@@ -1635,8 +1722,8 @@ LPCSTR DxilShaderReflection::CreateUpperCase(LPCSTR pValue) {
   return m_UpperCaseNames.back().get();
 }
 
-HRESULT DxilShaderReflection::Load(IDxcBlob *pBlob,
-                                   const DxilPartHeader *pPart) {
+HRESULT DxilModuleReflection::LoadModule(IDxcBlob *pBlob,
+                                         const DxilPartHeader *pPart) {
   DXASSERT_NOMSG(pBlob != nullptr);
   DXASSERT_NOMSG(pPart != nullptr);
   m_pContainer = pBlob;
@@ -1665,6 +1752,24 @@ HRESULT DxilShaderReflection::Load(IDxcBlob *pBlob,
   CATCH_CPP_RETURN_HRESULT();
 };
 
+HRESULT DxilShaderReflection::Load(IDxcBlob *pBlob,
+                                   const DxilPartHeader *pPart) {
+  IFR(LoadModule(pBlob, pPart));
+
+  try {
+    // Set cbuf usage.
+    SetCBufferUsage();
+
+    // Populate input/output/patch constant signatures.
+    CreateReflectionObjectsForSignature(m_pDxilModule->GetInputSignature(), m_InputSignature);
+    CreateReflectionObjectsForSignature(m_pDxilModule->GetOutputSignature(), m_OutputSignature);
+    CreateReflectionObjectsForSignature(m_pDxilModule->GetPatchConstantSignature(), m_PatchConstantSignature);
+    MarkUsedSignatureElements();
+    return S_OK;
+  }
+  CATCH_CPP_RETURN_HRESULT();
+}
+
 _Use_decl_annotations_
 HRESULT DxilShaderReflection::GetDesc(D3D12_SHADER_DESC *pDesc) {
   IFR(ZeroMemoryToOut(pDesc));
@@ -1789,20 +1894,26 @@ void DxilShaderReflection::MarkUsedSignatureElements() {
 
 _Use_decl_annotations_
 ID3D12ShaderReflectionConstantBuffer* DxilShaderReflection::GetConstantBufferByIndex(UINT Index) {
+  return DxilModuleReflection::_GetConstantBufferByIndex(Index);
+}
+ID3D12ShaderReflectionConstantBuffer* DxilModuleReflection::_GetConstantBufferByIndex(UINT Index) {
   if (Index >= m_CBs.size()) {
     return &g_InvalidSRConstantBuffer;
   }
-  return &m_CBs[Index];
+  return m_CBs[Index].get();
 }
 
 _Use_decl_annotations_
 ID3D12ShaderReflectionConstantBuffer* DxilShaderReflection::GetConstantBufferByName(LPCSTR Name) {
+  return DxilModuleReflection::_GetConstantBufferByName(Name);
+}
+ID3D12ShaderReflectionConstantBuffer* DxilModuleReflection::_GetConstantBufferByName(LPCSTR Name) {
   if (!Name) {
     return &g_InvalidSRConstantBuffer;
   }
   for (UINT index = 0; index < m_CBs.size(); ++index) {
-    if (0 == strcmp(m_CBs[index].GetName(), Name)) {
-      return &m_CBs[index];
+    if (0 == strcmp(m_CBs[index]->GetName(), Name)) {
+      return m_CBs[index].get();
     }
   }
   return &g_InvalidSRConstantBuffer;
@@ -1811,9 +1922,13 @@ ID3D12ShaderReflectionConstantBuffer* DxilShaderReflection::GetConstantBufferByN
 _Use_decl_annotations_
 HRESULT DxilShaderReflection::GetResourceBindingDesc(UINT ResourceIndex,
   _Out_ D3D12_SHADER_INPUT_BIND_DESC *pDesc) {
+  return DxilModuleReflection::_GetResourceBindingDesc(ResourceIndex, pDesc, m_PublicAPI);
+}
+HRESULT DxilModuleReflection::_GetResourceBindingDesc(UINT ResourceIndex,
+  _Out_ D3D12_SHADER_INPUT_BIND_DESC *pDesc, PublicAPI api) {
   IFRBOOL(pDesc != nullptr, E_INVALIDARG);
   IFRBOOL(ResourceIndex < m_Resources.size(), E_INVALIDARG);
-  if (m_PublicAPI != PublicAPI::D3D12) {
+  if (api != PublicAPI::D3D12) {
     memcpy(pDesc, &m_Resources[ResourceIndex], sizeof(D3D11_SHADER_INPUT_BIND_DESC));
   }
   else {
@@ -1869,10 +1984,13 @@ HRESULT DxilShaderReflection::GetPatchConstantParameterDesc(UINT ParameterIndex,
 
 _Use_decl_annotations_
 ID3D12ShaderReflectionVariable* DxilShaderReflection::GetVariableByName(LPCSTR Name) {
+  return DxilModuleReflection::_GetVariableByName(Name);
+}
+ID3D12ShaderReflectionVariable* DxilModuleReflection::_GetVariableByName(LPCSTR Name) {
   if (Name != nullptr) {
     // Iterate through all cbuffers to find the variable.
     for (UINT i = 0; i < m_CBs.size(); i++) {
-      ID3D12ShaderReflectionVariable *pVar = m_CBs[i].GetVariableByName(Name);
+      ID3D12ShaderReflectionVariable *pVar = m_CBs[i]->GetVariableByName(Name);
       if (pVar != &g_InvalidSRVariable) {
         return pVar;
       }
@@ -1885,11 +2003,15 @@ ID3D12ShaderReflectionVariable* DxilShaderReflection::GetVariableByName(LPCSTR N
 _Use_decl_annotations_
 HRESULT DxilShaderReflection::GetResourceBindingDescByName(LPCSTR Name,
   D3D12_SHADER_INPUT_BIND_DESC *pDesc) {
+  return DxilModuleReflection::_GetResourceBindingDescByName(Name, pDesc, m_PublicAPI);
+}
+HRESULT DxilModuleReflection::_GetResourceBindingDescByName(LPCSTR Name,
+  D3D12_SHADER_INPUT_BIND_DESC *pDesc, PublicAPI api) {
   IFRBOOL(Name != nullptr, E_INVALIDARG);
 
   for (UINT i = 0; i < m_Resources.size(); i++) {
     if (strcmp(m_Resources[i].Name, Name) == 0) {
-      if (m_PublicAPI != PublicAPI::D3D12) {
+      if (api != PublicAPI::D3D12) {
         memcpy(pDesc, &m_Resources[i], sizeof(D3D11_SHADER_INPUT_BIND_DESC));
       }
       else {
@@ -1951,3 +2073,244 @@ UINT64 DxilShaderReflection::GetRequiresFlags() {
   if (features & ShaderFeatureInfo_ViewportAndRTArrayIndexFromAnyShaderFeedingRasterizer) result |= D3D_SHADER_REQUIRES_VIEWPORT_AND_RT_ARRAY_INDEX_FROM_ANY_SHADER_FEEDING_RASTERIZER;
   return result;
 }
+
+
+// ID3D12FunctionReflection
+
+class CFunctionReflection : public ID3D12FunctionReflection {
+protected:
+  DxilLibraryReflection * m_pLibraryReflection = nullptr;
+  const Function *m_pFunction;
+  const DxilFunctionProps *m_pProps;  // nullptr if non-shader library function or patch constant function
+  std::string m_Name;
+  typedef SmallSetVector<UINT32, 8> ResourceUseSet;
+  ResourceUseSet m_UsedResources;
+  ResourceUseSet m_UsedCBs;
+
+public:
+  void Initialize(DxilLibraryReflection* pLibraryReflection, Function *pFunction) {
+    DXASSERT_NOMSG(pLibraryReflection);
+    DXASSERT_NOMSG(pFunction);
+    m_pLibraryReflection = pLibraryReflection;
+    m_pFunction = pFunction;
+
+    const DxilModule &M = *m_pLibraryReflection->m_pDxilModule;
+    m_Name = m_pFunction->getName().str();
+    m_pProps = nullptr;
+    if (M.HasDxilFunctionProps(m_pFunction)) {
+      m_pProps = &M.GetDxilFunctionProps(m_pFunction);
+    }
+  }
+  void AddResourceReference(UINT resIndex) {
+    m_UsedResources.insert(resIndex);
+  }
+  void AddCBReference(UINT cbIndex) {
+    m_UsedCBs.insert(cbIndex);
+  }
+
+  // ID3D12FunctionReflection
+  STDMETHOD(GetDesc)(THIS_ _Out_ D3D12_FUNCTION_DESC * pDesc);
+
+  // BufferIndex relative to used constant buffers here
+  STDMETHOD_(ID3D12ShaderReflectionConstantBuffer *, GetConstantBufferByIndex)(THIS_ _In_ UINT BufferIndex);
+  STDMETHOD_(ID3D12ShaderReflectionConstantBuffer *, GetConstantBufferByName)(THIS_ _In_ LPCSTR Name);
+
+  STDMETHOD(GetResourceBindingDesc)(THIS_ _In_ UINT ResourceIndex,
+    _Out_ D3D12_SHADER_INPUT_BIND_DESC * pDesc);
+
+  STDMETHOD_(ID3D12ShaderReflectionVariable *, GetVariableByName)(THIS_ _In_ LPCSTR Name);
+
+  STDMETHOD(GetResourceBindingDescByName)(THIS_ _In_ LPCSTR Name,
+    _Out_ D3D12_SHADER_INPUT_BIND_DESC * pDesc);
+
+  // Use D3D_RETURN_PARAMETER_INDEX to get description of the return value.
+  STDMETHOD_(ID3D12FunctionParameterReflection *, GetFunctionParameter)(THIS_ _In_ INT ParameterIndex) {
+    return &g_InvalidFunctionParameter;
+  }
+};
+
+_Use_decl_annotations_
+HRESULT CFunctionReflection::GetDesc(D3D12_FUNCTION_DESC *pDesc) {
+  DXASSERT_NOMSG(m_pLibraryReflection);
+  IFR(ZeroMemoryToOut(pDesc));
+
+  const ShaderModel* pSM = m_pLibraryReflection->m_pDxilModule->GetShaderModel();
+  DXIL::ShaderKind kind = DXIL::ShaderKind::Library;
+  if (m_pProps) {
+    kind = m_pProps->shaderKind;
+  }
+  pDesc->Version = EncodeVersion(kind, pSM->GetMajor(), pSM->GetMinor());
+
+  //Unset:  LPCSTR                  Creator;                     // Creator string
+  //Unset:  UINT                    Flags;                       // Shader compilation/parse flags
+
+  pDesc->ConstantBuffers = (UINT)m_UsedCBs.size();
+  pDesc->BoundResources = (UINT)m_UsedResources.size();
+
+  //Unset:  UINT                    InstructionCount;            // Number of emitted instructions
+  //Unset:  UINT                    TempRegisterCount;           // Number of temporary registers used 
+  //Unset:  UINT                    TempArrayCount;              // Number of temporary arrays used
+  //Unset:  UINT                    DefCount;                    // Number of constant defines 
+  //Unset:  UINT                    DclCount;                    // Number of declarations (input + output)
+  //Unset:  UINT                    TextureNormalInstructions;   // Number of non-categorized texture instructions
+  //Unset:  UINT                    TextureLoadInstructions;     // Number of texture load instructions
+  //Unset:  UINT                    TextureCompInstructions;     // Number of texture comparison instructions
+  //Unset:  UINT                    TextureBiasInstructions;     // Number of texture bias instructions
+  //Unset:  UINT                    TextureGradientInstructions; // Number of texture gradient instructions
+  //Unset:  UINT                    FloatInstructionCount;       // Number of floating point arithmetic instructions used
+  //Unset:  UINT                    IntInstructionCount;         // Number of signed integer arithmetic instructions used
+  //Unset:  UINT                    UintInstructionCount;        // Number of unsigned integer arithmetic instructions used
+  //Unset:  UINT                    StaticFlowControlCount;      // Number of static flow control instructions used
+  //Unset:  UINT                    DynamicFlowControlCount;     // Number of dynamic flow control instructions used
+  //Unset:  UINT                    MacroInstructionCount;       // Number of macro instructions used
+  //Unset:  UINT                    ArrayInstructionCount;       // Number of array instructions used
+  //Unset:  UINT                    MovInstructionCount;         // Number of mov instructions used
+  //Unset:  UINT                    MovcInstructionCount;        // Number of movc instructions used
+  //Unset:  UINT                    ConversionInstructionCount;  // Number of type conversion instructions used
+  //Unset:  UINT                    BitwiseInstructionCount;     // Number of bitwise arithmetic instructions used
+  //Unset:  D3D_FEATURE_LEVEL       MinFeatureLevel;             // Min target of the function byte code
+  //Unset:  UINT64                  RequiredFeatureFlags;        // Required feature flags
+
+  pDesc->Name = m_Name.c_str();
+
+  //Unset:  INT                     FunctionParameterCount;      // Number of logical parameters in the function signature (not including return)
+  //Unset:  BOOL                    HasReturn;                   // TRUE, if function returns a value, false - it is a subroutine
+  //Unset:  BOOL                    Has10Level9VertexShader;     // TRUE, if there is a 10L9 VS blob
+  //Unset:  BOOL                    Has10Level9PixelShader;      // TRUE, if there is a 10L9 PS blob
+  return S_OK;
+}
+
+// BufferIndex is relative to used constant buffers here
+ID3D12ShaderReflectionConstantBuffer *CFunctionReflection::GetConstantBufferByIndex(UINT BufferIndex) {
+  DXASSERT_NOMSG(m_pLibraryReflection);
+  if (BufferIndex >= m_UsedCBs.size())
+    return &g_InvalidSRConstantBuffer;
+  return m_pLibraryReflection->_GetConstantBufferByIndex(m_UsedCBs[BufferIndex]);
+}
+
+ID3D12ShaderReflectionConstantBuffer *CFunctionReflection::GetConstantBufferByName(LPCSTR Name) {
+  DXASSERT_NOMSG(m_pLibraryReflection);
+  return m_pLibraryReflection->_GetConstantBufferByName(Name);
+}
+
+HRESULT CFunctionReflection::GetResourceBindingDesc(UINT ResourceIndex,
+  D3D12_SHADER_INPUT_BIND_DESC * pDesc) {
+  DXASSERT_NOMSG(m_pLibraryReflection);
+  if (ResourceIndex >= m_UsedResources.size())
+    return E_INVALIDARG;
+  return m_pLibraryReflection->_GetResourceBindingDesc(m_UsedResources[ResourceIndex], pDesc);
+}
+
+ID3D12ShaderReflectionVariable * CFunctionReflection::GetVariableByName(LPCSTR Name) {
+  DXASSERT_NOMSG(m_pLibraryReflection);
+  return m_pLibraryReflection->_GetVariableByName(Name);
+}
+
+HRESULT CFunctionReflection::GetResourceBindingDescByName(LPCSTR Name,
+  D3D12_SHADER_INPUT_BIND_DESC * pDesc) {
+  DXASSERT_NOMSG(m_pLibraryReflection);
+  return m_pLibraryReflection->_GetResourceBindingDescByName(Name, pDesc);
+}
+
+
+// DxilLibraryReflection
+
+// From DxilContainerAssembler:
+static llvm::Function *FindUsingFunction(llvm::Value *User) {
+  if (llvm::Instruction *I = dyn_cast<llvm::Instruction>(User)) {
+    // Instruction should be inside a basic block, which is in a function
+    return cast<llvm::Function>(I->getParent()->getParent());
+  }
+  // User can be either instruction, constant, or operator. But User is an
+  // operator only if constant is a scalar value, not resource pointer.
+  llvm::Constant *CU = cast<llvm::Constant>(User);
+  if (!CU->user_empty())
+    return FindUsingFunction(*CU->user_begin());
+  else
+    return nullptr;
+}
+
+void DxilLibraryReflection::AddResourceUseToFunctions(DxilResourceBase &resource, unsigned resIndex) {
+  Constant *var = resource.GetGlobalSymbol();
+  if (var) {
+    for (auto user : var->users()) {
+      // Find the function.
+      if (llvm::Function *F = FindUsingFunction(user)) {
+        auto funcReflector = m_FunctionsByPtr[F];
+        funcReflector->AddResourceReference(resIndex);
+        if (resource.GetClass() == DXIL::ResourceClass::CBuffer) {
+          funcReflector->AddCBReference(resource.GetID());
+        }
+      }
+    }
+  }
+}
+
+void DxilLibraryReflection::AddResourceDependencies() {
+  for (auto &F : m_pModule->functions()) {
+    if (F.isDeclaration())
+      continue;
+    auto &func = m_FunctionMap[F.getName().str()];
+    DXASSERT(!func.get(), "otherwise duplicate named functions");
+    func.reset(new CFunctionReflection());
+    func->Initialize(this, &F);
+    m_FunctionsByPtr[&F] = func.get();
+  }
+  UINT resIndex = 0;
+  for (auto &resource : m_Resources) {
+    switch (resource.Type) {
+    case D3D_SIT_CBUFFER:
+      AddResourceUseToFunctions(m_pDxilModule->GetCBuffer(resource.uID), resIndex);
+      break;
+    case D3D_SIT_TBUFFER:   // TODO: Handle when TBuffers are added to CB list
+    case D3D_SIT_TEXTURE:
+    case D3D_SIT_STRUCTURED:
+    case D3D_SIT_BYTEADDRESS:
+      AddResourceUseToFunctions(m_pDxilModule->GetSRV(resource.uID), resIndex);
+      break;
+    case D3D_SIT_UAV_RWTYPED:
+    case D3D_SIT_UAV_RWSTRUCTURED:
+    case D3D_SIT_UAV_RWBYTEADDRESS:
+    case D3D_SIT_UAV_APPEND_STRUCTURED:
+    case D3D_SIT_UAV_CONSUME_STRUCTURED:
+    case D3D_SIT_UAV_RWSTRUCTURED_WITH_COUNTER:
+      AddResourceUseToFunctions(m_pDxilModule->GetUAV(resource.uID), resIndex);
+      break;
+    case D3D_SIT_SAMPLER:
+      AddResourceUseToFunctions(m_pDxilModule->GetSampler(resource.uID), resIndex);
+      break;
+    }
+    resIndex++;
+  }
+}
+
+// ID3D12LibraryReflection
+
+HRESULT DxilLibraryReflection::Load(IDxcBlob *pBlob,
+  const DxilPartHeader *pPart) {
+  IFR(LoadModule(pBlob, pPart));
+
+  try {
+    AddResourceDependencies();
+    return S_OK;
+  }
+  CATCH_CPP_RETURN_HRESULT();
+}
+
+_Use_decl_annotations_
+HRESULT DxilLibraryReflection::GetDesc(D3D12_LIBRARY_DESC * pDesc) {
+  IFR(ZeroMemoryToOut(pDesc));
+  //Unset:  LPCSTR    Creator;           // The name of the originator of the library.
+  //Unset:  UINT      Flags;             // Compilation flags.
+  //UINT      FunctionCount;     // Number of functions exported from the library.
+  pDesc->FunctionCount = (UINT)m_FunctionMap.size();
+  return S_OK;
+}
+
+_Use_decl_annotations_
+ID3D12FunctionReflection *DxilLibraryReflection::GetFunctionByIndex(INT FunctionIndex) {
+  if (FunctionIndex >= m_FunctionMap.size())
+    return &g_InvalidFunction;
+  return ((m_FunctionMap.begin() + FunctionIndex)->second).get();
+}
+

+ 65 - 18
lib/Support/Windows/MSFileSystem.inc.cpp

@@ -51,33 +51,80 @@ namespace fs {
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 // Per-thread MSFileSystem support.
 
-static DWORD g_FileSystemTls;
+namespace {
 
-error_code SetupPerThreadFileSystem() throw()
-{
-  assert(g_FileSystemTls == 0 && "otherwise this has already been initialized");
-  g_FileSystemTls = TlsAlloc();
-  if (g_FileSystemTls == TLS_OUT_OF_INDEXES)
-  {
-    g_FileSystemTls = 0;
-    return mapWindowsError(::GetLastError());
+template <typename _T>
+class ThreadLocalStorage {
+  DWORD m_Tls;
+  DWORD m_dwError;
+public:
+  ThreadLocalStorage() : m_Tls(TLS_OUT_OF_INDEXES), m_dwError(ERROR_NOT_READY) {}
+  DWORD Setup() {
+    if (m_Tls == TLS_OUT_OF_INDEXES) {
+      m_Tls = TlsAlloc();
+      m_dwError = (m_Tls == TLS_OUT_OF_INDEXES) ? ::GetLastError() : 0;
+    }
+    return m_dwError;
   }
-  return error_code();
+  void Cleanup() {
+    if (m_Tls != TLS_OUT_OF_INDEXES)
+      TlsFree(m_Tls);
+    m_Tls = TLS_OUT_OF_INDEXES;
+    m_dwError = ERROR_NOT_READY;
+  }
+  ~ThreadLocalStorage() { Cleanup(); }
+  _T GetValue() const {
+    if (m_Tls != TLS_OUT_OF_INDEXES)
+      return (_T)TlsGetValue(m_Tls);
+    else
+      return nullptr;
+  }
+  bool SetValue(_T value) {
+    if (m_Tls != TLS_OUT_OF_INDEXES) {
+      return TlsSetValue(m_Tls, (void*)value);
+    } else {
+      ::SetLastError(m_dwError);
+      return false;
+    }
+  }
+  // Retrieve error code if TlsAlloc() failed
+  DWORD GetError() const {
+    return m_dwError;
+  }
+  operator bool() const { return m_Tls != TLS_OUT_OF_INDEXES; }
+};
+
+static ThreadLocalStorage<MSFileSystemRef> g_PerThreadSystem;
+
 }
 
-void CleanupPerThreadFileSystem() throw()
-{
-  TlsFree(g_FileSystemTls);
-  g_FileSystemTls = 0;
+error_code GetFileSystemTlsStatus() throw() {
+  DWORD dwError = g_PerThreadSystem.GetError();
+  if (dwError)
+    return error_code(dwError, system_category());
+  else
+    return error_code();
 }
 
-MSFileSystemRef GetCurrentThreadFileSystem() throw()
-{
-  return (MSFileSystemRef)TlsGetValue(g_FileSystemTls);
+error_code SetupPerThreadFileSystem() throw() {
+  assert(!g_PerThreadSystem && g_PerThreadSystem.GetError() == ERROR_NOT_READY &&
+          "otherwise, PerThreadSystem already set up.");
+  if (g_PerThreadSystem.Setup())
+    return GetFileSystemTlsStatus();
+  return error_code();
+}
+void CleanupPerThreadFileSystem() throw() {
+  g_PerThreadSystem.Cleanup();
+}
+
+MSFileSystemRef GetCurrentThreadFileSystem() throw() {
+  assert(g_PerThreadSystem && "otherwise, TLS not initialized");
+  return g_PerThreadSystem.GetValue();
 }
 
 error_code SetCurrentThreadFileSystem(MSFileSystemRef value) throw()
 {
+  assert(g_PerThreadSystem && "otherwise, TLS not initialized");
   // For now, disallow reentrancy in APIs (i.e., replace the current instance with another one).
   if (value != nullptr)
   {
@@ -88,7 +135,7 @@ error_code SetCurrentThreadFileSystem(MSFileSystemRef value) throw()
     }
   }
 
-  if (!TlsSetValue(g_FileSystemTls, value))
+  if (!g_PerThreadSystem.SetValue(value))
   {
     return mapWindowsError(::GetLastError());
   }

+ 51 - 0
tools/clang/test/CodeGenHLSL/quick-test/d3dreflect/anon_struct.hlsl

@@ -0,0 +1,51 @@
+// RUN: %dxc -T ps_6_0 -E main %s | %D3DReflect %s | FileCheck %s
+
+struct {
+    int X;
+} CB;
+
+float main(int N : A, int C : B) : SV_TARGET {
+    return CB.X;
+}
+
+// CHECK: ID3D12ShaderReflection:
+// CHECK:   D3D12_SHADER_BUFFER_DESC:
+// CHECK:     Shader Version: Pixel 6.0
+// CHECK:     ConstantBuffers: 1
+// CHECK:     BoundResources: 1
+// CHECK:     InputParameters: 2
+// CHECK:     OutputParameters: 1
+// CHECK:   Constant Buffers:
+// CHECK:     ID3D12ShaderReflectionConstantBuffer:
+// CHECK:       D3D12_SHADER_BUFFER_DESC: Name: $Globals
+// CHECK:         Type: D3D_CT_CBUFFER
+// CHECK:         Size: 16
+// CHECK:         Num Variables: 1
+// CHECK:       {
+// CHECK:         ID3D12ShaderReflectionVariable:
+// CHECK:           D3D12_SHADER_VARIABLE_DESC: Name: CB
+// CHECK:             Size: 4
+// CHECK:             uFlags: 0x2
+// CHECK:           ID3D12ShaderReflectionType:
+// CHECK:             D3D12_SHADER_TYPE_DESC: Name: anon
+// CHECK:               Class: D3D_SVC_STRUCT
+// CHECK:               Type: D3D_SVT_VOID
+// CHECK:               Rows: 1
+// CHECK:               Columns: 1
+// CHECK:               Members: 1
+// CHECK:             {
+// CHECK:               ID3D12ShaderReflectionType:
+// CHECK:                 D3D12_SHADER_TYPE_DESC: Name: int
+// CHECK:                   Class: D3D_SVC_SCALAR
+// CHECK:                   Type: D3D_SVT_INT
+// CHECK:                   Rows: 1
+// CHECK:                   Columns: 1
+// CHECK:             }
+// CHECK:           CBuffer: $Globals
+// CHECK:       }
+// CHECK:   Bound Resources:
+// CHECK:     D3D12_SHADER_BUFFER_DESC: Name: $Globals
+// CHECK:       Type: D3D_SIT_CBUFFER
+// CHECK:       uID: 0
+// CHECK:       BindPoint: 0
+// CHECK:       Dimension: D3D_SRV_DIMENSION_UNKNOWN

+ 41 - 0
tools/clang/test/CodeGenHLSL/quick-test/d3dreflect/cb_array.hlsl

@@ -0,0 +1,41 @@
+// RUN: %dxc -E main -T ps_6_0 %s | %D3DReflect %s | FileCheck %s
+
+float A[6] : register(b0);
+float main(int i : A) : SV_TARGET
+{
+  return A[i] + A[i+1] + A[i+2] ;
+}
+
+// CHECK: ID3D12ShaderReflection:
+// CHECK:   D3D12_SHADER_BUFFER_DESC:
+// CHECK:     Shader Version: Pixel 6.0
+// CHECK:     ConstantBuffers: 1
+// CHECK:     BoundResources: 1
+// CHECK:     InputParameters: 1
+// CHECK:     OutputParameters: 1
+// CHECK:   Constant Buffers:
+// CHECK:     ID3D12ShaderReflectionConstantBuffer:
+// CHECK:       D3D12_SHADER_BUFFER_DESC: Name: $Globals
+// CHECK:         Type: D3D_CT_CBUFFER
+// CHECK:         Size: 96
+// CHECK:         Num Variables: 1
+// CHECK:       {
+// CHECK:         ID3D12ShaderReflectionVariable:
+// CHECK:           D3D12_SHADER_VARIABLE_DESC: Name: A
+// CHECK:             Size: 84
+// CHECK:             uFlags: 0x2
+// CHECK:           ID3D12ShaderReflectionType:
+// CHECK:             D3D12_SHADER_TYPE_DESC: Name: float
+// CHECK:               Class: D3D_SVC_SCALAR
+// CHECK:               Type: D3D_SVT_FLOAT
+// CHECK:               Elements: 6
+// CHECK:               Rows: 1
+// CHECK:               Columns: 1
+// CHECK:           CBuffer: $Globals
+// CHECK:       }
+// CHECK:   Bound Resources:
+// CHECK:     D3D12_SHADER_BUFFER_DESC: Name: $Globals
+// CHECK:       Type: D3D_SIT_CBUFFER
+// CHECK:       uID: 0
+// CHECK:       BindPoint: 0
+// CHECK:       Dimension: D3D_SRV_DIMENSION_UNKNOWN

+ 42 - 0
tools/clang/test/CodeGenHLSL/quick-test/d3dreflect/cbuffer_default_val.hlsl

@@ -0,0 +1,42 @@
+// RUN: %dxc -E main -T ps_6_0 %s | %D3DReflect %s | FileCheck %s
+
+float t = 0.5;
+
+float main() : SV_TARGET
+{
+  return sqrt(t);
+}
+
+// Default value unsupported for now:
+// CHECK: ID3D12ShaderReflection:
+// CHECK:   D3D12_SHADER_BUFFER_DESC:
+// CHECK:     Shader Version: Pixel 6.0
+// CHECK:     ConstantBuffers: 1
+// CHECK:     BoundResources: 1
+// CHECK:     OutputParameters: 1
+// CHECK:   Constant Buffers:
+// CHECK:     ID3D12ShaderReflectionConstantBuffer:
+// CHECK:       D3D12_SHADER_BUFFER_DESC: Name: $Globals
+// CHECK:         Type: D3D_CT_CBUFFER
+// CHECK:         Size: 16
+// CHECK:         Num Variables: 1
+// CHECK:       {
+// CHECK:         ID3D12ShaderReflectionVariable:
+// CHECK:           D3D12_SHADER_VARIABLE_DESC: Name: t
+// CHECK:             Size: 4
+// CHECK:             uFlags: 0x2
+// CHECK:             DefaultValue: <nullptr>
+// CHECK:           ID3D12ShaderReflectionType:
+// CHECK:             D3D12_SHADER_TYPE_DESC: Name: float
+// CHECK:               Class: D3D_SVC_SCALAR
+// CHECK:               Type: D3D_SVT_FLOAT
+// CHECK:               Rows: 1
+// CHECK:               Columns: 1
+// CHECK:           CBuffer: $Globals
+// CHECK:       }
+// CHECK:   Bound Resources:
+// CHECK:     D3D12_SHADER_BUFFER_DESC: Name: $Globals
+// CHECK:       Type: D3D_SIT_CBUFFER
+// CHECK:       uID: 0
+// CHECK:       BindPoint: 0
+// CHECK:       Dimension: D3D_SRV_DIMENSION_UNKNOWN

+ 62 - 0
tools/clang/test/CodeGenHLSL/quick-test/d3dreflect/empty_struct2.hlsl

@@ -0,0 +1,62 @@
+// RUN: %dxc -E main -T vs_6_0 %s | %D3DReflect %s | FileCheck %s
+
+// Make sure nest empty struct works.
+
+struct KillerStruct {};
+
+struct InnerStruct {
+  KillerStruct s;
+};
+
+struct OuterStruct {
+  InnerStruct s;
+};
+
+cbuffer Params_cbuffer : register(b0) {
+  OuterStruct constants;
+  float4 foo;
+};
+
+float4 main(float4 pos : POSITION) : SV_POSITION { return foo; }
+
+
+// CHECK: ID3D12ShaderReflection:
+// CHECK:   D3D12_SHADER_BUFFER_DESC:
+// CHECK:     Shader Version: Vertex 6.0
+// CHECK:     ConstantBuffers: 1
+// CHECK:     BoundResources: 1
+// CHECK:     InputParameters: 1
+// CHECK:     OutputParameters: 1
+// CHECK:   Constant Buffers:
+// CHECK:     ID3D12ShaderReflectionConstantBuffer:
+// CHECK:       D3D12_SHADER_BUFFER_DESC: Name: Params_cbuffer
+// CHECK:         Type: D3D_CT_CBUFFER
+// CHECK:         Size: 16
+// CHECK:         Num Variables: 2
+// CHECK:       {
+// CHECK:         ID3D12ShaderReflectionVariable:
+// CHECK:           D3D12_SHADER_VARIABLE_DESC: Name: constants
+// CHECK:           ID3D12ShaderReflectionType:
+// CHECK:             D3D12_SHADER_TYPE_DESC: Name: OuterStruct
+// CHECK:               Class: D3D_SVC_STRUCT
+// CHECK:               Type: D3D_SVT_VOID
+// CHECK:               Rows: 1
+// CHECK:           CBuffer: Params_cbuffer
+// CHECK:         ID3D12ShaderReflectionVariable:
+// CHECK:           D3D12_SHADER_VARIABLE_DESC: Name: foo
+// CHECK:             Size: 16
+// CHECK:             uFlags: 0x2
+// CHECK:           ID3D12ShaderReflectionType:
+// CHECK:             D3D12_SHADER_TYPE_DESC: Name: float4
+// CHECK:               Class: D3D_SVC_VECTOR
+// CHECK:               Type: D3D_SVT_FLOAT
+// CHECK:               Rows: 1
+// CHECK:               Columns: 4
+// CHECK:           CBuffer: Params_cbuffer
+// CHECK:       }
+// CHECK:   Bound Resources:
+// CHECK:     D3D12_SHADER_BUFFER_DESC: Name: Params_cbuffer
+// CHECK:       Type: D3D_SIT_CBUFFER
+// CHECK:       uID: 0
+// CHECK:       BindPoint: 0
+// CHECK:       Dimension: D3D_SRV_DIMENSION_UNKNOWN

+ 245 - 0
tools/clang/test/CodeGenHLSL/quick-test/d3dreflect/reflect-lib-1.hlsl

@@ -0,0 +1,245 @@
+// RUN: %dxc -T lib_6_3 %s | %D3DReflect %s | FileCheck %s
+
+float cbval1;
+cbuffer MyCB : register(b11, space2) { int4 cbval2, cbval3; }
+RWTexture1D<int4> tex : register(u5);
+Texture1D<float4> tex2 : register(t0);
+SamplerState samp : register(s7);
+RWByteAddressBuffer b_buf;
+float function0(min16float x) { 
+  return x + cbval2.x + tex[0].x; }
+float function1(float x, min12int i) {
+  return x + cbval1 + b_buf.Load(x) + tex2.Sample(samp, x).x; }
+[shader("vertex")]
+float function2(float4 x : POSITION) : SV_Position { return x + cbval1 + cbval3.x; }
+
+
+// CHECK: ID3D12LibraryReflection:
+// CHECK:   D3D12_LIBRARY_DESC:
+// CHECK:     FunctionCount: 4
+// CHECK:   ID3D12FunctionReflection:
+// CHECK:     D3D12_FUNCTION_DESC: Name: \01?function0@@YAM$f16@@Z
+// CHECK:       Shader Version: Library 6.3
+// CHECK:       ConstantBuffers: 1
+// CHECK:       BoundResources: 2
+// CHECK:     Constant Buffers:
+// CHECK:       ID3D12ShaderReflectionConstantBuffer:
+// CHECK:         D3D12_SHADER_BUFFER_DESC: Name: MyCB
+// CHECK:           Type: D3D_CT_CBUFFER
+// CHECK:           Size: 32
+// CHECK:           Num Variables: 2
+// CHECK:         {
+// CHECK:           ID3D12ShaderReflectionVariable:
+// CHECK:             D3D12_SHADER_VARIABLE_DESC: Name: cbval2
+// CHECK:               Size: 16
+// CHECK:               uFlags: 0x2
+// CHECK:             ID3D12ShaderReflectionType:
+// CHECK:               D3D12_SHADER_TYPE_DESC: Name: int4
+// CHECK:                 Class: D3D_SVC_VECTOR
+// CHECK:                 Type: D3D_SVT_INT
+// CHECK:                 Rows: 1
+// CHECK:                 Columns: 4
+// CHECK:             CBuffer: MyCB
+// CHECK:           ID3D12ShaderReflectionVariable:
+// CHECK:             D3D12_SHADER_VARIABLE_DESC: Name: cbval3
+// CHECK:               Size: 16
+// CHECK:               StartOffset: 16
+// CHECK:               uFlags: 0x2
+// CHECK:             ID3D12ShaderReflectionType:
+// CHECK:               D3D12_SHADER_TYPE_DESC: Name: int4
+// CHECK:                 Class: D3D_SVC_VECTOR
+// CHECK:                 Type: D3D_SVT_INT
+// CHECK:                 Rows: 1
+// CHECK:                 Columns: 4
+// CHECK:             CBuffer: MyCB
+// CHECK:         }
+// CHECK:     Bound Resources:
+// CHECK:       D3D12_SHADER_BUFFER_DESC: Name: MyCB
+// CHECK:         Type: D3D_SIT_CBUFFER
+// CHECK:         uID: 1
+// CHECK:         BindPoint: 11
+// CHECK:         Space: 2
+// CHECK:         Dimension: D3D_SRV_DIMENSION_UNKNOWN
+// CHECK:       D3D12_SHADER_BUFFER_DESC: Name: tex
+// CHECK:         Type: D3D_SIT_UAV_RWTYPED
+// CHECK:         uID: 0
+// CHECK:         BindPoint: 5
+// CHECK:         ReturnType: D3D_RETURN_TYPE_SINT
+// CHECK:         Dimension: D3D_SRV_DIMENSION_TEXTURE1D
+// CHECK:         uFlags: 0xc
+// CHECK:   ID3D12FunctionReflection:
+// CHECK:     D3D12_FUNCTION_DESC: Name: \01?function1@@YAMMF@Z
+// CHECK:       Shader Version: Library 6.3
+// CHECK:       ConstantBuffers: 1
+// CHECK:       BoundResources: 4
+// CHECK:     Constant Buffers:
+// CHECK:       ID3D12ShaderReflectionConstantBuffer:
+// CHECK:         D3D12_SHADER_BUFFER_DESC: Name: $Globals
+// CHECK:           Type: D3D_CT_CBUFFER
+// CHECK:           Size: 16
+// CHECK:           Num Variables: 1
+// CHECK:         {
+// CHECK:           ID3D12ShaderReflectionVariable:
+// CHECK:             D3D12_SHADER_VARIABLE_DESC: Name: cbval1
+// CHECK:               Size: 4
+// CHECK:               uFlags: 0x2
+// CHECK:             ID3D12ShaderReflectionType:
+// CHECK:               D3D12_SHADER_TYPE_DESC: Name: float
+// CHECK:                 Class: D3D_SVC_SCALAR
+// CHECK:                 Type: D3D_SVT_FLOAT
+// CHECK:                 Rows: 1
+// CHECK:                 Columns: 1
+// CHECK:             CBuffer: $Globals
+// CHECK:         }
+// CHECK:     Bound Resources:
+// CHECK:       D3D12_SHADER_BUFFER_DESC: Name: $Globals
+// CHECK:         Type: D3D_SIT_CBUFFER
+// CHECK:         uID: 0
+// CHECK:         Dimension: D3D_SRV_DIMENSION_UNKNOWN
+// CHECK:       D3D12_SHADER_BUFFER_DESC: Name: samp
+// CHECK:         Type: D3D_SIT_SAMPLER
+// CHECK:         uID: 0
+// CHECK:         BindPoint: 7
+// CHECK:         Dimension: D3D_SRV_DIMENSION_UNKNOWN
+// CHECK:       D3D12_SHADER_BUFFER_DESC: Name: tex2
+// CHECK:         Type: D3D_SIT_TEXTURE
+// CHECK:         uID: 0
+// CHECK:         BindPoint: 0
+// CHECK:         ReturnType: D3D_RETURN_TYPE_FLOAT
+// CHECK:         Dimension: D3D_SRV_DIMENSION_TEXTURE1D
+// CHECK:         uFlags: 0xc
+// CHECK:       D3D12_SHADER_BUFFER_DESC: Name: b_buf
+// CHECK:         Type: D3D_SIT_UAV_RWBYTEADDRESS
+// CHECK:         uID: 1
+// CHECK:         ReturnType: D3D_RETURN_TYPE_MIXED
+// CHECK:         Dimension: D3D_SRV_DIMENSION_BUFFER
+// CHECK:   ID3D12FunctionReflection:
+// CHECK:     D3D12_FUNCTION_DESC: Name: \01?function2@@YAMV?$vector@M$03@@@Z
+// CHECK:       Shader Version: Library 6.3
+// CHECK:       ConstantBuffers: 2
+// CHECK:       BoundResources: 2
+// CHECK:     Constant Buffers:
+// CHECK:       ID3D12ShaderReflectionConstantBuffer:
+// CHECK:         D3D12_SHADER_BUFFER_DESC: Name: $Globals
+// CHECK:           Type: D3D_CT_CBUFFER
+// CHECK:           Size: 16
+// CHECK:           Num Variables: 1
+// CHECK:         {
+// CHECK:           ID3D12ShaderReflectionVariable:
+// CHECK:             D3D12_SHADER_VARIABLE_DESC: Name: cbval1
+// CHECK:               Size: 4
+// CHECK:               uFlags: 0x2
+// CHECK:             ID3D12ShaderReflectionType:
+// CHECK:               D3D12_SHADER_TYPE_DESC: Name: float
+// CHECK:                 Class: D3D_SVC_SCALAR
+// CHECK:                 Type: D3D_SVT_FLOAT
+// CHECK:                 Rows: 1
+// CHECK:                 Columns: 1
+// CHECK:             CBuffer: $Globals
+// CHECK:         }
+// CHECK:       ID3D12ShaderReflectionConstantBuffer:
+// CHECK:         D3D12_SHADER_BUFFER_DESC: Name: MyCB
+// CHECK:           Type: D3D_CT_CBUFFER
+// CHECK:           Size: 32
+// CHECK:           Num Variables: 2
+// CHECK:         {
+// CHECK:           ID3D12ShaderReflectionVariable:
+// CHECK:             D3D12_SHADER_VARIABLE_DESC: Name: cbval2
+// CHECK:               Size: 16
+// CHECK:               uFlags: 0x2
+// CHECK:             ID3D12ShaderReflectionType:
+// CHECK:               D3D12_SHADER_TYPE_DESC: Name: int4
+// CHECK:                 Class: D3D_SVC_VECTOR
+// CHECK:                 Type: D3D_SVT_INT
+// CHECK:                 Rows: 1
+// CHECK:                 Columns: 4
+// CHECK:             CBuffer: MyCB
+// CHECK:           ID3D12ShaderReflectionVariable:
+// CHECK:             D3D12_SHADER_VARIABLE_DESC: Name: cbval3
+// CHECK:               Size: 16
+// CHECK:               StartOffset: 16
+// CHECK:               uFlags: 0x2
+// CHECK:             ID3D12ShaderReflectionType:
+// CHECK:               D3D12_SHADER_TYPE_DESC: Name: int4
+// CHECK:                 Class: D3D_SVC_VECTOR
+// CHECK:                 Type: D3D_SVT_INT
+// CHECK:                 Rows: 1
+// CHECK:                 Columns: 4
+// CHECK:             CBuffer: MyCB
+// CHECK:         }
+// CHECK:     Bound Resources:
+// CHECK:       D3D12_SHADER_BUFFER_DESC: Name: $Globals
+// CHECK:         Type: D3D_SIT_CBUFFER
+// CHECK:         uID: 0
+// CHECK:         Dimension: D3D_SRV_DIMENSION_UNKNOWN
+// CHECK:       D3D12_SHADER_BUFFER_DESC: Name: MyCB
+// CHECK:         Type: D3D_SIT_CBUFFER
+// CHECK:         uID: 1
+// CHECK:         BindPoint: 11
+// CHECK:         Space: 2
+// CHECK:         Dimension: D3D_SRV_DIMENSION_UNKNOWN
+// CHECK:   ID3D12FunctionReflection:
+// CHECK:     D3D12_FUNCTION_DESC: Name: function2
+// CHECK:       Shader Version: Vertex 6.3
+// CHECK:       ConstantBuffers: 2
+// CHECK:       BoundResources: 2
+// CHECK:     Constant Buffers:
+// CHECK:       ID3D12ShaderReflectionConstantBuffer:
+// CHECK:         D3D12_SHADER_BUFFER_DESC: Name: $Globals
+// CHECK:           Type: D3D_CT_CBUFFER
+// CHECK:           Size: 16
+// CHECK:           Num Variables: 1
+// CHECK:         {
+// CHECK:           ID3D12ShaderReflectionVariable:
+// CHECK:             D3D12_SHADER_VARIABLE_DESC: Name: cbval1
+// CHECK:               Size: 4
+// CHECK:               uFlags: 0x2
+// CHECK:             ID3D12ShaderReflectionType:
+// CHECK:               D3D12_SHADER_TYPE_DESC: Name: float
+// CHECK:                 Class: D3D_SVC_SCALAR
+// CHECK:                 Type: D3D_SVT_FLOAT
+// CHECK:                 Rows: 1
+// CHECK:                 Columns: 1
+// CHECK:             CBuffer: $Globals
+// CHECK:         }
+// CHECK:       ID3D12ShaderReflectionConstantBuffer:
+// CHECK:         D3D12_SHADER_BUFFER_DESC: Name: MyCB
+// CHECK:           Type: D3D_CT_CBUFFER
+// CHECK:           Size: 32
+// CHECK:           Num Variables: 2
+// CHECK:         {
+// CHECK:           ID3D12ShaderReflectionVariable:
+// CHECK:             D3D12_SHADER_VARIABLE_DESC: Name: cbval2
+// CHECK:               Size: 16
+// CHECK:               uFlags: 0x2
+// CHECK:             ID3D12ShaderReflectionType:
+// CHECK:               D3D12_SHADER_TYPE_DESC: Name: int4
+// CHECK:                 Class: D3D_SVC_VECTOR
+// CHECK:                 Type: D3D_SVT_INT
+// CHECK:                 Rows: 1
+// CHECK:                 Columns: 4
+// CHECK:             CBuffer: MyCB
+// CHECK:           ID3D12ShaderReflectionVariable:
+// CHECK:             D3D12_SHADER_VARIABLE_DESC: Name: cbval3
+// CHECK:               Size: 16
+// CHECK:               StartOffset: 16
+// CHECK:               uFlags: 0x2
+// CHECK:             ID3D12ShaderReflectionType:
+// CHECK:               D3D12_SHADER_TYPE_DESC: Name: int4
+// CHECK:                 Class: D3D_SVC_VECTOR
+// CHECK:                 Type: D3D_SVT_INT
+// CHECK:                 Rows: 1
+// CHECK:                 Columns: 4
+// CHECK:             CBuffer: MyCB
+// CHECK:         }
+// CHECK:     Bound Resources:
+// CHECK:       D3D12_SHADER_BUFFER_DESC: Name: $Globals
+// CHECK:         Type: D3D_SIT_CBUFFER
+// CHECK:         uID: 0
+// CHECK:         Dimension: D3D_SRV_DIMENSION_UNKNOWN
+// CHECK:       D3D12_SHADER_BUFFER_DESC: Name: MyCB
+// CHECK:         Type: D3D_SIT_CBUFFER
+// CHECK:         uID: 1
+// CHECK:         BindPoint: 11
+// CHECK:         Space: 2
+// CHECK:         Dimension: D3D_SRV_DIMENSION_UNKNOWN

+ 30 - 0
tools/clang/test/CodeGenHLSL/quick-test/d3dreflect/structured_buffer_getdim_stride.hlsl

@@ -0,0 +1,30 @@
+// RUN: %dxc -T lib_6_3 %s | %D3DReflect %s | FileCheck %s
+
+struct Foo
+{
+    float4 a;
+    uint b;
+};
+
+RWStructuredBuffer<Foo> g_buffer[2] : register(u0);
+
+uint UseBuf(int2 idx) {
+  return g_buffer[idx.x][idx.y].b;
+}
+
+// CHECK: ID3D12LibraryReflection:
+// CHECK:   D3D12_LIBRARY_DESC:
+// CHECK:     FunctionCount: 1
+// CHECK:   ID3D12FunctionReflection:
+// CHECK:     D3D12_FUNCTION_DESC: Name: \01?UseBuf@@YAIV?$vector@H$01@@@Z
+// CHECK:       Shader Version: Library 6.3
+// CHECK:       BoundResources: 1
+// CHECK:     Bound Resources:
+// CHECK:       D3D12_SHADER_BUFFER_DESC: Name: g_buffer
+// CHECK:         Type: D3D_SIT_UAV_RWSTRUCTURED
+// CHECK:         uID: 0
+// CHECK:         BindCount: 2
+// CHECK:         BindPoint: 0
+// CHECK:         ReturnType: D3D_RETURN_TYPE_MIXED
+// CHECK:         Dimension: D3D_SRV_DIMENSION_BUFFER
+// CHECK:         NumSamples (or stride): 40

+ 3 - 0
tools/clang/tools/driver/driver.cpp

@@ -373,6 +373,9 @@ static int ExecuteCC1Tool(ArrayRef<const char *> argv, StringRef Tool) {
 // HLSL Change: changed calling convention to __cdecl
 int __cdecl main(int argc_, const char **argv_) {
   // HLSL Change Starts
+  if (llvm::sys::fs::SetupPerThreadFileSystem())
+    return 1;
+  llvm::sys::fs::AutoCleanupPerThreadFileSystem auto_cleanup_fs;
   llvm::sys::fs::MSFileSystem* msfPtr;
   HRESULT hr;
   if (!SUCCEEDED(hr = CreateMSFileSystemForDisk(&msfPtr)))

+ 12 - 4
tools/clang/tools/dxcompiler/dxcdisassembler.cpp

@@ -676,10 +676,18 @@ void PrintStructLayout(StructType *ST, DxilTypeSystem &typeSys,
 
   unsigned fieldIndent = indent + 4;
 
-  for (unsigned i = 0; i < ST->getNumElements(); i++) {
-    PrintFieldLayout(ST->getElementType(i), annotation->GetFieldAnnotation(i),
-                     typeSys, OS, comment, offset, fieldIndent,
-                     offsetIndent - 4);
+  if (!annotation) {
+    if (!sizeOfStruct) {
+      (OS << comment).indent(indent) << "/* empty struct */\n";
+    } else {
+      (OS << comment).indent(indent) << "[" << sizeOfStruct << " x i8] (type annotation not present)\n";
+    }
+  } else {
+    for (unsigned i = 0; i < ST->getNumElements(); i++) {
+      PrintFieldLayout(ST->getElementType(i), annotation->GetFieldAnnotation(i),
+                       typeSys, OS, comment, offset, fieldIndent,
+                       offsetIndent - 4);
+    }
   }
   (OS << comment).indent(indent) << "\n";
   // The 2 in offsetIndent-indent-2 is for "} ".

+ 3 - 0
tools/clang/tools/dxl/dxl.cpp

@@ -120,6 +120,9 @@ using namespace hlsl::options;
 int __cdecl main(int argc, _In_reads_z_(argc) char **argv) {
   const char *pStage = "Operation";
   int retVal = 0;
+  if (llvm::sys::fs::SetupPerThreadFileSystem())
+    return 1;
+  llvm::sys::fs::AutoCleanupPerThreadFileSystem auto_cleanup_fs;
   if (FAILED(DxcInitThreadMalloc())) return 1;
   DxcSetThreadMallocOrDefault(nullptr);
   try {

+ 5 - 0
tools/clang/tools/dxopt/dxopt.cpp

@@ -27,6 +27,8 @@
 #include <iostream>
 #include <limits>
 
+#include "llvm/Support/FileSystem.h"
+
 inline bool wcseq(LPCWSTR a, LPCWSTR b) {
   return (a == nullptr && b == nullptr) || (a != nullptr && b != nullptr && wcscmp(a, b) == 0);
 }
@@ -211,6 +213,9 @@ static void PrintHelp() {
 int __cdecl wmain(int argc, const wchar_t **argv_) {
   const char *pStage = "Operation";
   int retVal = 0;
+  if (llvm::sys::fs::SetupPerThreadFileSystem())
+    return 1;
+  llvm::sys::fs::AutoCleanupPerThreadFileSystem auto_cleanup_fs;
   try {
     // Parse command line options.
     pStage = "Argument processing";

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

@@ -31,6 +31,7 @@ add_clang_library(clang-hlsl-tests SHARED
   FunctionTest.cpp
   HLSLTestData.h
   HlslTestUtils.h
+  D3DReflectionDumper.cpp
   LinkerTest.cpp
   MSFileSysTest.cpp
   Objects.cpp

+ 621 - 0
tools/clang/unittests/HLSL/D3DReflectionDumper.cpp

@@ -0,0 +1,621 @@
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// D3DReflectionDumper.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.                                     //
+//                                                                           //
+// Use this to dump D3D Reflection data for testing.                         //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+#include "dxc/Support/Global.h"
+#include "D3DReflectionDumper.h"
+#include "dxc/HLSL/DxilContainer.h"
+#include <sstream>
+
+// Copied from llvm/ADT/StringExtras.h
+static inline char hexdigit(unsigned X, bool LowerCase = false) {
+  const char HexChar = LowerCase ? 'a' : 'A';
+  return X < 10 ? '0' + X : HexChar + X - 10;
+}
+// Copied from lib/IR/AsmWriter.cpp
+// PrintEscapedString - Print each character of the specified string, escaping
+// it if it is not printable or if it is an escape char.
+static std::string EscapedString(const char *text) {
+  std::ostringstream ss;
+  size_t size = strlen(text);
+  for (unsigned i = 0, e = size; i != e; ++i) {
+    unsigned char C = text[i];
+    if (isprint(C) && C != '\\' && C != '"')
+      ss << C;
+    else
+      ss << '\\' << hexdigit(C >> 4) << hexdigit(C & 0x0F);
+  }
+  return ss.str();
+}
+
+LPCSTR ToString(D3D_CBUFFER_TYPE CBType) {
+  switch (CBType) {
+  case D3D_CT_CBUFFER: return "D3D_CT_CBUFFER";
+  case D3D_CT_TBUFFER: return "D3D_CT_TBUFFER";
+  case D3D_CT_INTERFACE_POINTERS: return "D3D_CT_INTERFACE_POINTERS";
+  case D3D_CT_RESOURCE_BIND_INFO: return "D3D_CT_RESOURCE_BIND_INFO";
+  default: return nullptr;
+  }
+}
+LPCSTR ToString(D3D_SHADER_INPUT_TYPE Type) {
+  switch (Type) {
+  case D3D_SIT_CBUFFER: return "D3D_SIT_CBUFFER";
+  case D3D_SIT_TBUFFER: return "D3D_SIT_TBUFFER";
+  case D3D_SIT_TEXTURE: return "D3D_SIT_TEXTURE";
+  case D3D_SIT_SAMPLER: return "D3D_SIT_SAMPLER";
+  case D3D_SIT_UAV_RWTYPED: return "D3D_SIT_UAV_RWTYPED";
+  case D3D_SIT_STRUCTURED: return "D3D_SIT_STRUCTURED";
+  case D3D_SIT_UAV_RWSTRUCTURED: return "D3D_SIT_UAV_RWSTRUCTURED";
+  case D3D_SIT_BYTEADDRESS: return "D3D_SIT_BYTEADDRESS";
+  case D3D_SIT_UAV_RWBYTEADDRESS: return "D3D_SIT_UAV_RWBYTEADDRESS";
+  case D3D_SIT_UAV_APPEND_STRUCTURED: return "D3D_SIT_UAV_APPEND_STRUCTURED";
+  case D3D_SIT_UAV_CONSUME_STRUCTURED: return "D3D_SIT_UAV_CONSUME_STRUCTURED";
+  case D3D_SIT_UAV_RWSTRUCTURED_WITH_COUNTER: return "D3D_SIT_UAV_RWSTRUCTURED_WITH_COUNTER";
+  default: return nullptr;
+  }
+}
+LPCSTR ToString(D3D_RESOURCE_RETURN_TYPE ReturnType) {
+  switch (ReturnType) {
+  case D3D_RETURN_TYPE_UNORM: return "D3D_RETURN_TYPE_UNORM";
+  case D3D_RETURN_TYPE_SNORM: return "D3D_RETURN_TYPE_SNORM";
+  case D3D_RETURN_TYPE_SINT: return "D3D_RETURN_TYPE_SINT";
+  case D3D_RETURN_TYPE_UINT: return "D3D_RETURN_TYPE_UINT";
+  case D3D_RETURN_TYPE_FLOAT: return "D3D_RETURN_TYPE_FLOAT";
+  case D3D_RETURN_TYPE_MIXED: return "D3D_RETURN_TYPE_MIXED";
+  case D3D_RETURN_TYPE_DOUBLE: return "D3D_RETURN_TYPE_DOUBLE";
+  case D3D_RETURN_TYPE_CONTINUED: return "D3D_RETURN_TYPE_CONTINUED";
+  default: return nullptr;
+  }
+}
+LPCSTR ToString(D3D_SRV_DIMENSION Dimension) {
+  switch (Dimension) {
+  case D3D_SRV_DIMENSION_UNKNOWN: return "D3D_SRV_DIMENSION_UNKNOWN";
+  case D3D_SRV_DIMENSION_BUFFER: return "D3D_SRV_DIMENSION_BUFFER";
+  case D3D_SRV_DIMENSION_TEXTURE1D: return "D3D_SRV_DIMENSION_TEXTURE1D";
+  case D3D_SRV_DIMENSION_TEXTURE1DARRAY: return "D3D_SRV_DIMENSION_TEXTURE1DARRAY";
+  case D3D_SRV_DIMENSION_TEXTURE2D: return "D3D_SRV_DIMENSION_TEXTURE2D";
+  case D3D_SRV_DIMENSION_TEXTURE2DARRAY: return "D3D_SRV_DIMENSION_TEXTURE2DARRAY";
+  case D3D_SRV_DIMENSION_TEXTURE2DMS: return "D3D_SRV_DIMENSION_TEXTURE2DMS";
+  case D3D_SRV_DIMENSION_TEXTURE2DMSARRAY: return "D3D_SRV_DIMENSION_TEXTURE2DMSARRAY";
+  case D3D_SRV_DIMENSION_TEXTURE3D: return "D3D_SRV_DIMENSION_TEXTURE3D";
+  case D3D_SRV_DIMENSION_TEXTURECUBE: return "D3D_SRV_DIMENSION_TEXTURECUBE";
+  case D3D_SRV_DIMENSION_TEXTURECUBEARRAY: return "D3D_SRV_DIMENSION_TEXTURECUBEARRAY";
+  case D3D_SRV_DIMENSION_BUFFEREX: return "D3D_SRV_DIMENSION_BUFFEREX";
+  default: return nullptr;
+  }
+}
+LPCSTR ToString(D3D_PRIMITIVE_TOPOLOGY GSOutputTopology) {
+  switch (GSOutputTopology) {
+  case D3D_PRIMITIVE_TOPOLOGY_UNDEFINED: return "D3D_PRIMITIVE_TOPOLOGY_UNDEFINED";
+  case D3D_PRIMITIVE_TOPOLOGY_POINTLIST: return "D3D_PRIMITIVE_TOPOLOGY_POINTLIST";
+  case D3D_PRIMITIVE_TOPOLOGY_LINELIST: return "D3D_PRIMITIVE_TOPOLOGY_LINELIST";
+  case D3D_PRIMITIVE_TOPOLOGY_LINESTRIP: return "D3D_PRIMITIVE_TOPOLOGY_LINESTRIP";
+  case D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST: return "D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST";
+  case D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP: return "D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP";
+  case D3D_PRIMITIVE_TOPOLOGY_LINELIST_ADJ: return "D3D_PRIMITIVE_TOPOLOGY_LINELIST_ADJ";
+  case D3D_PRIMITIVE_TOPOLOGY_LINESTRIP_ADJ: return "D3D_PRIMITIVE_TOPOLOGY_LINESTRIP_ADJ";
+  case D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST_ADJ: return "D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST_ADJ";
+  case D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP_ADJ: return "D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP_ADJ";
+  case D3D_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST: return "D3D_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST";
+  case D3D_PRIMITIVE_TOPOLOGY_2_CONTROL_POINT_PATCHLIST: return "D3D_PRIMITIVE_TOPOLOGY_2_CONTROL_POINT_PATCHLIST";
+  case D3D_PRIMITIVE_TOPOLOGY_3_CONTROL_POINT_PATCHLIST: return "D3D_PRIMITIVE_TOPOLOGY_3_CONTROL_POINT_PATCHLIST";
+  case D3D_PRIMITIVE_TOPOLOGY_4_CONTROL_POINT_PATCHLIST: return "D3D_PRIMITIVE_TOPOLOGY_4_CONTROL_POINT_PATCHLIST";
+  case D3D_PRIMITIVE_TOPOLOGY_5_CONTROL_POINT_PATCHLIST: return "D3D_PRIMITIVE_TOPOLOGY_5_CONTROL_POINT_PATCHLIST";
+  case D3D_PRIMITIVE_TOPOLOGY_6_CONTROL_POINT_PATCHLIST: return "D3D_PRIMITIVE_TOPOLOGY_6_CONTROL_POINT_PATCHLIST";
+  case D3D_PRIMITIVE_TOPOLOGY_7_CONTROL_POINT_PATCHLIST: return "D3D_PRIMITIVE_TOPOLOGY_7_CONTROL_POINT_PATCHLIST";
+  case D3D_PRIMITIVE_TOPOLOGY_8_CONTROL_POINT_PATCHLIST: return "D3D_PRIMITIVE_TOPOLOGY_8_CONTROL_POINT_PATCHLIST";
+  case D3D_PRIMITIVE_TOPOLOGY_9_CONTROL_POINT_PATCHLIST: return "D3D_PRIMITIVE_TOPOLOGY_9_CONTROL_POINT_PATCHLIST";
+  case D3D_PRIMITIVE_TOPOLOGY_10_CONTROL_POINT_PATCHLIST: return "D3D_PRIMITIVE_TOPOLOGY_10_CONTROL_POINT_PATCHLIST";
+  case D3D_PRIMITIVE_TOPOLOGY_11_CONTROL_POINT_PATCHLIST: return "D3D_PRIMITIVE_TOPOLOGY_11_CONTROL_POINT_PATCHLIST";
+  case D3D_PRIMITIVE_TOPOLOGY_12_CONTROL_POINT_PATCHLIST: return "D3D_PRIMITIVE_TOPOLOGY_12_CONTROL_POINT_PATCHLIST";
+  case D3D_PRIMITIVE_TOPOLOGY_13_CONTROL_POINT_PATCHLIST: return "D3D_PRIMITIVE_TOPOLOGY_13_CONTROL_POINT_PATCHLIST";
+  case D3D_PRIMITIVE_TOPOLOGY_14_CONTROL_POINT_PATCHLIST: return "D3D_PRIMITIVE_TOPOLOGY_14_CONTROL_POINT_PATCHLIST";
+  case D3D_PRIMITIVE_TOPOLOGY_15_CONTROL_POINT_PATCHLIST: return "D3D_PRIMITIVE_TOPOLOGY_15_CONTROL_POINT_PATCHLIST";
+  case D3D_PRIMITIVE_TOPOLOGY_16_CONTROL_POINT_PATCHLIST: return "D3D_PRIMITIVE_TOPOLOGY_16_CONTROL_POINT_PATCHLIST";
+  case D3D_PRIMITIVE_TOPOLOGY_17_CONTROL_POINT_PATCHLIST: return "D3D_PRIMITIVE_TOPOLOGY_17_CONTROL_POINT_PATCHLIST";
+  case D3D_PRIMITIVE_TOPOLOGY_18_CONTROL_POINT_PATCHLIST: return "D3D_PRIMITIVE_TOPOLOGY_18_CONTROL_POINT_PATCHLIST";
+  case D3D_PRIMITIVE_TOPOLOGY_19_CONTROL_POINT_PATCHLIST: return "D3D_PRIMITIVE_TOPOLOGY_19_CONTROL_POINT_PATCHLIST";
+  case D3D_PRIMITIVE_TOPOLOGY_20_CONTROL_POINT_PATCHLIST: return "D3D_PRIMITIVE_TOPOLOGY_20_CONTROL_POINT_PATCHLIST";
+  case D3D_PRIMITIVE_TOPOLOGY_21_CONTROL_POINT_PATCHLIST: return "D3D_PRIMITIVE_TOPOLOGY_21_CONTROL_POINT_PATCHLIST";
+  case D3D_PRIMITIVE_TOPOLOGY_22_CONTROL_POINT_PATCHLIST: return "D3D_PRIMITIVE_TOPOLOGY_22_CONTROL_POINT_PATCHLIST";
+  case D3D_PRIMITIVE_TOPOLOGY_23_CONTROL_POINT_PATCHLIST: return "D3D_PRIMITIVE_TOPOLOGY_23_CONTROL_POINT_PATCHLIST";
+  case D3D_PRIMITIVE_TOPOLOGY_24_CONTROL_POINT_PATCHLIST: return "D3D_PRIMITIVE_TOPOLOGY_24_CONTROL_POINT_PATCHLIST";
+  case D3D_PRIMITIVE_TOPOLOGY_25_CONTROL_POINT_PATCHLIST: return "D3D_PRIMITIVE_TOPOLOGY_25_CONTROL_POINT_PATCHLIST";
+  case D3D_PRIMITIVE_TOPOLOGY_26_CONTROL_POINT_PATCHLIST: return "D3D_PRIMITIVE_TOPOLOGY_26_CONTROL_POINT_PATCHLIST";
+  case D3D_PRIMITIVE_TOPOLOGY_27_CONTROL_POINT_PATCHLIST: return "D3D_PRIMITIVE_TOPOLOGY_27_CONTROL_POINT_PATCHLIST";
+  case D3D_PRIMITIVE_TOPOLOGY_28_CONTROL_POINT_PATCHLIST: return "D3D_PRIMITIVE_TOPOLOGY_28_CONTROL_POINT_PATCHLIST";
+  case D3D_PRIMITIVE_TOPOLOGY_29_CONTROL_POINT_PATCHLIST: return "D3D_PRIMITIVE_TOPOLOGY_29_CONTROL_POINT_PATCHLIST";
+  case D3D_PRIMITIVE_TOPOLOGY_30_CONTROL_POINT_PATCHLIST: return "D3D_PRIMITIVE_TOPOLOGY_30_CONTROL_POINT_PATCHLIST";
+  case D3D_PRIMITIVE_TOPOLOGY_31_CONTROL_POINT_PATCHLIST: return "D3D_PRIMITIVE_TOPOLOGY_31_CONTROL_POINT_PATCHLIST";
+  case D3D_PRIMITIVE_TOPOLOGY_32_CONTROL_POINT_PATCHLIST: return "D3D_PRIMITIVE_TOPOLOGY_32_CONTROL_POINT_PATCHLIST";
+  default: return nullptr;
+  }
+}
+LPCSTR ToString(D3D_PRIMITIVE InputPrimitive) {
+  switch (InputPrimitive) {
+  case D3D_PRIMITIVE_UNDEFINED: return "D3D_PRIMITIVE_UNDEFINED";
+  case D3D_PRIMITIVE_POINT: return "D3D_PRIMITIVE_POINT";
+  case D3D_PRIMITIVE_LINE: return "D3D_PRIMITIVE_LINE";
+  case D3D_PRIMITIVE_TRIANGLE: return "D3D_PRIMITIVE_TRIANGLE";
+  case D3D_PRIMITIVE_LINE_ADJ: return "D3D_PRIMITIVE_LINE_ADJ";
+  case D3D_PRIMITIVE_TRIANGLE_ADJ: return "D3D_PRIMITIVE_TRIANGLE_ADJ";
+  case D3D_PRIMITIVE_1_CONTROL_POINT_PATCH: return "D3D_PRIMITIVE_1_CONTROL_POINT_PATCH";
+  case D3D_PRIMITIVE_2_CONTROL_POINT_PATCH: return "D3D_PRIMITIVE_2_CONTROL_POINT_PATCH";
+  case D3D_PRIMITIVE_3_CONTROL_POINT_PATCH: return "D3D_PRIMITIVE_3_CONTROL_POINT_PATCH";
+  case D3D_PRIMITIVE_4_CONTROL_POINT_PATCH: return "D3D_PRIMITIVE_4_CONTROL_POINT_PATCH";
+  case D3D_PRIMITIVE_5_CONTROL_POINT_PATCH: return "D3D_PRIMITIVE_5_CONTROL_POINT_PATCH";
+  case D3D_PRIMITIVE_6_CONTROL_POINT_PATCH: return "D3D_PRIMITIVE_6_CONTROL_POINT_PATCH";
+  case D3D_PRIMITIVE_7_CONTROL_POINT_PATCH: return "D3D_PRIMITIVE_7_CONTROL_POINT_PATCH";
+  case D3D_PRIMITIVE_8_CONTROL_POINT_PATCH: return "D3D_PRIMITIVE_8_CONTROL_POINT_PATCH";
+  case D3D_PRIMITIVE_9_CONTROL_POINT_PATCH: return "D3D_PRIMITIVE_9_CONTROL_POINT_PATCH";
+  case D3D_PRIMITIVE_10_CONTROL_POINT_PATCH: return "D3D_PRIMITIVE_10_CONTROL_POINT_PATCH";
+  case D3D_PRIMITIVE_11_CONTROL_POINT_PATCH: return "D3D_PRIMITIVE_11_CONTROL_POINT_PATCH";
+  case D3D_PRIMITIVE_12_CONTROL_POINT_PATCH: return "D3D_PRIMITIVE_12_CONTROL_POINT_PATCH";
+  case D3D_PRIMITIVE_13_CONTROL_POINT_PATCH: return "D3D_PRIMITIVE_13_CONTROL_POINT_PATCH";
+  case D3D_PRIMITIVE_14_CONTROL_POINT_PATCH: return "D3D_PRIMITIVE_14_CONTROL_POINT_PATCH";
+  case D3D_PRIMITIVE_15_CONTROL_POINT_PATCH: return "D3D_PRIMITIVE_15_CONTROL_POINT_PATCH";
+  case D3D_PRIMITIVE_16_CONTROL_POINT_PATCH: return "D3D_PRIMITIVE_16_CONTROL_POINT_PATCH";
+  case D3D_PRIMITIVE_17_CONTROL_POINT_PATCH: return "D3D_PRIMITIVE_17_CONTROL_POINT_PATCH";
+  case D3D_PRIMITIVE_18_CONTROL_POINT_PATCH: return "D3D_PRIMITIVE_18_CONTROL_POINT_PATCH";
+  case D3D_PRIMITIVE_19_CONTROL_POINT_PATCH: return "D3D_PRIMITIVE_19_CONTROL_POINT_PATCH";
+  case D3D_PRIMITIVE_20_CONTROL_POINT_PATCH: return "D3D_PRIMITIVE_20_CONTROL_POINT_PATCH";
+  case D3D_PRIMITIVE_21_CONTROL_POINT_PATCH: return "D3D_PRIMITIVE_21_CONTROL_POINT_PATCH";
+  case D3D_PRIMITIVE_22_CONTROL_POINT_PATCH: return "D3D_PRIMITIVE_22_CONTROL_POINT_PATCH";
+  case D3D_PRIMITIVE_23_CONTROL_POINT_PATCH: return "D3D_PRIMITIVE_23_CONTROL_POINT_PATCH";
+  case D3D_PRIMITIVE_24_CONTROL_POINT_PATCH: return "D3D_PRIMITIVE_24_CONTROL_POINT_PATCH";
+  case D3D_PRIMITIVE_25_CONTROL_POINT_PATCH: return "D3D_PRIMITIVE_25_CONTROL_POINT_PATCH";
+  case D3D_PRIMITIVE_26_CONTROL_POINT_PATCH: return "D3D_PRIMITIVE_26_CONTROL_POINT_PATCH";
+  case D3D_PRIMITIVE_27_CONTROL_POINT_PATCH: return "D3D_PRIMITIVE_27_CONTROL_POINT_PATCH";
+  case D3D_PRIMITIVE_28_CONTROL_POINT_PATCH: return "D3D_PRIMITIVE_28_CONTROL_POINT_PATCH";
+  case D3D_PRIMITIVE_29_CONTROL_POINT_PATCH: return "D3D_PRIMITIVE_29_CONTROL_POINT_PATCH";
+  case D3D_PRIMITIVE_30_CONTROL_POINT_PATCH: return "D3D_PRIMITIVE_30_CONTROL_POINT_PATCH";
+  case D3D_PRIMITIVE_31_CONTROL_POINT_PATCH: return "D3D_PRIMITIVE_31_CONTROL_POINT_PATCH";
+  case D3D_PRIMITIVE_32_CONTROL_POINT_PATCH: return "D3D_PRIMITIVE_32_CONTROL_POINT_PATCH";
+  default: return nullptr;
+  }
+}
+LPCSTR ToString(D3D_TESSELLATOR_OUTPUT_PRIMITIVE HSOutputPrimitive) {
+  switch (HSOutputPrimitive) {
+  case D3D_TESSELLATOR_OUTPUT_UNDEFINED: return "D3D_TESSELLATOR_OUTPUT_UNDEFINED";
+  case D3D_TESSELLATOR_OUTPUT_POINT: return "D3D_TESSELLATOR_OUTPUT_POINT";
+  case D3D_TESSELLATOR_OUTPUT_LINE: return "D3D_TESSELLATOR_OUTPUT_LINE";
+  case D3D_TESSELLATOR_OUTPUT_TRIANGLE_CW: return "D3D_TESSELLATOR_OUTPUT_TRIANGLE_CW";
+  case D3D_TESSELLATOR_OUTPUT_TRIANGLE_CCW: return "D3D_TESSELLATOR_OUTPUT_TRIANGLE_CCW";
+  default: return nullptr;
+  }
+}
+LPCSTR ToString(D3D_TESSELLATOR_PARTITIONING HSPartitioning) {
+  switch (HSPartitioning) {
+  case D3D_TESSELLATOR_PARTITIONING_UNDEFINED: return "D3D_TESSELLATOR_PARTITIONING_UNDEFINED";
+  case D3D_TESSELLATOR_PARTITIONING_INTEGER: return "D3D_TESSELLATOR_PARTITIONING_INTEGER";
+  case D3D_TESSELLATOR_PARTITIONING_POW2: return "D3D_TESSELLATOR_PARTITIONING_POW2";
+  case D3D_TESSELLATOR_PARTITIONING_FRACTIONAL_ODD: return "D3D_TESSELLATOR_PARTITIONING_FRACTIONAL_ODD";
+  case D3D_TESSELLATOR_PARTITIONING_FRACTIONAL_EVEN: return "D3D_TESSELLATOR_PARTITIONING_FRACTIONAL_EVEN";
+  default: return nullptr;
+  }
+}
+LPCSTR ToString(D3D_TESSELLATOR_DOMAIN TessellatorDomain) {
+  switch (TessellatorDomain) {
+  case D3D_TESSELLATOR_DOMAIN_UNDEFINED: return "D3D_TESSELLATOR_DOMAIN_UNDEFINED";
+  case D3D_TESSELLATOR_DOMAIN_ISOLINE: return "D3D_TESSELLATOR_DOMAIN_ISOLINE";
+  case D3D_TESSELLATOR_DOMAIN_TRI: return "D3D_TESSELLATOR_DOMAIN_TRI";
+  case D3D_TESSELLATOR_DOMAIN_QUAD: return "D3D_TESSELLATOR_DOMAIN_QUAD";
+  default: return nullptr;
+  }
+}
+LPCSTR ToString(D3D_SHADER_VARIABLE_CLASS Class) {
+  switch (Class) {
+  case D3D_SVC_SCALAR: return "D3D_SVC_SCALAR";
+  case D3D_SVC_VECTOR: return "D3D_SVC_VECTOR";
+  case D3D_SVC_MATRIX_ROWS: return "D3D_SVC_MATRIX_ROWS";
+  case D3D_SVC_MATRIX_COLUMNS: return "D3D_SVC_MATRIX_COLUMNS";
+  case D3D_SVC_OBJECT: return "D3D_SVC_OBJECT";
+  case D3D_SVC_STRUCT: return "D3D_SVC_STRUCT";
+  case D3D_SVC_INTERFACE_CLASS: return "D3D_SVC_INTERFACE_CLASS";
+  case D3D_SVC_INTERFACE_POINTER: return "D3D_SVC_INTERFACE_POINTER";
+  default: return nullptr;
+  }
+}
+LPCSTR ToString(D3D_SHADER_VARIABLE_TYPE Type) {
+  switch (Type) {
+  case D3D_SVT_VOID: return "D3D_SVT_VOID";
+  case D3D_SVT_BOOL: return "D3D_SVT_BOOL";
+  case D3D_SVT_INT: return "D3D_SVT_INT";
+  case D3D_SVT_FLOAT: return "D3D_SVT_FLOAT";
+  case D3D_SVT_STRING: return "D3D_SVT_STRING";
+  case D3D_SVT_TEXTURE: return "D3D_SVT_TEXTURE";
+  case D3D_SVT_TEXTURE1D: return "D3D_SVT_TEXTURE1D";
+  case D3D_SVT_TEXTURE2D: return "D3D_SVT_TEXTURE2D";
+  case D3D_SVT_TEXTURE3D: return "D3D_SVT_TEXTURE3D";
+  case D3D_SVT_TEXTURECUBE: return "D3D_SVT_TEXTURECUBE";
+  case D3D_SVT_SAMPLER: return "D3D_SVT_SAMPLER";
+  case D3D_SVT_SAMPLER1D: return "D3D_SVT_SAMPLER1D";
+  case D3D_SVT_SAMPLER2D: return "D3D_SVT_SAMPLER2D";
+  case D3D_SVT_SAMPLER3D: return "D3D_SVT_SAMPLER3D";
+  case D3D_SVT_SAMPLERCUBE: return "D3D_SVT_SAMPLERCUBE";
+  case D3D_SVT_PIXELSHADER: return "D3D_SVT_PIXELSHADER";
+  case D3D_SVT_VERTEXSHADER: return "D3D_SVT_VERTEXSHADER";
+  case D3D_SVT_PIXELFRAGMENT: return "D3D_SVT_PIXELFRAGMENT";
+  case D3D_SVT_VERTEXFRAGMENT: return "D3D_SVT_VERTEXFRAGMENT";
+  case D3D_SVT_UINT: return "D3D_SVT_UINT";
+  case D3D_SVT_UINT8: return "D3D_SVT_UINT8";
+  case D3D_SVT_GEOMETRYSHADER: return "D3D_SVT_GEOMETRYSHADER";
+  case D3D_SVT_RASTERIZER: return "D3D_SVT_RASTERIZER";
+  case D3D_SVT_DEPTHSTENCIL: return "D3D_SVT_DEPTHSTENCIL";
+  case D3D_SVT_BLEND: return "D3D_SVT_BLEND";
+  case D3D_SVT_BUFFER: return "D3D_SVT_BUFFER";
+  case D3D_SVT_CBUFFER: return "D3D_SVT_CBUFFER";
+  case D3D_SVT_TBUFFER: return "D3D_SVT_TBUFFER";
+  case D3D_SVT_TEXTURE1DARRAY: return "D3D_SVT_TEXTURE1DARRAY";
+  case D3D_SVT_TEXTURE2DARRAY: return "D3D_SVT_TEXTURE2DARRAY";
+  case D3D_SVT_RENDERTARGETVIEW: return "D3D_SVT_RENDERTARGETVIEW";
+  case D3D_SVT_DEPTHSTENCILVIEW: return "D3D_SVT_DEPTHSTENCILVIEW";
+  case D3D_SVT_TEXTURE2DMS: return "D3D_SVT_TEXTURE2DMS";
+  case D3D_SVT_TEXTURE2DMSARRAY: return "D3D_SVT_TEXTURE2DMSARRAY";
+  case D3D_SVT_TEXTURECUBEARRAY: return "D3D_SVT_TEXTURECUBEARRAY";
+  case D3D_SVT_HULLSHADER: return "D3D_SVT_HULLSHADER";
+  case D3D_SVT_DOMAINSHADER: return "D3D_SVT_DOMAINSHADER";
+  case D3D_SVT_INTERFACE_POINTER: return "D3D_SVT_INTERFACE_POINTER";
+  case D3D_SVT_COMPUTESHADER: return "D3D_SVT_COMPUTESHADER";
+  case D3D_SVT_DOUBLE: return "D3D_SVT_DOUBLE";
+  case D3D_SVT_RWTEXTURE1D: return "D3D_SVT_RWTEXTURE1D";
+  case D3D_SVT_RWTEXTURE1DARRAY: return "D3D_SVT_RWTEXTURE1DARRAY";
+  case D3D_SVT_RWTEXTURE2D: return "D3D_SVT_RWTEXTURE2D";
+  case D3D_SVT_RWTEXTURE2DARRAY: return "D3D_SVT_RWTEXTURE2DARRAY";
+  case D3D_SVT_RWTEXTURE3D: return "D3D_SVT_RWTEXTURE3D";
+  case D3D_SVT_RWBUFFER: return "D3D_SVT_RWBUFFER";
+  case D3D_SVT_BYTEADDRESS_BUFFER: return "D3D_SVT_BYTEADDRESS_BUFFER";
+  case D3D_SVT_RWBYTEADDRESS_BUFFER: return "D3D_SVT_RWBYTEADDRESS_BUFFER";
+  case D3D_SVT_STRUCTURED_BUFFER: return "D3D_SVT_STRUCTURED_BUFFER";
+  case D3D_SVT_RWSTRUCTURED_BUFFER: return "D3D_SVT_RWSTRUCTURED_BUFFER";
+  case D3D_SVT_APPEND_STRUCTURED_BUFFER: return "D3D_SVT_APPEND_STRUCTURED_BUFFER";
+  case D3D_SVT_CONSUME_STRUCTURED_BUFFER: return "D3D_SVT_CONSUME_STRUCTURED_BUFFER";
+  case D3D_SVT_MIN8FLOAT: return "D3D_SVT_MIN8FLOAT";
+  case D3D_SVT_MIN10FLOAT: return "D3D_SVT_MIN10FLOAT";
+  case D3D_SVT_MIN16FLOAT: return "D3D_SVT_MIN16FLOAT";
+  case D3D_SVT_MIN12INT: return "D3D_SVT_MIN12INT";
+  case D3D_SVT_MIN16INT: return "D3D_SVT_MIN16INT";
+  case D3D_SVT_MIN16UINT: return "D3D_SVT_MIN16UINT";
+  default: return nullptr;
+  }
+}
+
+void D3DReflectionDumper::DumpDefaultValue(LPCVOID pDefaultValue, UINT Size) {
+  WriteLn("DefaultValue: ", pDefaultValue ? "<present>" : "<nullptr>");    // TODO: Dump DefaultValue
+}
+void D3DReflectionDumper::DumpShaderVersion(UINT Version) {
+  const char *szType = "<unknown>";
+  UINT Type = D3D12_SHVER_GET_TYPE(Version);
+  switch (Type) {
+  case (UINT)hlsl::DXIL::ShaderKind::Pixel: szType = "Pixel"; break;
+  case (UINT)hlsl::DXIL::ShaderKind::Vertex: szType = "Vertex"; break;
+  case (UINT)hlsl::DXIL::ShaderKind::Geometry: szType = "Geometry"; break;
+  case (UINT)hlsl::DXIL::ShaderKind::Hull: szType = "Hull"; break;
+  case (UINT)hlsl::DXIL::ShaderKind::Domain: szType = "Domain"; break;
+  case (UINT)hlsl::DXIL::ShaderKind::Compute: szType = "Compute"; break;
+  case (UINT)hlsl::DXIL::ShaderKind::Library: szType = "Library"; break;
+  case (UINT)hlsl::DXIL::ShaderKind::RayGeneration: szType = "RayGeneration"; break;
+  case (UINT)hlsl::DXIL::ShaderKind::Intersection: szType = "Intersection"; break;
+  case (UINT)hlsl::DXIL::ShaderKind::AnyHit: szType = "AnyHit"; break;
+  case (UINT)hlsl::DXIL::ShaderKind::ClosestHit: szType = "ClosestHit"; break;
+  case (UINT)hlsl::DXIL::ShaderKind::Miss: szType = "Miss"; break;
+  case (UINT)hlsl::DXIL::ShaderKind::Callable: szType = "Callable"; break;
+  case (UINT)hlsl::DXIL::ShaderKind::Invalid: szType = "Invalid"; break;
+  }
+  UINT Major = D3D12_SHVER_GET_MAJOR(Version);
+  UINT Minor = D3D12_SHVER_GET_MINOR(Version);
+  WriteLn("Shader Version: ", szType, " ", Major, ".", Minor);
+}
+
+void D3DReflectionDumper::Dump(D3D12_SHADER_TYPE_DESC &tyDesc) {
+  SetLastName(tyDesc.Name);
+  WriteLn("D3D12_SHADER_TYPE_DESC: Name: ", m_LastName);
+  Indent();
+  DumpEnum("Class", tyDesc.Class);
+  DumpEnum("Type", tyDesc.Type);
+  WriteLn("Elements: ", tyDesc.Elements);
+  WriteLn("Rows: ", tyDesc.Rows);
+  WriteLn("Columns: ", tyDesc.Columns);
+  WriteLn("Members: ", tyDesc.Members);
+  WriteLn("Offset: ", tyDesc.Offset);
+  Dedent();
+}
+void D3DReflectionDumper::Dump(D3D12_SHADER_VARIABLE_DESC &varDesc) {
+  SetLastName(varDesc.Name);
+  WriteLn("D3D12_SHADER_VARIABLE_DESC: Name: ", m_LastName);
+  Indent();
+  WriteLn("Size: ", varDesc.Size);
+  WriteLn("StartOffset: ", varDesc.StartOffset);
+  WriteLn("uFlags: ", std::hex, std::showbase, varDesc.uFlags);
+  DumpDefaultValue(varDesc.DefaultValue, varDesc.Size);
+  Dedent();
+}
+void D3DReflectionDumper::Dump(D3D12_SHADER_BUFFER_DESC &Desc) {
+  SetLastName(Desc.Name);
+  WriteLn("D3D12_SHADER_BUFFER_DESC: Name: ", m_LastName);
+  Indent();
+  DumpEnum("Type", Desc.Type);
+  WriteLn("Size: ", Desc.Size);
+  WriteLn("uFlags: ", std::hex, std::showbase, Desc.uFlags);
+  WriteLn("Num Variables: ", Desc.Variables);
+  Dedent();
+}
+void D3DReflectionDumper::Dump(D3D12_SHADER_INPUT_BIND_DESC &resDesc) {
+  SetLastName(resDesc.Name);
+  WriteLn("D3D12_SHADER_BUFFER_DESC: Name: ", m_LastName);
+  Indent();
+  DumpEnum("Type", resDesc.Type);
+  WriteLn("uID: ", resDesc.uID);
+  WriteLn("BindCount: ", resDesc.BindCount);
+  WriteLn("BindPoint: ", resDesc.BindPoint);
+  WriteLn("Space: ", resDesc.Space);
+  DumpEnum("ReturnType", resDesc.ReturnType);
+  DumpEnum("Dimension", resDesc.Dimension);
+  WriteLn("NumSamples (or stride): ", resDesc.NumSamples);
+  WriteLn("uFlags: ", std::hex, std::showbase, resDesc.uFlags);
+  Dedent();
+}
+void D3DReflectionDumper::Dump(D3D12_SHADER_DESC &Desc) {
+  WriteLn("D3D12_SHADER_BUFFER_DESC:");
+  Indent();
+  DumpShaderVersion(Desc.Version);
+  WriteLn("Creator: ", Desc.Creator ? Desc.Creator : "<nullptr>");
+  WriteLn("Flags: ", std::hex, std::showbase, Desc.Flags);
+  WriteLn("ConstantBuffers: ", Desc.ConstantBuffers);
+  WriteLn("BoundResources: ", Desc.BoundResources);
+  WriteLn("InputParameters: ", Desc.InputParameters);
+  WriteLn("OutputParameters: ", Desc.OutputParameters);
+  hlsl::DXIL::ShaderKind ShaderKind = (hlsl::DXIL::ShaderKind)D3D12_SHVER_GET_TYPE(Desc.Version);
+  if (ShaderKind == hlsl::DXIL::ShaderKind::Geometry) {
+    WriteLn("cGSInstanceCount: ", Desc.cGSInstanceCount);
+    WriteLn("GSMaxOutputVertexCount: ", Desc.GSMaxOutputVertexCount);
+    DumpEnum("GSOutputTopology", Desc.GSOutputTopology);
+    DumpEnum("InputPrimitive", Desc.InputPrimitive);
+  }
+  if (ShaderKind == hlsl::DXIL::ShaderKind::Hull) {
+    WriteLn("PatchConstantParameters: ", Desc.PatchConstantParameters);
+    WriteLn("cControlPoints: ", Desc.cControlPoints);
+    DumpEnum("InputPrimitive", Desc.InputPrimitive);
+    DumpEnum("HSOutputPrimitive", Desc.HSOutputPrimitive);
+    DumpEnum("HSPartitioning", Desc.HSPartitioning);
+    DumpEnum("TessellatorDomain", Desc.TessellatorDomain);
+  }
+  if (ShaderKind == hlsl::DXIL::ShaderKind::Domain) {
+    WriteLn("PatchConstantParameters: ", Desc.PatchConstantParameters);
+    WriteLn("cControlPoints: ", Desc.cControlPoints);
+    DumpEnum("TessellatorDomain", Desc.TessellatorDomain);
+  }
+  // TODO
+  Dedent();
+}
+void D3DReflectionDumper::Dump(D3D12_FUNCTION_DESC &Desc) {
+  SetLastName(Desc.Name);
+  WriteLn("D3D12_FUNCTION_DESC: Name: ", EscapedString(m_LastName));
+  Indent();
+  DumpShaderVersion(Desc.Version);
+  WriteLn("Creator: ", Desc.Creator ? Desc.Creator : "<nullptr>");
+  WriteLn("Flags: ", std::hex, std::showbase, Desc.Flags);
+  WriteLn("ConstantBuffers: ", Desc.ConstantBuffers);
+  WriteLn("BoundResources: ", Desc.BoundResources);
+  WriteLn("FunctionParameterCount: ", Desc.FunctionParameterCount);
+  WriteLn("HasReturn: ", Desc.HasReturn ? "TRUE" : "FALSE");
+  Dedent();
+}
+void D3DReflectionDumper::Dump(D3D12_LIBRARY_DESC &Desc) {
+  WriteLn("D3D12_LIBRARY_DESC:");
+  Indent();
+  WriteLn("Creator: ", Desc.Creator ? Desc.Creator : "<nullptr>");
+  WriteLn("Flags: ", std::hex, std::showbase, Desc.Flags);
+  WriteLn("FunctionCount: ", Desc.FunctionCount);
+  Dedent();
+}
+
+void D3DReflectionDumper::Dump(ID3D12ShaderReflectionType *pType) {
+  WriteLn("ID3D12ShaderReflectionType:");
+  Indent();
+  D3D12_SHADER_TYPE_DESC tyDesc;
+  if (!pType || FAILED(pType->GetDesc(&tyDesc))) {
+    Failure("GetDesc");
+    Dedent();
+    return;
+  }
+  Dump(tyDesc);
+  if (tyDesc.Members) {
+    WriteLn("{");
+    Indent();
+    for (UINT uMember = 0; uMember < tyDesc.Members; uMember++) {
+      Dump(pType->GetMemberTypeByIndex(uMember));
+    }
+    Dedent();
+    WriteLn("}");
+  }
+  Dedent();
+}
+void D3DReflectionDumper::Dump(ID3D12ShaderReflectionVariable *pVar) {
+  WriteLn("ID3D12ShaderReflectionVariable:");
+  Indent();
+  D3D12_SHADER_VARIABLE_DESC varDesc;
+  if (!pVar || FAILED(pVar->GetDesc(&varDesc))) {
+    Failure("GetDesc");
+    Dedent();
+    return;
+  }
+  Dump(varDesc);
+  Dump(pVar->GetType());
+  ID3D12ShaderReflectionConstantBuffer* pCB = pVar->GetBuffer();
+  D3D12_SHADER_BUFFER_DESC CBDesc;
+  if (pCB && SUCCEEDED(pCB->GetDesc(&CBDesc))) {
+    WriteLn("CBuffer: ", CBDesc.Name);
+  }
+  Dedent();
+}
+
+void D3DReflectionDumper::Dump(ID3D12ShaderReflectionConstantBuffer *pCBReflection) {
+  WriteLn("ID3D12ShaderReflectionConstantBuffer:");
+  Indent();
+  D3D12_SHADER_BUFFER_DESC Desc;
+  if (!pCBReflection || FAILED(pCBReflection->GetDesc(&Desc))) {
+    Failure("GetDesc");
+    Dedent();
+    return;
+  }
+  Dump(Desc);
+  if (Desc.Variables) {
+    WriteLn("{");
+    Indent();
+    bool bCheckByNameFailed = false;
+    for (UINT uVar = 0; uVar < Desc.Variables; uVar++) {
+      if (m_bCheckByName)
+        SetLastName();
+      ID3D12ShaderReflectionVariable *pVar = pCBReflection->GetVariableByIndex(uVar);
+      Dump(pVar);
+      if (m_bCheckByName) {
+        if (pCBReflection->GetVariableByName(m_LastName) != pVar) {
+          bCheckByNameFailed = true;
+          Failure("GetVariableByName ", m_LastName);
+        }
+      }
+    }
+    if (m_bCheckByName && !bCheckByNameFailed) {
+      WriteLn("GetVariableByName checks succeeded.");
+    }
+    Dedent();
+    WriteLn("}");
+  }
+  Dedent();
+}
+
+void D3DReflectionDumper::Dump(ID3D12ShaderReflection *pShaderReflection) {
+  WriteLn("ID3D12ShaderReflection:");
+  Indent();
+  D3D12_SHADER_DESC Desc;
+  if (!pShaderReflection || FAILED(pShaderReflection->GetDesc(&Desc))) {
+    Failure("GetDesc");
+    Dedent();
+    return;
+  }
+  Dump(Desc);
+  if (Desc.ConstantBuffers) {
+    WriteLn("Constant Buffers:");
+    Indent();
+    bool bCheckByNameFailed = false;
+    for (UINT uCB = 0; uCB < Desc.ConstantBuffers; uCB++) {
+      ID3D12ShaderReflectionConstantBuffer *pCB = pShaderReflection->GetConstantBufferByIndex(uCB);
+      Dump(pCB);
+      if (m_bCheckByName && m_LastName) {
+        if (pShaderReflection->GetConstantBufferByName(m_LastName) != pCB) {
+          bCheckByNameFailed = true;
+          Failure("GetConstantBufferByName ", m_LastName);
+        }
+      }
+    }
+    if (m_bCheckByName && !bCheckByNameFailed) {
+      WriteLn("GetConstantBufferByName checks succeeded.");
+    }
+    Dedent();
+  }
+  if (Desc.BoundResources) {
+    WriteLn("Bound Resources:");
+    Indent();
+    bool bCheckByNameFailed = false;
+    for (UINT uRes = 0; uRes < Desc.BoundResources; uRes++) {
+      D3D12_SHADER_INPUT_BIND_DESC bindDesc;
+      if (FAILED(pShaderReflection->GetResourceBindingDesc(uRes, &bindDesc))) {
+      }
+      Dump(bindDesc);
+      if (m_bCheckByName && bindDesc.Name) {
+        D3D12_SHADER_INPUT_BIND_DESC bindDesc2;
+        if (FAILED(pShaderReflection->GetResourceBindingDescByName(bindDesc.Name, &bindDesc2)) || bindDesc2.Name != bindDesc.Name) {
+          bCheckByNameFailed = true;
+          Failure("GetResourceBindingDescByName ", bindDesc.Name);
+        }
+      }
+    }
+    if (m_bCheckByName && !bCheckByNameFailed) {
+      WriteLn("GetResourceBindingDescByName checks succeeded.");
+    }
+    Dedent();
+  }
+  // TODO
+  Dedent();
+}
+
+void D3DReflectionDumper::Dump(ID3D12FunctionReflection *pFunctionReflection) {
+  WriteLn("ID3D12FunctionReflection:");
+  Indent();
+  D3D12_FUNCTION_DESC Desc;
+  if (!pFunctionReflection || FAILED(pFunctionReflection->GetDesc(&Desc))) {
+    Failure("GetDesc");
+    Dedent();
+    return;
+  }
+  Dump(Desc);
+  if (Desc.ConstantBuffers) {
+    WriteLn("Constant Buffers:");
+    Indent();
+    bool bCheckByNameFailed = false;
+    for (UINT uCB = 0; uCB < Desc.ConstantBuffers; uCB++) {
+      ID3D12ShaderReflectionConstantBuffer *pCB = pFunctionReflection->GetConstantBufferByIndex(uCB);
+      Dump(pCB);
+      if (m_bCheckByName && m_LastName) {
+        if (pFunctionReflection->GetConstantBufferByName(m_LastName) != pCB) {
+          bCheckByNameFailed = true;
+          Failure("GetConstantBufferByName ", m_LastName);
+        }
+      }
+    }
+    if (m_bCheckByName && !bCheckByNameFailed) {
+      WriteLn("GetConstantBufferByName checks succeeded.");
+    }
+    Dedent();
+  }
+  if (Desc.BoundResources) {
+    WriteLn("Bound Resources:");
+    Indent();
+    bool bCheckByNameFailed = false;
+    for (UINT uRes = 0; uRes < Desc.BoundResources; uRes++) {
+      D3D12_SHADER_INPUT_BIND_DESC bindDesc;
+      if (FAILED(pFunctionReflection->GetResourceBindingDesc(uRes, &bindDesc))) {
+      }
+      Dump(bindDesc);
+      if (m_bCheckByName && bindDesc.Name) {
+        D3D12_SHADER_INPUT_BIND_DESC bindDesc2;
+        if (FAILED(pFunctionReflection->GetResourceBindingDescByName(bindDesc.Name, &bindDesc2)) || bindDesc2.Name != bindDesc.Name) {
+          bCheckByNameFailed = true;
+          Failure("GetResourceBindingDescByName ", bindDesc.Name);
+        }
+      }
+    }
+    if (m_bCheckByName && !bCheckByNameFailed) {
+      WriteLn("GetResourceBindingDescByName checks succeeded.");
+    }
+    Dedent();
+  }
+  // TODO
+  Dedent();
+}
+
+void D3DReflectionDumper::Dump(ID3D12LibraryReflection *pLibraryReflection) {
+  WriteLn("ID3D12LibraryReflection:");
+  Indent();
+  D3D12_LIBRARY_DESC Desc;
+  if (!pLibraryReflection || FAILED(pLibraryReflection->GetDesc(&Desc))) {
+    Failure("GetDesc");
+    Dedent();
+    return;
+  }
+  Dump(Desc);
+  if (Desc.FunctionCount) {
+    for (UINT uFunc = 0; uFunc < Desc.FunctionCount; uFunc++)
+      Dump(pLibraryReflection->GetFunctionByIndex((INT)uFunc));
+  }
+  Dedent();
+}
+

+ 118 - 0
tools/clang/unittests/HLSL/D3DReflectionDumper.h

@@ -0,0 +1,118 @@
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// D3DReflectionDumper.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.                                     //
+//                                                                           //
+// Use this to dump D3D Reflection data for testing.                         //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+#pragma once
+
+#include "dxc/Support/Global.h"
+#include <algorithm>
+#include <string>
+#include <ostream>
+#include <iomanip>
+#include "dxc/Support/WinIncludes.h"
+#include <d3d12shader.h>
+#include "dxc/HLSL/DxilContainer.h"
+
+LPCSTR ToString(D3D_CBUFFER_TYPE CBType);
+LPCSTR ToString(D3D_SHADER_INPUT_TYPE Type);
+LPCSTR ToString(D3D_RESOURCE_RETURN_TYPE ReturnType);
+LPCSTR ToString(D3D_SRV_DIMENSION Dimension);
+LPCSTR ToString(D3D_PRIMITIVE_TOPOLOGY GSOutputTopology);
+LPCSTR ToString(D3D_PRIMITIVE InputPrimitive);
+LPCSTR ToString(D3D_TESSELLATOR_OUTPUT_PRIMITIVE HSOutputPrimitive);
+LPCSTR ToString(D3D_TESSELLATOR_PARTITIONING HSPartitioning);
+LPCSTR ToString(D3D_TESSELLATOR_DOMAIN TessellatorDomain);
+LPCSTR ToString(D3D_SHADER_VARIABLE_CLASS Class);
+LPCSTR ToString(D3D_SHADER_VARIABLE_TYPE Type);
+
+class DumperBase {
+private:
+  std::ostream &m_out;
+  unsigned m_indent = 0;
+  bool m_bCheckByName = false;
+  std::ostream &DoIndent() {
+    return m_out << std::setfill(' ')
+      << std::setw(std::min(m_indent * 2, (unsigned)32))
+      << "";
+  }
+
+public:
+  DumperBase(std::ostream &outStream) : m_out(outStream) {}
+
+  void Indent() { if (m_indent < (1 << 30)) m_indent++; }
+  void Dedent() { if (m_indent > 0) m_indent--; }
+
+  template<typename _T>
+  std::ostream &Write(std::ostream &out, _T t) {
+    return out << t;
+  }
+  template<typename _T, typename... Args>
+  std::ostream &Write(std::ostream &out, _T t, Args... args) {
+    return Write(out << t, args...);
+  }
+
+  template<typename _T>
+  std::ostream &WriteLn(_T t) {
+    return Write(DoIndent(), t) << std::endl
+      << std::resetiosflags(std::ios_base::basefield | std::ios_base::showbase);
+  }
+  template<typename _T, typename... Args>
+  std::ostream &WriteLn(_T t, Args... args) {
+    return Write(Write(DoIndent(), t), args...) << std::endl
+      << std::resetiosflags(std::ios_base::basefield | std::ios_base::showbase);
+  }
+
+  template<typename _T>
+  void DumpEnum(const char *Name, _T eValue) {
+    LPCSTR szValue = ToString(eValue);
+    if (szValue)
+      WriteLn(Name, ": ", szValue);
+    else
+      WriteLn(Name, ": <unknown: ", std::hex, std::showbase, (UINT)eValue, ">");
+  }
+
+  template<typename... Args>
+  void Failure(Args... args) {
+    WriteLn("Failed: ", args...);
+  }
+
+};
+
+class D3DReflectionDumper : public DumperBase {
+private:
+  bool m_bCheckByName = false;
+  const char *m_LastName = nullptr;
+  void SetLastName(const char *Name = nullptr) { m_LastName = Name ? Name : "<nullptr>"; }
+
+public:
+  D3DReflectionDumper(std::ostream &outStream) : DumperBase(outStream) {}
+  void SetCheckByName(bool bCheckByName) { m_bCheckByName = bCheckByName; }
+
+  void DumpShaderVersion(UINT Version);
+  void DumpDefaultValue(LPCVOID pDefaultValue, UINT Size);
+
+  void Dump(D3D12_SHADER_TYPE_DESC &tyDesc);
+  void Dump(D3D12_SHADER_VARIABLE_DESC &varDesc);
+  void Dump(D3D12_SHADER_BUFFER_DESC &Desc);
+  void Dump(D3D12_SHADER_INPUT_BIND_DESC &resDesc);
+  void Dump(D3D12_SHADER_DESC &Desc);
+  void Dump(D3D12_FUNCTION_DESC &Desc);
+  void Dump(D3D12_LIBRARY_DESC &Desc);
+
+  void Dump(ID3D12ShaderReflectionType *pType);
+  void Dump(ID3D12ShaderReflectionVariable *pVar);
+
+  void Dump(ID3D12ShaderReflectionConstantBuffer *pCBReflection);
+
+  void Dump(ID3D12ShaderReflection *pShaderReflection);
+  void Dump(ID3D12FunctionReflection *pFunctionReflection);
+  void Dump(ID3D12LibraryReflection *pLibraryReflection);
+
+};

+ 3 - 0
tools/clang/unittests/HLSL/DxcTestUtils.h

@@ -9,6 +9,8 @@
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
+#pragma once
+
 #include <string>
 #include <vector>
 #include "dxc/dxcapi.h"
@@ -58,6 +60,7 @@ private:
   void RunDxc(const FileRunCommandPart *Prior);
   void RunDxv(const FileRunCommandPart *Prior);
   void RunOpt(const FileRunCommandPart *Prior);
+  void RunD3DReflect(const FileRunCommandPart *Prior);
   void RunTee(const FileRunCommandPart *Prior);
 public:
   FileRunCommandPart(const FileRunCommandPart&) = default;

+ 307 - 0
tools/clang/unittests/HLSL/DxilContainerTest.cpp

@@ -75,6 +75,7 @@ public:
   TEST_METHOD(CompileWhenDebugSourceThenSourceMatters)
   TEST_METHOD(CompileWhenOkThenCheckRDAT)
   TEST_METHOD(CompileWhenOkThenCheckRDAT2)
+  TEST_METHOD(CompileWhenOkThenCheckReflection1)
   TEST_METHOD(CompileWhenOKThenIncludesFeatureInfo)
   TEST_METHOD(CompileWhenOKThenIncludesSignatures)
   TEST_METHOD(CompileWhenSigSquareThenIncludeSplit)
@@ -870,6 +871,312 @@ TEST_F(DxilContainerTest, CompileWhenOkThenCheckRDAT2) {
   IFTBOOLMSG(blobFound, E_FAIL, "failed to find RDAT blob after compiling");
 }
 
+static uint32_t EncodedVersion_lib_6_3 = hlsl::EncodeVersion(hlsl::DXIL::ShaderKind::Library, 6, 3);
+static uint32_t EncodedVersion_vs_6_3 = hlsl::EncodeVersion(hlsl::DXIL::ShaderKind::Vertex, 6, 3);
+
+static void Ref1_CheckCBuffer_Globals(ID3D12ShaderReflectionConstantBuffer *pCBReflection, D3D12_SHADER_BUFFER_DESC &cbDesc) {
+  std::string cbName = cbDesc.Name;
+  VERIFY_IS_TRUE(cbName.compare("$Globals") == 0);
+  VERIFY_ARE_EQUAL(cbDesc.Size, 16);
+  VERIFY_ARE_EQUAL(cbDesc.Type, D3D_CT_CBUFFER);
+  VERIFY_ARE_EQUAL(cbDesc.Variables, 1);
+
+  // cbval1
+  ID3D12ShaderReflectionVariable *pVar = pCBReflection->GetVariableByIndex(0);
+  D3D12_SHADER_VARIABLE_DESC varDesc;
+  VERIFY_SUCCEEDED(pVar->GetDesc(&varDesc));
+  VERIFY_ARE_EQUAL_STR(varDesc.Name, "cbval1");
+  VERIFY_ARE_EQUAL(varDesc.StartOffset, 0);
+  VERIFY_ARE_EQUAL(varDesc.Size, 4);
+  // TODO: verify rest of variable
+  ID3D12ShaderReflectionType *pType = pVar->GetType();
+  D3D12_SHADER_TYPE_DESC tyDesc;
+  VERIFY_SUCCEEDED(pType->GetDesc(&tyDesc));
+  VERIFY_ARE_EQUAL(tyDesc.Class, D3D_SVC_SCALAR);
+  VERIFY_ARE_EQUAL(tyDesc.Type, D3D_SVT_FLOAT);
+  // TODO: verify rest of type
+}
+
+static void Ref1_CheckCBuffer_MyCB(ID3D12ShaderReflectionConstantBuffer *pCBReflection, D3D12_SHADER_BUFFER_DESC &cbDesc) {
+  std::string cbName = cbDesc.Name;
+  VERIFY_IS_TRUE(cbName.compare("MyCB") == 0);
+  VERIFY_ARE_EQUAL(cbDesc.Size, 32);
+  VERIFY_ARE_EQUAL(cbDesc.Type, D3D_CT_CBUFFER);
+  VERIFY_ARE_EQUAL(cbDesc.Variables, 2);
+
+  // cbval2
+  {
+    ID3D12ShaderReflectionVariable *pVar =  pCBReflection->GetVariableByIndex(0);
+    D3D12_SHADER_VARIABLE_DESC varDesc;
+    VERIFY_SUCCEEDED(pVar->GetDesc(&varDesc));
+    VERIFY_ARE_EQUAL_STR(varDesc.Name, "cbval2");
+    VERIFY_ARE_EQUAL(varDesc.StartOffset, 0);
+    VERIFY_ARE_EQUAL(varDesc.Size, 16);
+    // TODO: verify rest of variable
+    ID3D12ShaderReflectionType *pType = pVar->GetType();
+    D3D12_SHADER_TYPE_DESC tyDesc;
+    VERIFY_SUCCEEDED(pType->GetDesc(&tyDesc));
+    VERIFY_ARE_EQUAL(tyDesc.Class, D3D_SVC_VECTOR);
+    VERIFY_ARE_EQUAL(tyDesc.Type, D3D_SVT_INT);
+    // TODO: verify rest of type
+  }
+
+  // cbval3
+  {
+    ID3D12ShaderReflectionVariable *pVar = pCBReflection->GetVariableByIndex(1);
+    D3D12_SHADER_VARIABLE_DESC varDesc;
+    VERIFY_SUCCEEDED(pVar->GetDesc(&varDesc));
+    VERIFY_ARE_EQUAL_STR(varDesc.Name, "cbval3");
+    VERIFY_ARE_EQUAL(varDesc.StartOffset, 16);
+    VERIFY_ARE_EQUAL(varDesc.Size, 16);
+    // TODO: verify rest of variable
+    ID3D12ShaderReflectionType *pType = pVar->GetType();
+    D3D12_SHADER_TYPE_DESC tyDesc;
+    VERIFY_SUCCEEDED(pType->GetDesc(&tyDesc));
+    VERIFY_ARE_EQUAL(tyDesc.Class, D3D_SVC_VECTOR);
+    VERIFY_ARE_EQUAL(tyDesc.Type, D3D_SVT_INT);
+    // TODO: verify rest of type
+  }
+}
+
+static void Ref1_CheckBinding_Globals(D3D12_SHADER_INPUT_BIND_DESC &resDesc) {
+  std::string resName = resDesc.Name;
+  VERIFY_IS_TRUE(resName.compare("$Globals") == 0);
+  VERIFY_ARE_EQUAL(resDesc.Type, D3D_SIT_CBUFFER);
+  // not explicitly bound:
+  VERIFY_ARE_EQUAL(resDesc.BindPoint, 4294967295);
+  VERIFY_ARE_EQUAL(resDesc.Space, 0);
+  VERIFY_ARE_EQUAL(resDesc.BindCount, 1);
+}
+
+static void Ref1_CheckBinding_MyCB(D3D12_SHADER_INPUT_BIND_DESC &resDesc) {
+  std::string resName = resDesc.Name;
+  VERIFY_IS_TRUE(resName.compare("MyCB") == 0);
+  VERIFY_ARE_EQUAL(resDesc.Type, D3D_SIT_CBUFFER);
+  VERIFY_ARE_EQUAL(resDesc.BindPoint, 11);
+  VERIFY_ARE_EQUAL(resDesc.Space, 2);
+  VERIFY_ARE_EQUAL(resDesc.BindCount, 1);
+}
+
+static void Ref1_CheckBinding_tex(D3D12_SHADER_INPUT_BIND_DESC &resDesc) {
+  std::string resName = resDesc.Name;
+  VERIFY_IS_TRUE(resName.compare("tex") == 0);
+  VERIFY_ARE_EQUAL(resDesc.Type, D3D_SIT_UAV_RWTYPED);
+  VERIFY_ARE_EQUAL(resDesc.BindPoint, 5);
+  VERIFY_ARE_EQUAL(resDesc.Space, 0);
+  VERIFY_ARE_EQUAL(resDesc.BindCount, 1);
+}
+
+static void Ref1_CheckBinding_tex2(D3D12_SHADER_INPUT_BIND_DESC &resDesc) {
+  std::string resName = resDesc.Name;
+  VERIFY_IS_TRUE(resName.compare("tex2") == 0);
+  VERIFY_ARE_EQUAL(resDesc.Type, D3D_SIT_TEXTURE);
+  VERIFY_ARE_EQUAL(resDesc.BindPoint, 0);
+  VERIFY_ARE_EQUAL(resDesc.Space, 0);
+  VERIFY_ARE_EQUAL(resDesc.BindCount, 1);
+}
+
+static void Ref1_CheckBinding_samp(D3D12_SHADER_INPUT_BIND_DESC &resDesc) {
+  std::string resName = resDesc.Name;
+  VERIFY_IS_TRUE(resName.compare("samp") == 0);
+  VERIFY_ARE_EQUAL(resDesc.Type, D3D_SIT_SAMPLER);
+  VERIFY_ARE_EQUAL(resDesc.BindPoint, 7);
+  VERIFY_ARE_EQUAL(resDesc.Space, 0);
+  VERIFY_ARE_EQUAL(resDesc.BindCount, 1);
+}
+
+static void Ref1_CheckBinding_b_buf(D3D12_SHADER_INPUT_BIND_DESC &resDesc) {
+  std::string resName = resDesc.Name;
+  VERIFY_IS_TRUE(resName.compare("b_buf") == 0);
+  VERIFY_ARE_EQUAL(resDesc.Type, D3D_SIT_UAV_RWBYTEADDRESS);
+  // not explicitly bound:
+  VERIFY_ARE_EQUAL(resDesc.BindPoint, 4294967295);
+  VERIFY_ARE_EQUAL(resDesc.Space, 0);
+  VERIFY_ARE_EQUAL(resDesc.BindCount, 1);
+}
+
+
+TEST_F(DxilContainerTest, CompileWhenOkThenCheckReflection1) {
+  if (m_ver.SkipDxilVersion(1, 3)) return;
+  const char *shader =
+    "float cbval1;"
+    "cbuffer MyCB : register(b11, space2) { int4 cbval2, cbval3; }"
+    "RWTexture1D<int4> tex : register(u5);"
+    "Texture1D<float4> tex2 : register(t0);"
+    "SamplerState samp : register(s7);"
+    "RWByteAddressBuffer b_buf;"
+    "float function0(min16float x) { "
+    "  return x + cbval2.x + tex[0].x; }"
+    "float function1(float x, min12int i) {"
+    "  return x + cbval1 + b_buf.Load(x) + tex2.Sample(samp, x).x; }"
+    "[shader(\"vertex\")]"
+    "float function2(float4 x : POSITION) : SV_Position { return x + cbval1 + cbval3.x; }";
+
+  CComPtr<IDxcCompiler> pCompiler;
+  CComPtr<IDxcBlobEncoding> pSource;
+  CComPtr<IDxcBlob> pProgram;
+  CComPtr<IDxcBlobEncoding> pDisassembly;
+  CComPtr<IDxcOperationResult> pResult;
+  CComPtr<ID3D12LibraryReflection> pLibraryReflection;
+
+  VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
+  CreateBlobFromText(shader, &pSource);
+  VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"hlsl.hlsl", L"",
+    L"lib_6_3", nullptr, 0, nullptr, 0,
+    nullptr, &pResult));
+  VERIFY_SUCCEEDED(pResult->GetResult(&pProgram));
+  CComPtr<IDxcContainerReflection> containerReflection;
+  uint32_t partCount;
+  VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcContainerReflection, &containerReflection));
+  VERIFY_SUCCEEDED(containerReflection->Load(pProgram));
+  VERIFY_SUCCEEDED(containerReflection->GetPartCount(&partCount));
+  bool blobFound = false;
+
+  for (uint32_t i = 0; i < partCount; ++i) {
+    uint32_t kind;
+    VERIFY_SUCCEEDED(containerReflection->GetPartKind(i, &kind));
+    if (kind == (uint32_t)hlsl::DxilFourCC::DFCC_DXIL) {
+      blobFound = true;
+      VERIFY_SUCCEEDED(containerReflection->GetPartReflection(i, IID_PPV_ARGS(&pLibraryReflection)));
+      D3D12_LIBRARY_DESC LibDesc;
+      VERIFY_SUCCEEDED(pLibraryReflection->GetDesc(&LibDesc));
+      VERIFY_ARE_EQUAL(LibDesc.FunctionCount, 4);
+      for (INT iFn = 0; iFn < (INT)LibDesc.FunctionCount; iFn++) {
+        ID3D12FunctionReflection *pFunctionReflection = pLibraryReflection->GetFunctionByIndex(iFn);
+        D3D12_FUNCTION_DESC FnDesc;
+        pFunctionReflection->GetDesc(&FnDesc);
+        std::string Name = FnDesc.Name;
+        if (Name.compare("\01?function0@@YAM$f16@@Z") == 0) {
+          VERIFY_ARE_EQUAL(FnDesc.Version, EncodedVersion_lib_6_3);
+          VERIFY_ARE_EQUAL(FnDesc.ConstantBuffers, 1);
+          VERIFY_ARE_EQUAL(FnDesc.BoundResources, 2);
+          D3D12_SHADER_BUFFER_DESC cbDesc;
+          ID3D12ShaderReflectionConstantBuffer *pCBReflection = pFunctionReflection->GetConstantBufferByIndex(0);
+          VERIFY_SUCCEEDED(pCBReflection->GetDesc(&cbDesc));
+          std::string cbName = cbDesc.Name;
+          (void)(cbName);
+          Ref1_CheckCBuffer_MyCB(pCBReflection, cbDesc);
+
+          for (INT iRes = 0; iRes < (INT)FnDesc.BoundResources; iRes++) {
+            D3D12_SHADER_INPUT_BIND_DESC resDesc;
+            pFunctionReflection->GetResourceBindingDesc(iRes, &resDesc);
+            std::string resName = resDesc.Name;
+            if (resName.compare("$Globals") == 0) {
+              Ref1_CheckBinding_Globals(resDesc);
+            } else if (resName.compare("MyCB") == 0) {
+              Ref1_CheckBinding_MyCB(resDesc);
+            } else if (resName.compare("samp") == 0) {
+              Ref1_CheckBinding_samp(resDesc);
+            } else if (resName.compare("tex") == 0) {
+              Ref1_CheckBinding_tex(resDesc);
+            } else if (resName.compare("tex2") == 0) {
+              Ref1_CheckBinding_tex2(resDesc);
+            } else if (resName.compare("b_buf") == 0) {
+              Ref1_CheckBinding_b_buf(resDesc);
+            } else {
+              VERIFY_FAIL(L"Unexpected resource used");
+            }
+          }
+        } else if (Name.compare("\01?function1@@YAMMF@Z") == 0) {
+          VERIFY_ARE_EQUAL(FnDesc.Version, EncodedVersion_lib_6_3);
+          VERIFY_ARE_EQUAL(FnDesc.ConstantBuffers, 1);
+          VERIFY_ARE_EQUAL(FnDesc.BoundResources, 4);
+          D3D12_SHADER_BUFFER_DESC cbDesc;
+          ID3D12ShaderReflectionConstantBuffer *pCBReflection = pFunctionReflection->GetConstantBufferByIndex(0);
+          VERIFY_SUCCEEDED(pCBReflection->GetDesc(&cbDesc));
+          std::string cbName = cbDesc.Name;
+          (void)(cbName);
+          Ref1_CheckCBuffer_Globals(pCBReflection, cbDesc);
+
+          for (INT iRes = 0; iRes < (INT)FnDesc.BoundResources; iRes++) {
+            D3D12_SHADER_INPUT_BIND_DESC resDesc;
+            pFunctionReflection->GetResourceBindingDesc(iRes, &resDesc);
+            std::string resName = resDesc.Name;
+            if (resName.compare("$Globals") == 0) {
+              Ref1_CheckBinding_Globals(resDesc);
+            } else if (resName.compare("MyCB") == 0) {
+              Ref1_CheckBinding_MyCB(resDesc);
+            } else if (resName.compare("samp") == 0) {
+              Ref1_CheckBinding_samp(resDesc);
+            } else if (resName.compare("tex") == 0) {
+              Ref1_CheckBinding_tex(resDesc);
+            } else if (resName.compare("tex2") == 0) {
+              Ref1_CheckBinding_tex2(resDesc);
+            } else if (resName.compare("b_buf") == 0) {
+              Ref1_CheckBinding_b_buf(resDesc);
+            } else {
+              VERIFY_FAIL(L"Unexpected resource used");
+            }
+          }
+        } else if (Name.compare("\01?function2@@YAMV?$vector@M$03@@@Z") == 0) {
+          // library version of shader function is mangled
+          VERIFY_ARE_EQUAL(FnDesc.Version, EncodedVersion_lib_6_3);
+          VERIFY_ARE_EQUAL(FnDesc.ConstantBuffers, 2);
+          VERIFY_ARE_EQUAL(FnDesc.BoundResources, 2);
+          for (INT iCB = 0; iCB < (INT)FnDesc.BoundResources; iCB++) {
+            D3D12_SHADER_BUFFER_DESC cbDesc;
+            ID3D12ShaderReflectionConstantBuffer *pCBReflection = pFunctionReflection->GetConstantBufferByIndex(0);
+            VERIFY_SUCCEEDED(pCBReflection->GetDesc(&cbDesc));
+            std::string cbName = cbDesc.Name;
+            if (cbName.compare("$Globals") == 0) {
+              Ref1_CheckCBuffer_Globals(pCBReflection, cbDesc);
+            } else if (cbName.compare("MyCB") == 0) {
+              Ref1_CheckCBuffer_MyCB(pCBReflection, cbDesc);
+            }
+          }
+
+          for (INT iRes = 0; iRes < (INT)FnDesc.BoundResources; iRes++) {
+            D3D12_SHADER_INPUT_BIND_DESC resDesc;
+            pFunctionReflection->GetResourceBindingDesc(iRes, &resDesc);
+            std::string resName = resDesc.Name;
+            if (resName.compare("$Globals") == 0) {
+              Ref1_CheckBinding_Globals(resDesc);
+            } else if (resName.compare("MyCB") == 0) {
+              Ref1_CheckBinding_MyCB(resDesc);
+            } else {
+              VERIFY_FAIL(L"Unexpected resource used");
+            }
+          }
+        } else if (Name.compare("function2") == 0) {
+          // shader function with unmangled name
+          VERIFY_ARE_EQUAL(FnDesc.Version, EncodedVersion_vs_6_3);
+          VERIFY_ARE_EQUAL(FnDesc.ConstantBuffers, 2);
+          VERIFY_ARE_EQUAL(FnDesc.BoundResources, 2);
+          for (INT iCB = 0; iCB < (INT)FnDesc.BoundResources; iCB++) {
+            D3D12_SHADER_BUFFER_DESC cbDesc;
+            ID3D12ShaderReflectionConstantBuffer *pCBReflection = pFunctionReflection->GetConstantBufferByIndex(0);
+            VERIFY_SUCCEEDED(pCBReflection->GetDesc(&cbDesc));
+            std::string cbName = cbDesc.Name;
+            if (cbName.compare("$Globals") == 0) {
+              Ref1_CheckCBuffer_Globals(pCBReflection, cbDesc);
+            } else if (cbName.compare("MyCB") == 0) {
+              Ref1_CheckCBuffer_MyCB(pCBReflection, cbDesc);
+            }
+          }
+
+          for (INT iRes = 0; iRes < (INT)FnDesc.BoundResources; iRes++) {
+            D3D12_SHADER_INPUT_BIND_DESC resDesc;
+            pFunctionReflection->GetResourceBindingDesc(iRes, &resDesc);
+            std::string resName = resDesc.Name;
+            if (resName.compare("$Globals") == 0) {
+              Ref1_CheckBinding_Globals(resDesc);
+            } else if (resName.compare("MyCB") == 0) {
+              Ref1_CheckBinding_MyCB(resDesc);
+            } else {
+              VERIFY_FAIL(L"Unexpected resource used");
+            }
+          }
+        } else {
+          VERIFY_FAIL(L"Unexpected function");
+        }
+      }
+
+      // TODO: FINISH THIS
+    }
+  }
+  IFTBOOLMSG(blobFound, E_FAIL, "failed to find RDAT blob after compiling");
+}
+
 TEST_F(DxilContainerTest, CompileWhenOKThenIncludesFeatureInfo) {
   CComPtr<IDxcCompiler> pCompiler;
   CComPtr<IDxcBlobEncoding> pSource;

+ 9 - 1
tools/clang/unittests/HLSL/DxilModuleTest.cpp

@@ -41,6 +41,8 @@ public:
     TEST_METHOD_PROPERTY(L"Priority", L"0")
   END_TEST_CLASS()
 
+  TEST_CLASS_SETUP(InitSupport);
+
   dxc::DxcDllSupport m_dllSupport;
 
   // Basic loading tests.
@@ -58,6 +60,13 @@ public:
   TEST_METHOD(Precise7);
 };
 
+bool DxilModuleTest::InitSupport() {
+  if (!m_dllSupport.IsEnabled()) {
+    VERIFY_SUCCEEDED(m_dllSupport.Initialize());
+  }
+  return true;
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 // Compilation and dxil module loading support.
 
@@ -69,7 +78,6 @@ public:
     , m_msf(CreateMSFileSystem())
     , m_pts(m_msf.get())
   {
-    VERIFY_SUCCEEDED(m_dllSupport.Initialize());
     m_ver.Initialize(m_dllSupport);
     VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcCompiler, &pCompiler));
   }

+ 0 - 18
tools/clang/unittests/HLSL/FileCheckForTest.cpp

@@ -1298,26 +1298,8 @@ bool ReadCheckFile(SourceMgr &SM,
   return false;
 }
 
-// This would typically be done in DLL load.
-struct GlobalPerThreadSys {
-  bool success;
-
-  GlobalPerThreadSys() {
-    success = ::llvm::sys::fs::SetupPerThreadFileSystem() ? false : true;
-
-  }
-  ~GlobalPerThreadSys() {
-    if (success)
-      ::llvm::sys::fs::CleanupPerThreadFileSystem();
-  }
-};
-
 int run_main() {
   // HLSL Change Starts
-  GlobalPerThreadSys gpts;
-  if (!gpts.success) {
-    return 1;
-  }
   llvm::sys::fs::MSFileSystem* msfPtr;
   HRESULT hr;
   if (!SUCCEEDED(hr = CreateMSFileSystemForDisk(&msfPtr)))

+ 90 - 0
tools/clang/unittests/HLSL/FileCheckerTest.cpp

@@ -32,6 +32,10 @@
 #include "dxc/Support/dxcapi.use.h"
 #include "dxc/Support/HLSLOptions.h"
 #include "dxc/Support/Unicode.h"
+#include "dxc/HLSL/DxilContainer.h"
+#include "D3DReflectionDumper.h"
+
+#include "d3d12shader.h"
 
 using namespace std;
 using namespace hlsl_test;
@@ -105,6 +109,9 @@ static string trim(string value) {
       else if (0 == _stricmp(Command.c_str(), "%opt")) {
         RunOpt(Prior);
       }
+      else if (0 == _stricmp(Command.c_str(), "%D3DReflect")) {
+        RunD3DReflect(Prior);
+      }
       else {
         RunResult = 1;
         StdErr = "Unrecognized command ";
@@ -364,6 +371,89 @@ static string trim(string value) {
       RunResult = 0;
     }
 
+    void FileRunCommandPart::RunD3DReflect(const FileRunCommandPart *Prior) {
+      std::string args(strtrim(Arguments));
+      if (args != "%s") {
+        StdErr = "Only supported pattern is a plain input file";
+        RunResult = 1;
+        return;
+      }
+      if (!Prior) {
+        StdErr = "Prior command required to generate stdin";
+        RunResult = 1;
+        return;
+      }
+
+      CComPtr<IDxcLibrary> pLibrary;
+      CComPtr<IDxcBlobEncoding> pSource;
+      CComPtr<IDxcAssembler> pAssembler;
+      CComPtr<IDxcOperationResult> pResult;
+      CComPtr<ID3D12ShaderReflection> pShaderReflection;
+      CComPtr<ID3D12LibraryReflection> pLibraryReflection;
+      CComPtr<IDxcContainerReflection> containerReflection;
+      uint32_t partCount;
+      CComPtr<IDxcBlob> pContainerBlob;
+      HRESULT resultStatus;
+      bool blobFound = false;
+      std::ostringstream ss;
+      D3DReflectionDumper dumper(ss);
+
+      IFT(DllSupport->CreateInstance(CLSID_DxcLibrary, &pLibrary));
+      IFT(DllSupport->CreateInstance(CLSID_DxcAssembler, &pAssembler));
+
+      IFT(pLibrary->CreateBlobWithEncodingFromPinned(
+          (LPBYTE)Prior->StdOut.c_str(), Prior->StdOut.size(), CP_UTF8,
+          &pSource));
+
+      IFT(pAssembler->AssembleToContainer(pSource, &pResult));
+      IFT(pResult->GetStatus(&resultStatus));
+      if (FAILED(resultStatus)) {
+        CComPtr<IDxcBlobEncoding> pAssembleBlob;
+        IFT(pResult->GetErrorBuffer(&pAssembleBlob));
+        StdErr = BlobToUtf8(pAssembleBlob);
+        RunResult = resultStatus;
+        return;
+      }
+      IFT(pResult->GetResult(&pContainerBlob));
+
+      VERIFY_SUCCEEDED(DllSupport->CreateInstance(CLSID_DxcContainerReflection, &containerReflection));
+      VERIFY_SUCCEEDED(containerReflection->Load(pContainerBlob));
+      VERIFY_SUCCEEDED(containerReflection->GetPartCount(&partCount));
+
+      for (uint32_t i = 0; i < partCount; ++i) {
+        uint32_t kind;
+        VERIFY_SUCCEEDED(containerReflection->GetPartKind(i, &kind));
+        if (kind == (uint32_t)hlsl::DxilFourCC::DFCC_DXIL) {
+          blobFound = true;
+          CComPtr<IDxcBlob> pPart;
+          IFT(containerReflection->GetPartContent(i, &pPart));
+          const hlsl::DxilProgramHeader *pProgramHeader =
+            reinterpret_cast<const hlsl::DxilProgramHeader*>(pPart->GetBufferPointer());
+          VERIFY_IS_TRUE(IsValidDxilProgramHeader(pProgramHeader, (uint32_t)pPart->GetBufferSize()));
+          hlsl::DXIL::ShaderKind SK = hlsl::GetVersionShaderType(pProgramHeader->ProgramVersion);
+          if (SK == hlsl::DXIL::ShaderKind::Library)
+            VERIFY_SUCCEEDED(containerReflection->GetPartReflection(i, IID_PPV_ARGS(&pLibraryReflection)));
+          else
+            VERIFY_SUCCEEDED(containerReflection->GetPartReflection(i, IID_PPV_ARGS(&pShaderReflection)));
+          break;
+        }
+      }
+
+      if (!blobFound) {
+        StdErr = "Unable to find DXIL part";
+        RunResult = 1;
+        return;
+      } else if (pShaderReflection) {
+        dumper.Dump(pShaderReflection);
+      } else if (pLibraryReflection) {
+        dumper.Dump(pLibraryReflection);
+      }
+
+      ss.flush();
+      StdOut = ss.str();
+      RunResult = 0;
+    }
+
     void FileRunCommandPart::RunTee(const FileRunCommandPart *Prior) {
       if (Prior == nullptr) {
         StdErr = "tee requires a prior command";

+ 4 - 0
tools/clang/unittests/HLSL/VerifierTest.cpp

@@ -15,6 +15,7 @@
 #include "HLSLTestData.h"
 #include "llvm/Support/ManagedStatic.h"
 #include "dxc/Support/HLSLOptions.h"
+#include "llvm/Support/FileSystem.h"
 
 #include <fstream>
 
@@ -131,6 +132,8 @@ public:
 };
 
 bool TestModuleSetup() {
+  if (llvm::sys::fs::SetupPerThreadFileSystem())
+    return false;
   // Use this module-level function to set up LLVM dependencies.
   if (hlsl::options::initHlslOptTable()) {
     return false;
@@ -143,6 +146,7 @@ bool TestModuleCleanup() {
   // In particular, clean up managed static allocations used by
   // parsing options with the LLVM library.
   ::hlsl::options::cleanupHlslOptTable();
+  llvm::sys::fs::CleanupPerThreadFileSystem();
   ::llvm::llvm_shutdown();
   return true;
 }

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

@@ -832,6 +832,9 @@ int DxcBatchContext::BatchCompile(bool bMultiThread, bool bLibLink) {
 int __cdecl wmain(int argc, const wchar_t **argv_) {
   const char *pStage = "Initialization";
   int retVal = 0;
+  if (llvm::sys::fs::SetupPerThreadFileSystem())
+    return 1;
+  llvm::sys::fs::AutoCleanupPerThreadFileSystem auto_cleanup_fs;
   try {
     auto t_start = std::chrono::high_resolution_clock::now();
 

+ 1 - 0
tools/clang/utils/TableGen/TableGen.cpp

@@ -252,6 +252,7 @@ int main(int argc, char **argv) {
   HRESULT hr;
   if (std::error_code ec = llvm::sys::fs::SetupPerThreadFileSystem())
       return 1;
+  llvm::sys::fs::AutoCleanupPerThreadFileSystem auto_cleanup_fs;
   if (!SUCCEEDED(hr = CreateMSFileSystemForDisk(&msfPtr)))
     return 1;
   std::unique_ptr<llvm::sys::fs::MSFileSystem> msf(msfPtr);

+ 1 - 0
utils/TableGen/TableGen.cpp

@@ -182,6 +182,7 @@ int main(int argc, char **argv) {
   // HLSL Change Starts
   if (std::error_code ec = llvm::sys::fs::SetupPerThreadFileSystem())
       return 1;
+  llvm::sys::fs::AutoCleanupPerThreadFileSystem auto_cleanup_fs;
   llvm::sys::fs::MSFileSystem* msfPtr;
   HRESULT hr;
   if (!SUCCEEDED(hr = CreateMSFileSystemForDisk(&msfPtr)))