summaryrefslogtreecommitdiff
path: root/src/passes/pass.cpp
diff options
context:
space:
mode:
authorAlon Zakai <azakai@google.com>2022-08-12 14:29:12 -0700
committerGitHub <noreply@github.com>2022-08-12 14:29:12 -0700
commit6c6aae1358d657fe16fcfdc3a0eccfcea66cc841 (patch)
tree2fc4a82526e88b056d5854c02dce19200b0bfe1b /src/passes/pass.cpp
parent48d5a5d529cf3e51605a5e50a746603b74a72e97 (diff)
downloadbinaryen-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.cpp34
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) {