123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460 |
- ///////////////////////////////////////////////////////////////////////////////
- // //
- // FileCheckerTest.cpp //
- // Copyright (C) Microsoft Corporation. All rights reserved. //
- // This file is distributed under the University of Illinois Open Source //
- // License. See LICENSE.TXT for details. //
- // //
- // Provides tests that are based on FileChecker. //
- // //
- ///////////////////////////////////////////////////////////////////////////////
- #ifndef UNICODE
- #define UNICODE
- #endif
- #include <memory>
- #include <vector>
- #include <string>
- #include <cassert>
- #include <algorithm>
- #include "dxc/Support/WinIncludes.h"
- #include "dxc/dxcapi.h"
- #include <atlfile.h>
- #include "HLSLTestData.h"
- #include "WexTestClass.h"
- #include "HlslTestUtils.h"
- #include "DxcTestUtils.h"
- #include "llvm/Support/raw_os_ostream.h"
- #include "dxc/Support/Global.h"
- #include "dxc/Support/dxcapi.use.h"
- #include "dxc/Support/HLSLOptions.h"
- #include "dxc/Support/Unicode.h"
- using namespace std;
- using namespace hlsl_test;
- static std::string strltrim(std::string value) {
- return value.erase(0, value.find_first_not_of(" \t\r\n"));
- }
- static std::string strrtrim(std::string value) {
- size_t last = value.find_last_not_of(" \t\r\n");
- return last == string::npos ? value : value.substr(0, last + 1);
- }
- static std::string strtrim(const std::string &value) {
- return strltrim(strrtrim(value));
- }
- static string trim(string value) {
- size_t leading = value.find_first_not_of(' ');
- if (leading != std::string::npos) {
- value.erase(0, leading);
- }
- size_t trailing = value.find_last_not_of(' ');
- if (leading != std::string::npos) {
- value.erase(trailing + 1);
- }
- return value;
- }
- FileRunCommandPart::FileRunCommandPart(const std::string &command, const std::string &arguments, LPCWSTR commandFileName) :
- Command(command), Arguments(arguments), CommandFileName(commandFileName) { }
- FileRunCommandPart::FileRunCommandPart(FileRunCommandPart && other) :
- Command(std::move(other.Command)),
- CommandFileName(other.CommandFileName),
- Arguments(std::move(other.Arguments)),
- RunResult(other.RunResult),
- StdOut(std::move(other.StdOut)),
- StdErr(std::move(other.StdErr)) { }
- void FileRunCommandPart::Run(const FileRunCommandPart *Prior) {
- bool isFileCheck =
- 0 == _stricmp(Command.c_str(), "FileCheck") ||
- 0 == _stricmp(Command.c_str(), "%FileCheck");
- // For now, propagate errors.
- if (Prior && Prior->RunResult) {
- if (isFileCheck) {
- RunFileChecker(Prior);
- } else {
- StdErr = Prior->StdErr;
- RunResult = Prior->RunResult;
- }
- return;
- }
- // We would add support for 'not' and 'llc' here.
- if (isFileCheck) {
- RunFileChecker(Prior);
- }
- else if (0 == _stricmp(Command.c_str(), "StdErrCheck")) {
- RunStdErrChecker(Prior);
- }
- else if (0 == _stricmp(Command.c_str(), "tee")) {
- RunTee(Prior);
- }
- else if (0 == _stricmp(Command.c_str(), "%dxc")) {
- RunDxc(Prior);
- }
- else if (0 == _stricmp(Command.c_str(), "%dxv")) {
- RunDxv(Prior);
- }
- else if (0 == _stricmp(Command.c_str(), "%opt")) {
- RunOpt(Prior);
- }
- else {
- RunResult = 1;
- StdErr = "Unrecognized command ";
- StdErr += Command;
- }
- }
- void FileRunCommandPart::RunFileChecker(const FileRunCommandPart *Prior) {
- std::string args(strtrim(Arguments));
- if (args != "%s") {
- StdErr = "Only supported pattern is a plain input file";
- RunResult = 1;
- return;
- }
- if (!Prior) {
- StdErr = "Prior command required to generate stdin";
- RunResult = 1;
- return;
- }
- CW2A fileName(CommandFileName, CP_UTF8);
- FileCheckForTest t;
- t.CheckFilename = fileName;
- if (Prior->RunResult)
- t.InputForStdin = Prior->StdErr;
- else
- t.InputForStdin = Prior->StdOut;
- RunResult = t.Run();
- StdOut = t.test_outs;
- StdErr = t.test_errs;
- // Capture the input as well.
- if (RunResult != 0 && Prior != nullptr) {
- StdErr += "\n<full input to FileCheck>\n";
- StdErr += t.InputForStdin;
- }
- }
- void FileRunCommandPart::RunStdErrChecker(const FileRunCommandPart *Prior) {
- std::string args(strtrim(Arguments));
- if (args != "%s") {
- StdErr = "Only supported pattern is a plain input file";
- RunResult = 1;
- return;
- }
- if (!Prior) {
- StdErr = "Prior command required to generate stdin";
- RunResult = 1;
- return;
- }
- CW2A fileName(CommandFileName, CP_UTF8);
- FileCheckForTest t;
- t.CheckFilename = fileName;
-
- t.InputForStdin = Prior->StdErr;
-
- RunResult = t.Run();
- StdOut = t.test_outs;
- StdErr = t.test_errs;
- // Capture the input as well.
- if (RunResult != 0 && Prior != nullptr) {
- StdErr += "\n<full input to StdErrCheck>\n";
- StdErr += t.InputForStdin;
- }
- }
- void FileRunCommandPart::ReadOptsForDxc(hlsl::options::MainArgs &argStrings,
- hlsl::options::DxcOpts &Opts) {
- std::string args(strtrim(Arguments));
- const char *inputPos = strstr(args.c_str(), "%s");
- if (inputPos == nullptr) {
- StdErr = "Only supported pattern includes input file as argument";
- RunResult = 1;
- return;
- }
- args.erase(inputPos - args.c_str(), strlen("%s"));
- llvm::StringRef argsRef = args;
- llvm::SmallVector<llvm::StringRef, 8> splitArgs;
- argsRef.split(splitArgs, " ");
- argStrings = hlsl::options::MainArgs(splitArgs);
- std::string errorString;
- llvm::raw_string_ostream errorStream(errorString);
- IFT(ReadDxcOpts(hlsl::options::getHlslOptTable(), /*flagsToInclude*/ 0,
- argStrings, Opts, errorStream));
- }
- void FileRunCommandPart::RunDxc(const FileRunCommandPart *Prior) {
- // Support piping stdin from prior if needed.
- UNREFERENCED_PARAMETER(Prior);
- hlsl::options::MainArgs args;
- hlsl::options::DxcOpts opts;
- ReadOptsForDxc(args, opts);
- std::wstring entry =
- Unicode::UTF8ToUTF16StringOrThrow(opts.EntryPoint.str().c_str());
- std::wstring profile =
- Unicode::UTF8ToUTF16StringOrThrow(opts.TargetProfile.str().c_str());
- std::vector<LPCWSTR> flags;
- if (opts.CodeGenHighLevel) {
- flags.push_back(L"-fcgl");
- }
- std::vector<std::wstring> argWStrings;
- CopyArgsToWStrings(opts.Args, hlsl::options::CoreOption, argWStrings);
- for (const std::wstring &a : argWStrings)
- flags.push_back(a.data());
- CComPtr<IDxcLibrary> pLibrary;
- CComPtr<IDxcCompiler> pCompiler;
- CComPtr<IDxcOperationResult> pResult;
- CComPtr<IDxcBlobEncoding> pSource;
- CComPtr<IDxcBlobEncoding> pDisassembly;
- CComPtr<IDxcBlob> pCompiledBlob;
- CComPtr<IDxcIncludeHandler> pIncludeHandler;
- HRESULT resultStatus;
- IFT(DllSupport->CreateInstance(CLSID_DxcLibrary, &pLibrary));
- IFT(pLibrary->CreateBlobFromFile(CommandFileName, nullptr, &pSource));
- IFT(pLibrary->CreateIncludeHandler(&pIncludeHandler));
- IFT(DllSupport->CreateInstance(CLSID_DxcCompiler, &pCompiler));
- IFT(pCompiler->Compile(pSource, CommandFileName, entry.c_str(), profile.c_str(),
- flags.data(), flags.size(), nullptr, 0, pIncludeHandler, &pResult));
- IFT(pResult->GetStatus(&resultStatus));
- if (SUCCEEDED(resultStatus)) {
- IFT(pResult->GetResult(&pCompiledBlob));
- if (!opts.AstDump) {
- IFT(pCompiler->Disassemble(pCompiledBlob, &pDisassembly));
- StdOut = BlobToUtf8(pDisassembly);
- } else {
- StdOut = BlobToUtf8(pCompiledBlob);
- }
- CComPtr<IDxcBlobEncoding> pStdErr;
- IFT(pResult->GetErrorBuffer(&pStdErr));
- StdErr = BlobToUtf8(pStdErr);
- RunResult = 0;
- }
- else {
- IFT(pResult->GetErrorBuffer(&pDisassembly));
- StdErr = BlobToUtf8(pDisassembly);
- RunResult = resultStatus;
- }
- OpResult = pResult;
- }
- void FileRunCommandPart::RunDxv(const FileRunCommandPart *Prior) {
- std::string args(strtrim(Arguments));
- const char *inputPos = strstr(args.c_str(), "%s");
- if (inputPos == nullptr) {
- StdErr = "Only supported pattern includes input file as argument";
- RunResult = 1;
- return;
- }
- args.erase(inputPos - args.c_str(), strlen("%s"));
- llvm::StringRef argsRef = args;
- llvm::SmallVector<llvm::StringRef, 8> splitArgs;
- argsRef.split(splitArgs, " ");
- IFTMSG(splitArgs.size()==1, "wrong arg num for dxv");
-
- CComPtr<IDxcLibrary> pLibrary;
- CComPtr<IDxcAssembler> pAssembler;
- CComPtr<IDxcValidator> pValidator;
- CComPtr<IDxcOperationResult> pResult;
- CComPtr<IDxcBlobEncoding> pSource;
- CComPtr<IDxcBlob> pContainerBlob;
- HRESULT resultStatus;
- IFT(DllSupport->CreateInstance(CLSID_DxcLibrary, &pLibrary));
- IFT(pLibrary->CreateBlobFromFile(CommandFileName, nullptr, &pSource));
- IFT(DllSupport->CreateInstance(CLSID_DxcAssembler, &pAssembler));
- IFT(pAssembler->AssembleToContainer(pSource, &pResult));
- IFT(pResult->GetStatus(&resultStatus));
- if (FAILED(resultStatus)) {
- CComPtr<IDxcBlobEncoding> pAssembleBlob;
- IFT(pResult->GetErrorBuffer(&pAssembleBlob));
- StdErr = BlobToUtf8(pAssembleBlob);
- RunResult = resultStatus;
- return;
- }
- IFT(pResult->GetResult(&pContainerBlob));
- IFT(DllSupport->CreateInstance(CLSID_DxcValidator, &pValidator));
- CComPtr<IDxcOperationResult> pValidationResult;
- IFT(pValidator->Validate(pContainerBlob, DxcValidatorFlags_InPlaceEdit,
- &pValidationResult));
- IFT(pValidationResult->GetStatus(&resultStatus));
- if (resultStatus) {
- CComPtr<IDxcBlobEncoding> pValidateBlob;
- IFT(pValidationResult->GetErrorBuffer(&pValidateBlob));
- StdOut = BlobToUtf8(pValidateBlob);
- }
- RunResult = 0;
- }
- void FileRunCommandPart::RunOpt(const FileRunCommandPart *Prior) {
- std::string args(strtrim(Arguments));
- const char *inputPos = strstr(args.c_str(), "%s");
- if (inputPos == nullptr && Prior == nullptr) {
- StdErr = "Only supported patterns are input file as argument or prior "
- "command with disassembly";
- RunResult = 1;
- return;
- }
- CComPtr<IDxcLibrary> pLibrary;
- CComPtr<IDxcOptimizer> pOptimizer;
- CComPtr<IDxcBlobEncoding> pSource;
- CComPtr<IDxcBlobEncoding> pOutputText;
- CComPtr<IDxcBlob> pOutputModule;
- IFT(DllSupport->CreateInstance(CLSID_DxcLibrary, &pLibrary));
- IFT(DllSupport->CreateInstance(CLSID_DxcOptimizer, &pOptimizer));
- if (inputPos != nullptr) {
- args.erase(inputPos - args.c_str(), strlen("%s"));
- IFT(pLibrary->CreateBlobFromFile(CommandFileName, nullptr, &pSource));
- }
- else {
- assert(Prior != nullptr && "else early check should have returned");
- CComPtr<IDxcAssembler> pAssembler;
- IFT(DllSupport->CreateInstance(CLSID_DxcAssembler, &pAssembler));
- IFT(pLibrary->CreateBlobWithEncodingFromPinned(
- (LPBYTE)Prior->StdOut.c_str(), Prior->StdOut.size(), CP_UTF8,
- &pSource));
- }
- args = trim(args);
- llvm::StringRef argsRef = args;
- llvm::SmallVector<llvm::StringRef, 8> splitArgs;
- argsRef.split(splitArgs, " ");
- std::vector<LPCWSTR> options;
- std::vector<std::wstring> optionStrings;
- for (llvm::StringRef S : splitArgs) {
- optionStrings.push_back(
- Unicode::UTF8ToUTF16StringOrThrow(trim(S.str()).c_str()));
- }
- // Add the options outside the above loop in case the vector is resized.
- for (const std::wstring& str : optionStrings)
- options.push_back(str.c_str());
- IFT(pOptimizer->RunOptimizer(pSource, options.data(), options.size(),
- &pOutputModule, &pOutputText));
- StdOut = BlobToUtf8(pOutputText);
- RunResult = 0;
- }
- void FileRunCommandPart::RunTee(const FileRunCommandPart *Prior) {
- if (Prior == nullptr) {
- StdErr = "tee requires a prior command";
- RunResult = 1;
- return;
- }
- // Ignore commands for now - simply log out through test framework.
- {
- CA2W outWide(Prior->StdOut.c_str(), CP_UTF8);
- WEX::Logging::Log::Comment(outWide.m_psz);
- }
- if (!Prior->StdErr.empty()) {
- CA2W errWide(Prior->StdErr.c_str(), CP_UTF8);
- WEX::Logging::Log::Comment(L"<stderr>");
- WEX::Logging::Log::Comment(errWide.m_psz);
- }
- StdErr = Prior->StdErr;
- StdOut = Prior->StdOut;
- RunResult = Prior->RunResult;
- }
- class FileRunTestResultImpl : public FileRunTestResult {
- dxc::DxcDllSupport &m_support;
- void RunFileCheckFromCommands(LPCSTR commands, LPCWSTR fileName) {
- std::vector<FileRunCommandPart> parts;
- ParseCommandParts(commands, fileName, parts);
- FileRunCommandPart *prior = nullptr;
- for (FileRunCommandPart & part : parts) {
- part.DllSupport = &m_support;
- part.Run(prior);
- prior = ∂
- }
- if (prior == nullptr) {
- this->RunResult = 1;
- this->ErrorMessage = "FileCheck found no commands to run";
- }
- else {
- this->RunResult = prior->RunResult;
- this->ErrorMessage = prior->StdErr;
- }
- }
- public:
- FileRunTestResultImpl(dxc::DxcDllSupport &support) : m_support(support) {}
- void RunFileCheckFromFileCommands(LPCWSTR fileName) {
- // Assume UTF-8 files.
- std::string commands(GetFirstLine(fileName));
- return RunFileCheckFromCommands(commands.c_str(), fileName);
- }
- };
- FileRunTestResult FileRunTestResult::RunFromFileCommands(LPCWSTR fileName) {
- dxc::DxcDllSupport dllSupport;
- IFT(dllSupport.Initialize());
- FileRunTestResultImpl result(dllSupport);
- result.RunFileCheckFromFileCommands(fileName);
- return result;
- }
- FileRunTestResult FileRunTestResult::RunFromFileCommands(LPCWSTR fileName, dxc::DxcDllSupport &dllSupport) {
- FileRunTestResultImpl result(dllSupport);
- result.RunFileCheckFromFileCommands(fileName);
- return result;
- }
- void ParseCommandParts(LPCSTR commands, LPCWSTR fileName,
- std::vector<FileRunCommandPart> &parts) {
- // Barely enough parsing here.
- commands = strstr(commands, "RUN: ");
- if (!commands) {
- return;
- }
- commands += strlen("RUN: ");
- LPCSTR endCommands = strchr(commands, '\0');
- while (commands != endCommands) {
- LPCSTR nextStart;
- LPCSTR thisEnd = strchr(commands, '|');
- if (!thisEnd) {
- nextStart = thisEnd = endCommands;
- } else {
- nextStart = thisEnd + 2;
- }
- LPCSTR commandEnd = strchr(commands, ' ');
- if (!commandEnd)
- commandEnd = endCommands;
- parts.emplace_back(std::string(commands, commandEnd),
- std::string(commandEnd, thisEnd), fileName);
- commands = nextStart;
- }
- }
- void ParseCommandPartsFromFile(LPCWSTR fileName,
- std::vector<FileRunCommandPart> &parts) {
- // Assume UTF-8 files.
- std::string commands(GetFirstLine(fileName));
- ParseCommandParts(commands.c_str(), fileName, parts);
- }
|