diff options
author | Alon Zakai <azakai@google.com> | 2022-08-12 14:29:12 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-08-12 14:29:12 -0700 |
commit | 6c6aae1358d657fe16fcfdc3a0eccfcea66cc841 (patch) | |
tree | 2fc4a82526e88b056d5854c02dce19200b0bfe1b /src/passes/pass.cpp | |
parent | 48d5a5d529cf3e51605a5e50a746603b74a72e97 (diff) | |
download | binaryen-6c6aae1358d657fe16fcfdc3a0eccfcea66cc841.tar.gz binaryen-6c6aae1358d657fe16fcfdc3a0eccfcea66cc841.tar.bz2 binaryen-6c6aae1358d657fe16fcfdc3a0eccfcea66cc841.zip |
Function-level pass-debug mode 2 validation (#4897)
In BINARYEN_PASS_DEBUG=2 we save the module before each pass, and if
validation fails afterwards, we print the module before. This PR does the same for
function-parallel passes - in that case, we can actually show the specific function
that broke validation, as opposed to the whole module.
Diffstat (limited to 'src/passes/pass.cpp')
-rw-r--r-- | src/passes/pass.cpp | 34 |
1 files changed, 32 insertions, 2 deletions
diff --git a/src/passes/pass.cpp b/src/passes/pass.cpp index 8dcc7e417..570cd8610 100644 --- a/src/passes/pass.cpp +++ b/src/passes/pass.cpp @@ -891,18 +891,48 @@ void PassRunner::runPass(Pass* pass) { void PassRunner::runPassOnFunction(Pass* pass, Function* func) { assert(pass->isFunctionParallel()); + + auto passDebug = getPassDebug(); + + // Add extra validation logic in pass-debug mode 2. The main logic in + // PassRunner::run will work at the module level, and here for a function- + // parallel pass we can do the same at the function level: we can print the + // function before the pass, run the pass on the function, and then if it + // fails to validate we can show an error and print the state right before the + // pass broke it. + // + // Skip nameless passes for this. Anything without a name is an internal + // component of some larger pass, and information about it won't be very + // useful - leave it to the entire module to fail validation in that case. + bool extraFunctionValidation = + passDebug == 2 && options.validate && !pass->name.empty(); + std::stringstream bodyBefore; + if (extraFunctionValidation) { + bodyBefore << *func->body << '\n'; + } + // function-parallel passes get a new instance per function auto instance = std::unique_ptr<Pass>(pass->create()); std::unique_ptr<AfterEffectFunctionChecker> checker; - if (getPassDebug()) { + if (passDebug) { checker = std::unique_ptr<AfterEffectFunctionChecker>( new AfterEffectFunctionChecker(func)); } instance->runOnFunction(this, wasm, func); handleAfterEffects(pass, func); - if (getPassDebug()) { + if (passDebug) { checker->check(); } + + if (extraFunctionValidation) { + if (!WasmValidator().validate(func, *wasm, WasmValidator::Minimal)) { + Fatal() << "Last nested function-parallel pass (" << pass->name + << ") broke validation of function " << func->name + << ". Here is the function body before:\n" + << bodyBefore.str() << "\n\nAnd here it is now:\n" + << *func->body << '\n'; + } + } } void PassRunner::handleAfterEffects(Pass* pass, Function* func) { |