summaryrefslogtreecommitdiff
path: root/src/passes/param-utils.cpp
Commit message (Collapse)AuthorAgeFilesLines
* [NFC] Avoid repeated work in DeadArgumentElimination scanning (#6869)Alon Zakai2024-09-031-5/+9
| | | | | | | | | | | | | | | | | | | This pass may do multiple iterations, and before this PR it scanned the entire module each time. That is simpler than tracking stale data, but it can be quite slow. This PR adds staleness tracking, which makes it over 3x faster (and this can be one of our slowest passes in some cases, so this is significant). To achieve this: * Add a staleness marker on function info. * Rewrite how we track unseen calls. Previously we used atomics in a clever way, * now we just accumulate the data in a simple way (easier for staleness tracking). * Add staleness invalidation in the proper places. * Add a param to localizeCallsTo to allow us to learn when a function is changed. This kind of staleness analysis is usually not worthwhile, but given the 3x plus speedup it seems justified. I fuzzed it directly, and also any staleness bug can lead to validation errors, so normal fuzzing also gives us good coverage here.
* [NFC] Optimize ParamUtils::getUsedParams() (#6866)Alon Zakai2024-08-261-15/+40
| | | | | | | | | | | | | This constructed a LocalGraph, which computes the sets that reach each get. But all we need to know is which params are live, so instead we can do a liveness computation (which is just a boolean, not the list of sets). Also, it is simple to get the liveness computation to only work on the parameters and not all the locals, as a further optimization. Existing tests cover this, though I did find that the case of unreachability needed a new test. On a large testcase I am looking at, this makes --dae 17% faster.
* DeadArgumentElimination/SignaturePruning: Prune params even if called with ↵Alon Zakai2024-03-181-38/+145
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | effects (#6395) Before this PR, when we saw a param was unused we sometimes could not remove it. For example, if there was one call like this: (call $target (call $other) ) That nested call has effects, so we can't just remove it from the outer call - we'd need to move it first. That motion was hard to integrate which was why it was left out, but it turns out that is sometimes very important. E.g. in Java it is common to have such calls that send the this parameter as the result of another call; not being able to remove such params meant we kept those nested calls alive, creating empty structs just to have something to send there. To fix this, this builds on top of #6394 which makes it easier to move all children out of a parent, leaving only nested things that can be easily moved around and removed. In more detail, DeadArgumentElimination/SignaturePruning track whether we run into effects that prevent removing a field. If we do, then we queue an operation to move the children out, which we do using a new utility ParamUtils::localizeCallsTo. The pass then does another iteration after that operation. Alternatively we could try to move things around immediately, but that is quite hard: those passes already track a lot of state. It is simpler to do the fixup in an entirely separate utility. That does come at the cost of the utility doing another pass on the module and the pass itself running another iteration, but this situation is not the most common.
* Only look at the relevant parameter in param-utils:removeParameter (#4937)Alon Zakai2022-08-231-5/+2
| | | Followup to #4910.
* Fix DeadArgumentElimination + TrapsNeverHappen to not leave stale types (#4910)Alon Zakai2022-08-181-5/+25
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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).
* Generalize PossibleConstantValues for immutable globals (#4549)Alon Zakai2022-03-281-15/+3
| | | | | | | | | | | | This moves more logic from ConstantFieldPropagation into PossibleConstantValues, that is, instead of handling the two cases of a Literal or a Name before calling PossibleConstantValues, move that code into the helper class. That way all users of PossibleConstantValues can benefit from it. In particular, this makes DeadArgumentElimination now support optimizing immutable globals, as well as ref.func and ref.null. (Changes to test/lit/passes/dae-gc-refine-params.wast are to avoid the new optimizations from kicking in, so that it still tests what it tested before.)
* [Wasm GC] Signature Pruning (#4545)Alon Zakai2022-03-251-3/+12
| | | | | | | | | | | | | This adds a new signature-pruning pass that prunes parameters from signature types where those parameters are never used in any function that has that type. This is similar to DeadArgumentElimination but works on a set of functions, and it can handle indirect calls. Also move a little code from SignatureRefining into a shared place to avoid duplication of logic to update signature types. This pattern happens in j2wasm code, for example if all method functions for some virtual method just return a constant and do not use the this pointer.
* [NFC] Move and generalize constant-parameter code from ↵Alon Zakai2022-03-251-2/+60
| | | | | | | DeadArgumentElimination (#4547) Similar to #4544, this moves the code to a utility function, and also slightly generalizes it to support a list of functions (and not just 1) and also a list of call_refs (and not just calls).
* [NFC] Move and generalize parameter-removing logic from ↵Alon Zakai2022-03-231-0/+177
DeadArgumentElimination (#4544) In preparation for removing dead arguments from all functions sharing a heap type (which seems useful for j2wasm output), first this PR refactors that code so it is reusable. This moves the code out of the pass into FunctionUtils, and also generalizes it slightly by supporting a set of functions and not just a single one, and receiving a list of call_refs and not just calls (no other changes to anything).