Explorar o código

Updates to DxcValidator and DxcCompiler wrt. versioning/flags (#269)

Make DxcCreateInstance load validator from dxil.dll when available
Add DxcVersionInfoFlags_Internal flag to indicate internal validator
Add DxcValidatorFlags_ModuleOnly to indicate absense of full container for validation, requiring explicit use. This will not succeed when using dxil.dll validator.
Bump Validator version
Implement IDxcVersionInfo in DxcCompiler to indicate DXIL highest version supported and debug flag for compiler separately from validator
Refactor version detection code for tests, adding dxil and validator versions
Make SystemValueTest version aware
Add version check to AttributeAtVertex and SV_Barycentrics tests.
Fix line endings for HlslTestUtils.h
Tex Riddell %!s(int64=8) %!d(string=hai) anos
pai
achega
da5f98bb95

+ 22 - 0
include/dxc/Support/microcom.h

@@ -176,6 +176,28 @@ HRESULT DoBasicQueryInterface3(TObject* self, REFIID iid, void** ppvObject)
   return DoBasicQueryInterface2<TInterface, TInterface2, TObject>(self, iid, ppvObject);
 }
 
+/// <summary>
+/// Provides a QueryInterface implementation for a class that supports
+/// four interfaces in addition to IUnknown.
+/// </summary>
+/// <remarks>
+/// This implementation will also report the instance as not supporting
+/// marshaling. This will help catch marshaling problems early or avoid
+/// them altogether.
+/// </remarks>
+template <typename TInterface, typename TInterface2, typename TInterface3, typename TInterface4, typename TObject>
+HRESULT DoBasicQueryInterface4(TObject* self, REFIID iid, void** ppvObject)
+{
+  if (ppvObject == nullptr) return E_POINTER;
+  if (IsEqualIID(iid, __uuidof(TInterface4))) {
+    *(TInterface4**)ppvObject = self;
+    self->AddRef();
+    return S_OK;
+  }
+
+  return DoBasicQueryInterface3<TInterface, TInterface2, TInterface3, TObject>(self, iid, ppvObject);
+}
+
 template <typename T>
 HRESULT AssignToOut(T value, _Out_ T* pResult) {
   if (pResult == nullptr)

+ 3 - 1
include/dxc/dxcapi.h

@@ -165,7 +165,8 @@ IDxcCompiler : public IUnknown {
 static const UINT32 DxcValidatorFlags_Default = 0;
 static const UINT32 DxcValidatorFlags_InPlaceEdit = 1;  // Validator is allowed to update shader blob in-place.
 static const UINT32 DxcValidatorFlags_RootSignatureOnly = 2;
-static const UINT32 DxcValidatorFlags_ValidMask = 0x3;
+static const UINT32 DxcValidatorFlags_ModuleOnly = 4;
+static const UINT32 DxcValidatorFlags_ValidMask = 0x7;
 
 struct __declspec(uuid("A6E82BD2-1FD7-4826-9811-2857E797F49A"))
 IDxcValidator : public IUnknown {
@@ -225,6 +226,7 @@ IDxcOptimizer : public IUnknown {
 
 static const UINT32 DxcVersionInfoFlags_None = 0;
 static const UINT32 DxcVersionInfoFlags_Debug = 1; // Matches VS_FF_DEBUG
+static const UINT32 DxcVersionInfoFlags_Internal = 2; // Internal Validator (non-signing)
 
 struct __declspec(uuid("b04f5b50-2059-4f12-a8ff-a1e0cde1cc7e"))
 IDxcVersionInfo : public IUnknown {

+ 1 - 1
lib/HLSL/DxilValidation.cpp

@@ -4072,7 +4072,7 @@ static void ValidateUninitializedOutput(ValidationContext &ValCtx) {
 void GetValidationVersion(_Out_ unsigned *pMajor, _Out_ unsigned *pMinor) {
   // Bump these versions after 1.0 to account for additional validation rules.
   *pMajor = 1;
-  *pMinor = 0;
+  *pMinor = 1;
 }
 
 _Use_decl_annotations_ HRESULT

+ 6 - 1
tools/clang/tools/dxcompiler/dxcapi.cpp

@@ -16,6 +16,7 @@
 #include "dxc/dxcisense.h"
 #include "dxc/dxctools.h"
 #include "dxcetw.h"
+#include "dxillib.h"
 #include <memory>
 
 HRESULT CreateDxcCompiler(_In_ REFIID riid, _Out_ LPVOID *ppv);
@@ -76,7 +77,11 @@ DxcCreateInstance(_In_ REFCLSID   rclsid,
     hr = CreateDxcLibrary(riid, ppv);
   }
   else if (IsEqualCLSID(rclsid, CLSID_DxcValidator)) {
-    hr = CreateDxcValidator(riid, ppv);
+    if (DxilLibIsEnabled()) {
+      hr = DxilLibCreateInstance(rclsid, riid, (IUnknown**)ppv);
+    } else {
+      hr = CreateDxcValidator(riid, ppv);
+    }
   }
   else if (IsEqualCLSID(rclsid, CLSID_DxcAssembler)) {
     hr = CreateDxcAssembler(riid, ppv);

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

@@ -1964,7 +1964,7 @@ private:
   std::unique_ptr<llvm::Module> m_llvmModuleWithDebugInfo;
 };
 
-class DxcCompiler : public IDxcCompiler, public IDxcLangExtensions, public IDxcContainerEvent {
+class DxcCompiler : public IDxcCompiler, public IDxcLangExtensions, public IDxcContainerEvent, public IDxcVersionInfo {
 private:
   DXC_MICROCOM_REF_FIELD(m_dwRef)
   DxcLangExtensionsHelper m_langExtensionsHelper;
@@ -2023,7 +2023,7 @@ public:
   }
 
   HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **ppvObject) {
-    return DoBasicQueryInterface3<IDxcCompiler, IDxcLangExtensions, IDxcContainerEvent>(this, iid, ppvObject);
+    return DoBasicQueryInterface4<IDxcCompiler, IDxcLangExtensions, IDxcContainerEvent, IDxcVersionInfo>(this, iid, ppvObject);
   }
 
   // Compile a single entry point to the target shader model
@@ -2672,6 +2672,25 @@ public:
 
     compiler.getCodeGenOpts().HLSLExtensionsCodegen = std::make_shared<HLSLExtensionsCodegenHelperImpl>(compiler, m_langExtensionsHelper, Opts.RootSignatureDefine);
   }
+
+  // IDxcVersionInfo
+  __override HRESULT STDMETHODCALLTYPE GetVersion(_Out_ UINT32 *pMajor, _Out_ UINT32 *pMinor) {
+    if (pMajor == nullptr || pMinor == nullptr)
+      return E_INVALIDARG;
+    *pMajor = DXIL::kDxilMajor;
+    *pMinor = DXIL::kDxilMinor;
+    return S_OK;
+  }
+  __override HRESULT STDMETHODCALLTYPE GetFlags(_Out_ UINT32 *pFlags) {
+    if (pFlags == nullptr)
+      return E_INVALIDARG;
+    *pFlags = DxcVersionInfoFlags_None;
+#ifdef _DEBUG
+    *pFlags |= DxcVersionInfoFlags_Debug;
+#endif
+    return S_OK;
+  }
+
 };
 
 HRESULT CreateDxcCompiler(_In_ REFIID riid, _Out_ LPVOID* ppv) {

+ 20 - 7
tools/clang/tools/dxcompiler/dxcvalidator.cpp

@@ -84,6 +84,7 @@ private:
 
   HRESULT RunValidation(
     _In_ IDxcBlob *pShader,                       // Shader to validate.
+    _In_ UINT32 Flags,                            // Validation flags.
     _In_ llvm::Module *pModule,                   // Module to validate, if available.
     _In_ llvm::Module *pDebugModule,              // Debug module to validate, if available
     _In_ AbstractMemoryStream *pDiagStream);
@@ -129,6 +130,8 @@ HRESULT STDMETHODCALLTYPE DxcValidator::Validate(
 ) {
   if (pShader == nullptr || ppResult == nullptr || Flags & ~DxcValidatorFlags_ValidMask)
     return E_INVALIDARG;
+  if ((Flags & DxcValidatorFlags_ModuleOnly) && (Flags & (DxcValidatorFlags_InPlaceEdit | DxcValidatorFlags_RootSignatureOnly)))
+    return E_INVALIDARG;
   return ValidateWithOptModules(pShader, Flags, nullptr, nullptr, ppResult);
 }
 
@@ -154,7 +157,7 @@ HRESULT DxcValidator::ValidateWithOptModules(
     if (Flags & DxcValidatorFlags_RootSignatureOnly) {
       validationStatus = RunRootSignatureValidation(pShader, pDiagStream);
     } else {
-      validationStatus = RunValidation(pShader, pModule, pDebugModule, pDiagStream);
+      validationStatus = RunValidation(pShader, Flags, pModule, pDebugModule, pDiagStream);
     }
     if (FAILED(validationStatus)) {
       std::string msg("Validation failed.\n");
@@ -189,11 +192,13 @@ HRESULT STDMETHODCALLTYPE DxcValidator::GetFlags(_Out_ UINT32 *pFlags) {
 #ifdef _DEBUG
   *pFlags |= DxcVersionInfoFlags_Debug;
 #endif
+  *pFlags |= DxcVersionInfoFlags_Internal;
   return S_OK;
 }
 
 HRESULT DxcValidator::RunValidation(
   _In_ IDxcBlob *pShader,
+  _In_ UINT32 Flags,                            // Validation flags.
   _In_ llvm::Module *pModule,                   // Module to validate, if available.
   _In_ llvm::Module *pDebugModule,              // Debug module to validate, if available
   _In_ AbstractMemoryStream *pDiagStream) {
@@ -204,12 +209,18 @@ HRESULT DxcValidator::RunValidation(
 
   raw_stream_ostream DiagStream(pDiagStream);
 
+  if (Flags & DxcValidatorFlags_ModuleOnly) {
+    IFRBOOL(!IsDxilContainerLike(pShader->GetBufferPointer(), pShader->GetBufferSize()), E_INVALIDARG);
+  } else {
+    IFRBOOL(IsDxilContainerLike(pShader->GetBufferPointer(), pShader->GetBufferSize()), DXC_E_CONTAINER_INVALID);
+  }
+
   if (!pModule) {
     DXASSERT_NOMSG(pDebugModule == nullptr);
-    if (IsDxilContainerLike(pShader->GetBufferPointer(), pShader->GetBufferSize())) {
-      return ValidateDxilContainer(pShader->GetBufferPointer(), pShader->GetBufferSize(), DiagStream);
-    } else {
+    if (Flags & DxcValidatorFlags_ModuleOnly) {
       return ValidateDxilBitcode((const char*)pShader->GetBufferPointer(), (uint32_t)pShader->GetBufferSize(), DiagStream);
+    } else {
+      return ValidateDxilContainer(pShader->GetBufferPointer(), pShader->GetBufferSize(), DiagStream);
     }
   }
 
@@ -218,9 +229,11 @@ HRESULT DxcValidator::RunValidation(
   DiagRestore DR(pModule->getContext(), &DiagContext);
 
   IFR(hlsl::ValidateDxilModule(pModule, pDebugModule));
-  IFR(ValidateDxilContainerParts(pModule, pDebugModule,
-                    IsDxilContainerLike(pShader->GetBufferPointer(), pShader->GetBufferSize()),
-                    (uint32_t)pShader->GetBufferSize()));
+  if (!(Flags & DxcValidatorFlags_ModuleOnly)) {
+    IFR(ValidateDxilContainerParts(pModule, pDebugModule,
+                      IsDxilContainerLike(pShader->GetBufferPointer(), pShader->GetBufferSize()),
+                      (uint32_t)pShader->GetBufferSize()));
+  }
 
   if (DiagContext.HasErrors() || DiagContext.HasWarnings()) {
     return DXC_E_IR_VERIFICATION_FAILED;

+ 65 - 21
tools/clang/unittests/HLSL/CompilerTest.cpp

@@ -91,6 +91,64 @@ void Utf16ToBlob(dxc::DxcDllSupport &dllSupport, const std::wstring &val, _Outpt
   Utf16ToBlob(dllSupport, val, (IDxcBlobEncoding**)ppBlob);
 }
 
+// VersionSupportInfo Implementation
+VersionSupportInfo::VersionSupportInfo() :
+  m_CompilerPreservesBBNames(false),
+  m_InternalValidator(false),
+  m_DxilMajor(0),
+  m_DxilMinor(0),
+  m_ValMajor(0),
+  m_ValMinor(0)
+{}
+void VersionSupportInfo::Initialize(dxc::DxcDllSupport &dllSupport) {
+  VERIFY_IS_TRUE(dllSupport.IsEnabled());
+
+  // Default to Dxil 1.0 and internal Val 1.0
+  m_DxilMajor = m_ValMajor = 1;
+  m_DxilMinor = m_ValMinor = 0;
+  m_InternalValidator = true;
+  CComPtr<IDxcVersionInfo> pVersionInfo;
+  UINT32 VersionFlags = 0;
+
+  // If the following fails, we have Dxil 1.0 compiler
+  if (SUCCEEDED(dllSupport.CreateInstance(CLSID_DxcCompiler, &pVersionInfo))) {
+    VERIFY_SUCCEEDED(pVersionInfo->GetVersion(&m_DxilMajor, &m_DxilMinor));
+    VERIFY_SUCCEEDED(pVersionInfo->GetFlags(&VersionFlags));
+    m_CompilerPreservesBBNames = (VersionFlags & DxcVersionInfoFlags_Debug) ? true : false;
+    pVersionInfo.Release();
+  }
+
+  if (SUCCEEDED(dllSupport.CreateInstance(CLSID_DxcValidator, &pVersionInfo))) {
+    VERIFY_SUCCEEDED(pVersionInfo->GetVersion(&m_ValMajor, &m_ValMinor));
+    VERIFY_SUCCEEDED(pVersionInfo->GetFlags(&VersionFlags));
+    if (m_ValMinor > 0) {
+      // flag only exists on newer validator, assume internal otherwise.
+      m_InternalValidator = (VersionFlags & DxcVersionInfoFlags_Internal) ? true : false;
+    } else {
+      // With old compiler, validator is the only way to get this
+      m_CompilerPreservesBBNames = (VersionFlags & DxcVersionInfoFlags_Debug) ? true : false;
+    }
+  } else {
+    // If create instance of IDxcVersionInfo on validator failed, we have an old validator from dxil.dll
+    m_InternalValidator = false;
+  }
+}
+bool VersionSupportInfo::SkipIRSensitiveTest() {
+  if (!m_CompilerPreservesBBNames) {
+    WEX::Logging::Log::Comment(L"Test skipped due to name preservation requirment.");
+    return true;
+  }
+  return false;
+}
+bool VersionSupportInfo::SkipDxil_1_1_Test() {
+  if (m_DxilMajor < 1 || m_DxilMinor < 1 || m_ValMajor < 1 || m_ValMinor < 1) {
+    WEX::Logging::Log::Comment(L"Test skipped because it requires Dxil 1.1 and Validator 1.1.");
+    return true;
+  }
+  return false;
+}
+
+
 // Aligned to SymTagEnum.
 const char *SymTagEnumText[] =
 {
@@ -873,15 +931,7 @@ public:
   TEST_METHOD(HoistConstantArray)
 
   dxc::DxcDllSupport m_dllSupport;
-  bool m_CompilerPreservesBBNames;
-
-  bool SkipIRSensitiveTest() {
-    if (!m_CompilerPreservesBBNames) {
-      WEX::Logging::Log::Comment(L"Test skipped due to name preservation requirment.");
-      return true;
-    }
-    return false;
-  }
+  VersionSupportInfo m_ver;
 
   void CreateBlobPinned(_In_bytecount_(size) LPCVOID data, SIZE_T size,
                         UINT32 codePage, _Outptr_ IDxcBlobEncoding **ppBlob) {
@@ -1276,15 +1326,7 @@ HRESULT CreateDiaSourceFromDxbcBlob(IDxcLibrary *pLib, IDxcBlob *pDxbcBlob,
 bool CompilerTest::InitSupport() {
   if (!m_dllSupport.IsEnabled()) {
     VERIFY_SUCCEEDED(m_dllSupport.Initialize());
-
-    // This is a very indirect way of testing this. Consider improving support.
-    CComPtr<IDxcValidator> pValidator;
-    CComPtr<IDxcVersionInfo> pVersionInfo;
-    UINT32 VersionFlags = 0;
-    VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcValidator, &pValidator));
-    VERIFY_SUCCEEDED(pValidator.QueryInterface(&pVersionInfo));
-    VERIFY_SUCCEEDED(pVersionInfo->GetFlags(&VersionFlags));
-    m_CompilerPreservesBBNames = (VersionFlags & DxcVersionInfoFlags_Debug) ? true : false;
+    m_ver.Initialize(m_dllSupport);
   }
   return true;
 }
@@ -2179,10 +2221,12 @@ TEST_F(CompilerTest, CodeGenAtomic) {
 }
 
 TEST_F(CompilerTest, CodeGenAttributeAtVertex) {
+  if (m_ver.SkipDxil_1_1_Test()) return;
   CodeGenTestCheck(L"..\\CodeGenHLSL\\attributeAtVertex.hlsl");
 }
 
 TEST_F(CompilerTest, CodeGenBarycentrics) {
+  if (m_ver.SkipDxil_1_1_Test()) return;
   CodeGenTestCheck(L"..\\CodeGenHLSL\\barycentrics.hlsl");
 }
 
@@ -2679,12 +2723,12 @@ TEST_F(CompilerTest, CodeGenMatIn) {
 }
 
 TEST_F(CompilerTest, CodeGenMatIn1) {
-  if (SkipIRSensitiveTest()) return;
+  if (m_ver.SkipIRSensitiveTest()) return;
   CodeGenTestCheck(L"..\\CodeGenHLSL\\matrixIn1.hlsl");
 }
 
 TEST_F(CompilerTest, CodeGenMatIn2) {
-  if (SkipIRSensitiveTest()) return;
+  if (m_ver.SkipIRSensitiveTest()) return;
   CodeGenTestCheck(L"..\\CodeGenHLSL\\matrixIn2.hlsl");
 }
 
@@ -4149,7 +4193,7 @@ TEST_F(CompilerTest, CodeGenDx12MiniEngineFxaapass2Vdebugcs){
 }
 
 TEST_F(CompilerTest, CodeGenDx12MiniEngineFxaaresolveworkqueuecs){
-  if (SkipIRSensitiveTest()) return;
+  if (m_ver.SkipIRSensitiveTest()) return;
   CodeGenTestCheck(L"..\\CodeGenHLSL\\Samples\\MiniEngine\\FXAAResolveWorkQueueCS.hlsl");
 }
 

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

@@ -109,3 +109,19 @@ void Utf8ToBlob(dxc::DxcDllSupport &dllSupport, const std::string &val, _Outptr_
 void Utf8ToBlob(dxc::DxcDllSupport &dllSupport, const char *pVal, _Outptr_ IDxcBlobEncoding **ppBlob);
 void Utf16ToBlob(dxc::DxcDllSupport &dllSupport, const std::wstring &val, _Outptr_ IDxcBlob **ppBlob);
 void Utf16ToBlob(dxc::DxcDllSupport &dllSupport, const std::wstring &val, _Outptr_ IDxcBlobEncoding **ppBlob);
+
+class VersionSupportInfo {
+public:
+  bool m_CompilerPreservesBBNames;
+  bool m_InternalValidator;
+  unsigned m_DxilMajor, m_DxilMinor;
+  unsigned m_ValMajor, m_ValMinor;
+
+  VersionSupportInfo();
+  // Initialize version info structure.  TODO: add device shader model support
+  void Initialize(dxc::DxcDllSupport &dllSupport);
+  // Return true if IR sensitive test should be skipped, and log comment
+  bool SkipIRSensitiveTest();
+  // Return true if DXIL 1.1 test should be skipped, and log comment
+  bool SkipDxil_1_1_Test();
+};

+ 230 - 230
tools/clang/unittests/HLSL/HlslTestUtils.h

@@ -1,208 +1,208 @@
-///////////////////////////////////////////////////////////////////////////////
-//                                                                           //
-// HlslTestUtils.h                                                           //
-// Copyright (C) Microsoft Corporation. All rights reserved.                 //
-// This file is distributed under the University of Illinois Open Source     //
-// License. See LICENSE.TXT for details.                                     //
-//                                                                           //
-// Provides utility functions for HLSL tests.                                //
-//                                                                           //
-///////////////////////////////////////////////////////////////////////////////
-
-#include <string>
-#include <sstream>
-#include <fstream>
-#include "dxc/Support/Unicode.h"
-#include <dxgiformat.h>
-
-// If TAEF verify macros are available, use them to alias other legacy
-// comparison macros that don't have a direct translation.
-//
-// Other common replacements are as follows.
-//
-// EXPECT_EQ -> VERIFY_ARE_EQUAL
-// ASSERT_EQ -> VERIFY_ARE_EQUAL
-//
-// Note that whether verification throws or continues depends on
-// preprocessor settings.
-
-#ifdef VERIFY_ARE_EQUAL
-#define EXPECT_STREQ(a, b) VERIFY_ARE_EQUAL(0, strcmp(a, b))
-#define EXPECT_STREQW(a, b) VERIFY_ARE_EQUAL(0, wcscmp(a, b))
-#define VERIFY_ARE_EQUAL_CMP(a, b, ...) VERIFY_IS_TRUE(a == b, __VA_ARGS__)
-#define VERIFY_ARE_EQUAL_STR(a, b, ...) { \
-  const char *pTmpA = (a);\
-  const char *pTmpB = (b);\
-  if (0 != strcmp(pTmpA, pTmpB)) {\
-    CA2W conv(pTmpB, CP_UTF8); WEX::Logging::Log::Comment(conv);\
-    const char *pA = pTmpA; const char *pB = pTmpB; \
-    while(*pA == *pB) { pA++; pB++; } \
-    wchar_t diffMsg[32]; swprintf_s(diffMsg, _countof(diffMsg), L"diff at %u", (unsigned)(pA-pTmpA)); \
-    WEX::Logging::Log::Comment(diffMsg); \
-  } \
-  VERIFY_ARE_EQUAL(0, strcmp(pTmpA, pTmpB), __VA_ARGS__); \
-}
-#define VERIFY_ARE_EQUAL_WSTR(a, b, ...) { \
-  if (0 != wcscmp(a, b)) { WEX::Logging::Log::Comment(b);} \
-  VERIFY_ARE_EQUAL(0, wcscmp(a, b), __VA_ARGS__); \
-}
-#define ASSERT_EQ(expected, actual) VERIFY_ARE_EQUAL(expected, actual)
-#define ASSERT_NE(expected, actual) VERIFY_ARE_NOT_EQUAL(expected, actual)
-#define TEST_F(typeName, functionName) void typeName::functionName()
-#define ASSERT_HRESULT_SUCCEEDED VERIFY_SUCCEEDED
-#define EXPECT_EQ(expected, actual) VERIFY_ARE_EQUAL(expected, actual)
-#endif
-
-namespace hlsl_test {
-
-inline std::wstring
-vFormatToWString(_In_z_ _Printf_format_string_ const wchar_t *fmt, va_list argptr) {
-  std::wstring result;
-  int len = _vscwprintf(fmt, argptr);
-  result.resize(len + 1);
-  vswprintf_s((wchar_t *)result.data(), len + 1, fmt, argptr);
-  return result;
-}
-
-inline std::wstring
-FormatToWString(_In_z_ _Printf_format_string_ const wchar_t *fmt, ...) {
-  va_list args;
-  va_start(args, fmt);
-  std::wstring result(vFormatToWString(fmt, args));
-  va_end(args);
-  return result;
-}
-
-inline void LogCommentFmt(_In_z_ _Printf_format_string_ const wchar_t *fmt, ...) {
-  va_list args;
-  va_start(args, fmt);
-  std::wstring buf(vFormatToWString(fmt, args));
-  va_end(args);
-  WEX::Logging::Log::Comment(buf.data());
-}
-
-inline void LogErrorFmt(_In_z_ _Printf_format_string_ const wchar_t *fmt, ...) {
-    va_list args;
-    va_start(args, fmt);
-    std::wstring buf(vFormatToWString(fmt, args));
-    va_end(args);
-    WEX::Logging::Log::Error(buf.data());
-}
-
-inline std::wstring GetPathToHlslDataFile(const wchar_t* relative) {
-  WEX::TestExecution::SetVerifyOutput verifySettings(WEX::TestExecution::VerifyOutputSettings::LogOnlyFailures);
-  WEX::Common::String HlslDataDirValue;
-  ASSERT_HRESULT_SUCCEEDED(WEX::TestExecution::RuntimeParameters::TryGetValue(L"HlslDataDir", HlslDataDirValue));
-
-  wchar_t envPath[MAX_PATH];
-  wchar_t expanded[MAX_PATH];
-  swprintf_s(envPath, _countof(envPath), L"%s\\%s", reinterpret_cast<wchar_t*>(HlslDataDirValue.GetBuffer()), relative);
-  VERIFY_WIN32_BOOL_SUCCEEDED(ExpandEnvironmentStringsW(envPath, expanded, _countof(expanded)));
-  return std::wstring(expanded);
-}
-
-inline bool PathLooksAbsolute(LPCWSTR name) {
-  // Very simplified, only for the cases we care about in the test suite.
-  return name && *name && ((*name == L'\\') || (name[1] == L':'));
-}
-
-inline std::string GetFirstLine(LPCWSTR name) {
-  char firstLine[300];
-  memset(firstLine, 0, sizeof(firstLine));
-
-  const std::wstring path = PathLooksAbsolute(name)
-                                ? std::wstring(name)
-                                : hlsl_test::GetPathToHlslDataFile(name);
-  std::ifstream infile(path);
-  if (infile.bad()) {
-    std::wstring errMsg(L"Unable to read file ");
-    errMsg += path;
-    WEX::Logging::Log::Error(errMsg.c_str());
-    VERIFY_FAIL();
-  }
-
-  infile.getline(firstLine, _countof(firstLine));
-  return firstLine;
-}
-
-inline HANDLE CreateFileForReading(LPCWSTR path) {
-  HANDLE sourceHandle = CreateFileW(path, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0);
-  if (sourceHandle == INVALID_HANDLE_VALUE) {
-    DWORD err = GetLastError();
-    std::wstring errorMessage(FormatToWString(L"Unable to open file '%s', err=%u", path, err).c_str());
-    VERIFY_SUCCEEDED(HRESULT_FROM_WIN32(err), errorMessage.c_str());
-  }
-  return sourceHandle;
-}
-
-inline HANDLE CreateNewFileForReadWrite(LPCWSTR path) {
-  HANDLE sourceHandle = CreateFileW(path, GENERIC_READ | GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0);
-  if (sourceHandle == INVALID_HANDLE_VALUE) {
-    DWORD err = GetLastError();
-    std::wstring errorMessage(FormatToWString(L"Unable to create file '%s', err=%u", path, err).c_str());
-    VERIFY_SUCCEEDED(HRESULT_FROM_WIN32(err), errorMessage.c_str());
-  }
-  return sourceHandle;
-}
-
-inline bool GetTestParamBool(LPCWSTR name) {
-  WEX::Common::String ParamValue;
-  WEX::Common::String NameValue;
-  if (FAILED(WEX::TestExecution::RuntimeParameters::TryGetValue(name,
-                                                                ParamValue))) {
-    return false;
-  }
-  if (ParamValue.IsEmpty()) {
-    return false;
-  }
-  if (0 == wcscmp(ParamValue, L"*")) {
-    return true;
-  }
-  VERIFY_SUCCEEDED(WEX::TestExecution::RuntimeParameters::TryGetValue(
-      L"TestName", NameValue));
-  if (NameValue.IsEmpty()) {
-    return false;
-  }
-  return Unicode::IsStarMatchUTF16(ParamValue, ParamValue.GetLength(),
-                                   NameValue, NameValue.GetLength());
-}
-
-inline bool GetTestParamUseWARP(bool defaultVal) {
-  WEX::Common::String AdapterValue;
-  if (FAILED(WEX::TestExecution::RuntimeParameters::TryGetValue(
-          L"Adapter", AdapterValue))) {
-    return defaultVal;
-  }
-  if (defaultVal && AdapterValue.IsEmpty() ||
-      AdapterValue.CompareNoCase(L"WARP") == 0) {
-    return true;
-  }
-  return false;
-}
-
-}
-
-inline bool isdenorm(float f) {
-  return FP_SUBNORMAL == fpclassify(f);
-}
-
-inline bool isdenorm(double d) {
-  return FP_SUBNORMAL == fpclassify(d);
-}
-
-inline float ifdenorm_flushf(float a) {
-  return isdenorm(a) ? copysign(0.0f, a) : a;
-}
-
-inline bool ifdenorm_flushf_eq(float a, float b) {
-  return ifdenorm_flushf(a) == ifdenorm_flushf(b);
-}
-
-inline bool ifdenorm_flushf_eq_or_nans(float a, float b) {
-  if (isnan(a) && isnan(b)) return true;
-  return ifdenorm_flushf(a) == ifdenorm_flushf(b);
-}
-
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// HlslTestUtils.h                                                           //
+// Copyright (C) Microsoft Corporation. All rights reserved.                 //
+// This file is distributed under the University of Illinois Open Source     //
+// License. See LICENSE.TXT for details.                                     //
+//                                                                           //
+// Provides utility functions for HLSL tests.                                //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+#include <string>
+#include <sstream>
+#include <fstream>
+#include "dxc/Support/Unicode.h"
+#include <dxgiformat.h>
+
+// If TAEF verify macros are available, use them to alias other legacy
+// comparison macros that don't have a direct translation.
+//
+// Other common replacements are as follows.
+//
+// EXPECT_EQ -> VERIFY_ARE_EQUAL
+// ASSERT_EQ -> VERIFY_ARE_EQUAL
+//
+// Note that whether verification throws or continues depends on
+// preprocessor settings.
+
+#ifdef VERIFY_ARE_EQUAL
+#define EXPECT_STREQ(a, b) VERIFY_ARE_EQUAL(0, strcmp(a, b))
+#define EXPECT_STREQW(a, b) VERIFY_ARE_EQUAL(0, wcscmp(a, b))
+#define VERIFY_ARE_EQUAL_CMP(a, b, ...) VERIFY_IS_TRUE(a == b, __VA_ARGS__)
+#define VERIFY_ARE_EQUAL_STR(a, b, ...) { \
+  const char *pTmpA = (a);\
+  const char *pTmpB = (b);\
+  if (0 != strcmp(pTmpA, pTmpB)) {\
+    CA2W conv(pTmpB, CP_UTF8); WEX::Logging::Log::Comment(conv);\
+    const char *pA = pTmpA; const char *pB = pTmpB; \
+    while(*pA == *pB) { pA++; pB++; } \
+    wchar_t diffMsg[32]; swprintf_s(diffMsg, _countof(diffMsg), L"diff at %u", (unsigned)(pA-pTmpA)); \
+    WEX::Logging::Log::Comment(diffMsg); \
+  } \
+  VERIFY_ARE_EQUAL(0, strcmp(pTmpA, pTmpB), __VA_ARGS__); \
+}
+#define VERIFY_ARE_EQUAL_WSTR(a, b, ...) { \
+  if (0 != wcscmp(a, b)) { WEX::Logging::Log::Comment(b);} \
+  VERIFY_ARE_EQUAL(0, wcscmp(a, b), __VA_ARGS__); \
+}
+#define ASSERT_EQ(expected, actual) VERIFY_ARE_EQUAL(expected, actual)
+#define ASSERT_NE(expected, actual) VERIFY_ARE_NOT_EQUAL(expected, actual)
+#define TEST_F(typeName, functionName) void typeName::functionName()
+#define ASSERT_HRESULT_SUCCEEDED VERIFY_SUCCEEDED
+#define EXPECT_EQ(expected, actual) VERIFY_ARE_EQUAL(expected, actual)
+#endif
+
+namespace hlsl_test {
+
+inline std::wstring
+vFormatToWString(_In_z_ _Printf_format_string_ const wchar_t *fmt, va_list argptr) {
+  std::wstring result;
+  int len = _vscwprintf(fmt, argptr);
+  result.resize(len + 1);
+  vswprintf_s((wchar_t *)result.data(), len + 1, fmt, argptr);
+  return result;
+}
+
+inline std::wstring
+FormatToWString(_In_z_ _Printf_format_string_ const wchar_t *fmt, ...) {
+  va_list args;
+  va_start(args, fmt);
+  std::wstring result(vFormatToWString(fmt, args));
+  va_end(args);
+  return result;
+}
+
+inline void LogCommentFmt(_In_z_ _Printf_format_string_ const wchar_t *fmt, ...) {
+  va_list args;
+  va_start(args, fmt);
+  std::wstring buf(vFormatToWString(fmt, args));
+  va_end(args);
+  WEX::Logging::Log::Comment(buf.data());
+}
+
+inline void LogErrorFmt(_In_z_ _Printf_format_string_ const wchar_t *fmt, ...) {
+    va_list args;
+    va_start(args, fmt);
+    std::wstring buf(vFormatToWString(fmt, args));
+    va_end(args);
+    WEX::Logging::Log::Error(buf.data());
+}
+
+inline std::wstring GetPathToHlslDataFile(const wchar_t* relative) {
+  WEX::TestExecution::SetVerifyOutput verifySettings(WEX::TestExecution::VerifyOutputSettings::LogOnlyFailures);
+  WEX::Common::String HlslDataDirValue;
+  ASSERT_HRESULT_SUCCEEDED(WEX::TestExecution::RuntimeParameters::TryGetValue(L"HlslDataDir", HlslDataDirValue));
+
+  wchar_t envPath[MAX_PATH];
+  wchar_t expanded[MAX_PATH];
+  swprintf_s(envPath, _countof(envPath), L"%s\\%s", reinterpret_cast<wchar_t*>(HlslDataDirValue.GetBuffer()), relative);
+  VERIFY_WIN32_BOOL_SUCCEEDED(ExpandEnvironmentStringsW(envPath, expanded, _countof(expanded)));
+  return std::wstring(expanded);
+}
+
+inline bool PathLooksAbsolute(LPCWSTR name) {
+  // Very simplified, only for the cases we care about in the test suite.
+  return name && *name && ((*name == L'\\') || (name[1] == L':'));
+}
+
+inline std::string GetFirstLine(LPCWSTR name) {
+  char firstLine[300];
+  memset(firstLine, 0, sizeof(firstLine));
+
+  const std::wstring path = PathLooksAbsolute(name)
+                                ? std::wstring(name)
+                                : hlsl_test::GetPathToHlslDataFile(name);
+  std::ifstream infile(path);
+  if (infile.bad()) {
+    std::wstring errMsg(L"Unable to read file ");
+    errMsg += path;
+    WEX::Logging::Log::Error(errMsg.c_str());
+    VERIFY_FAIL();
+  }
+
+  infile.getline(firstLine, _countof(firstLine));
+  return firstLine;
+}
+
+inline HANDLE CreateFileForReading(LPCWSTR path) {
+  HANDLE sourceHandle = CreateFileW(path, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0);
+  if (sourceHandle == INVALID_HANDLE_VALUE) {
+    DWORD err = GetLastError();
+    std::wstring errorMessage(FormatToWString(L"Unable to open file '%s', err=%u", path, err).c_str());
+    VERIFY_SUCCEEDED(HRESULT_FROM_WIN32(err), errorMessage.c_str());
+  }
+  return sourceHandle;
+}
+
+inline HANDLE CreateNewFileForReadWrite(LPCWSTR path) {
+  HANDLE sourceHandle = CreateFileW(path, GENERIC_READ | GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0);
+  if (sourceHandle == INVALID_HANDLE_VALUE) {
+    DWORD err = GetLastError();
+    std::wstring errorMessage(FormatToWString(L"Unable to create file '%s', err=%u", path, err).c_str());
+    VERIFY_SUCCEEDED(HRESULT_FROM_WIN32(err), errorMessage.c_str());
+  }
+  return sourceHandle;
+}
+
+inline bool GetTestParamBool(LPCWSTR name) {
+  WEX::Common::String ParamValue;
+  WEX::Common::String NameValue;
+  if (FAILED(WEX::TestExecution::RuntimeParameters::TryGetValue(name,
+                                                                ParamValue))) {
+    return false;
+  }
+  if (ParamValue.IsEmpty()) {
+    return false;
+  }
+  if (0 == wcscmp(ParamValue, L"*")) {
+    return true;
+  }
+  VERIFY_SUCCEEDED(WEX::TestExecution::RuntimeParameters::TryGetValue(
+      L"TestName", NameValue));
+  if (NameValue.IsEmpty()) {
+    return false;
+  }
+  return Unicode::IsStarMatchUTF16(ParamValue, ParamValue.GetLength(),
+                                   NameValue, NameValue.GetLength());
+}
+
+inline bool GetTestParamUseWARP(bool defaultVal) {
+  WEX::Common::String AdapterValue;
+  if (FAILED(WEX::TestExecution::RuntimeParameters::TryGetValue(
+          L"Adapter", AdapterValue))) {
+    return defaultVal;
+  }
+  if (defaultVal && AdapterValue.IsEmpty() ||
+      AdapterValue.CompareNoCase(L"WARP") == 0) {
+    return true;
+  }
+  return false;
+}
+
+}
+
+inline bool isdenorm(float f) {
+  return FP_SUBNORMAL == fpclassify(f);
+}
+
+inline bool isdenorm(double d) {
+  return FP_SUBNORMAL == fpclassify(d);
+}
+
+inline float ifdenorm_flushf(float a) {
+  return isdenorm(a) ? copysign(0.0f, a) : a;
+}
+
+inline bool ifdenorm_flushf_eq(float a, float b) {
+  return ifdenorm_flushf(a) == ifdenorm_flushf(b);
+}
+
+inline bool ifdenorm_flushf_eq_or_nans(float a, float b) {
+  if (isnan(a) && isnan(b)) return true;
+  return ifdenorm_flushf(a) == ifdenorm_flushf(b);
+}
+
 inline bool CompareFloatULP(const float &fsrc, const float &fref, int ULPTolerance) {
     if (isnan(fsrc)) {
         return isnan(fref);
@@ -231,8 +231,8 @@ inline bool CompareFloatEpsilon(const float &fsrc, const float &fref, float epsi
 // Compare using relative error (relative error < 2^{nRelativeExp})
 inline bool CompareFloatRelativeEpsilon(const float &fsrc, const float &fref, int nRelativeExp) {
     return CompareFloatULP(fsrc, fref, 23 - nRelativeExp);
-}
-
+}
+
 // returns the number of bytes per pixel for a given dxgi format
 // add more cases if different format needed to copy back resources
 inline UINT GetByteSizeForFormat(DXGI_FORMAT value) {
@@ -308,26 +308,26 @@ inline UINT GetByteSizeForFormat(DXGI_FORMAT value) {
         return 0;
     }
 }
-
-
-#define SIMPLE_IUNKNOWN_IMPL1(_IFACE_) \
-  private: volatile ULONG m_dwRef; \
-  public:\
-  ULONG STDMETHODCALLTYPE AddRef() { return InterlockedIncrement(&m_dwRef); } \
-  ULONG STDMETHODCALLTYPE Release() { \
-    ULONG result = InterlockedDecrement(&m_dwRef); \
-    if (result == 0) delete this; \
-    return result; \
-  } \
-  HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void** ppvObject) { \
-    if (ppvObject == nullptr) return E_POINTER; \
-    if (IsEqualIID(iid, __uuidof(IUnknown)) || \
-      IsEqualIID(iid, __uuidof(INoMarshal)) || \
-      IsEqualIID(iid, __uuidof(_IFACE_))) { \
-      *ppvObject = reinterpret_cast<_IFACE_*>(this); \
-      reinterpret_cast<_IFACE_*>(this)->AddRef(); \
-      return S_OK; \
-    } \
-    return E_NOINTERFACE; \
-  }
-
+
+
+#define SIMPLE_IUNKNOWN_IMPL1(_IFACE_) \
+  private: volatile ULONG m_dwRef; \
+  public:\
+  ULONG STDMETHODCALLTYPE AddRef() { return InterlockedIncrement(&m_dwRef); } \
+  ULONG STDMETHODCALLTYPE Release() { \
+    ULONG result = InterlockedDecrement(&m_dwRef); \
+    if (result == 0) delete this; \
+    return result; \
+  } \
+  HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void** ppvObject) { \
+    if (ppvObject == nullptr) return E_POINTER; \
+    if (IsEqualIID(iid, __uuidof(IUnknown)) || \
+      IsEqualIID(iid, __uuidof(INoMarshal)) || \
+      IsEqualIID(iid, __uuidof(_IFACE_))) { \
+      *ppvObject = reinterpret_cast<_IFACE_*>(this); \
+      reinterpret_cast<_IFACE_*>(this)->AddRef(); \
+      return S_OK; \
+    } \
+    return E_NOINTERFACE; \
+  }
+

+ 29 - 14
tools/clang/unittests/HLSL/SystemValueTest.cpp

@@ -39,9 +39,6 @@ using namespace std;
 using namespace hlsl_test;
 using namespace hlsl;
 
-static const unsigned HighestMajor = 6;
-static const unsigned HighestMinor = 1;
-
 class SystemValueTest {
 public:
   BEGIN_TEST_CLASS(SystemValueTest)
@@ -66,7 +63,7 @@ public:
   TEST_METHOD(VerifyVersionedSemantics)
   TEST_METHOD(VerifyMissingSemanticFailure)
 
-  void CompileHLSLTemplate(CComPtr<IDxcOperationResult> &pResult, DXIL::SigPointKind sigPointKind, DXIL::SemanticKind semKind, bool addArb, unsigned Major = HighestMajor, unsigned Minor = HighestMinor) {
+  void CompileHLSLTemplate(CComPtr<IDxcOperationResult> &pResult, DXIL::SigPointKind sigPointKind, DXIL::SemanticKind semKind, bool addArb, unsigned Major = 0, unsigned Minor = 0) {
     const Semantic *sem = Semantic::Get(semKind);
     const char* pSemName = sem->GetName();
     std::wstring sigDefValue(L"");
@@ -85,7 +82,7 @@ public:
     return CompileHLSLTemplate(pResult, sigPointKind, sigDefValue, Major, Minor);
   }
 
-  void CompileHLSLTemplate(CComPtr<IDxcOperationResult> &pResult, DXIL::SigPointKind sigPointKind, const std::wstring &sigDefValue, unsigned Major = HighestMajor, unsigned Minor = HighestMinor) {
+  void CompileHLSLTemplate(CComPtr<IDxcOperationResult> &pResult, DXIL::SigPointKind sigPointKind, const std::wstring &sigDefValue, unsigned Major = 0, unsigned Minor = 0) {
     const SigPoint * sigPoint = SigPoint::GetSigPoint(sigPointKind);
     DXIL::ShaderKind shaderKind = sigPoint->GetShaderKind();
 
@@ -101,7 +98,6 @@ public:
       IFT(library->CreateBlobFromFile(path.c_str(), nullptr, &m_pSource));
     }
 
-    static_assert(6 == HighestMajor && 1 == HighestMinor, "otherwise, need to update default profiles below");
     LPCWSTR entry, profile;
     wchar_t profile_buf[] = L"vs_6_1";
     switch(shaderKind) {
@@ -112,7 +108,11 @@ public:
       case DXIL::ShaderKind::Domain:    entry = L"DSMain"; profile = L"ds_6_1"; break;
       case DXIL::ShaderKind::Compute:   entry = L"CSMain"; profile = L"cs_6_1"; break;
     }
-    if (Major != HighestMajor || Minor != HighestMinor) {
+    if (Major == 0) {
+      Major = m_HighestMajor;
+      Minor = m_HighestMinor;
+    }
+    if (Major != 6 || Minor != 1) {
       profile_buf[0] = profile[0];
       profile_buf[3] = L'0' + (wchar_t)Major;
       profile_buf[5] = L'0' + (wchar_t)Minor;
@@ -157,12 +157,22 @@ public:
   }
 
   dxc::DxcDllSupport m_dllSupport;
+  VersionSupportInfo m_ver;
+  unsigned m_HighestMajor, m_HighestMinor;  // Shader Model Supported
+
   CComPtr<IDxcBlobEncoding> m_pSource;
 };
 
 bool SystemValueTest::InitSupport() {
   if (!m_dllSupport.IsEnabled()) {
     VERIFY_SUCCEEDED(m_dllSupport.Initialize());
+    m_ver.Initialize(m_dllSupport);
+    m_HighestMajor = 6;
+    m_HighestMinor = 0;
+    if ((m_ver.m_DxilMajor > 1 || (m_ver.m_DxilMajor == 1 && m_ver.m_DxilMinor > 1)) &&
+        (m_ver.m_ValMajor > 1 || (m_ver.m_ValMajor == 1 && m_ver.m_ValMinor > 1))) {
+      m_HighestMinor = 1;
+    }
   }
   return true;
 }
@@ -186,6 +196,7 @@ static bool ArbAllowed(DXIL::SigPointKind sp) {
 }
 
 TEST_F(SystemValueTest, VerifyArbitrarySupport) {
+  WEX::TestExecution::SetVerifyOutput verifySettings(WEX::TestExecution::VerifyOutputSettings::LogOnlyFailures);
   for (DXIL::SigPointKind sp = (DXIL::SigPointKind)0; sp < DXIL::SigPointKind::Invalid; sp = (DXIL::SigPointKind)((unsigned)sp + 1)) {
     CComPtr<IDxcOperationResult> pResult;
     CompileHLSLTemplate(pResult, sp, DXIL::SemanticKind::Invalid, true);
@@ -214,7 +225,7 @@ TEST_F(SystemValueTest, VerifyNotAvailableFail) {
   WEX::TestExecution::SetVerifyOutput verifySettings(WEX::TestExecution::VerifyOutputSettings::LogOnlyFailures);
   for (DXIL::SigPointKind sp = (DXIL::SigPointKind)0; sp < DXIL::SigPointKind::Invalid; sp = (DXIL::SigPointKind)((unsigned)sp + 1)) {
     for (DXIL::SemanticKind sv = (DXIL::SemanticKind)((unsigned)DXIL::SemanticKind::Arbitrary + 1); sv < DXIL::SemanticKind::Invalid; sv = (DXIL::SemanticKind)((unsigned)sv + 1)) {
-      DXIL::SemanticInterpretationKind interpretation = hlsl::SigPoint::GetInterpretation(sv, sp, HighestMajor, HighestMinor);
+      DXIL::SemanticInterpretationKind interpretation = hlsl::SigPoint::GetInterpretation(sv, sp, m_HighestMajor, m_HighestMinor);
       if (interpretation == DXIL::SemanticInterpretationKind::NA) {
         CComPtr<IDxcOperationResult> pResult;
         CompileHLSLTemplate(pResult, sp, sv, false);
@@ -241,7 +252,7 @@ TEST_F(SystemValueTest, VerifySVAsArbitrary) {
   WEX::TestExecution::SetVerifyOutput verifySettings(WEX::TestExecution::VerifyOutputSettings::LogOnlyFailures);
   for (DXIL::SigPointKind sp = (DXIL::SigPointKind)0; sp < DXIL::SigPointKind::Invalid; sp = (DXIL::SigPointKind)((unsigned)sp + 1)) {
     for (DXIL::SemanticKind sv = (DXIL::SemanticKind)((unsigned)DXIL::SemanticKind::Arbitrary + 1); sv < DXIL::SemanticKind::Invalid; sv = (DXIL::SemanticKind)((unsigned)sv + 1)) {
-      DXIL::SemanticInterpretationKind interpretation = hlsl::SigPoint::GetInterpretation(sv, sp, HighestMajor, HighestMinor);
+      DXIL::SemanticInterpretationKind interpretation = hlsl::SigPoint::GetInterpretation(sv, sp, m_HighestMajor, m_HighestMinor);
       if (interpretation == DXIL::SemanticInterpretationKind::Arb) {
         CComPtr<IDxcOperationResult> pResult;
         CompileHLSLTemplate(pResult, sp, sv, false);
@@ -259,7 +270,7 @@ TEST_F(SystemValueTest, VerifySVAsSV) {
   WEX::TestExecution::SetVerifyOutput verifySettings(WEX::TestExecution::VerifyOutputSettings::LogOnlyFailures);
   for (DXIL::SigPointKind sp = (DXIL::SigPointKind)0; sp < DXIL::SigPointKind::Invalid; sp = (DXIL::SigPointKind)((unsigned)sp + 1)) {
     for (DXIL::SemanticKind sv = (DXIL::SemanticKind)((unsigned)DXIL::SemanticKind::Arbitrary + 1); sv < DXIL::SemanticKind::Invalid; sv = (DXIL::SemanticKind)((unsigned)sv + 1)) {
-      DXIL::SemanticInterpretationKind interpretation = hlsl::SigPoint::GetInterpretation(sv, sp, HighestMajor, HighestMinor);
+      DXIL::SemanticInterpretationKind interpretation = hlsl::SigPoint::GetInterpretation(sv, sp, m_HighestMajor, m_HighestMinor);
       if (interpretation == DXIL::SemanticInterpretationKind::SV || interpretation == DXIL::SemanticInterpretationKind::SGV) {
         CComPtr<IDxcOperationResult> pResult;
         CompileHLSLTemplate(pResult, sp, sv, false);
@@ -277,7 +288,7 @@ TEST_F(SystemValueTest, VerifySGV) {
   WEX::TestExecution::SetVerifyOutput verifySettings(WEX::TestExecution::VerifyOutputSettings::LogOnlyFailures);
   for (DXIL::SigPointKind sp = (DXIL::SigPointKind)0; sp < DXIL::SigPointKind::Invalid; sp = (DXIL::SigPointKind)((unsigned)sp + 1)) {
     for (DXIL::SemanticKind sv = (DXIL::SemanticKind)((unsigned)DXIL::SemanticKind::Arbitrary + 1); sv < DXIL::SemanticKind::Invalid; sv = (DXIL::SemanticKind)((unsigned)sv + 1)) {
-      DXIL::SemanticInterpretationKind interpretation = hlsl::SigPoint::GetInterpretation(sv, sp, HighestMajor, HighestMinor);
+      DXIL::SemanticInterpretationKind interpretation = hlsl::SigPoint::GetInterpretation(sv, sp, m_HighestMajor, m_HighestMinor);
       if (interpretation == DXIL::SemanticInterpretationKind::SGV) {
         CComPtr<IDxcOperationResult> pResult;
         CompileHLSLTemplate(pResult, sp, sv, true);
@@ -296,7 +307,7 @@ TEST_F(SystemValueTest, VerifySVNotPacked) {
   WEX::TestExecution::SetVerifyOutput verifySettings(WEX::TestExecution::VerifyOutputSettings::LogOnlyFailures);
   for (DXIL::SigPointKind sp = (DXIL::SigPointKind)0; sp < DXIL::SigPointKind::Invalid; sp = (DXIL::SigPointKind)((unsigned)sp + 1)) {
     for (DXIL::SemanticKind sv = (DXIL::SemanticKind)((unsigned)DXIL::SemanticKind::Arbitrary + 1); sv < DXIL::SemanticKind::Invalid; sv = (DXIL::SemanticKind)((unsigned)sv + 1)) {
-      DXIL::SemanticInterpretationKind interpretation = hlsl::SigPoint::GetInterpretation(sv, sp, HighestMajor, HighestMinor);
+      DXIL::SemanticInterpretationKind interpretation = hlsl::SigPoint::GetInterpretation(sv, sp, m_HighestMajor, m_HighestMinor);
       if (interpretation == DXIL::SemanticInterpretationKind::NotPacked) {
         CComPtr<IDxcOperationResult> pResult;
         CompileHLSLTemplate(pResult, sp, sv, false);
@@ -314,7 +325,7 @@ TEST_F(SystemValueTest, VerifySVNotInSig) {
   WEX::TestExecution::SetVerifyOutput verifySettings(WEX::TestExecution::VerifyOutputSettings::LogOnlyFailures);
   for (DXIL::SigPointKind sp = (DXIL::SigPointKind)0; sp < DXIL::SigPointKind::Invalid; sp = (DXIL::SigPointKind)((unsigned)sp + 1)) {
     for (DXIL::SemanticKind sv = (DXIL::SemanticKind)((unsigned)DXIL::SemanticKind::Arbitrary + 1); sv < DXIL::SemanticKind::Invalid; sv = (DXIL::SemanticKind)((unsigned)sv + 1)) {
-      DXIL::SemanticInterpretationKind interpretation = hlsl::SigPoint::GetInterpretation(sv, sp, HighestMajor, HighestMinor);
+      DXIL::SemanticInterpretationKind interpretation = hlsl::SigPoint::GetInterpretation(sv, sp, m_HighestMajor, m_HighestMinor);
       if (interpretation == DXIL::SemanticInterpretationKind::NotInSig) {
         CComPtr<IDxcOperationResult> pResult;
         CompileHLSLTemplate(pResult, sp, sv, false);
@@ -374,7 +385,7 @@ TEST_F(SystemValueTest, VerifyShadowEntries) {
   WEX::TestExecution::SetVerifyOutput verifySettings(WEX::TestExecution::VerifyOutputSettings::LogOnlyFailures);
   for (DXIL::SigPointKind sp = (DXIL::SigPointKind)0; sp < DXIL::SigPointKind::Invalid; sp = (DXIL::SigPointKind)((unsigned)sp + 1)) {
     for (DXIL::SemanticKind sv = (DXIL::SemanticKind)((unsigned)DXIL::SemanticKind::Arbitrary + 1); sv < DXIL::SemanticKind::Invalid; sv = (DXIL::SemanticKind)((unsigned)sv + 1)) {
-      DXIL::SemanticInterpretationKind interpretation = hlsl::SigPoint::GetInterpretation(sv, sp, HighestMajor, HighestMinor);
+      DXIL::SemanticInterpretationKind interpretation = hlsl::SigPoint::GetInterpretation(sv, sp, m_HighestMajor, m_HighestMinor);
       if (interpretation == DXIL::SemanticInterpretationKind::Shadow) {
         CComPtr<IDxcOperationResult> pResult;
         CompileHLSLTemplate(pResult, sp, sv, false);
@@ -430,6 +441,10 @@ TEST_F(SystemValueTest, VerifyVersionedSemantics) {
     if (MajorLower < 6)
       continue;
 
+    // Don't try targets our compiler/validator combination do not support.
+    if (test.Major > m_HighestMajor || test.Minor > m_HighestMinor)
+      continue;
+
     {
       CComPtr<IDxcOperationResult> pResult;
       CompileHLSLTemplate(pResult, test.sp, test.sv, false, test.Major, test.Minor);

+ 27 - 25
tools/clang/unittests/HLSL/ValidationTest.cpp

@@ -300,15 +300,7 @@ public:
   TEST_METHOD(ViewIDNoSpaceFail)
 
   dxc::DxcDllSupport m_dllSupport;
-  bool m_CompilerPreservesBBNames;
-
-  bool SkipIRSensitiveTest() {
-    if (!m_CompilerPreservesBBNames) {
-      WEX::Logging::Log::Comment(L"Test skipped due to name preservation requirment.");
-      return true;
-    }
-    return false;
-  }
+  VersionSupportInfo m_ver;
 
   void TestCheck(LPCWSTR name) {
     std::wstring fullPath = hlsl_test::GetPathToHlslDataFile(name);
@@ -324,8 +316,18 @@ public:
     CComPtr<IDxcValidator> pValidator;
     CComPtr<IDxcOperationResult> pResult;
 
+    UINT32 Flags = DxcValidatorFlags_Default;
+    if (!IsDxilContainerLike(pBlob->GetBufferPointer(), pBlob->GetBufferSize())) {
+      // Validation of raw bitcode as opposed to DxilContainer is not supported through DXIL.dll
+      if (!m_ver.m_InternalValidator) {
+        WEX::Logging::Log::Comment(L"Test skipped due to validation of raw bitcode without container and use of external DXIL.dll validator.");
+        return;
+      }
+      Flags |= DxcValidatorFlags_ModuleOnly;
+    }
+
     VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcValidator, &pValidator));
-    VERIFY_SUCCEEDED(pValidator->Validate(pBlob, DxcValidatorFlags_Default, &pResult));
+    VERIFY_SUCCEEDED(pValidator->Validate(pBlob, Flags, &pResult));
 
     CheckOperationResultMsgs(pResult, pErrorMsgs, false, bRegex);
   }
@@ -521,15 +523,7 @@ public:
 bool ValidationTest::InitSupport() {
   if (!m_dllSupport.IsEnabled()) {
     VERIFY_SUCCEEDED(m_dllSupport.Initialize());
-
-    // This is a very indirect way of testing this. Consider improving support.
-    CComPtr<IDxcValidator> pValidator;
-    CComPtr<IDxcVersionInfo> pVersionInfo;
-    UINT32 VersionFlags = 0;
-    VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcValidator, &pValidator));
-    VERIFY_SUCCEEDED(pValidator.QueryInterface(&pVersionInfo));
-    VERIFY_SUCCEEDED(pVersionInfo->GetFlags(&VersionFlags));
-    m_CompilerPreservesBBNames = (VersionFlags & DxcVersionInfoFlags_Debug) ? true : false;
+    m_ver.Initialize(m_dllSupport);
   }
   return true;
 }
@@ -653,7 +647,7 @@ TEST_F(ValidationTest, WhenDepthNotFloatThenFail) {
 }
 
 TEST_F(ValidationTest, BarrierFail) {
-  if (SkipIRSensitiveTest()) return;
+  if (m_ver.SkipIRSensitiveTest()) return;
     RewriteAssemblyCheckMsg(
       L"..\\CodeGenHLSL\\barrier.hlsl", "cs_6_0",
       {"dx.op.barrier(i32 80, i32 8)",
@@ -702,7 +696,7 @@ TEST_F(ValidationTest, CsThreadSizeFail) {
       });
 }
 TEST_F(ValidationTest, DeadLoopFail) {
-  if (SkipIRSensitiveTest()) return;
+  if (m_ver.SkipIRSensitiveTest()) return;
   RewriteAssemblyCheckMsg(
       L"..\\CodeGenHLSL\\loop1.hlsl", "ps_6_0",
       {"br i1 %exitcond, label %for.end.loopexit, label %for.body, !llvm.loop !([0-9]+)",
@@ -798,7 +792,7 @@ TEST_F(ValidationTest, MultiStream2Fail) {
       "Multiple GS output streams are used but 'XXX' is not pointlist");
 }
 TEST_F(ValidationTest, PhiTGSMFail) {
-  if (SkipIRSensitiveTest()) return;
+  if (m_ver.SkipIRSensitiveTest()) return;
   RewriteAssemblyCheckMsg(
       L"..\\CodeGenHLSL\\phiTGSM.hlsl", "cs_6_0",
       "ret void",
@@ -808,7 +802,7 @@ TEST_F(ValidationTest, PhiTGSMFail) {
       "TGSM pointers must originate from an unambiguous TGSM global variable");
 }
 TEST_F(ValidationTest, ReducibleFail) {
-  if (SkipIRSensitiveTest()) return;
+  if (m_ver.SkipIRSensitiveTest()) return;
   RewriteAssemblyCheckMsg(
       L"..\\CodeGenHLSL\\reducible.hlsl", "ps_6_0",
       {"%conv\n"
@@ -954,7 +948,7 @@ TEST_F(ValidationTest, SimpleGs1Fail) {
        "Stream index (5) must between 0 and 3"});
 }
 TEST_F(ValidationTest, UavBarrierFail) {
-  if (SkipIRSensitiveTest()) return;
+  if (m_ver.SkipIRSensitiveTest()) return;
   RewriteAssemblyCheckMsg(
       L"..\\CodeGenHLSL\\uavBarrier.hlsl", "ps_6_0",
       {"dx.op.barrier(i32 80, i32 2)",
@@ -976,7 +970,7 @@ TEST_F(ValidationTest, UndefValueFail) {
   TestCheck(L"..\\CodeGenHLSL\\UndefValue.hlsl");
 }
 TEST_F(ValidationTest, UpdateCounterFail) {
-  if (SkipIRSensitiveTest()) return;
+  if (m_ver.SkipIRSensitiveTest()) return;
   RewriteAssemblyCheckMsg(
       L"..\\CodeGenHLSL\\UpdateCounter2.hlsl", "ps_6_0",
       {"%2 = call i32 @dx.op.bufferUpdateCounter(i32 70, %dx.types.Handle %buf2_UAV_structbuf, i8 1)",
@@ -2898,6 +2892,7 @@ TEST_F(ValidationTest, WhenFeatureInfoMismatchThenFail) {
 }
 
 TEST_F(ValidationTest, ViewIDInCSFail) {
+  if (m_ver.SkipDxil_1_1_Test()) return;
   RewriteAssemblyCheckMsg(" \
 RWStructuredBuffer<uint> Buf; \
 [numthreads(1,1,1)] \
@@ -2914,6 +2909,7 @@ void main(uint id : SV_GroupIndex) \
 }
 
 TEST_F(ValidationTest, ViewIDIn60Fail) {
+  if (m_ver.SkipDxil_1_1_Test()) return;
   RewriteAssemblyCheckMsg(" \
 [domain(\"tri\")] \
 float4 main(float3 pos : Position, uint id : SV_PrimitiveID) : SV_Position \
@@ -2929,6 +2925,7 @@ float4 main(float3 pos : Position, uint id : SV_PrimitiveID) : SV_Position \
 }
 
 TEST_F(ValidationTest, ViewIDNoSpaceFail) {
+  if (m_ver.SkipDxil_1_1_Test()) return;
   RewriteAssemblyCheckMsg(" \
 float4 main(uint vid : SV_ViewID, float3 In[31] : INPUT) : SV_Target \
 { return float4(In[vid], 1); } \
@@ -2943,6 +2940,7 @@ float4 main(uint vid : SV_ViewID, float3 In[31] : INPUT) : SV_Target \
 }
 
 TEST_F(ValidationTest, GetAttributeAtVertexInVSFail) {
+  if (m_ver.SkipDxil_1_1_Test()) return;
   RewriteAssemblyCheckMsg(
     "float4 main(float4 pos: POSITION) : SV_POSITION { return pos.x; }",
     "vs_6_1",
@@ -2955,6 +2953,7 @@ TEST_F(ValidationTest, GetAttributeAtVertexInVSFail) {
 }
 
 TEST_F(ValidationTest, GetAttributeAtVertexIn60Fail) {
+  if (m_ver.SkipDxil_1_1_Test()) return;
   RewriteAssemblyCheckMsg(
     "float4 main(float4 col : COLOR) : "
     "SV_Target { return EvaluateAttributeCentroid(col).x; }",
@@ -2968,6 +2967,7 @@ TEST_F(ValidationTest, GetAttributeAtVertexIn60Fail) {
 }
 
 TEST_F(ValidationTest, GetAttributeAtVertexInterpFail) {
+  if (m_ver.SkipDxil_1_1_Test()) return;
   RewriteAssemblyCheckMsg("float4 main(nointerpolation float4 col : COLOR) : "
                           "SV_Target { return GetAttributeAtVertex(col, 0); }",
                           "ps_6_1", {"!\"COLOR\", i8 9, i8 0, (![0-9]+), i8 1"},
@@ -2978,6 +2978,7 @@ TEST_F(ValidationTest, GetAttributeAtVertexInterpFail) {
 }
 
 TEST_F(ValidationTest, BarycentricNoInterpolationFail) {
+  if (m_ver.SkipDxil_1_1_Test()) return;
   RewriteAssemblyCheckMsg(
       "float4 main(float3 bary : SV_Barycentrics) : "
       "SV_Target { return bary.x * float4(1,0,0,0) + bary.y * float4(0,1,0,0) "
@@ -2989,6 +2990,7 @@ TEST_F(ValidationTest, BarycentricNoInterpolationFail) {
 }
 
 TEST_F(ValidationTest, BarycentricFloat4Fail) {
+  if (m_ver.SkipDxil_1_1_Test()) return;
   RewriteAssemblyCheckMsg(
       "float4 main(float4 col : COLOR) : SV_Target { return col; }", "ps_6_1",
       {"!\"COLOR\", i8 9, i8 0"}, {"!\"SV_Barycentrics\", i8 9, i8 28"},