FileCheckerTest.cpp 37 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // //
  3. // FileCheckerTest.cpp //
  4. // Copyright (C) Microsoft Corporation. All rights reserved. //
  5. // This file is distributed under the University of Illinois Open Source //
  6. // License. See LICENSE.TXT for details. //
  7. // //
  8. // Provides tests that are based on FileChecker. //
  9. // //
  10. ///////////////////////////////////////////////////////////////////////////////
  11. #ifndef UNICODE
  12. #define UNICODE
  13. #endif
  14. #include <memory>
  15. #include <vector>
  16. #include <string>
  17. #include <cctype>
  18. #include <cassert>
  19. #include <algorithm>
  20. #include "dxc/Support/WinIncludes.h"
  21. #include "dxc/dxcapi.h"
  22. #ifdef _WIN32
  23. #include <atlfile.h>
  24. #endif
  25. #include "dxc/Test/HlslTestData.h"
  26. #include "dxc/Test/HlslTestUtils.h"
  27. #include "dxc/Test/DxcTestUtils.h"
  28. #include "llvm/Support/raw_os_ostream.h"
  29. #include "llvm/Support/MD5.h"
  30. #include "dxc/Support/Global.h"
  31. #include "dxc/Support/dxcapi.use.h"
  32. #include "dxc/dxctools.h"
  33. #include "dxc/Support/HLSLOptions.h"
  34. #include "dxc/Support/Unicode.h"
  35. #include "dxc/DxilContainer/DxilContainer.h"
  36. #include "dxc/Test/D3DReflectionDumper.h"
  37. #include "d3d12shader.h"
  38. using namespace std;
  39. using namespace hlsl_test;
  40. FileRunCommandPart::FileRunCommandPart(const std::string &command, const std::string &arguments, LPCWSTR commandFileName) :
  41. Command(command), Arguments(arguments), CommandFileName(commandFileName) { }
  42. FileRunCommandResult FileRunCommandPart::RunHashTests(dxc::DxcDllSupport &DllSupport) {
  43. if (0 == _stricmp(Command.c_str(), "%dxc")) {
  44. return RunDxcHashTest(DllSupport);
  45. }
  46. else {
  47. return FileRunCommandResult::Success();
  48. }
  49. }
  50. FileRunCommandResult FileRunCommandPart::Run(dxc::DxcDllSupport &DllSupport, const FileRunCommandResult *Prior,
  51. PluginToolsPaths *pPluginToolsPaths /*=nullptr*/) {
  52. bool isFileCheck =
  53. 0 == _stricmp(Command.c_str(), "FileCheck") ||
  54. 0 == _stricmp(Command.c_str(), "%FileCheck");
  55. bool isXFail = 0 == _stricmp(Command.c_str(), "xfail");
  56. bool consumeErrors = isFileCheck || isXFail;
  57. // Stop the pipeline if on errors unless the command can consume them.
  58. if (Prior != nullptr && Prior->ExitCode && !consumeErrors) {
  59. FileRunCommandResult result = *Prior;
  60. result.AbortPipeline = true;
  61. return result;
  62. }
  63. // We would add support for 'not' and 'llc' here.
  64. if (isFileCheck) {
  65. return RunFileChecker(Prior);
  66. }
  67. else if (isXFail) {
  68. return RunXFail(Prior);
  69. }
  70. else if (0 == _stricmp(Command.c_str(), "tee")) {
  71. return RunTee(Prior);
  72. }
  73. else if (0 == _stricmp(Command.c_str(), "fc")) {
  74. return RunFileCompareText(Prior);
  75. }
  76. else if (0 == _stricmp(Command.c_str(), "%dxilver")) {
  77. return RunDxilVer(DllSupport, Prior);
  78. }
  79. else if (0 == _stricmp(Command.c_str(), "%dxc")) {
  80. return RunDxc(DllSupport, Prior);
  81. }
  82. else if (0 == _stricmp(Command.c_str(), "%dxv")) {
  83. return RunDxv(DllSupport, Prior);
  84. }
  85. else if (0 == _stricmp(Command.c_str(), "%opt")) {
  86. return RunOpt(DllSupport, Prior);
  87. }
  88. else if (0 == _stricmp(Command.c_str(), "%D3DReflect")) {
  89. return RunD3DReflect(DllSupport, Prior);
  90. }
  91. else if (0 == _stricmp(Command.c_str(), "%dxr")) {
  92. return RunDxr(DllSupport, Prior);
  93. }
  94. else if (pPluginToolsPaths != nullptr) {
  95. auto it = pPluginToolsPaths->find(Command.c_str());
  96. if (it != pPluginToolsPaths->end()) {
  97. return RunFromPath(it->second, Prior);
  98. }
  99. }
  100. FileRunCommandResult result {};
  101. result.ExitCode = 1;
  102. result.StdErr = "Unrecognized command ";
  103. result.StdErr += Command;
  104. return result;
  105. }
  106. FileRunCommandResult FileRunCommandPart::RunFileChecker(const FileRunCommandResult *Prior) {
  107. if (!Prior) return FileRunCommandResult::Error("Prior command required to generate stdin");
  108. FileCheckForTest t;
  109. t.CheckFilename = CW2A(CommandFileName, CP_UTF8);
  110. t.InputForStdin = Prior->ExitCode ? Prior->StdErr : Prior->StdOut;
  111. // Parse command arguments
  112. static constexpr char checkPrefixStr[] = "-check-prefix=";
  113. static constexpr char checkPrefixesStr[] = "-check-prefixes=";
  114. bool hasInputFilename = false;
  115. for (const std::string& arg : strtok(Arguments)) {
  116. if (arg == "%s") hasInputFilename = true;
  117. else if (arg == "-input=stderr") t.InputForStdin = Prior->StdErr;
  118. else if (strstartswith(arg, checkPrefixStr))
  119. t.CheckPrefixes.emplace_back(arg.substr(sizeof(checkPrefixStr) - 1));
  120. else if (strstartswith(arg, checkPrefixesStr)) {
  121. auto prefixes = strtok(arg.substr(sizeof(checkPrefixesStr) - 1), ", ");
  122. for (auto &prefix : prefixes)
  123. t.CheckPrefixes.emplace_back(prefix);
  124. }
  125. else return FileRunCommandResult::Error("Invalid argument");
  126. }
  127. if (!hasInputFilename) return FileRunCommandResult::Error("Missing input filename");
  128. FileRunCommandResult result {};
  129. // Run
  130. result.ExitCode = t.Run();
  131. result.StdOut = t.test_outs;
  132. result.StdErr = t.test_errs;
  133. // Capture the input as well.
  134. if (result.ExitCode != 0 && Prior != nullptr) {
  135. result.StdErr += "\n<full input to FileCheck>\n";
  136. result.StdErr += t.InputForStdin;
  137. }
  138. return result;
  139. }
  140. FileRunCommandResult FileRunCommandPart::ReadOptsForDxc(
  141. hlsl::options::MainArgs &argStrings, hlsl::options::DxcOpts &Opts,
  142. unsigned flagsToInclude) {
  143. std::string args(strtrim(Arguments));
  144. const char *inputPos = strstr(args.c_str(), "%s");
  145. if (inputPos == nullptr)
  146. return FileRunCommandResult::Error("Only supported pattern includes input file as argument");
  147. args.erase(inputPos - args.c_str(), strlen("%s"));
  148. llvm::StringRef argsRef = args;
  149. llvm::SmallVector<llvm::StringRef, 8> splitArgs;
  150. argsRef.split(splitArgs, " ");
  151. argStrings = hlsl::options::MainArgs(splitArgs);
  152. std::string errorString;
  153. llvm::raw_string_ostream errorStream(errorString);
  154. int RunResult = ReadDxcOpts(hlsl::options::getHlslOptTable(), flagsToInclude,
  155. argStrings, Opts, errorStream);
  156. errorStream.flush();
  157. if (RunResult)
  158. return FileRunCommandResult::Error(RunResult, errorString);
  159. return FileRunCommandResult::Success("");
  160. }
  161. static HRESULT ReAssembleTo(dxc::DxcDllSupport &DllSupport, void *bitcode, UINT32 size, IDxcBlob **pBlob) {
  162. CComPtr<IDxcAssembler> pAssembler;
  163. CComPtr<IDxcLibrary> pLibrary;
  164. IFT(DllSupport.CreateInstance(CLSID_DxcLibrary, &pLibrary));
  165. IFT(DllSupport.CreateInstance(CLSID_DxcAssembler, &pAssembler));
  166. CComPtr<IDxcBlobEncoding> pInBlob;
  167. IFT(pLibrary->CreateBlobWithEncodingFromPinned(bitcode, size, 0, &pInBlob));
  168. CComPtr<IDxcOperationResult> pResult;
  169. pAssembler->AssembleToContainer(pInBlob, &pResult);
  170. HRESULT Result = 0;
  171. IFT(pResult->GetStatus(&Result));
  172. IFT(Result);
  173. IFT(pResult->GetResult(pBlob));
  174. return S_OK;
  175. }
  176. static HRESULT GetDxilBitcode(dxc::DxcDllSupport &DllSupport, IDxcBlob *pCompiledBlob, IDxcBlob **pBitcodeBlob) {
  177. CComPtr<IDxcContainerReflection> pReflection;
  178. CComPtr<IDxcLibrary> pLibrary;
  179. IFT(DllSupport.CreateInstance(CLSID_DxcContainerReflection, &pReflection));
  180. IFT(DllSupport.CreateInstance(CLSID_DxcLibrary, &pLibrary));
  181. IFT(pReflection->Load(pCompiledBlob));
  182. UINT32 uIndex = 0;
  183. IFT(pReflection->FindFirstPartKind(hlsl::DFCC_DXIL, &uIndex));
  184. CComPtr<IDxcBlob> pPart;
  185. IFT(pReflection->GetPartContent(uIndex, &pPart));
  186. auto header = (hlsl::DxilProgramHeader*)pPart->GetBufferPointer();
  187. void *bitcode = (char *)&header->BitcodeHeader + header->BitcodeHeader.BitcodeOffset;
  188. UINT32 bitcode_size = header->BitcodeHeader.BitcodeSize;
  189. CComPtr<IDxcBlobEncoding> pBlob;
  190. IFT(pLibrary->CreateBlobWithEncodingFromPinned(bitcode, bitcode_size, 0, &pBlob));
  191. *pBitcodeBlob = pBlob.Detach();
  192. return S_OK;
  193. }
  194. static HRESULT CompileForHash(hlsl::options::DxcOpts &opts, LPCWSTR CommandFileName, dxc::DxcDllSupport &DllSupport, std::vector<LPCWSTR> &flags, IDxcBlob **ppHashBlob, std::string &output) {
  195. CComPtr<IDxcLibrary> pLibrary;
  196. CComPtr<IDxcCompiler> pCompiler;
  197. CComPtr<IDxcCompiler2> pCompiler2;
  198. CComPtr<IDxcOperationResult> pResult;
  199. CComPtr<IDxcBlobEncoding> pSource;
  200. CComPtr<IDxcBlob> pCompiledBlob;
  201. CComPtr<IDxcBlob> pCompiledName;
  202. CComPtr<IDxcIncludeHandler> pIncludeHandler;
  203. WCHAR *pDebugName = nullptr;
  204. CComPtr<IDxcBlob> pPDBBlob;
  205. std::wstring entry =
  206. Unicode::UTF8ToUTF16StringOrThrow(opts.EntryPoint.str().c_str());
  207. std::wstring profile =
  208. Unicode::UTF8ToUTF16StringOrThrow(opts.TargetProfile.str().c_str());
  209. IFT(DllSupport.CreateInstance(CLSID_DxcLibrary, &pLibrary));
  210. IFT(pLibrary->CreateBlobFromFile(CommandFileName, nullptr, &pSource));
  211. IFT(pLibrary->CreateIncludeHandler(&pIncludeHandler));
  212. IFT(DllSupport.CreateInstance(CLSID_DxcCompiler, &pCompiler));
  213. IFT(pCompiler.QueryInterface(&pCompiler2));
  214. IFT(pCompiler2->CompileWithDebug(pSource, CommandFileName, entry.c_str(), profile.c_str(),
  215. flags.data(), flags.size(), nullptr, 0, pIncludeHandler, &pResult, &pDebugName, &pPDBBlob));
  216. HRESULT resultStatus = 0;
  217. IFT(pResult->GetStatus(&resultStatus));
  218. if (SUCCEEDED(resultStatus)) {
  219. IFT(pResult->GetResult(&pCompiledBlob));
  220. CComPtr<IDxcContainerReflection> pReflection;
  221. IFT(DllSupport.CreateInstance(CLSID_DxcContainerReflection, &pReflection));
  222. // If failed to load here, it's likely some non-compile operation thing. Just fail the hash generation.
  223. if (FAILED(pReflection->Load(pCompiledBlob)))
  224. return E_FAIL;
  225. *ppHashBlob = nullptr;
  226. UINT32 uHashIdx = 0;
  227. if (SUCCEEDED(pReflection->FindFirstPartKind(hlsl::DFCC_ShaderHash, &uHashIdx))) {
  228. CComPtr<IDxcBlob> pHashBlob;
  229. IFT(pReflection->GetPartContent(uHashIdx, &pHashBlob));
  230. *ppHashBlob = pHashBlob.Detach();
  231. }
  232. // Test that PDB is generated correctly.
  233. // This test needs to be done elsewhere later, ideally a fully
  234. // customizable test on all our test set with different compile options.
  235. if (pPDBBlob) {
  236. IFT(pReflection->Load(pPDBBlob));
  237. UINT32 uDebugInfoIndex = 0;
  238. IFT(pReflection->FindFirstPartKind(hlsl::DFCC_ShaderDebugInfoDXIL, &uDebugInfoIndex));
  239. }
  240. return S_OK;
  241. }
  242. else {
  243. CComPtr<IDxcBlobEncoding> pErrors;
  244. IFT(pResult->GetErrorBuffer(&pErrors));
  245. const char *errors = (char *)pErrors->GetBufferPointer();
  246. output = errors;
  247. return resultStatus;
  248. }
  249. }
  250. FileRunCommandResult FileRunCommandPart::RunDxcHashTest(dxc::DxcDllSupport &DllSupport) {
  251. hlsl::options::MainArgs args;
  252. hlsl::options::DxcOpts opts;
  253. ReadOptsForDxc(args, opts);
  254. std::vector<std::wstring> argWStrings;
  255. CopyArgsToWStrings(opts.Args, hlsl::options::CoreOption, argWStrings);
  256. // Extract the vanilla flags for the test (i.e. no debug or ast-dump)
  257. std::vector<LPCWSTR> original_flags;
  258. bool skipNext = false;
  259. for (const std::wstring &a : argWStrings) {
  260. if (skipNext) {
  261. skipNext = false;
  262. continue;
  263. }
  264. if (a.find(L"ast-dump") != std::wstring::npos) continue;
  265. if (a.find(L"Zi") != std::wstring::npos) continue;
  266. std::wstring optValVer(L"validator-version");
  267. if (a.substr(1, optValVer.length()).compare(optValVer) == 0) {
  268. skipNext = a.length() == optValVer.length() + 1;
  269. continue;
  270. }
  271. original_flags.push_back(a.data());
  272. }
  273. std::string originalOutput;
  274. CComPtr<IDxcBlob> pOriginalHash;
  275. // If failed the original compilation, just pass the test. The original test was likely
  276. // testing for failure.
  277. if (FAILED(CompileForHash(opts, CommandFileName, DllSupport, original_flags, &pOriginalHash, originalOutput)))
  278. return FileRunCommandResult::Success();
  279. // Results of our compilations
  280. CComPtr<IDxcBlob> pHash1;
  281. std::string Output0;
  282. CComPtr<IDxcBlob> pHash0;
  283. std::string Output1;
  284. // Fail if -Qstrip_reflect failed the compilation
  285. std::vector<LPCWSTR> normal_flags = original_flags;
  286. normal_flags.push_back(L"-Qstrip_reflect");
  287. normal_flags.push_back(L"-Zsb");
  288. std::string StdErr;
  289. if (FAILED(CompileForHash(opts, CommandFileName, DllSupport, normal_flags, &pHash0, Output0))) {
  290. StdErr += "Adding Qstrip_reflect failed compilation.";
  291. StdErr += originalOutput;
  292. StdErr += Output0;
  293. return FileRunCommandResult::Error(StdErr);
  294. }
  295. // Fail if -Qstrip_reflect failed the compilation
  296. std::vector<LPCWSTR> dbg_flags = original_flags;
  297. dbg_flags.push_back(L"/Zi");
  298. dbg_flags.push_back(L"-Qstrip_reflect");
  299. dbg_flags.push_back(L"-Zsb");
  300. if (FAILED(CompileForHash(opts, CommandFileName, DllSupport, dbg_flags, &pHash1, Output1))) {
  301. return FileRunCommandResult::Error("Adding Qstrip_reflect and Zi failed compilation.");
  302. }
  303. if (pHash0->GetBufferSize() != pHash1->GetBufferSize() || 0 != memcmp(pHash0->GetBufferPointer(), pHash0->GetBufferPointer(), pHash1->GetBufferSize())) {
  304. StdErr = "Hashes do not match between normal and debug!!!\n";
  305. StdErr += Output0;
  306. StdErr += Output1;
  307. return FileRunCommandResult::Error(StdErr);
  308. }
  309. return FileRunCommandResult::Success();
  310. }
  311. static FileRunCommandResult CheckDxilVer(dxc::DxcDllSupport& DllSupport,
  312. unsigned RequiredDxilMajor,
  313. unsigned RequiredDxilMinor,
  314. bool bCheckValidator = true) {
  315. bool Supported = true;
  316. // If the following fails, we have Dxil 1.0 compiler
  317. unsigned DxilMajor = 1, DxilMinor = 0;
  318. GetVersion(DllSupport, CLSID_DxcCompiler, DxilMajor, DxilMinor);
  319. Supported &= hlsl::DXIL::CompareVersions(DxilMajor, DxilMinor, RequiredDxilMajor, RequiredDxilMinor) >= 0;
  320. if (bCheckValidator) {
  321. // If the following fails, we have validator 1.0
  322. unsigned ValMajor = 1, ValMinor = 0;
  323. GetVersion(DllSupport, CLSID_DxcValidator, ValMajor, ValMinor);
  324. Supported &= hlsl::DXIL::CompareVersions(ValMajor, ValMinor, RequiredDxilMajor, RequiredDxilMinor) >= 0;
  325. }
  326. if (!Supported) {
  327. FileRunCommandResult result {};
  328. result.StdErr = "Skipping test due to unsupported dxil version";
  329. result.ExitCode = 0; // Succeed the test
  330. result.AbortPipeline = true;
  331. return result;
  332. }
  333. return FileRunCommandResult::Success();
  334. }
  335. FileRunCommandResult FileRunCommandPart::RunDxc(dxc::DxcDllSupport &DllSupport, const FileRunCommandResult *Prior) {
  336. // Support piping stdin from prior if needed.
  337. UNREFERENCED_PARAMETER(Prior);
  338. hlsl::options::MainArgs args;
  339. hlsl::options::DxcOpts opts;
  340. FileRunCommandResult readOptsResult = ReadOptsForDxc(args, opts);
  341. if (readOptsResult.ExitCode) return readOptsResult;
  342. std::wstring entry =
  343. Unicode::UTF8ToUTF16StringOrThrow(opts.EntryPoint.str().c_str());
  344. std::wstring profile =
  345. Unicode::UTF8ToUTF16StringOrThrow(opts.TargetProfile.str().c_str());
  346. std::vector<LPCWSTR> flags;
  347. if (opts.CodeGenHighLevel) {
  348. flags.push_back(L"-fcgl");
  349. }
  350. // Skip targets that require a newer compiler or validator.
  351. // Some features may require newer compiler/validator than indicated by the
  352. // shader model, but these should use %dxilver explicitly.
  353. {
  354. unsigned RequiredDxilMajor = 1, RequiredDxilMinor = 0;
  355. llvm::StringRef stage;
  356. IFTBOOL(ParseTargetProfile(opts.TargetProfile, stage, RequiredDxilMajor, RequiredDxilMinor), E_INVALIDARG);
  357. if (RequiredDxilMinor != 0xF && stage.compare("rootsig") != 0) {
  358. // Convert stage to minimum dxil/validator version:
  359. RequiredDxilMajor = std::max(RequiredDxilMajor, (unsigned)6) - 5;
  360. FileRunCommandResult result = CheckDxilVer(DllSupport, RequiredDxilMajor, RequiredDxilMinor, !opts.DisableValidation);
  361. if (result.AbortPipeline) {
  362. return result;
  363. }
  364. }
  365. }
  366. // For now, too many tests are sensitive to stripping the refleciton info
  367. // from the main module, so use this flag to prevent this until tests
  368. // can be updated.
  369. // That is, unless the test explicitly requests -Qstrip_reflect_from_dxil or -Qstrip_reflect
  370. if (!opts.StripReflectionFromDxil && !opts.StripReflection) {
  371. flags.push_back(L"-Qkeep_reflect_in_dxil");
  372. }
  373. std::vector<std::wstring> argWStrings;
  374. CopyArgsToWStrings(opts.Args, hlsl::options::CoreOption, argWStrings);
  375. for (const std::wstring &a : argWStrings)
  376. flags.push_back(a.data());
  377. CComPtr<IDxcLibrary> pLibrary;
  378. CComPtr<IDxcCompiler> pCompiler;
  379. CComPtr<IDxcOperationResult> pResult;
  380. CComPtr<IDxcBlobEncoding> pSource;
  381. CComPtr<IDxcBlobEncoding> pDisassembly;
  382. CComPtr<IDxcBlob> pCompiledBlob;
  383. CComPtr<IDxcIncludeHandler> pIncludeHandler;
  384. HRESULT resultStatus;
  385. IFT(DllSupport.CreateInstance(CLSID_DxcLibrary, &pLibrary));
  386. IFT(pLibrary->CreateBlobFromFile(CommandFileName, nullptr, &pSource));
  387. IFT(pLibrary->CreateIncludeHandler(&pIncludeHandler));
  388. IFT(DllSupport.CreateInstance(CLSID_DxcCompiler, &pCompiler));
  389. IFT(pCompiler->Compile(pSource, CommandFileName, entry.c_str(), profile.c_str(),
  390. flags.data(), flags.size(), nullptr, 0, pIncludeHandler, &pResult));
  391. IFT(pResult->GetStatus(&resultStatus));
  392. FileRunCommandResult result = {};
  393. if (SUCCEEDED(resultStatus)) {
  394. IFT(pResult->GetResult(&pCompiledBlob));
  395. if (!opts.AstDump) {
  396. IFT(pCompiler->Disassemble(pCompiledBlob, &pDisassembly));
  397. result.StdOut = BlobToUtf8(pDisassembly);
  398. } else {
  399. result.StdOut = BlobToUtf8(pCompiledBlob);
  400. }
  401. CComPtr<IDxcBlobEncoding> pStdErr;
  402. IFT(pResult->GetErrorBuffer(&pStdErr));
  403. result.StdErr = BlobToUtf8(pStdErr);
  404. result.ExitCode = 0;
  405. }
  406. else {
  407. IFT(pResult->GetErrorBuffer(&pDisassembly));
  408. result.StdErr = BlobToUtf8(pDisassembly);
  409. result.ExitCode = resultStatus;
  410. }
  411. result.OpResult = pResult;
  412. return result;
  413. }
  414. FileRunCommandResult FileRunCommandPart::RunDxv(dxc::DxcDllSupport &DllSupport, const FileRunCommandResult *Prior) {
  415. std::string args(strtrim(Arguments));
  416. const char *inputPos = strstr(args.c_str(), "%s");
  417. if (inputPos == nullptr) {
  418. return FileRunCommandResult::Error("Only supported pattern includes input file as argument");
  419. }
  420. args.erase(inputPos - args.c_str(), strlen("%s"));
  421. llvm::StringRef argsRef = args;
  422. llvm::SmallVector<llvm::StringRef, 8> splitArgs;
  423. argsRef.split(splitArgs, " ");
  424. IFTMSG(splitArgs.size()==1, "wrong arg num for dxv");
  425. CComPtr<IDxcLibrary> pLibrary;
  426. CComPtr<IDxcAssembler> pAssembler;
  427. CComPtr<IDxcValidator> pValidator;
  428. CComPtr<IDxcOperationResult> pResult;
  429. CComPtr<IDxcBlobEncoding> pSource;
  430. CComPtr<IDxcBlob> pContainerBlob;
  431. HRESULT resultStatus;
  432. IFT(DllSupport.CreateInstance(CLSID_DxcLibrary, &pLibrary));
  433. IFT(pLibrary->CreateBlobFromFile(CommandFileName, nullptr, &pSource));
  434. IFT(DllSupport.CreateInstance(CLSID_DxcAssembler, &pAssembler));
  435. IFT(pAssembler->AssembleToContainer(pSource, &pResult));
  436. IFT(pResult->GetStatus(&resultStatus));
  437. if (FAILED(resultStatus)) {
  438. CComPtr<IDxcBlobEncoding> pAssembleBlob;
  439. IFT(pResult->GetErrorBuffer(&pAssembleBlob));
  440. return FileRunCommandResult::Error(resultStatus, BlobToUtf8(pAssembleBlob));
  441. }
  442. IFT(pResult->GetResult(&pContainerBlob));
  443. IFT(DllSupport.CreateInstance(CLSID_DxcValidator, &pValidator));
  444. CComPtr<IDxcOperationResult> pValidationResult;
  445. IFT(pValidator->Validate(pContainerBlob, DxcValidatorFlags_InPlaceEdit,
  446. &pValidationResult));
  447. IFT(pValidationResult->GetStatus(&resultStatus));
  448. if (FAILED(resultStatus)) {
  449. CComPtr<IDxcBlobEncoding> pValidateBlob;
  450. IFT(pValidationResult->GetErrorBuffer(&pValidateBlob));
  451. return FileRunCommandResult::Success(BlobToUtf8(pValidateBlob));
  452. }
  453. return FileRunCommandResult::Success("");
  454. }
  455. FileRunCommandResult FileRunCommandPart::RunOpt(dxc::DxcDllSupport &DllSupport, const FileRunCommandResult *Prior) {
  456. std::string args(strtrim(Arguments));
  457. const char *inputPos = strstr(args.c_str(), "%s");
  458. if (inputPos == nullptr && Prior == nullptr) {
  459. return FileRunCommandResult::Error("Only supported patterns are input file as argument or prior "
  460. "command with disassembly");
  461. }
  462. CComPtr<IDxcLibrary> pLibrary;
  463. CComPtr<IDxcOptimizer> pOptimizer;
  464. CComPtr<IDxcBlobEncoding> pSource;
  465. CComPtr<IDxcBlobEncoding> pOutputText;
  466. CComPtr<IDxcBlob> pOutputModule;
  467. IFT(DllSupport.CreateInstance(CLSID_DxcLibrary, &pLibrary));
  468. IFT(DllSupport.CreateInstance(CLSID_DxcOptimizer, &pOptimizer));
  469. if (inputPos != nullptr) {
  470. args.erase(inputPos - args.c_str(), strlen("%s"));
  471. IFT(pLibrary->CreateBlobFromFile(CommandFileName, nullptr, &pSource));
  472. }
  473. else {
  474. assert(Prior != nullptr && "else early check should have returned");
  475. CComPtr<IDxcAssembler> pAssembler;
  476. IFT(DllSupport.CreateInstance(CLSID_DxcAssembler, &pAssembler));
  477. IFT(pLibrary->CreateBlobWithEncodingFromPinned(
  478. Prior->StdOut.c_str(), Prior->StdOut.size(), CP_UTF8,
  479. &pSource));
  480. }
  481. args = strtrim(args);
  482. llvm::StringRef argsRef = args;
  483. llvm::SmallVector<llvm::StringRef, 8> splitArgs;
  484. argsRef.split(splitArgs, " ");
  485. std::vector<LPCWSTR> options;
  486. std::vector<std::wstring> optionStrings;
  487. for (llvm::StringRef S : splitArgs) {
  488. optionStrings.push_back(
  489. Unicode::UTF8ToUTF16StringOrThrow(strtrim(S.str()).c_str()));
  490. }
  491. // Add the options outside the above loop in case the vector is resized.
  492. for (const std::wstring& str : optionStrings)
  493. options.push_back(str.c_str());
  494. IFT(pOptimizer->RunOptimizer(pSource, options.data(), options.size(),
  495. &pOutputModule, &pOutputText));
  496. return FileRunCommandResult::Success(BlobToUtf8(pOutputText));
  497. }
  498. FileRunCommandResult FileRunCommandPart::RunD3DReflect(dxc::DxcDllSupport &DllSupport, const FileRunCommandResult *Prior) {
  499. std::string args(strtrim(Arguments));
  500. if (args != "%s")
  501. return FileRunCommandResult::Error("Only supported pattern is a plain input file");
  502. if (!Prior)
  503. return FileRunCommandResult::Error("Prior command required to generate stdin");
  504. CComPtr<IDxcLibrary> pLibrary;
  505. CComPtr<IDxcBlobEncoding> pSource;
  506. CComPtr<IDxcAssembler> pAssembler;
  507. CComPtr<IDxcOperationResult> pResult;
  508. CComPtr<ID3D12ShaderReflection> pShaderReflection;
  509. CComPtr<ID3D12LibraryReflection> pLibraryReflection;
  510. CComPtr<IDxcContainerReflection> containerReflection;
  511. uint32_t partCount;
  512. CComPtr<IDxcBlob> pContainerBlob;
  513. HRESULT resultStatus;
  514. bool blobFound = false;
  515. std::ostringstream ss;
  516. D3DReflectionDumper dumper(ss);
  517. IFT(DllSupport.CreateInstance(CLSID_DxcLibrary, &pLibrary));
  518. IFT(DllSupport.CreateInstance(CLSID_DxcAssembler, &pAssembler));
  519. IFT(pLibrary->CreateBlobWithEncodingFromPinned(
  520. (LPBYTE)Prior->StdOut.c_str(), Prior->StdOut.size(), CP_UTF8,
  521. &pSource));
  522. IFT(pAssembler->AssembleToContainer(pSource, &pResult));
  523. IFT(pResult->GetStatus(&resultStatus));
  524. if (FAILED(resultStatus)) {
  525. CComPtr<IDxcBlobEncoding> pAssembleBlob;
  526. IFT(pResult->GetErrorBuffer(&pAssembleBlob));
  527. return FileRunCommandResult::Error(resultStatus, BlobToUtf8(pAssembleBlob));
  528. }
  529. IFT(pResult->GetResult(&pContainerBlob));
  530. VERIFY_SUCCEEDED(DllSupport.CreateInstance(CLSID_DxcContainerReflection, &containerReflection));
  531. VERIFY_SUCCEEDED(containerReflection->Load(pContainerBlob));
  532. VERIFY_SUCCEEDED(containerReflection->GetPartCount(&partCount));
  533. for (uint32_t i = 0; i < partCount; ++i) {
  534. uint32_t kind;
  535. VERIFY_SUCCEEDED(containerReflection->GetPartKind(i, &kind));
  536. if (kind == (uint32_t)hlsl::DxilFourCC::DFCC_DXIL) {
  537. blobFound = true;
  538. CComPtr<IDxcBlob> pPart;
  539. IFT(containerReflection->GetPartContent(i, &pPart));
  540. const hlsl::DxilProgramHeader *pProgramHeader =
  541. reinterpret_cast<const hlsl::DxilProgramHeader*>(pPart->GetBufferPointer());
  542. VERIFY_IS_TRUE(IsValidDxilProgramHeader(pProgramHeader, (uint32_t)pPart->GetBufferSize()));
  543. hlsl::DXIL::ShaderKind SK = hlsl::GetVersionShaderType(pProgramHeader->ProgramVersion);
  544. if (SK == hlsl::DXIL::ShaderKind::Library)
  545. VERIFY_SUCCEEDED(containerReflection->GetPartReflection(i, IID_PPV_ARGS(&pLibraryReflection)));
  546. else
  547. VERIFY_SUCCEEDED(containerReflection->GetPartReflection(i, IID_PPV_ARGS(&pShaderReflection)));
  548. break;
  549. }
  550. }
  551. if (!blobFound) {
  552. return FileRunCommandResult::Error("Unable to find DXIL part");
  553. } else if (pShaderReflection) {
  554. dumper.Dump(pShaderReflection);
  555. } else if (pLibraryReflection) {
  556. dumper.Dump(pLibraryReflection);
  557. }
  558. ss.flush();
  559. return FileRunCommandResult::Success(ss.str());
  560. }
  561. FileRunCommandResult FileRunCommandPart::RunDxr(dxc::DxcDllSupport &DllSupport, const FileRunCommandResult *Prior) {
  562. // Support piping stdin from prior if needed.
  563. UNREFERENCED_PARAMETER(Prior);
  564. hlsl::options::MainArgs args;
  565. hlsl::options::DxcOpts opts;
  566. FileRunCommandResult readOptsResult = ReadOptsForDxc(args, opts,
  567. hlsl::options::HlslFlags::RewriteOption);
  568. if (readOptsResult.ExitCode) return readOptsResult;
  569. std::wstring entry =
  570. Unicode::UTF8ToUTF16StringOrThrow(opts.EntryPoint.str().c_str());
  571. std::vector<LPCWSTR> flags;
  572. std::vector<std::wstring> argWStrings;
  573. CopyArgsToWStrings(opts.Args, hlsl::options::RewriteOption, argWStrings);
  574. for (const std::wstring &a : argWStrings)
  575. flags.push_back(a.data());
  576. CComPtr<IDxcLibrary> pLibrary;
  577. CComPtr<IDxcRewriter2> pRewriter;
  578. CComPtr<IDxcOperationResult> pResult;
  579. CComPtr<IDxcBlobEncoding> pSource;
  580. CComPtr<IDxcBlob> pResultBlob;
  581. CComPtr<IDxcIncludeHandler> pIncludeHandler;
  582. IFT(DllSupport.CreateInstance(CLSID_DxcLibrary, &pLibrary));
  583. IFT(pLibrary->CreateBlobFromFile(CommandFileName, nullptr, &pSource));
  584. IFT(pLibrary->CreateIncludeHandler(&pIncludeHandler));
  585. IFT(DllSupport.CreateInstance(CLSID_DxcRewriter, &pRewriter));
  586. IFT(pRewriter->RewriteWithOptions(pSource, CommandFileName,
  587. flags.data(), flags.size(), nullptr, 0,
  588. pIncludeHandler, &pResult));
  589. HRESULT resultStatus;
  590. IFT(pResult->GetStatus(&resultStatus));
  591. FileRunCommandResult result = {};
  592. CComPtr<IDxcBlobEncoding> pStdErr;
  593. IFT(pResult->GetErrorBuffer(&pStdErr));
  594. result.StdErr = BlobToUtf8(pStdErr);
  595. result.ExitCode = resultStatus;
  596. if (SUCCEEDED(resultStatus)) {
  597. IFT(pResult->GetResult(&pResultBlob));
  598. result.StdOut = BlobToUtf8(pResultBlob);
  599. }
  600. result.OpResult = pResult;
  601. return result;
  602. }
  603. FileRunCommandResult FileRunCommandPart::RunTee(const FileRunCommandResult *Prior) {
  604. if (Prior == nullptr) {
  605. return FileRunCommandResult::Error("tee requires a prior command");
  606. }
  607. // Ignore commands for now - simply log out through test framework.
  608. {
  609. CA2W outWide(Prior->StdOut.c_str(), CP_UTF8);
  610. WEX::Logging::Log::Comment(outWide.m_psz);
  611. }
  612. if (!Prior->StdErr.empty()) {
  613. CA2W errWide(Prior->StdErr.c_str(), CP_UTF8);
  614. WEX::Logging::Log::Comment(L"<stderr>");
  615. WEX::Logging::Log::Comment(errWide.m_psz);
  616. }
  617. return *Prior;
  618. }
  619. void FileRunCommandPart::SubstituteFilenameVars(std::string &args) {
  620. size_t pos;
  621. std::string baseFileName = CW2A(CommandFileName);
  622. if ((pos = baseFileName.find_last_of(".")) != std::string::npos) {
  623. baseFileName = baseFileName.substr(0, pos);
  624. }
  625. while ((pos = args.find("%t")) != std::string::npos) {
  626. args.replace(pos, 2, baseFileName.c_str());
  627. }
  628. while ((pos = args.find("%b")) != std::string::npos) {
  629. args.replace(pos, 2, baseFileName.c_str());
  630. }
  631. }
  632. #if _WIN32
  633. bool FileRunCommandPart::ReadFileContentToString(HANDLE hFile, std::string &str) {
  634. char buffer[1024];
  635. DWORD len;
  636. size_t size = ::GetFileSize(hFile, nullptr);
  637. if (size == INVALID_FILE_SIZE) {
  638. return false;
  639. }
  640. str.reserve(size);
  641. if (::SetFilePointer(hFile, 0, nullptr, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
  642. return false;
  643. }
  644. while (::ReadFile(hFile, buffer, sizeof(buffer), &len, nullptr) && len > 0) {
  645. str.append(buffer, len);
  646. }
  647. return true;
  648. }
  649. #endif
  650. FileRunCommandResult FileRunCommandPart::RunFileCompareText(const FileRunCommandResult *Prior) {
  651. if (Prior != nullptr) {
  652. return FileRunCommandResult::Error("prior command not supported");
  653. }
  654. FileRunCommandResult result;
  655. result.ExitCode = 1;
  656. // strip leading and trailing spaces and split
  657. std::string args(strtrim(Arguments));
  658. size_t pos;
  659. if ((pos = args.find_first_of(' ')) == std::string::npos) {
  660. return FileRunCommandResult::Error("RunFileCompareText expected 2 file arguments.");
  661. }
  662. std::string fileName1 = args.substr(0, pos);
  663. std::string fileName2 = strtrim(args.substr(pos + 1));
  664. // replace %t and %b with the command file name without extension
  665. SubstituteFilenameVars(fileName1);
  666. SubstituteFilenameVars(fileName2);
  667. // read file content and compare
  668. CA2W fileName1W(fileName1.c_str());
  669. CA2W fileName2W(fileName2.c_str());
  670. hlsl_test::LogCommentFmt(L"Comparing files %s and %s", fileName1W.m_psz, fileName2W.m_psz);
  671. std::ifstream ifs1(fileName1, std::ifstream::in);
  672. if (ifs1.fail()) {
  673. hlsl_test::LogCommentFmt(L"Failed to open %s", fileName1W.m_psz);
  674. return result;
  675. }
  676. std::string file1Content((std::istreambuf_iterator<char>(ifs1)), (std::istreambuf_iterator<char>()));
  677. std::ifstream ifs2(fileName2, std::ifstream::in);
  678. if (ifs2.fail()) {
  679. hlsl_test::LogCommentFmt(L"Failed to open %s", fileName2W.m_psz);
  680. return result;
  681. }
  682. std::string file2Content((std::istreambuf_iterator<char>(ifs2)), (std::istreambuf_iterator<char>()));
  683. if (file1Content.compare(file2Content) == 0) {
  684. hlsl_test::LogCommentFmt(L"No differences found.");
  685. result.ExitCode = 0;
  686. }
  687. else {
  688. hlsl_test::LogCommentFmt(L"Files are different!");
  689. }
  690. return result;
  691. }
  692. FileRunCommandResult FileRunCommandPart::RunXFail(const FileRunCommandResult *Prior) {
  693. if (Prior == nullptr)
  694. return FileRunCommandResult::Error("XFail requires a prior command");
  695. if (Prior->ExitCode == 0) {
  696. return FileRunCommandResult::Error("XFail expected a failure from previous command");
  697. } else {
  698. return FileRunCommandResult::Success("");
  699. }
  700. }
  701. FileRunCommandResult FileRunCommandPart::RunDxilVer(dxc::DxcDllSupport& DllSupport, const FileRunCommandResult* Prior) {
  702. Arguments = strtrim(Arguments);
  703. if (Arguments.size() != 3 || !std::isdigit(Arguments[0]) || Arguments[1] != '.' || !std::isdigit(Arguments[2])) {
  704. return FileRunCommandResult::Error("Invalid dxil version format");
  705. }
  706. unsigned RequiredDxilMajor = Arguments[0] - '0';
  707. unsigned RequiredDxilMinor = Arguments[2] - '0';
  708. return CheckDxilVer(DllSupport, RequiredDxilMajor, RequiredDxilMinor);
  709. }
  710. #ifndef _WIN32
  711. FileRunCommandResult FileRunCommandPart::RunFromPath(const std::string &toolPath, const FileRunCommandResult *Prior) {
  712. return FileRunCommandResult::Error("RunFromPath not supported");
  713. }
  714. #else //_WIN32
  715. FileRunCommandResult FileRunCommandPart::RunFromPath(const std::string &toolPath, const FileRunCommandResult *Prior) {
  716. if (Prior != nullptr) {
  717. return FileRunCommandResult::Error("prior command not supported");
  718. }
  719. std::string args = Arguments;
  720. // replace %s with command file name
  721. size_t pos;
  722. while ((pos = args.find("%s")) != std::string::npos) {
  723. args.replace(pos, 2, CW2A(CommandFileName));
  724. }
  725. // replace %t and %b with the command file name without extension
  726. SubstituteFilenameVars(args);
  727. // Run the tool via CreateProcess, redirect stdout and strerr to temporary files
  728. std::wstring stdOutFileName = std::wstring(CommandFileName) + L".tmp_stdout";
  729. std::wstring stdErrFileName = std::wstring(CommandFileName) + L".tmp_stderr";
  730. SECURITY_ATTRIBUTES sa;
  731. ZeroMemory(&sa, sizeof(sa));
  732. sa.nLength = sizeof(SECURITY_ATTRIBUTES);
  733. sa.bInheritHandle = true;
  734. HANDLE hStdOutFile = CreateFileW(stdOutFileName.c_str(), GENERIC_READ | GENERIC_WRITE, 0, &sa,
  735. CREATE_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE, nullptr);
  736. IFT(hStdOutFile != INVALID_HANDLE_VALUE);
  737. HANDLE hStdErrFile = CreateFileW(stdErrFileName.c_str(), GENERIC_READ | GENERIC_WRITE, 0, &sa,
  738. CREATE_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE, nullptr);
  739. IFT(hStdErrFile!= INVALID_HANDLE_VALUE);
  740. STARTUPINFOA si;
  741. ZeroMemory(&si, sizeof(si));
  742. si.cb = sizeof(si);
  743. si.hStdOutput = hStdOutFile;
  744. si.hStdError = hStdErrFile;
  745. si.dwFlags |= STARTF_USESTDHANDLES;
  746. PROCESS_INFORMATION pi;
  747. ZeroMemory(&pi, sizeof(pi));
  748. std::vector<char> args2(args.c_str(), args.c_str() + args.size() + 1); // args to CreateProcess cannot be const char *
  749. if (!CreateProcessA(toolPath.c_str(), args2.data(), nullptr, nullptr, true, 0, nullptr, nullptr, &si, &pi)) {
  750. return FileRunCommandResult::Error("CreateProcess failed.");
  751. }
  752. ::WaitForSingleObject(pi.hProcess, 10000); // 10s timeout
  753. // Get exit code of the process
  754. FileRunCommandResult result;
  755. DWORD exitCode;
  756. if (!::GetExitCodeProcess(pi.hProcess, &exitCode)) {
  757. result = FileRunCommandResult::Error("GetExitCodeProcess failed.");
  758. }
  759. else {
  760. result.ExitCode = exitCode;
  761. }
  762. // Close process and thread handles
  763. ::CloseHandle(pi.hProcess);
  764. ::CloseHandle(pi.hThread);
  765. // Read stdout and strerr output from temporary files
  766. if (!ReadFileContentToString(hStdOutFile, result.StdOut) ||
  767. !ReadFileContentToString(hStdErrFile, result.StdErr)) {
  768. result = FileRunCommandResult::Error("RunFromPaths failed.");
  769. }
  770. // Close temporary file handles - will delete the files
  771. IFT(::CloseHandle(hStdOutFile));
  772. IFT(::CloseHandle(hStdErrFile));
  773. return result;
  774. }
  775. #endif //_WIN32
  776. class FileRunTestResultImpl : public FileRunTestResult {
  777. dxc::DxcDllSupport &m_support;
  778. PluginToolsPaths *m_pPluginToolsPaths;
  779. void RunHashTestFromCommands(LPCSTR commands, LPCWSTR fileName) {
  780. std::vector<FileRunCommandPart> parts;
  781. ParseCommandParts(commands, fileName, parts);
  782. FileRunCommandResult result;
  783. bool ran = false;
  784. for (FileRunCommandPart & part : parts) {
  785. result = part.RunHashTests(m_support);
  786. ran = true;
  787. break;
  788. }
  789. if (ran) {
  790. this->RunResult = result.ExitCode;
  791. this->ErrorMessage = result.StdErr;
  792. }
  793. else {
  794. this->RunResult = 0;
  795. }
  796. }
  797. void RunFileCheckFromCommands(LPCSTR commands, LPCWSTR fileName) {
  798. std::vector<FileRunCommandPart> parts;
  799. ParseCommandParts(commands, fileName, parts);
  800. if (parts.empty()) {
  801. this->RunResult = 1;
  802. this->ErrorMessage = "FileCheck found no commands to run";
  803. return;
  804. }
  805. FileRunCommandResult result;
  806. FileRunCommandResult* previousResult = nullptr;
  807. for (FileRunCommandPart & part : parts) {
  808. result = part.Run(m_support, previousResult, m_pPluginToolsPaths);
  809. previousResult = &result;
  810. if (result.AbortPipeline) break;
  811. }
  812. this->RunResult = result.ExitCode;
  813. this->ErrorMessage = result.StdErr;
  814. }
  815. public:
  816. FileRunTestResultImpl(dxc::DxcDllSupport &support, PluginToolsPaths *pPluginToolsPaths = nullptr)
  817. : m_support(support), m_pPluginToolsPaths(pPluginToolsPaths) {}
  818. void RunFileCheckFromFileCommands(LPCWSTR fileName) {
  819. // Assume UTF-8 files.
  820. auto cmds = GetRunLines(fileName);
  821. // Iterate over all RUN lines
  822. for (auto &cmd : cmds) {
  823. RunFileCheckFromCommands(cmd.c_str(), fileName);
  824. // If any of the RUN cmd fails then skip executing remaining cmds
  825. // and report the error
  826. if (this->RunResult != 0) break;
  827. }
  828. }
  829. void RunHashTestFromFileCommands(LPCWSTR fileName) {
  830. // Assume UTF-8 files.
  831. std::string commands(GetFirstLine(fileName));
  832. return RunHashTestFromCommands(commands.c_str(), fileName);
  833. }
  834. };
  835. FileRunTestResult FileRunTestResult::RunHashTestFromFileCommands(LPCWSTR fileName) {
  836. dxc::DxcDllSupport dllSupport;
  837. IFT(dllSupport.Initialize());
  838. FileRunTestResultImpl result(dllSupport);
  839. result.RunHashTestFromFileCommands(fileName);
  840. return result;
  841. }
  842. FileRunTestResult FileRunTestResult::RunFromFileCommands(LPCWSTR fileName,
  843. PluginToolsPaths *pPluginToolsPaths /*=nullptr*/) {
  844. dxc::DxcDllSupport dllSupport;
  845. IFT(dllSupport.Initialize());
  846. FileRunTestResultImpl result(dllSupport, pPluginToolsPaths);
  847. result.RunFileCheckFromFileCommands(fileName);
  848. return result;
  849. }
  850. FileRunTestResult FileRunTestResult::RunFromFileCommands(LPCWSTR fileName, dxc::DxcDllSupport &dllSupport,
  851. PluginToolsPaths *pPluginToolsPaths /*=nullptr*/) {
  852. FileRunTestResultImpl result(dllSupport, pPluginToolsPaths);
  853. result.RunFileCheckFromFileCommands(fileName);
  854. return result;
  855. }
  856. void ParseCommandParts(LPCSTR commands, LPCWSTR fileName,
  857. std::vector<FileRunCommandPart> &parts) {
  858. // Barely enough parsing here.
  859. commands = strstr(commands, "RUN: ");
  860. if (!commands) {
  861. return;
  862. }
  863. commands += strlen("RUN: ");
  864. LPCSTR endCommands = strchr(commands, '\0');
  865. while (commands != endCommands) {
  866. LPCSTR nextStart;
  867. LPCSTR thisEnd = strchr(commands, '|');
  868. if (!thisEnd) {
  869. nextStart = thisEnd = endCommands;
  870. } else {
  871. nextStart = thisEnd + 2;
  872. }
  873. LPCSTR commandEnd = strchr(commands, ' ');
  874. if (!commandEnd)
  875. commandEnd = endCommands;
  876. parts.emplace_back(std::string(commands, commandEnd),
  877. std::string(commandEnd, thisEnd), fileName);
  878. commands = nextStart;
  879. }
  880. }
  881. void ParseCommandPartsFromFile(LPCWSTR fileName,
  882. std::vector<FileRunCommandPart> &parts) {
  883. // Assume UTF-8 files.
  884. std::string commands(GetFirstLine(fileName));
  885. ParseCommandParts(commands.c_str(), fileName, parts);
  886. }