diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 94a3a4d8cb..73213a6f3a 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -45,7 +45,23 @@ stages: - script: | call utils\hct\hctstart.cmd %HLSL_SRC_DIR% %HLSL_BLD_DIR% call utils\hct\hcttest.cmd -$(configuration) exec - displayName: 'DXIL Execution Tests' + displayName: 'DXIL Execution Tests' + - script: | + call utils\hct\hctstart.cmd %HLSL_SRC_DIR% %HLSL_BLD_DIR% + call utils\hct\hcttest.cmd -$(configuration) compat-suite 1.6 + displayName: 'DXIL Compat Suite Tests (1.6 release)' + condition: succeededOrFailed() + - script: | + call utils\hct\hctstart.cmd %HLSL_SRC_DIR% %HLSL_BLD_DIR% + call utils\hct\hcttest.cmd -$(configuration) compat-suite 1.7 + displayName: 'DXIL Compat Suite Tests (1.7 release)' + condition: succeededOrFailed() + - script: | + call utils\hct\hctstart.cmd %HLSL_SRC_DIR% %HLSL_BLD_DIR% + call utils\hct\hcttest.cmd -$(configuration) compat-suite 1.8 + displayName: 'DXIL Compat Suite Tests (1.8 release)' + condition: succeededOrFailed() + - job: Nix timeoutInMinutes: 165 diff --git a/include/dxc/Support/HLSLOptions.h b/include/dxc/Support/HLSLOptions.h index 4a6868956a..010bb6f572 100644 --- a/include/dxc/Support/HLSLOptions.h +++ b/include/dxc/Support/HLSLOptions.h @@ -227,6 +227,7 @@ class DxcOpts { std::string TimeTrace = ""; // OPT_ftime_trace[EQ] unsigned TimeTraceGranularity = 500; // OPT_ftime_trace_granularity_EQ bool VerifyDiagnostics = false; // OPT_verify + bool Verbose = false; // OPT_verbose // Optimization pass enables, disables and selects OptimizationToggles @@ -257,6 +258,11 @@ class DxcOpts { bool EmbedPDBName() const; // Zi or Fd bool DebugFileIsDirectory() const; // Fd ends in '\\' llvm::StringRef GetPDBName() const; // Fd name + bool ProduceDxModule() + const; // !AstDump && !OptDump && !GenSPIRV && !DumpDependencies && + // !VerifyDiagnostics && Preprocess.empty(); + bool ProduceFullContainer() const; // ProduceDxModule() && CodeGenHighLevel + bool NeedsValidation() const; // ProduceFullContainer() && !DisableValidation // SPIRV Change Starts #ifdef ENABLE_SPIRV_CODEGEN diff --git a/include/dxc/Support/HLSLOptions.td b/include/dxc/Support/HLSLOptions.td index 4a38e275c3..40182f85b9 100644 --- a/include/dxc/Support/HLSLOptions.td +++ b/include/dxc/Support/HLSLOptions.td @@ -197,6 +197,18 @@ def verify : Joined<["-"], "verify">, Group, Flags<[CoreOption, DriverOption]>, HelpText<"Verify diagnostic output using comment directives">; +def verbose : Flag<["-"], "verbose">, + Group, + Flags<[DriverOption]>, + HelpText<"Allow emission of verbose compiler information">; + +// Short alias '-v' for the verbose option +def v : Flag<["-"], "v">, + Alias, + Group, + Flags<[DriverOption]>, + HelpText<"Alias for -verbose">; + /* def fno_caret_diagnostics : Flag<["-"], "fno-caret-diagnostics">, Group, Flags<[CoreOption]>; diff --git a/include/dxc/Support/dxcapi.extval.h b/include/dxc/Support/dxcapi.extval.h index e479c9cce1..3e48ce6f55 100644 --- a/include/dxc/Support/dxcapi.extval.h +++ b/include/dxc/Support/dxcapi.extval.h @@ -1,8 +1,12 @@ #include "dxc/Support/dxcapi.use.h" +#include "dxc/WinAdapter.h" +#include "llvm/Support/raw_ostream.h" + #include #include namespace dxc { + class DxcDllExtValidationLoader : public DllLoader { // DxCompilerSupport manages the // lifetime of dxcompiler.dll, while DxilExtValSupport @@ -12,8 +16,15 @@ class DxcDllExtValidationLoader : public DllLoader { std::string DxilDllPath; public: - std::string GetDxilDllPath() { return DxilDllPath; } - bool DxilDllFailedToLoad() { + std::string getDxilDllPath() { return DxilDllPath; } + enum InitializationFailures { + FailedNone = 0, + FailedCompilerLoad, + FailedDxilPath, + FailedDxilLoad, + } FailureReason = FailedNone; + InitializationFailures getFailureReason() { return FailureReason; } + bool dxilDllFailedToLoad() { return !DxilDllPath.empty() && !DxilExtValSupport.IsEnabled(); } @@ -22,7 +33,8 @@ class DxcDllExtValidationLoader : public DllLoader { HRESULT CreateInstance2Impl(IMalloc *pMalloc, REFCLSID clsid, REFIID riid, IUnknown **pResult) override; - HRESULT Initialize(); + HRESULT initialize(); + HRESULT InitializeForDll(LPCSTR dllName, LPCSTR fnName); bool IsEnabled() const override { return DxCompilerSupport.IsEnabled(); } }; diff --git a/lib/DxcSupport/HLSLOptions.cpp b/lib/DxcSupport/HLSLOptions.cpp index 06e6a1bed6..3955ace86b 100644 --- a/lib/DxcSupport/HLSLOptions.cpp +++ b/lib/DxcSupport/HLSLOptions.cpp @@ -165,6 +165,24 @@ llvm::StringRef DxcOpts::GetPDBName() const { return llvm::StringRef(); } +bool DxcOpts::ProduceDxModule() const { + + return !AstDump && !OptDump && +#ifdef ENABLE_SPIRV_CODEGEN + !GenSPIRV && +#endif + !DumpDependencies && !VerifyDiagnostics && !IsRootSignatureProfile() && + Preprocess.empty(); +} + +bool DxcOpts::ProduceFullContainer() const { + return DxcOpts::ProduceDxModule() && !CodeGenHighLevel; +} + +bool DxcOpts::NeedsValidation() const { + return ProduceFullContainer() && !DisableValidation; +} + MainArgs::MainArgs(int argc, const wchar_t **argv, int skipArgCount) { if (argc > skipArgCount) { Utf8StringVector.reserve(argc - skipArgCount); @@ -871,6 +889,7 @@ int ReadDxcOpts(const OptTable *optionTable, unsigned flagsToInclude, opts.TimeReport = Args.hasFlag(OPT_ftime_report, OPT_INVALID, false); opts.TimeTrace = Args.hasFlag(OPT_ftime_trace, OPT_INVALID, false) ? "-" : ""; opts.VerifyDiagnostics = Args.hasFlag(OPT_verify, OPT_INVALID, false); + opts.Verbose = Args.hasFlag(OPT_verbose, OPT_INVALID, false); if (Args.hasArg(OPT_ftime_trace_EQ)) opts.TimeTrace = Args.getLastArgValue(OPT_ftime_trace_EQ); if (Arg *A = Args.getLastArg(OPT_ftime_trace_granularity_EQ)) { diff --git a/lib/DxcSupport/dxcapi.extval.cpp b/lib/DxcSupport/dxcapi.extval.cpp index 699873cc3d..8dd07101e5 100644 --- a/lib/DxcSupport/dxcapi.extval.cpp +++ b/lib/DxcSupport/dxcapi.extval.cpp @@ -1,42 +1,421 @@ +#ifndef _WIN32 +#include "dxc/WinAdapter.h" +#endif + +#include "dxc/Support/Global.h" // for hresult handling +#include "dxc/Support/HLSLOptions.h" #include "dxc/Support/WinIncludes.h" -#include // for hresult handling with DXC_FAILED -#include // C++17 and later +#include // C++17 and later +#include // WinIncludes must come before dxcapi.extval.h +#include "dxc/Support/FileIOHelper.h" #include "dxc/Support/dxcapi.extval.h" +#include "dxc/Support/dxcapi.impl.h" +#include "dxc/Support/microcom.h" +#include "dxc/dxcapi.internal.h" +#include + +#include "llvm/ADT/SmallVector.h" + +namespace { + +// The ExtValidationArgHelper class helps manage arguments for external +// validation, as well as perform the validation step if needed. +class ExtValidationArgHelper { +public: + ExtValidationArgHelper() = default; + ExtValidationArgHelper(const ExtValidationArgHelper &) = delete; + HRESULT initialize(IDxcValidator *NewValidator, LPCWSTR **Arguments, + UINT32 *ArgCount, LPCWSTR TargetProfile = nullptr) { + IFR(setValidator(NewValidator)); + IFR(processArgs(Arguments, ArgCount, TargetProfile)); + return S_OK; + } + + HRESULT doValidation(IDxcOperationResult *CompileResult, REFIID Riid, + void **ValResult) { + + if (!CompileResult) + return E_INVALIDARG; + + // No validation needed; just set the result and return. + if (!NeedsValidation) + return CompileResult->QueryInterface(Riid, ValResult); + + // Get the compiled shader. + CComPtr CompiledBlob; + IFR(CompileResult->GetResult(&CompiledBlob)); + + // If no compiled blob; just place the compile result + // into ValResult and return. + if (!CompiledBlob) + return CompileResult->QueryInterface(Riid, ValResult); + + // Validate the compiled shader. + CComPtr TempValidationResult; + UINT32 DxcValidatorFlags = + DxcValidatorFlags_InPlaceEdit | + (RootSignatureOnly ? DxcValidatorFlags_RootSignatureOnly : 0); + IFR(Validator->Validate(CompiledBlob, DxcValidatorFlags, + &TempValidationResult)); + + // Return the validation result if it failed. + HRESULT HR; + IFR(TempValidationResult->GetStatus(&HR)); + if (FAILED(HR)) { + // prefix the stderr output + fprintf(stderr, "error: validation errors\r\n"); + return TempValidationResult->QueryInterface(Riid, ValResult); + } + + // Validation succeeded. Return the original compile result. + return CompileResult->QueryInterface(Riid, ValResult); + } + +private: + std::vector ArgStorage; + llvm::SmallVector NewArgs; + hlsl::options::DxcOpts Opts; + CComPtr Validator; + UINT32 ValidatorVersionMajor = 0; + UINT32 ValidatorVersionMinor = 0; + bool NeedsValidation = false; + bool RootSignatureOnly = false; + + /// Add argument to ArgStorage to be referenced by NewArgs. + void addArgument(const std::wstring &Arg) { ArgStorage.push_back(Arg); } + + HRESULT setValidator(IDxcValidator *NewValidator) { + DXASSERT(NewValidator, "Invalid Validator argument"); + Validator = NewValidator; + + // 1.0 had no version interface. + ValidatorVersionMajor = 1; + ValidatorVersionMinor = 0; + CComPtr ValidatorVersionInfo; + if (SUCCEEDED( + Validator->QueryInterface(IID_PPV_ARGS(&ValidatorVersionInfo)))) { + if (FAILED(ValidatorVersionInfo->GetVersion(&ValidatorVersionMajor, + &ValidatorVersionMinor))) { + DXASSERT(false, "Failed to get validator version"); + return E_FAIL; + } + } + return S_OK; + } + + /// Process arguments, adding validator version and disable validation if + /// needed. If TargetProfile provided, use this instead of -T argument. + HRESULT processArgs(LPCWSTR **Arguments, UINT32 *ArgCount, + LPCWSTR TargetProfile = nullptr) { + DXASSERT((Arguments && ArgCount) && (*Arguments || *ArgCount == 0) && + *ArgCount < INT_MAX - 3, + "Invalid Arguments and ArgCount arguments"); + NeedsValidation = false; + + // Must not call twice. + DXASSERT(NewArgs.empty(), "Must not call twice"); + + // Parse compiler arguments to Opts. + std::string Errors; + llvm::raw_string_ostream OS(Errors); + hlsl::options::MainArgs MainArgs(static_cast(*ArgCount), *Arguments, + 0); + if (hlsl::options::ReadDxcOpts(hlsl::options::getHlslOptTable(), + hlsl::options::CompilerFlags, MainArgs, Opts, + OS)) + return E_FAIL; + + // Determine important conditions from arguments. + const bool ProduceDxModule = Opts.ProduceDxModule(); + NeedsValidation = Opts.NeedsValidation(); + RootSignatureOnly = Opts.IsRootSignatureProfile(); + + // Add extra arguments as needed + if (ProduceDxModule) { + if (Opts.ValVerMajor == UINT_MAX) { + // If not supplied, add validator version arguments. + addArgument(L"-validator-version"); + std::wstring VerStr = std::to_wstring(ValidatorVersionMajor) + L"." + + std::to_wstring(ValidatorVersionMinor); + addArgument(VerStr); + } + + // Add argument to disable validation, so we can call it ourselves + // later. + if (NeedsValidation) + addArgument(L"-Vd"); + } + + if (ArgStorage.empty()) + return S_OK; + + // Reference added arguments from storage. + NewArgs.reserve(*ArgCount + ArgStorage.size()); + + // Copied arguments refer to original strings. + for (UINT32 I = 0; I < *ArgCount; ++I) + NewArgs.push_back((*Arguments)[I]); + + for (const auto &Arg : ArgStorage) + NewArgs.push_back(Arg.c_str()); + + *Arguments = NewArgs.data(); + *ArgCount = (UINT32)NewArgs.size(); + return S_OK; + } +}; + +// ExternalValidationCompiler wraps a DxCompiler to use an external validator +// instead of the internal one. It disables internal validation by adding +// '-Vd' and sets the default validator version with '-validator-version'. +// After a successful compilation, it uses the provided IDxcValidator to +// perform validation when it would normally be performed. +class ExternalValidationCompiler : public IDxcCompiler2, public IDxcCompiler3 { +public: + ExternalValidationCompiler(IMalloc *Malloc, IDxcValidator *OtherValidator, + IUnknown *OtherCompiler) + : Validator(OtherValidator), Compiler(OtherCompiler), m_pMalloc(Malloc) {} + + // IUnknown implementation + DXC_MICROCOM_TM_ADDREF_RELEASE_IMPL() + DXC_MICROCOM_TM_ALLOC(ExternalValidationCompiler) + + // QueryInterface creates a new wrapper for the correct compiler interface + // retrieved by calling QueryInterface on the compiler. The new wrapper + // keeps the IID and returned compiler interface pointer for use in + // associated interface methods. Those methods can then use + // castCompilerUnsafe to upcast the pointer to the appropriate interface + // for the method. + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID Iid, + void **ResultObject) override { + if (!ResultObject) + return E_POINTER; + + *ResultObject = nullptr; + + // Get pointer for an interface the compiler object supports. + CComPtr TempCompiler; + IFR(Compiler->QueryInterface(Iid, (void **)&TempCompiler)); + + try { + // This can throw; do not leak C++ exceptions through COM method + // calls. + CComPtr NewWrapper( + Alloc(m_pMalloc, Validator, TempCompiler)); + return DoBasicQueryInterface( + NewWrapper.p, Iid, ResultObject); + } catch (...) { + return E_FAIL; + } + } + + // IDxcCompiler implementation + HRESULT STDMETHODCALLTYPE + Compile(IDxcBlob *Source, LPCWSTR SourceName, LPCWSTR EntryPoint, + LPCWSTR TargetProfile, LPCWSTR *Arguments, UINT32 ArgCount, + const DxcDefine *Defines, UINT32 DefineCount, + IDxcIncludeHandler *IncludeHandler, + IDxcOperationResult **ResultObject) override { + if (ResultObject == nullptr) + return E_INVALIDARG; + + DxcThreadMalloc TM(m_pMalloc); + // initialize will update Arguments and ArgCount if needed. + ExtValidationArgHelper Helper; + IFR(Helper.initialize(Validator, &Arguments, &ArgCount, TargetProfile)); + + CComPtr CompileResult; + IFR(cast()->Compile( + Source, SourceName, EntryPoint, TargetProfile, Arguments, ArgCount, + Defines, DefineCount, IncludeHandler, &CompileResult)); + HRESULT CompileHR; + CompileResult->GetStatus(&CompileHR); + if (SUCCEEDED(CompileHR)) + return Helper.doValidation(CompileResult, IID_PPV_ARGS(ResultObject)); + CompileResult->QueryInterface(ResultObject); + return S_OK; + } + + HRESULT STDMETHODCALLTYPE + Preprocess(IDxcBlob *Source, LPCWSTR SourceName, LPCWSTR *Arguments, + UINT32 ArgCount, const DxcDefine *Defines, UINT32 DefineCount, + IDxcIncludeHandler *IncludeHandler, + IDxcOperationResult **ResultObject) override { + return cast()->Preprocess(Source, SourceName, Arguments, + ArgCount, Defines, DefineCount, + IncludeHandler, ResultObject); + } + + HRESULT STDMETHODCALLTYPE + Disassemble(IDxcBlob *Source, IDxcBlobEncoding **Disassembly) override { + return cast()->Disassemble(Source, Disassembly); + } + + // IDxcCompiler2 implementation + HRESULT STDMETHODCALLTYPE CompileWithDebug( + IDxcBlob *Source, LPCWSTR SourceName, LPCWSTR EntryPoint, + LPCWSTR TargetProfile, LPCWSTR *Arguments, UINT32 ArgCount, + const DxcDefine *pDefines, UINT32 DefineCount, + IDxcIncludeHandler *IncludeHandler, IDxcOperationResult **ResultObject, + LPWSTR *DebugBlobName, IDxcBlob **DebugBlob) override { + if (ResultObject == nullptr) + return E_INVALIDARG; + + DxcThreadMalloc TM(m_pMalloc); + // ProcessArgs will update Arguments and ArgCount if needed. + ExtValidationArgHelper Helper; + + IFR(Helper.initialize(Validator, &Arguments, &ArgCount, TargetProfile)); + + CComPtr CompileResult; + IFR(cast()->CompileWithDebug( + Source, SourceName, EntryPoint, TargetProfile, Arguments, ArgCount, + pDefines, DefineCount, IncludeHandler, &CompileResult, DebugBlobName, + DebugBlob)); + + return Helper.doValidation(CompileResult, IID_PPV_ARGS(ResultObject)); + } + + // IDxcCompiler3 implementation + HRESULT STDMETHODCALLTYPE Compile(const DxcBuffer *Source, LPCWSTR *Arguments, + UINT32 ArgCount, + IDxcIncludeHandler *IncludeHandler, + REFIID Riid, + LPVOID *ResultObject) override { + if (ResultObject == nullptr) + return E_INVALIDARG; + + DxcThreadMalloc TM(m_pMalloc); + // ProcessArgs will update Arguments and ArgCount if needed. + ExtValidationArgHelper Helper; + + Helper.initialize(Validator, &Arguments, &ArgCount); + + CComPtr CompileResult; + IFR(cast()->Compile(Source, Arguments, ArgCount, + IncludeHandler, + IID_PPV_ARGS(&CompileResult))); + + return Helper.doValidation(CompileResult, Riid, ResultObject); + } + + HRESULT STDMETHODCALLTYPE Disassemble(const DxcBuffer *Object, REFIID Riid, + LPVOID *ResultObject) override { + return cast()->Disassemble(Object, Riid, ResultObject); + } + +private: + CComPtr Validator; + + // This wrapper wraps one particular compiler interface. + // When QueryInterface is called, we create a new wrapper + // for the requested interface, which wraps the result of QueryInterface + // on the compiler object. Compiler pointer is held as IUnknown and must + // be upcast to the appropriate interface on use. + CComPtr Compiler; + DXC_MICROCOM_TM_REF_FIELDS() + + template CComPtr cast() const { + CComPtr Result; + if (Compiler) + Compiler->QueryInterface(__uuidof(T), reinterpret_cast(&Result)); + assert(Result); + return Result; + } +}; +} // namespace namespace dxc { -HRESULT DxcDllExtValidationLoader::CreateInstanceImpl(REFCLSID clsid, - REFIID riid, - IUnknown **pResult) { - if (DxilExtValSupport.IsEnabled() && clsid == CLSID_DxcValidator) - return DxilExtValSupport.CreateInstance(clsid, riid, pResult); +static HRESULT createCompilerWrapper(IMalloc *Malloc, + SpecificDllLoader &DxCompilerSupport, + SpecificDllLoader &DxilExtValSupport, + REFIID Riid, IUnknown **ResultObject) { + DXASSERT(ResultObject, "Invalid ResultObject"); + *ResultObject = nullptr; + + CComPtr Compiler; + CComPtr Validator; - return DxCompilerSupport.CreateInstance(clsid, riid, pResult); + // Create compiler and validator + if (Malloc) { + IFR(DxCompilerSupport.CreateInstance2(Malloc, CLSID_DxcCompiler, Riid, + &Compiler)); + IFR(DxilExtValSupport.CreateInstance2( + Malloc, CLSID_DxcValidator, &Validator)); + } else { + IFR(DxCompilerSupport.CreateInstance(CLSID_DxcCompiler, Riid, &Compiler)); + IFR(DxilExtValSupport.CreateInstance(CLSID_DxcValidator, + &Validator)); + } + + // Wrap compiler + CComPtr CompilerWrapper = + ExternalValidationCompiler::Alloc( + Malloc ? Malloc : DxcGetThreadMallocNoRef(), Validator, Compiler); + return CompilerWrapper->QueryInterface(Riid, (void **)ResultObject); } -HRESULT DxcDllExtValidationLoader::CreateInstance2Impl(IMalloc *pMalloc, - REFCLSID clsid, - REFIID riid, - IUnknown **pResult) { - if (DxilExtValSupport.IsEnabled() && clsid == CLSID_DxcValidator) - return DxilExtValSupport.CreateInstance2(pMalloc, clsid, riid, pResult); +HRESULT DxcDllExtValidationLoader::CreateInstanceImpl(REFCLSID Clsid, + REFIID Riid, + IUnknown **ResultObject) { + if (!ResultObject) + return E_POINTER; + + *ResultObject = nullptr; - return DxCompilerSupport.CreateInstance2(pMalloc, clsid, riid, pResult); + // If there is intent to use an external dxil.dll + if (!DxilDllPath.empty() && !dxilDllFailedToLoad()) { + if (Clsid == CLSID_DxcValidator) { + return DxilExtValSupport.CreateInstance(Clsid, Riid, ResultObject); + } + if (Clsid == CLSID_DxcCompiler) { + return createCompilerWrapper(nullptr, DxCompilerSupport, + DxilExtValSupport, Riid, ResultObject); + } + } + + // Fallback: let DxCompiler handle it + return DxCompilerSupport.CreateInstance(Clsid, Riid, ResultObject); } -HRESULT DxcDllExtValidationLoader::Initialize() { +HRESULT DxcDllExtValidationLoader::CreateInstance2Impl( + IMalloc *Malloc, REFCLSID Clsid, REFIID Riid, IUnknown **ResultObject) { + if (!ResultObject) + return E_POINTER; + + *ResultObject = nullptr; + // If there is intent to use an external dxil.dll + if (!DxilDllPath.empty() && !dxilDllFailedToLoad()) { + if (Clsid == CLSID_DxcValidator) { + return DxilExtValSupport.CreateInstance2(Malloc, Clsid, Riid, + ResultObject); + } + if (Clsid == CLSID_DxcCompiler) { + return createCompilerWrapper(Malloc, DxCompilerSupport, DxilExtValSupport, + Riid, ResultObject); + } + } + + // Fallback: let DxCompiler handle it + return DxCompilerSupport.CreateInstance2(Malloc, Clsid, Riid, ResultObject); +} + +HRESULT +DxcDllExtValidationLoader::InitializeForDll(LPCSTR dllName, LPCSTR fnName) { // Load dxcompiler.dll - HRESULT Result = - DxCompilerSupport.InitializeForDll(kDxCompilerLib, "DxcCreateInstance"); + HRESULT Result = DxCompilerSupport.InitializeForDll(dllName, fnName); // if dxcompiler.dll fails to load, return the failed HRESULT - if (DXC_FAILED(Result)) { + if (FAILED(Result)) { + FailureReason = FailedCompilerLoad; return Result; } // now handle external dxil.dll const char *EnvVarVal = std::getenv("DXC_DXIL_DLL_PATH"); if (!EnvVarVal || std::string(EnvVarVal).empty()) { + // no need to emit anything if external validation isn't wanted return S_OK; } @@ -45,10 +424,22 @@ HRESULT DxcDllExtValidationLoader::Initialize() { // Check if path is absolute and exists if (!DllPath.is_absolute() || !std::filesystem::exists(DllPath)) { + FailureReason = FailedDxilPath; return E_INVALIDARG; } - return DxilExtValSupport.InitializeForDll(DxilDllPath.c_str(), - "DxcCreateInstance"); + Result = DxilExtValSupport.InitializeForDll(DxilDllPath.c_str(), + "DxcCreateInstance"); + if (FAILED(Result)) { + FailureReason = FailedDxilLoad; + return Result; + } + + return Result; } + +HRESULT DxcDllExtValidationLoader::initialize() { + return InitializeForDll(kDxCompilerLib, "DxcCreateInstance"); +} + } // namespace dxc diff --git a/tools/clang/test/CMakeLists.txt b/tools/clang/test/CMakeLists.txt index eb297a75de..438105b2eb 100644 --- a/tools/clang/test/CMakeLists.txt +++ b/tools/clang/test/CMakeLists.txt @@ -179,25 +179,19 @@ foreach(i RANGE 0 ${loop_end}) set(DXC_PATH ${CMAKE_BINARY_DIR}/tools/clang/test/dxc_releases/${version}/${name}/bin/${TARGET_ARCH}/dxil.dll) # Create a lit target for this release - add_lit_target("check-clang-${name}" "Running clang regression tests with ${name}\n" + add_lit_target("check-dxilcompat-${name}" "Running clang regression tests with dxil validator from ${name}\n" ${CMAKE_CURRENT_SOURCE_DIR} - PARAMS ${CLANG_TEST_PARAMS} DXC_DXIL_DLL_PATH=${DXC_PATH} - skip_taef_exec=True + PARAMS ${CLANG_TEST_PARAMS} + DXC_DXIL_DLL_PATH=${DXC_PATH} + DXC_RELEASE_VERSION_TAG=${version} + skip_taef_exec=True DEPENDS ${CLANG_TEST_DEPS} ${name} ARGS ${CLANG_TEST_EXTRA_ARGS} ) - # Ensure there is a top-level check-clang target - if(NOT TARGET check-clang) - add_custom_target(check-clang) - endif() - - # Make check-clang depend on this particular release's tests - add_dependencies(check-clang "check-clang-${name}") - # Hook into check-all if (WIN32 AND TARGET check-all) - add_dependencies(check-all "check-clang-${name}") + add_dependencies(check-all "check-dxilcompat-${name}") endif() endif() endforeach() diff --git a/tools/clang/test/CodeGenDXIL/hlsl/types/longvec-wave-intrinsics.hlsl b/tools/clang/test/CodeGenDXIL/hlsl/types/longvec-wave-intrinsics.hlsl index e2aadb0eba..69ee278ac1 100644 --- a/tools/clang/test/CodeGenDXIL/hlsl/types/longvec-wave-intrinsics.hlsl +++ b/tools/clang/test/CodeGenDXIL/hlsl/types/longvec-wave-intrinsics.hlsl @@ -1,3 +1,4 @@ +// REQUIRES: dxil-1-9 // RUN: %dxc -T ps_6_9 %s | FileCheck %s RWByteAddressBuffer buf; diff --git a/tools/clang/test/LitDXILValidation/validate_1_6_2112.hlsl b/tools/clang/test/LitDXILValidation/validate_1_6_2112.hlsl new file mode 100644 index 0000000000..ab7315e1cf --- /dev/null +++ b/tools/clang/test/LitDXILValidation/validate_1_6_2112.hlsl @@ -0,0 +1,13 @@ +// REQUIRES: dxilval-v1.6.2112 + +// Verify that the older DLL is being loaded, and that +// due to it being older, it errors on something that would +// be accepted in newer validators. +// Specifically, the v1.6.2112 validator would emit the +// below validation error, while validators newer than 1.6 +// would be able to validate the module. + +// RUN: not dxc -T cs_6_0 -validator-version 1.7 %s 2>&1 | FileCheck %s +// CHECK: error: Validator version in metadata (1.7) is not supported; maximum: (1.6). +[numthreads(1, 1, 1)] +void main() {} diff --git a/tools/clang/test/LitDXILValidation/validate_isspecialfloat.ll b/tools/clang/test/LitDXILValidation/validate_isspecialfloat.ll index 140d16520c..3bf85ac7c7 100644 --- a/tools/clang/test/LitDXILValidation/validate_isspecialfloat.ll +++ b/tools/clang/test/LitDXILValidation/validate_isspecialfloat.ll @@ -1,3 +1,4 @@ +; REQUIRES: dxil-1-8 ; RUN: not %dxv %s 2>&1 | FileCheck %s ; The purpose of this test is to verify an error is emitted when pre-sm6.9 diff --git a/tools/clang/test/SemaHLSL/hlsl/vectors/slice.hlsl b/tools/clang/test/SemaHLSL/hlsl/vectors/slice.hlsl index 529b8ec250..573fb7fae7 100644 --- a/tools/clang/test/SemaHLSL/hlsl/vectors/slice.hlsl +++ b/tools/clang/test/SemaHLSL/hlsl/vectors/slice.hlsl @@ -1,3 +1,4 @@ +// REQUIRES: dxil-1-9 // RUN: %dxc -I %hlsl_headers -T ps_6_9 -E main %s | FileCheck %s #include diff --git a/tools/clang/test/lit.cfg b/tools/clang/test/lit.cfg index 1f3e6dfe3e..1af4a05958 100644 --- a/tools/clang/test/lit.cfg +++ b/tools/clang/test/lit.cfg @@ -99,6 +99,8 @@ if dxc_dll_path and os.path.exists(dxc_dll_path): lit_config.note("Setting DXC_DXIL_DLL_PATH environment variable") config.environment.update({'DXC_DXIL_DLL_PATH' : dxc_dll_path}) config.available_features.add("dxc_dxil_dll_path") + dxc_release_version_tag = lit_config.params.get('DXC_RELEASE_VERSION_TAG', None) + config.available_features.add("dxilval-"+dxc_release_version_tag) # Tweak the PATH to include the tools dir and the scripts dir. if clang_obj_root is not None: @@ -515,7 +517,10 @@ if config.metal: # Check supported dxil version def get_dxil_version(): - result = subprocess.run([lit.util.which('dxc', llvm_tools_dir), "--version"], stdout=subprocess.PIPE) + if "DXC_DXIL_DLL_PATH" in config.environment: + result = subprocess.run([lit.util.which('dxc', llvm_tools_dir), "--version"], stdout=subprocess.PIPE, env=config.environment) + else: + result = subprocess.run([lit.util.which('dxc', llvm_tools_dir), "--version"], stdout=subprocess.PIPE) output = result.stdout.decode("utf-8") dxcPat = re.compile(r"(dxcompiler.dll|libdxcompiler.so|libdxcompiler.dylib): (?P[0-9]+)\.(?P[0-9]+).") m = dxcPat.search(output) diff --git a/tools/clang/tools/dxclib/dxc.cpp b/tools/clang/tools/dxclib/dxc.cpp index cd29547b9e..8388cd70e0 100644 --- a/tools/clang/tools/dxclib/dxc.cpp +++ b/tools/clang/tools/dxclib/dxc.cpp @@ -51,6 +51,7 @@ #include "dxc/DxilRootSignature/DxilRootSignature.h" #include "dxc/Support/FileIOHelper.h" #include "dxc/Support/HLSLOptions.h" +#include "dxc/Support/dxcapi.extval.h" #include "dxc/Support/dxcapi.use.h" #include "dxc/Support/microcom.h" #include "dxc/dxcapi.h" @@ -125,7 +126,7 @@ class DxcContext { private: DxcOpts &m_Opts; - SpecificDllLoader &m_dxcSupport; + DxcDllExtValidationLoader &m_dxcSupport; int ActOnBlob(IDxcBlob *pBlob); int ActOnBlob(IDxcBlob *pBlob, IDxcBlob *pDebugBlob, LPCWSTR pDebugBlobName); @@ -155,7 +156,7 @@ class DxcContext { } public: - DxcContext(DxcOpts &Opts, SpecificDllLoader &dxcSupport) + DxcContext(DxcOpts &Opts, DxcDllExtValidationLoader &dxcSupport) : m_Opts(Opts), m_dxcSupport(dxcSupport) {} int Compile(); @@ -871,6 +872,12 @@ int DxcContext::Compile() { outputPDBPath += pDebugName.m_pData; } } else { + // This may or may not use the external validator after compilation, + // depending on the environment. Compilation via the Compile(...) + // function is deferred to whatever object was chosen to be pCompiler, + // which must implement the IDxcCompiler interface. External validation + // will only take place if the DXC_DXIL_DLL_PATH env var is set + // correctly. IFT(pCompiler->Compile( pSource, StringRefWide(m_Opts.InputFile), StringRefWide(m_Opts.EntryPoint), StringRefWide(TargetProfile), @@ -1416,7 +1423,6 @@ int dxc::main(int argc, const char **argv_) { const OptTable *optionTable = getHlslOptTable(); MainArgs argStrings(argc, argv_); DxcOpts dxcOpts; - DXCLibraryDllLoader dxcSupport; // Read options and check errors. { @@ -1448,20 +1454,45 @@ int dxc::main(int argc, const char **argv_) { #endif // Setup a helper DLL. + DxcDllExtValidationLoader dxcSupport; { - std::string dllErrorString; - llvm::raw_string_ostream dllErrorStream(dllErrorString); - int dllResult = - SetupSpecificDllLoader(dxcOpts, dxcSupport, dllErrorStream); - dllErrorStream.flush(); - if (dllErrorString.size()) { - fprintf(stderr, "%s\n", dllErrorString.data()); - } - if (dllResult) + HRESULT dllResult; + if (!dxcOpts.ExternalLib.empty() || !dxcOpts.ExternalFn.empty()) + dllResult = + dxcSupport.InitializeForDll(dxcOpts.ExternalLib.str().c_str(), + dxcOpts.ExternalFn.str().c_str()); + else + dllResult = dxcSupport.initialize(); + + if (DXC_FAILED(dllResult)) { + switch (dxcSupport.getFailureReason()) { + case dxcSupport.FailedCompilerLoad: { + fprintf(stderr, "dxcompiler.dll failed to load\n"); + break; + } + case dxcSupport.FailedDxilPath: { + fprintf(stderr, "dxil.dll path %s could not be found", + dxcSupport.getDxilDllPath().c_str()); + break; + } + case dxcSupport.FailedDxilLoad: { + fprintf(stderr, "%s failed to load", + dxcSupport.getDxilDllPath().c_str()); + break; + } + default: { + llvm_unreachable("unexpected failure reason"); + } + } return dllResult; + } + + // if no errors setting up, print the log string as stdout + if (dxcOpts.Verbose) + fprintf(stdout, "Loading external dxil.dll from %s", + dxcSupport.getDxilDllPath().c_str()); } - EnsureEnabled(dxcSupport); DxcContext context(dxcOpts, dxcSupport); // Handle help request, which overrides any other processing. if (dxcOpts.ShowHelp) { diff --git a/tools/clang/tools/dxcompiler/dxcompilerobj.cpp b/tools/clang/tools/dxcompiler/dxcompilerobj.cpp index 84b568df9c..230047b4a8 100644 --- a/tools/clang/tools/dxcompiler/dxcompilerobj.cpp +++ b/tools/clang/tools/dxcompiler/dxcompilerobj.cpp @@ -714,8 +714,6 @@ class DxcCompiler : public IDxcCompiler3, unsigned rootSigMajor = 0; unsigned rootSigMinor = 0; - // NOTE: this calls the validation component from dxil.dll; the built-in - // validator can be used as a fallback. bool produceFullContainer = false; bool needsValidation = false; bool validateRootSigContainer = false; @@ -747,7 +745,7 @@ class DxcCompiler : public IDxcCompiler3, // Parse and apply if (opts.BindingTableDefine.size()) { - // Just pas the define for now because preprocessor is not available + // Just pass the define for now because preprocessor is not available // yet. struct BindingTableParserImpl : public CodeGenOptions::BindingTableParserType { @@ -830,13 +828,8 @@ class DxcCompiler : public IDxcCompiler3, compiler.getLangOpts().HLSLEntryFunction = compiler.getCodeGenOpts().HLSLEntryFunction = ""; - // NOTE: this calls the validation component from dxil.dll; the built-in - // validator can be used as a fallback. - produceFullContainer = !opts.CodeGenHighLevel && !opts.AstDump && - !opts.OptDump && rootSigMajor == 0 && - !opts.DumpDependencies && - !opts.VerifyDiagnostics; - needsValidation = produceFullContainer && !opts.DisableValidation; + produceFullContainer = opts.ProduceFullContainer(); + needsValidation = opts.NeedsValidation(); if (compiler.getCodeGenOpts().HLSLProfile == "lib_6_x") { // Currently do not support stripping reflection from offline linking diff --git a/tools/clang/tools/dxcompiler/dxcutil.cpp b/tools/clang/tools/dxcompiler/dxcutil.cpp index 4e5c5c95e8..880a207238 100644 --- a/tools/clang/tools/dxcompiler/dxcutil.cpp +++ b/tools/clang/tools/dxcompiler/dxcutil.cpp @@ -45,16 +45,6 @@ HRESULT RunInternalValidator(IDxcValidator *pValidator, llvm::Module *pDebugModule, IDxcBlob *pShader, UINT32 Flags, IDxcOperationResult **ppResult); -namespace { -// AssembleToContainer helper functions. - -// return true if the internal validator was used, false otherwise -void CreateValidator(CComPtr &pValidator) { - IFT(CreateDxcValidator(IID_PPV_ARGS(&pValidator))); -} - -} // namespace - namespace dxcutil { AssembleInputs::AssembleInputs( @@ -77,7 +67,7 @@ void GetValidatorVersion(unsigned *pMajor, unsigned *pMinor) { return; CComPtr pValidator; - CreateValidator(pValidator); + IFT(CreateDxcValidator(IID_PPV_ARGS(&pValidator))); CComPtr pVersionInfo; if (SUCCEEDED(pValidator.QueryInterface(&pVersionInfo))) { @@ -149,7 +139,7 @@ HRESULT ValidateAndAssembleToContainer(AssembleInputs &inputs) { std::unique_ptr llvmModuleWithDebugInfo; CComPtr pValidator; - CreateValidator(pValidator); + IFT(CreateDxcValidator(IID_PPV_ARGS(&pValidator))); if (llvm::getDebugMetadataVersionFromModule(*inputs.pM) != 0) llvmModuleWithDebugInfo.reset(llvm::CloneModule(inputs.pM.get())); @@ -191,7 +181,7 @@ HRESULT ValidateRootSignatureInContainer(IDxcBlob *pRootSigContainer, HRESULT valHR = S_OK; CComPtr pValidator; CComPtr pValResult; - CreateValidator(pValidator); + IFT(CreateDxcValidator(IID_PPV_ARGS(&pValidator))); IFT(pValidator->Validate(pRootSigContainer, DxcValidatorFlags_RootSignatureOnly | DxcValidatorFlags_InPlaceEdit, diff --git a/tools/clang/tools/dxv/dxv.cpp b/tools/clang/tools/dxv/dxv.cpp index 3dedcbfaa5..e8c3b1de1f 100644 --- a/tools/clang/tools/dxv/dxv.cpp +++ b/tools/clang/tools/dxv/dxv.cpp @@ -15,6 +15,7 @@ #include "dxc/DxilContainer/DxilContainer.h" #include "dxc/Support/HLSLOptions.h" +#include "dxc/Support/dxcapi.extval.h" #include "dxc/Support/dxcapi.use.h" #include "dxc/dxcapi.h" #include "dxc/dxcapi.internal.h" @@ -42,10 +43,11 @@ static cl::opt class DxvContext { private: - SpecificDllLoader &m_dxcSupport; + DxcDllExtValidationLoader &m_dxcSupport; public: - DxvContext(SpecificDllLoader &dxcSupport) : m_dxcSupport(dxcSupport) {} + DxvContext(DxcDllExtValidationLoader &dxcSupport) + : m_dxcSupport(dxcSupport) {} void Validate(); }; @@ -160,8 +162,30 @@ int main(int argc, const char **argv) { return 2; } - DxCompilerDllLoader dxcSupport; - IFT(dxcSupport.Initialize()); + DxcDllExtValidationLoader dxcSupport; + HRESULT dllResult = dxcSupport.initialize(); + if (DXC_FAILED(dllResult)) { + switch (dxcSupport.getFailureReason()) { + case dxcSupport.InitializationFailures::FailedCompilerLoad: { + fprintf(stderr, "dxcompiler.dll failed to load\n"); + break; + } + case dxcSupport.InitializationFailures::FailedDxilPath: { + fprintf(stderr, "dxil.dll path %s could not be found", + dxcSupport.getDxilDllPath().c_str()); + break; + } + case dxcSupport.InitializationFailures::FailedDxilLoad: { + fprintf(stderr, "%s failed to load", + dxcSupport.getDxilDllPath().c_str()); + break; + } + default: { + llvm_unreachable("unexpected failure reason"); + } + } + return dllResult; + } DxvContext context(dxcSupport); pStage = "Validation"; diff --git a/tools/clang/unittests/HLSL/ValidationTest.cpp b/tools/clang/unittests/HLSL/ValidationTest.cpp index 3918901d74..374affa399 100644 --- a/tools/clang/unittests/HLSL/ValidationTest.cpp +++ b/tools/clang/unittests/HLSL/ValidationTest.cpp @@ -12,6 +12,7 @@ #include "dxc/Support/WinIncludes.h" #include +#include #include #include #include @@ -4221,13 +4222,17 @@ void SetEnvVarW(const std::wstring &VarName, const std::wstring &VarValue) { _wputenv_s(VarName.c_str(), VarValue.c_str()); } -// For now, 3 things are tested: +// For now, 4 things are tested: // 1. The environment variable is not set. GetDxilDllPath() is empty and // DxilDllFailedToLoad() returns false // 2. Given a bogus path in the environment variable, and an initialized // DxcDllExtValidationSupport object, GetDxilDllPath() // retrieves the bogus path despite DxcDllExtValidationSupport failing to load // it as a dll, and DxilDllFailedToLoad() returns true. +// 3. Given a valid path in the environment variable to a non-dll file, +// and an initialized DxcDllExtValidationSupport object, GetDxilDllPath() +// retrieves the valid path despite DxcDllExtValidationSupport failing to load +// it as a dll, and DxilDllFailedToLoad() returns true. // 3. CLSID_DxcCompiler, CLSID_DxcLinker, CLSID_DxcValidator // may be created through DxcDllExtValidationSupport. // This is all to simply test that the new class, DxcDllExtValidationSupport, @@ -4236,6 +4241,7 @@ void SetEnvVarW(const std::wstring &VarName, const std::wstring &VarValue) { TEST_F(ValidationTest, UnitTestExtValidationSupport) { dxc::DxcDllExtValidationLoader ExtSupportEmpty; dxc::DxcDllExtValidationLoader ExtSupportBogus; + dxc::DxcDllExtValidationLoader ExtSupportValidNonDLLPath; // capture any existing value in the environment variable, // so that it can be restored after the test @@ -4247,26 +4253,44 @@ TEST_F(ValidationTest, UnitTestExtValidationSupport) { SetEnvVarW(L"DXC_DXIL_DLL_PATH", L""); // empty initialization should succeed - VERIFY_SUCCEEDED(ExtSupportEmpty.Initialize()); + VERIFY_SUCCEEDED(ExtSupportEmpty.initialize()); - VERIFY_IS_FALSE(ExtSupportEmpty.DxilDllFailedToLoad()); - std::string EmptyPath = ExtSupportBogus.GetDxilDllPath(); + VERIFY_IS_FALSE(ExtSupportEmpty.dxilDllFailedToLoad()); + std::string EmptyPath = ExtSupportEmpty.getDxilDllPath(); VERIFY_ARE_EQUAL_STR(EmptyPath.c_str(), ""); // 2. Test with a bogus path in the environment variable SetEnvVarW(L"DXC_DXIL_DLL_PATH", L"bogus"); if (!ExtSupportBogus.IsEnabled()) { - VERIFY_FAILED(ExtSupportBogus.Initialize()); + VERIFY_FAILED(ExtSupportBogus.initialize()); + VERIFY_ARE_EQUAL(ExtSupportBogus.getFailureReason(), + ExtSupportBogus.FailedDxilPath); } - // validate that m_dllExtSupport2 was able to capture the environment + // validate that ExtSupportBogus was able to capture the environment // variable's value, and that loading the bogus path was unsuccessful - std::string BogusPath = ExtSupportBogus.GetDxilDllPath(); + std::string BogusPath = ExtSupportBogus.getDxilDllPath(); VERIFY_ARE_EQUAL_STR(BogusPath.c_str(), "bogus"); - VERIFY_IS_TRUE(ExtSupportBogus.DxilDllFailedToLoad()); + VERIFY_IS_TRUE(ExtSupportBogus.dxilDllFailedToLoad()); + + // 3. Test with a valid path to this file in the environment variable + std::filesystem::path p = std::filesystem::absolute(__FILE__); + SetEnvVarW(L"DXC_DXIL_DLL_PATH", p.wstring()); + + if (!ExtSupportValidNonDLLPath.IsEnabled()) { + VERIFY_FAILED(ExtSupportValidNonDLLPath.initialize()); + VERIFY_ARE_EQUAL(ExtSupportValidNonDLLPath.getFailureReason(), + ExtSupportValidNonDLLPath.FailedDxilLoad); + } + + // validate that ExtSupportValidNonDLLPath was able to capture the environment + // variable's value, and that loading the valid non-dll path was unsuccessful + std::string ValidNonDLLPath = ExtSupportValidNonDLLPath.getDxilDllPath(); + VERIFY_ARE_EQUAL_STR(ValidNonDLLPath.c_str(), __FILE__); + VERIFY_IS_TRUE(ExtSupportValidNonDLLPath.dxilDllFailedToLoad()); - // 3. Test production of class IDs CLSID_DxcCompiler, CLSID_DxcLinker, + // 4. Test production of class IDs CLSID_DxcCompiler, CLSID_DxcLinker, // and CLSID_DxcValidator through DxcDllExtValidationSupport. CComPtr Compiler; CComPtr Linker; diff --git a/utils/hct/hcttest.cmd b/utils/hct/hcttest.cmd index b9e05ce524..b2e3f9a0e5 100644 --- a/utils/hct/hcttest.cmd +++ b/utils/hct/hcttest.cmd @@ -98,6 +98,10 @@ if "%1"=="-clean" ( echo Fallback to taef when use taef only options. set TEST_CLANG_FILTER=%2 shift /1 +) else if "%1"=="compat-suite" ( + set TEST_ALL=0 + set TEST_COMPAT_SUITE=%2 + shift /1 ) else if "%1"=="file-check" ( set TEST_ALL=0 set TEST_MANUAL_FILE_CHECK=1 @@ -330,6 +334,18 @@ if "%TEST_USE_LIT%"=="1" ( cmake --build %HLSL_BLD_DIR% --config %BUILD_CONFIG% --target check-clang set RES_CLANG=!ERRORLEVEL! ) + if "!TEST_COMPAT_SUITE!"=="1.6" ( + cmake --build %HLSL_BLD_DIR% --config %BUILD_CONFIG% --target check-dxilcompat-dxc_2021_12_08 + set RES_COMPAT_1_6=!ERRORLEVEL! + ) + if "!TEST_COMPAT_SUITE!"=="1.7" ( + cmake --build %HLSL_BLD_DIR% --config %BUILD_CONFIG% --target check-dxilcompat-dxc_2023_08_14 + set RES_COMPAT_1_7=!ERRORLEVEL! + ) + if "!TEST_COMPAT_SUITE!"=="1.8" ( + cmake --build %HLSL_BLD_DIR% --config %BUILD_CONFIG% --target check-dxilcompat-dxc_2025_02_20 + set RES_COMPAT_1_8=!ERRORLEVEL! + ) if "!TEST_EXEC!"=="1" ( if defined EXEC_ADAPTER ( py %HLSL_SRC_DIR%/utils/lit/lit.py -v --no-progress-bar --param build_mode=%BUILD_CONFIG% --param clang_site_config=%HLSL_BLD_DIR%/tools/clang/test/lit.site.cfg --param clang_taef_exec_site_config=%HLSL_BLD_DIR%/tools/clang/test/taef_exec/lit.site.cfg %EXEC_ADAPTER% %HLSL_SRC_DIR%/tools/clang/test/taef_exec @@ -423,7 +439,6 @@ if "%TEST_CLANG%"=="1" ( set RES_CLANG=!ERRORLEVEL! ) - if "%TEST_EXEC%"=="1" ( call :copyagility ) @@ -497,6 +512,9 @@ if "%TEST_EXEC%"=="1" ( call :check_result "hcttest-extras tests" %RES_EXTRAS% call :check_result "hcttest-after script" %RES_HCTTEST_AFTER% call :check_result "dxilconv tests" %RES_DXILCONV% +call :check_result "compat-suite 1.6 tests" %RES_COMPAT_1_6% +call :check_result "compat-suite 1.7 tests" %RES_COMPAT_1_7% +call :check_result "compat-suite 1.8 tests" %RES_COMPAT_1_8% set EXIT_CODE=%TESTS_FAILED% if not "%TESTS_PASSED%"=="0" ( @@ -546,7 +564,7 @@ echo clang - run clang tests. echo file-check - run file-check test on single file. echo - hcttest file-check "..\CodeGenHLSL\shader-compat-suite\lib_arg_flatten\lib_arg_flatten.hlsl" echo compat-suite - run compat-suite test. -echo - hcttest compat-suite "..\CodeGenHLSL\shader-compat-suite\lib_arg_flatten" +echo - hcttest compat-suite ^(1.6 ^| 1.7 ^| 1.8^) echo cmd - run command line tool tests. echo dxilconv - run dxilconv tests echo v - run the subset of clang tests that are verified-based.