瀏覽代碼

Support same resource declared in different lib.
1. Add debug code in CompileFromBlob to help debug in release build.
2. Add dxl to help debug linker.
3. Check type match for resource when link.

Xiang Li 8 年之前
父節點
當前提交
459b5998a4

+ 70 - 3
lib/HLSL/DxilLinker.cpp

@@ -323,7 +323,7 @@ const char kShaderKindMismatch[] =
     "Profile mismatch between entry function and target profile:";
 const char kNoEntryProps[] =
     "Cannot find function property for entry function ";
-const char kRefineResource[] =
+const char kRedefineResource[] =
     "Resource already exists as ";
 } // namespace
 //------------------------------------------------------------------------------
@@ -331,14 +331,81 @@ const char kRefineResource[] =
 // DxilLinkJob methods.
 //
 
+namespace {
+// Helper function to check type match.
+bool IsMatchedType(Type *Ty0, Type *Ty);
+
+StringRef RemoveNameSuffix(StringRef Name) {
+  size_t DotPos = Name.rfind('.');
+  if (DotPos != StringRef::npos && Name.back() != '.' &&
+      isdigit(static_cast<unsigned char>(Name[DotPos + 1])))
+    Name = Name.substr(0, DotPos);
+  return Name;
+}
+
+bool IsMatchedStructType(StructType *ST0, StructType *ST) {
+  StringRef Name0 = RemoveNameSuffix(ST0->getName());
+  StringRef Name = RemoveNameSuffix(ST->getName());
+
+  if (Name0 != Name)
+    return false;
+
+  if (ST0->getNumElements() != ST->getNumElements())
+    return false;
+
+  if (ST0->isLayoutIdentical(ST))
+    return true;
+
+  for (unsigned i = 0; i < ST->getNumElements(); i++) {
+    Type *Ty = ST->getElementType(i);
+    Type *Ty0 = ST0->getElementType(i);
+    if (!IsMatchedType(Ty, Ty0))
+      return false;
+  }
+  return true;
+}
+
+bool IsMatchedArrayType(ArrayType *AT0, ArrayType *AT) {
+  if (AT0->getNumElements() != AT->getNumElements())
+    return false;
+  return IsMatchedType(AT0->getElementType(), AT->getElementType());
+}
+
+bool IsMatchedType(Type *Ty0, Type *Ty) {
+  if (Ty0->isStructTy() && Ty->isStructTy()) {
+    StructType *ST0 = cast<StructType>(Ty0);
+    StructType *ST = cast<StructType>(Ty);
+    return IsMatchedStructType(ST0, ST);
+  }
+
+  if (Ty0->isArrayTy() && Ty->isArrayTy()) {
+    ArrayType *AT0 = cast<ArrayType>(Ty0);
+    ArrayType *AT = cast<ArrayType>(Ty);
+    return IsMatchedArrayType(AT0, AT);
+  }
+
+  if (Ty0->isPointerTy() && Ty->isPointerTy()) {
+    if (Ty0->getPointerAddressSpace() != Ty->getPointerAddressSpace())
+      return false;
+
+    return IsMatchedType(Ty0->getPointerElementType(),
+                         Ty->getPointerElementType());
+  }
+
+  return Ty0 == Ty;
+}
+} // namespace
+
 bool DxilLinkJob::AddResource(DxilResourceBase *res, llvm::GlobalVariable *GV) {
   if (m_resourceMap.count(res->GetGlobalName())) {
     DxilResourceBase *res0 = m_resourceMap[res->GetGlobalName()].first;
+    Type *Ty0 = res0->GetGlobalSymbol()->getType()->getPointerElementType();
+    Type *Ty = res->GetGlobalSymbol()->getType()->getPointerElementType();
     // Make sure res0 match res.
-    bool bMatch = res->GetGlobalSymbol()->getType() == res0->GetGlobalSymbol()->getType();
+    bool bMatch = IsMatchedType(Ty0, Ty);
     if (!bMatch) {
       // Report error.
-      m_ctx.emitError(Twine(kRefineResource) + res->GetResClassName() + " for " +
+      m_ctx.emitError(Twine(kRedefineResource) + res->GetResClassName() + " for " +
                       res->GetGlobalName());
       return false;
     }

+ 17 - 0
tools/clang/test/CodeGenHLSL/lib_entry4.hlsl

@@ -0,0 +1,17 @@
+// Make sure same cbuffer decalred in different lib works.
+
+cbuffer A {
+  float a;
+  float v;
+}
+
+Texture2D	tex;
+SamplerState	samp;
+
+float GetV();
+
+[shader("pixel")]
+float4 main() : SV_Target
+{
+   return tex.Sample(samp, float2(a, GetV()));
+}

+ 15 - 0
tools/clang/test/CodeGenHLSL/lib_res_match.hlsl

@@ -0,0 +1,15 @@
+
+
+// Make sure same cbuffer decalred in different lib works.
+
+cbuffer A {
+  float a;
+  float v;
+}
+
+Texture2D	tex;
+SamplerState	samp;
+
+float GetV() {
+  return v + tex.Load(uint3(a, v, a)).y;
+}

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

@@ -28,6 +28,7 @@ add_subdirectory(dxcompiler)
 add_subdirectory(dxa)
 add_subdirectory(dxc)
 add_subdirectory(dxopt)
+add_subdirectory(dxl)
 add_subdirectory(dxr)
 add_subdirectory(dxv)
 add_subdirectory(dotnetc)

+ 39 - 0
tools/clang/tools/dxl/CMakeLists.txt

@@ -0,0 +1,39 @@
+# Copyright (C) Microsoft Corporation. All rights reserved.
+# This file is distributed under the University of Illinois Open Source License. See LICENSE.TXT for details.
+# Builds dxl.exe
+
+find_package(DiaSDK REQUIRED) # Used for constants and declarations.
+
+set( LLVM_LINK_COMPONENTS
+  ${LLVM_TARGETS_TO_BUILD}
+  HLSL
+  dxcsupport
+  Option     # option library
+  )
+
+add_clang_executable(dxl
+  dxl.cpp
+  )
+
+target_link_libraries(dxl
+  dxcompiler
+  )
+
+set_target_properties(dxl PROPERTIES VERSION ${CLANG_EXECUTABLE_VERSION})
+
+include_directories(AFTER ${DIASDK_INCLUDE_DIRS})
+
+add_dependencies(dxl dxcompiler)
+
+if(UNIX)
+  set(CLANGXX_LINK_OR_COPY create_symlink)
+# Create a relative symlink
+  set(dxl_binary "dxl${CMAKE_EXECUTABLE_SUFFIX}")
+else()
+  set(CLANGXX_LINK_OR_COPY copy)
+  set(dxl_binary "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${CMAKE_CFG_INTDIR}/dxl${CMAKE_EXECUTABLE_SUFFIX}")
+endif()
+
+install(TARGETS dxl
+  RUNTIME DESTINATION bin)
+

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

@@ -0,0 +1,147 @@
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// dxl.cpp                                                                   //
+// Copyright (C) Microsoft Corporation. All rights reserved.                 //
+// This file is distributed under the University of Illinois Open Source     //
+// License. See LICENSE.TXT for details.                                     //
+//                                                                           //
+// Provides the entry point for the dxl console program.                     //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+#include "dxc/Support/Global.h"
+#include "dxc/Support/Unicode.h"
+#include "dxc/Support/WinIncludes.h"
+
+#include "dxc/dxcapi.h"
+#include "dxc/Support/dxcapi.use.h"
+#include "dxc/Support/HLSLOptions.h"
+#include "dxc/HLSL/DxilContainer.h"
+
+#include "llvm/Support/CommandLine.h"
+#include <dia2.h>
+#include <intsafe.h>
+
+using namespace llvm;
+using namespace llvm::opt;
+using namespace dxc;
+using namespace hlsl::options;
+
+static cl::opt<std::string> InputFiles(cl::Positional, cl::Required,
+                                        cl::desc("<input .lib files>"));
+
+static cl::opt<std::string> EntryName("E", cl::desc("Entry function name"),
+                                      cl::value_desc("entryfunction"),
+                                      cl::init("main"));
+
+static cl::opt<std::string> TargetProfile("T", cl::Required,
+                                          cl::desc("Target profile"),
+                                          cl::value_desc("profile"));
+
+static cl::opt<std::string> OutputFilename("Fo",
+                                           cl::desc("Override output filename"),
+                                           cl::value_desc("filename"));
+
+
+class DxlContext {
+
+private:
+  DxcDllSupport &m_dxcSupport;
+  template <typename TInterface>
+  HRESULT CreateInstance(REFCLSID clsid, _Outptr_ TInterface **pResult) {
+    return m_dxcSupport.CreateInstance(clsid, pResult);
+  }
+
+public:
+  DxlContext(DxcDllSupport &dxcSupport) : m_dxcSupport(dxcSupport) {}
+
+  void Link();
+};
+
+void DxlContext::Link() {
+  std::string entry = EntryName;
+  std::string profile = TargetProfile;
+
+  CComPtr<IDxcLinker> pLinker;
+  IFT(CreateInstance(CLSID_DxcLinker, &pLinker));
+
+  StringRef InputFilesRef(InputFiles);
+  SmallVector<StringRef, 2> InputFileList;
+  InputFilesRef.split(InputFileList, ";");
+
+  std::vector<std::wstring> wInputFiles;
+  std::vector<LPCWSTR> wpInputFiles;
+  for (auto &file : InputFileList) {
+    wInputFiles.emplace_back(StringRefUtf16(file.str()));
+    wpInputFiles.emplace_back(wInputFiles.back().c_str());
+    CComPtr<IDxcBlobEncoding> pLib;
+    ReadFileIntoBlob(m_dxcSupport, wInputFiles.back().c_str(), &pLib);
+    IFT(pLinker->RegisterLibrary(wInputFiles.back().c_str(), pLib));
+  }
+
+  CComPtr<IDxcOperationResult> pLinkResult;
+
+  IFT(pLinker->Link(StringRefUtf16(entry), StringRefUtf16(profile),
+                wpInputFiles.data(), wpInputFiles.size(), nullptr, 0,
+                &pLinkResult));
+
+  HRESULT status;
+  IFT(pLinkResult->GetStatus(&status));
+  if (SUCCEEDED(status)) {
+    CComPtr<IDxcBlob> pContainer;
+    IFT(pLinkResult->GetResult(&pContainer));
+    if (pContainer.p != nullptr) {
+      // Infer the output filename if needed.
+      if (OutputFilename.empty()) {
+        OutputFilename = EntryName + ".dxbc";
+      }
+      WriteBlobToFile(pContainer, StringRefUtf16(OutputFilename));
+    }
+  }
+}
+
+using namespace hlsl::options;
+
+int __cdecl main(int argc, _In_reads_z_(argc) char **argv) {
+  const char *pStage = "Operation";
+  try {
+    pStage = "Argument processing";
+
+    // Parse command line options.
+    cl::ParseCommandLineOptions(argc, argv, "dxil linker\n");
+
+    DxcDllSupport dxcSupport;
+
+    // Read options and check errors.
+    dxc::EnsureEnabled(dxcSupport);
+    DxlContext context(dxcSupport);
+
+    pStage = "Linking";
+    context.Link();
+  } catch (const ::hlsl::Exception &hlslException) {
+    try {
+      const char *msg = hlslException.what();
+      Unicode::acp_char printBuffer[128]; // printBuffer is safe to treat as
+                                          // UTF-8 because we use ASCII only errors
+                                          // only
+      if (msg == nullptr || *msg == '\0') {
+        sprintf_s(printBuffer, _countof(printBuffer),
+                  "Link failed - error code 0x%08x.", hlslException.hr);
+        msg = printBuffer;
+      }
+      printf("%s\n", msg);
+    } catch (...) {
+      printf("%s failed - unable to retrieve error message.\n", pStage);
+    }
+
+    return 1;
+  } catch (std::bad_alloc &) {
+    printf("%s failed - out of memory.\n", pStage);
+    return 1;
+  } catch (...) {
+    printf("%s failed - unknown error.\n", pStage);
+    return 1;
+  }
+
+  return 0;
+}

+ 30 - 0
tools/clang/tools/dxlib-sample/lib_share_compile.cpp

@@ -158,9 +158,33 @@ HRESULT CompileFromBlob(IDxcBlobEncoding *pSource, LPCWSTR pSourceName,
     std::string processedHeader = "";
     std::vector<std::wstring> hashStrList;
     std::vector<LPCWSTR> hashList;
+//#define LIB_SHARE_DBG
+#ifdef LIB_SHARE_DBG
+    std::vector<std::wstring> defineList;
+    defineList.emplace_back(L"");
+    for (auto &def : defines) {
+      std::wstring strDef = std::wstring(L"#define ") + std::wstring(def.Name);
+      if (def.Value) {
+        strDef.push_back(L' ');
+        strDef += std::wstring(def.Value);
+        strDef.push_back(L'\n');
+      }
+      defineList[0] += strDef;
+      defineList.emplace_back(strDef);
+    }
+    std::string contents;
+    std::vector<std::wstring> contentStrList;
+    std::vector<LPCWSTR> contentList;
+#endif
     for (const auto &snippet : snippets) {
       CComPtr<IDxcBlob> pOutputBlob;
       size_t hash;
+#ifdef LIB_SHARE_DBG
+      contents = processedHeader + snippet;
+      CA2W tmpContents(contents.c_str());
+      contentStrList.emplace_back(tmpContents.m_psz);
+      contentList.emplace_back(contentStrList.back().c_str());
+#endif
       if (!libCache.GetLibBlob(processedHeader, snippet, compilerInput, hash, &pOutputBlob)) {
         // Cannot find existing blob, create from pSource.
         IDxcBlob **ppCode = &pOutputBlob;
@@ -181,8 +205,14 @@ HRESULT CompileFromBlob(IDxcBlobEncoding *pSource, LPCWSTR pSourceName,
     std::wstring wTarget = Unicode::UTF8ToUTF16StringOrThrow(Target);
 
     // Link
+#ifdef LIB_SHARE_DBG
+    return linker->Link(wEntry.c_str(), wTarget.c_str(), hashList.data(),
+                        hashList.size(), contentList.data(), 0,
+                        ppOperationResult);
+#else
     return linker->Link(wEntry.c_str(), wTarget.c_str(), hashList.data(),
                         hashList.size(), nullptr, 0, ppOperationResult);
+#endif
   }
   CATCH_CPP_ASSIGN_HRESULT();
   return hr;

+ 1 - 1
utils/hct/hcttest.cmd

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

+ 23 - 0
utils/hct/hcttestcmds.cmd

@@ -524,6 +524,26 @@ if %errorlevel% neq 0 (
   exit /b 1
 )
 
+echo Smoke test for dxl command line ...
+dxc.exe -T lib_6_1 "%2"\..\CodeGenHLSL\lib_entry4.hlsl -Fo lib_entry4.dxbc 1>nul
+if %errorlevel% neq 0 (
+  echo Failed to run dxc.exe -T "%2"\..\CodeGenHLSL\lib_6_1 lib_entry4.hlsl -Fo lib_entry4.dxbc
+  call :cleanup 2>nul
+  exit /b 1
+)
+dxc.exe -T lib_6_1 "%2"\..\CodeGenHLSL\lib_res_match.hlsl -Fo lib_res_match.dxbc 1>nul
+if %errorlevel% neq 0 (
+  echo Failed to run dxc.exe -T "%2"\..\CodeGenHLSL\lib_6_1 lib_res_match.hlsl -Fo lib_res_match.dxbc
+  call :cleanup 2>nul
+  exit /b 1
+)
+
+dxl.exe -T ps_6_1 lib_res_match.dxbc;lib_entry4.dxbc -Fo res_match_entry.dxbc 1>nul
+if %errorlevel% neq 0 (
+  echo Failed to run dxl.exe -T ps_6_1 lib_res_match.dxbc;lib_entry4.dxbc -Fo res_match_entry.dxbc
+  call :cleanup 2>nul
+  exit /b 1
+)
 
 rem Skipping shader model 6.2 when dxil.dll is present
 if exist dxil.dll (
@@ -595,6 +615,9 @@ del %CD%\smoke.opt.ll
 del %CD%\smoke.opt.prn.txt
 del %CD%\smoke.rebuilt-container.cso
 del %CD%\smoke.rebuilt-container2.cso
+del %CD%\lib_res_match.dxbc
+del %CD%\lib_entry4.dxbc
+del %CD%\res_match_entry.dxbc
 
 exit /b 0