88#include < filesystem> // C++17 and later
99#include < sstream>
1010// WinIncludes must come before dxcapi.extval.h
11+ #include " dxc/Support/FileIOHelper.h"
1112#include " dxc/Support/dxcapi.extval.h"
1213#include " dxc/Support/microcom.h"
14+ #include " llvm/ADT/StringRef.h"
1315#include < iostream>
1416
17+ static bool CheckNeedsValidationFromCompileArgs (LPCWSTR *pArgs,
18+ UINT32 argCount) {
19+ std::vector<std::wstring> Args (pArgs, pArgs + argCount);
20+
21+ // validation will normally take place upon a compilation unless
22+ // any of these compilation flags were passed:
23+ for (size_t i = 0 ; i < argCount; i++) {
24+ if (Args[i] == L" -fcgl" || Args[i] == L" /fcgl" || Args[i] == L" -ast-dump" ||
25+ Args[i] == L" /ast-dump" || Args[i] == L" -Odump" ||
26+ Args[i] == L" /Odump" || Args[i] == L" -dump_dependencies" ||
27+ Args[i] == L" /dump_dependencies" || Args[i] == L" -verify" ||
28+ Args[i] == L" /verify" || Args[i] == L" -Vd" || Args[i] == L" /Vd" ||
29+ Args[i] == L" -P" || Args[i] == L" /P" ||
30+ Args[i].rfind (L" rootsig_1" ) != std::wstring::npos ||
31+ Args[i].rfind (L" -Trootsig_1" ) != std::wstring::npos ||
32+ Args[i].rfind (L" /Trootsig_1" ) != std::wstring::npos)
33+ return false ;
34+
35+ #ifdef ENABLE_SPIRV_CODEGEN
36+ if (Args[i] == L" -spirv" || Args[i] == L" /spirv" )
37+ return false ;
38+
39+ #endif
40+ }
41+
42+ return true ;
43+ }
44+
1545static std::vector<std::wstring> AddExtValCompilationArgs (UINT32 ArgCount,
1646 LPCWSTR *pArguments,
1747 UINT32 Major,
1848 UINT32 Minor) {
19- /* We need to add 3 args to the compiler automatically in the external
20- validation case:
49+ /* We need to add 2 args to the compiler automatically in the external
50+ validation case:
2151 1. -Vd, to disable internal validation. No need to run the internal
2252 validator when the external validator was requested to validate.
2353 2. -validator-version to write the validator version to the resulting
2454 module. Without this, the modern compiler will write its own version, which
2555 will be to0 new for older validators, and the validator will fail. However,
2656 if explicitly specified on the command line, we shouldn't overwrite it.
27- 3. -Od to remove optimization and have a reliable validation step,
28- expecially with older validators.
2957 */
58+
3059 std::vector<std::wstring> newArgs = {pArguments, pArguments + ArgCount};
3160
3261 // Track whether the user already passed -validator-version
3362 bool hasValidatorVersion = false ;
3463 for (size_t i = 0 ; i < newArgs.size (); ++i) {
35- if (newArgs[i] == L" -validator-version" ) {
64+ if (newArgs[i] == L" -validator-version" ||
65+ newArgs[i] == L" /validator-version" ) {
3666 // Either the value is in the same arg ("-validator-version=1.6")
3767 // or the next arg is the version ("-validator-version", "1.6").
3868 hasValidatorVersion = true ;
3969 break ;
4070 }
41- if (newArgs[i].rfind (L" -validator-version" , 0 ) == 0 ) {
71+ if (newArgs[i].rfind (L" -validator-version" , 0 ) != std::wstring::npos ||
72+ newArgs[i].rfind (L" /validator-version" , 0 ) != std::wstring::npos) {
4273 // Handles "-validator-version=1.6"
4374 hasValidatorVersion = true ;
4475 break ;
@@ -55,8 +86,6 @@ static std::vector<std::wstring> AddExtValCompilationArgs(UINT32 ArgCount,
5586 newArgs.push_back (ss.str ());
5687 }
5788
58- newArgs.push_back (L" -Od" );
59-
6089 return newArgs;
6190}
6291
@@ -73,14 +102,16 @@ class ExternalValidationHelper : public IDxcCompiler, public IDxcCompiler3 {
73102private:
74103 CComPtr<IDxcCompiler> m_pCompiler;
75104 CComPtr<IDxcCompiler3> m_pCompiler3;
105+ CComPtr<IDxcValidator> m_pValidator;
76106 UINT32 ValidatorVersionMajor;
77107 UINT32 ValidatorVersionMinor;
78108
79109public:
80110 ExternalValidationHelper (CComPtr<IDxcCompiler> compiler,
81- CComPtr<IDxcCompiler3> compiler3, UINT32 major,
111+ CComPtr<IDxcCompiler3> compiler3,
112+ CComPtr<IDxcValidator> validator, UINT32 major,
82113 UINT32 minor, IMalloc *pMalloc = nullptr )
83- : m_pCompiler(compiler), m_pCompiler3(compiler3),
114+ : m_pCompiler(compiler), m_pCompiler3(compiler3), m_pValidator(validator),
84115 ValidatorVersionMajor (major), ValidatorVersionMinor(minor),
85116 m_pMalloc(pMalloc) {}
86117
@@ -125,7 +156,15 @@ class ExternalValidationHelper : public IDxcCompiler, public IDxcCompiler3 {
125156 UINT32 defineCount,
126157 IDxcIncludeHandler *pIncludeHandler,
127158 IDxcOperationResult **ppResult) override {
128- // First, add the external validation compilation args
159+
160+ // if validation will not be needed, compile as normal
161+ if (!CheckNeedsValidationFromCompileArgs (pArguments, argCount)) {
162+ return m_pCompiler->Compile (
163+ pSource, pSourceName, pEntryPoint, pTargetProfile, pArguments,
164+ argCount, pDefines, defineCount, pIncludeHandler, ppResult);
165+ }
166+
167+ // Otherwise, first, add the external validation compilation args
129168 std::vector<std::wstring> newArgs = AddExtValCompilationArgs (
130169 argCount, pArguments, ValidatorVersionMajor, ValidatorVersionMinor);
131170
@@ -136,9 +175,50 @@ class ExternalValidationHelper : public IDxcCompiler, public IDxcCompiler3 {
136175 rawArgs.push_back (a.c_str ());
137176 }
138177
139- return m_pCompiler->Compile (
178+ HRESULT CompHR = m_pCompiler->Compile (
140179 pSource, pSourceName, pEntryPoint, pTargetProfile, rawArgs.data (),
141180 rawArgs.size (), pDefines, defineCount, pIncludeHandler, ppResult);
181+ if (DXC_FAILED (CompHR))
182+ return CompHR;
183+
184+ HRESULT status;
185+ (*ppResult)->GetStatus (&status);
186+
187+ // Then validate, only if compilation succeeded.
188+ // The caller is responsible for handling compilation errors,
189+ // but this function should return whether there was a critical
190+ // failure in compilation or not at this point
191+ if (DXC_FAILED (status))
192+ return CompHR;
193+
194+ CComPtr<IDxcBlob> pProgram;
195+ CComPtr<IDxcOperationResult> pValResult;
196+
197+ IFT ((*ppResult)->GetResult (&pProgram));
198+
199+ // This checks the validator ran without any critical failures,
200+ // not that the program was valid.
201+ IFT (m_pValidator->Validate (pProgram, DxcValidatorFlags_InPlaceEdit,
202+ &pValResult));
203+ CComPtr<IDxcResult> pResult;
204+ HRESULT ValHR;
205+ IFT (pValResult->GetStatus (&ValHR));
206+ if (FAILED (ValHR)) {
207+ // emulate having a diagnostic context, but leave
208+ // the rest of the error print out to the caller
209+ fwprintf (stderr, L" error: validation errors\r\n " );
210+ }
211+
212+ // regardless if there were errors or not, we want to replace
213+ // the output blob with the result of the validator
214+ if (*ppResult) {
215+ (*ppResult)->Release ();
216+ *ppResult = nullptr ;
217+ }
218+
219+ *ppResult = pValResult.Detach (); // Transfers ownership to caller
220+
221+ return S_OK;
142222 }
143223
144224 HRESULT STDMETHODCALLTYPE
@@ -187,12 +267,13 @@ class ExternalValidationHelper : public IDxcCompiler, public IDxcCompiler3 {
187267static ExternalValidationHelper *Alloc (IMalloc *pMalloc,
188268 CComPtr<IDxcCompiler> compiler,
189269 CComPtr<IDxcCompiler3> compiler3,
270+ CComPtr<IDxcValidator> validator,
190271 UINT32 major, UINT32 minor) {
191272 void *P = pMalloc->Alloc (sizeof (ExternalValidationHelper));
192273 try {
193274 if (P)
194- return new (P)
195- ExternalValidationHelper (compiler, compiler3, major, minor, pMalloc);
275+ return new (P) ExternalValidationHelper (compiler, compiler3, validator,
276+ major, minor, pMalloc);
196277 } catch (...) {
197278 pMalloc->Free (P);
198279 throw ;
@@ -260,7 +341,7 @@ HRESULT DxcDllExtValidationLoader::CreateInstanceImpl(REFCLSID clsid,
260341
261342 ExternalValidationHelper *evh =
262343 Alloc (DxcGetThreadMallocNoRef (), DxcCompiler, DxcCompiler3,
263- validatorMajor, validatorMinor);
344+ DxcValidator, validatorMajor, validatorMinor);
264345
265346 if (!evh)
266347 return E_OUTOFMEMORY;
@@ -325,8 +406,9 @@ HRESULT DxcDllExtValidationLoader::CreateInstance2Impl(IMalloc *pMalloc,
325406 return hr;
326407
327408 // Allocate properly with TM allocator
328- ExternalValidationHelper *evh = Alloc (pMalloc, DxcCompiler, DxcCompiler3,
329- validatorMajor, validatorMinor);
409+ ExternalValidationHelper *evh =
410+ Alloc (pMalloc, DxcCompiler, DxcCompiler3, DxcValidator,
411+ validatorMajor, validatorMinor);
330412 if (!evh)
331413 return E_OUTOFMEMORY;
332414
0 commit comments