diff options
Diffstat (limited to 'src/tools/wasm-reduce.cpp')
-rw-r--r-- | src/tools/wasm-reduce.cpp | 132 |
1 files changed, 125 insertions, 7 deletions
diff --git a/src/tools/wasm-reduce.cpp b/src/tools/wasm-reduce.cpp index e858bfcdd..f8ed04abb 100644 --- a/src/tools/wasm-reduce.cpp +++ b/src/tools/wasm-reduce.cpp @@ -36,7 +36,35 @@ #include "wasm-builder.h" #include "ir/literal-utils.h" #include "wasm-validator.h" - +#ifdef _WIN32 +#ifndef NOMINMAX +#define NOMINMAX +#endif +#include <Windows.h> +// Create a string with last error message
+std::string GetLastErrorStdStr() {
+ DWORD error = GetLastError();
+ if (error) {
+ LPVOID lpMsgBuf;
+ DWORD bufLen = FormatMessage(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ error,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPTSTR) &lpMsgBuf,
+ 0, NULL );
+ if (bufLen) {
+ LPCSTR lpMsgStr = (LPCSTR)lpMsgBuf;
+ std::string result(lpMsgStr, lpMsgStr+bufLen);
+ LocalFree(lpMsgBuf);
+ return result;
+ }
+ }
+ return std::string();
+} +#endif using namespace wasm; // a timeout on every execution of the command @@ -52,6 +80,89 @@ struct ProgramResult { getFromExecution(command); } +#ifdef _WIN32 + void getFromExecution(std::string command) { + Timer timer; + timer.start(); + SECURITY_ATTRIBUTES saAttr; + saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); + saAttr.bInheritHandle = TRUE; + saAttr.lpSecurityDescriptor = NULL; + + HANDLE hChildStd_OUT_Rd; + HANDLE hChildStd_OUT_Wr; + + if ( + // Create a pipe for the child process's STDOUT. + !CreatePipe(&hChildStd_OUT_Rd, &hChildStd_OUT_Wr, &saAttr, 0) || + // Ensure the read handle to the pipe for STDOUT is not inherited. + !SetHandleInformation(hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0) + ) { + Fatal() << "CreatePipe \"" << command << "\" failed: " << GetLastErrorStdStr() << ".\n"; + } + + STARTUPINFO si; + PROCESS_INFORMATION pi; + + ZeroMemory(&si, sizeof(si)); + si.cb = sizeof(si); + si.hStdError = hChildStd_OUT_Wr; + si.hStdOutput = hChildStd_OUT_Wr; + si.dwFlags |= STARTF_USESTDHANDLES; + ZeroMemory(&pi, sizeof(pi)); + + // Start the child process. + if (!CreateProcess(NULL, // No module name (use command line) + (LPSTR)command.c_str(),// Command line + NULL, // Process handle not inheritable + NULL, // Thread handle not inheritable + TRUE, // Set handle inheritance to TRUE + 0, // No creation flags + NULL, // Use parent's environment block + NULL, // Use parent's starting directory + &si, // Pointer to STARTUPINFO structure + &pi ) // Pointer to PROCESS_INFORMATION structure + ) { + Fatal() << "CreateProcess \"" << command << "\" failed: " << GetLastErrorStdStr() << ".\n"; + } + + // Wait until child process exits. + DWORD retVal = WaitForSingleObject(pi.hProcess, timeout * 1000); + if (retVal == WAIT_TIMEOUT) { + printf("Command timeout: %s", command.c_str()); + TerminateProcess(pi.hProcess, -1); + } + DWORD dwordExitCode; + if (!GetExitCodeProcess(pi.hProcess, &dwordExitCode)) { + Fatal() << "GetExitCodeProcess failed: " << GetLastErrorStdStr() << ".\n"; + } + code = (int)dwordExitCode; + + // Close process and thread handles. + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + + // Read output from the child process's pipe for STDOUT + // Stop when there is no more data. + { + const int BUFSIZE = 4096; + DWORD dwRead, dwTotal, dwTotalRead = 0; + CHAR chBuf[BUFSIZE]; + BOOL bSuccess = FALSE; + + PeekNamedPipe(hChildStd_OUT_Rd, NULL, 0, NULL, &dwTotal, NULL); + while (dwTotalRead < dwTotal) { + bSuccess = ReadFile(hChildStd_OUT_Rd, chBuf, BUFSIZE - 1, &dwRead, NULL); + if (!bSuccess || dwRead == 0) break; + chBuf[dwRead] = 0; + dwTotalRead += dwRead; + output.append(chBuf); + } + } + timer.stop(); + time = timer.getTotal(); + } +#else // POSIX // runs the command and notes the output // TODO: also stderr, not just stdout? void getFromExecution(std::string command) { @@ -70,6 +181,7 @@ struct ProgramResult { timer.stop(); time = timer.getTotal() / 2; } +#endif // _WIN32 bool operator==(ProgramResult& other) { return code == other.code && output == other.output; @@ -104,12 +216,12 @@ ProgramResult expected; static std::unordered_set<Name> functionsWeTriedToRemove; struct Reducer : public WalkerPass<PostWalker<Reducer, UnifiedExpressionVisitor<Reducer>>> { - std::string command, test, working; + std::string command, test, working, binaryenBinDir; bool verbose, debugInfo; // test is the file we write to that the command will operate on // working is the current temporary state, the reduction so far - Reducer(std::string command, std::string test, std::string working, bool verbose, bool debugInfo) : command(command), test(test), working(working), verbose(verbose), debugInfo(debugInfo) {} + Reducer(std::string command, std::string test, std::string working, bool verbose, bool debugInfo, std::string binaryenBinDir) : command(command), test(test), working(working), binaryenBinDir(binaryenBinDir), verbose(verbose), debugInfo(debugInfo) {} // runs passes in order to reduce, until we can't reduce any more // the criterion here is wasm binary size @@ -149,7 +261,7 @@ struct Reducer : public WalkerPass<PostWalker<Reducer, UnifiedExpressionVisitor< // try both combining with a generic shrink (so minor pass overhead is compensated for), and without for (auto shrinking : { false, true }) { for (auto pass : passes) { - std::string currCommand = Path::getBinaryenBinaryTool("wasm-opt") + " "; + std::string currCommand = binaryenBinDir + "wasm-opt" + " "; if (shrinking) currCommand += " --dce --vacuum "; currCommand += working + " -o " + test + " " + pass; if (debugInfo) currCommand += " -g "; @@ -614,7 +726,7 @@ struct Reducer : public WalkerPass<PostWalker<Reducer, UnifiedExpressionVisitor< // int main(int argc, const char* argv[]) { - std::string input, test, working, command; + std::string input, test, working, command, binaryenBinDir = Path::getBinaryenBinDir(); bool verbose = false, debugInfo = false, force = false; @@ -638,6 +750,12 @@ int main(int argc, const char* argv[]) { [&](Options* o, const std::string& argument) { working = argument; }) + .add("--binaries", "-b", "binaryen binaries location", + Options::Arguments::One, + [&](Options* o, const std::string& argument) { + // Add separator just in case + binaryenBinDir = argument + Path::getPathSeparator(); + }) .add("--verbose", "-v", "Verbose output mode", Options::Arguments::Zero, [&](Options* o, const std::string& argument) { @@ -706,7 +824,7 @@ int main(int argc, const char* argv[]) { std::cerr << "|checking that command has expected behavior on canonicalized (read-written) binary\n"; { // read and write it - ProgramResult readWrite(Path::getBinaryenBinaryTool("wasm-opt") + " " + input + " -o " + test); + ProgramResult readWrite(binaryenBinDir + "wasm-opt" + " " + input + " -o " + test); if (readWrite.failed()) { stopIfNotForced("failed to read and write the binary", readWrite); } else { @@ -730,7 +848,7 @@ int main(int argc, const char* argv[]) { bool stopping = false; while (1) { - Reducer reducer(command, test, working, verbose, debugInfo); + Reducer reducer(command, test, working, verbose, debugInfo, binaryenBinDir); // run binaryen optimization passes to reduce. passes are fast to run // and can often reduce large amounts of code efficiently, as opposed |