summaryrefslogtreecommitdiff
path: root/src/ir/struct-utils.h
diff options
context:
space:
mode:
authorAlon Zakai <azakai@google.com>2022-08-18 09:13:47 -0700
committerGitHub <noreply@github.com>2022-08-18 09:13:47 -0700
commit0c9ffd618ba69128caa61583a7cd9a831fef1d98 (patch)
tree4e97b43c4d8660213cfd160354a78b4b8c3c8eef /src/ir/struct-utils.h
parent8a92ab5f5f0529fec4b71223858fac853837884e (diff)
downloadbinaryen-0c9ffd618ba69128caa61583a7cd9a831fef1d98.tar.gz
binaryen-0c9ffd618ba69128caa61583a7cd9a831fef1d98.tar.bz2
binaryen-0c9ffd618ba69128caa61583a7cd9a831fef1d98.zip
Fix DeadArgumentElimination + TrapsNeverHappen to not leave stale types (#4910)
DAE will normally not remove an unreachable parameter, because it checks for effects there. But in TrapsNeverHappen mode, we assume that an unreachable is an effect we can remove, so we are willing to remove it: (func $foo (param $unused i32) ;; never use $unused ) (func $bar (call $foo (unreachable))) ;;=> dae+tnh (func $foo ) (func $bar (call $foo)) But that transformation is invalid: the call's type was unreachable before but no longer is. What went wrong here is that, yes, it is valid to remove an unreachable, but we may need to update types while doing so, which we were not doing. This wasn't noticed before due to a combination of unfortunate factors: The main reason is that this only happens in TrapsNeverHappens mode. We don't fuzz that, because it's difficult: that mode can assume a trap never happens, so a trap is undefined behavior really. On real-world code this is great, but in the fuzzer it means that the output can seem to change after optimizations. The validator happened to be missing an error for a call that has type unreachable but shouldn't: Validator: Validate unreachable calls more carefully #4909 . Without that, we'd only get an error if the bad type influenced a subsequent pass in a confusing way - which is possible, but difficult to achieve (what ended up happening in practice is that SignatureRefining on J2Wasm relied on the unreachable and refined a type too much). Even with that fix, for the problem to be detected we'd need for the validation error to happen in the final output, after running all the passes. In practice, though, that's not likely, since other passes tend to remove unreachables etc. Pass-debug mode is very useful for finding stuff like this, as it validates after every individual pass. Sadly it turns out that global validation was off there: Validator: Validate globally by default #4906 (so it was catching the 99% of validation errors that are local, but this particular error was in the remaining 1%...). As a fix, simply ignore this case. It's not really worth the effort to optimize it, since DCE will just remove unreachables like that anyhow. So if we run again after a DCE we'd get a chance to optimize. This updates some existing tests to avoid (unreachable). That was used as an example of something with effects, but after this change it is treated more carefully. Replace those things with something else that has effects (a call).
Diffstat (limited to 'src/ir/struct-utils.h')
0 files changed, 0 insertions, 0 deletions