summaryrefslogtreecommitdiff
path: root/test/lit/passes/vacuum-tnh.wast
Commit message (Collapse)AuthorAgeFilesLines
* Use TopologicalSort::minSort to order rec groups (#6892)Thomas Lively2024-09-041-5/+5
| | | | | | | | | | | | | | | | Rec groups need to be topologically sorted for the output module to be valid, but the specific order of rec groups also affects the module size because types at lower indices requires fewer bytes to reference. We previously optimized for code size when gathering types by sorting the list of groups before doing the topological sort. This was brittle, though, and depended on implementation details of the topological sort to be correct. Replace the old topological sort with use of the new `TopologicalSort::minSort` utility, which is a more principled method of achieving a minimal topological sort with respect to some comparator. Also draw inspiration from ReorderGlobals and apply an exponential factor to take the users of a rec group into account when determining its weight.
* Fix Vacuuming of code leading up to an infinite loop (#6632)Alon Zakai2024-05-291-22/+41
| | | | | We had that logic right in other places, but the specific part of Vacuum that looks at code that leads up to an unreachable did not check for infinite loops, so it could remove them.
* Require `then` and `else` with `if` (#6201)Thomas Lively2024-01-041-90/+152
| | | | | | | | | | | | We previously supported (and primarily used) a non-standard text format for conditionals in which the condition, if-true expression, and if-false expression were all simply s-expression children of the `if` expression. The standard text format, however, requires the use of `then` and `else` forms to introduce the if-true and if-false arms of the conditional. Update the legacy text parser to require the standard format and update all tests to match. Update the printer to print the standard format as well. The .wast and .wat test inputs were mechanically updated with this script: https://gist.github.com/tlively/85ae7f01f92f772241ec994c840ccbb1
* Simplify and consolidate type printing (#5816)Thomas Lively2023-08-241-32/+32
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | When printing Binaryen IR, we previously generated names for unnamed heap types based on their structure. This was useful for seeing the structure of simple types at a glance without having to separately go look up their definitions, but it also had two problems: 1. The same name could be generated for multiple types. The generated names did not take into account rec group structure or finality, so types that differed only in these properties would have the same name. Also, generated type names were limited in length, so very large types that shared only some structure could also end up with the same names. Using the same name for multiple types produces incorrect and unparsable output. 2. The generated names were not useful beyond the most trivial examples. Even with length limits, names for nontrivial types were extremely long and visually noisy, which made reading disassembled real-world code more challenging. Fix these problems by emitting simple indexed names for unnamed heap types instead. This regresses readability for very simple examples, but the trade off is worth it. This change also reduces the number of type printing systems we have by one. Previously we had the system in Print.cpp, but we had another, more general and extensible system in wasm-type-printing.h and wasm-type.cpp as well. Remove the old type printing system from Print.cpp and replace it with a much smaller use of the new system. This requires significant refactoring of Print.cpp so that PrintExpressionContents object now holds a reference to a parent PrintSExpression object that holds the type name state. This diff is very large because almost every test output changed slightly. To minimize the diff and ease review, change the type printer in wasm-type.cpp to behave the same as the old type printer in Print.cpp except for the differences in name generation. These changes will be reverted in much smaller PRs in the future to generally improve how types are printed.
* Use the standard syntax for ref.cast, ref.test and array.new_fixed (#5894)Jérôme Vouillon2023-08-231-2/+2
| | | | | | | | | * Update text output for `ref.cast` and `ref.test` * Update text output for `array.new_fixed` * Update tests with new syntax for `ref.cast` and `ref.test` * Update tests with new `array.new_fixed` syntax
* Remove legacy WasmGC instructions (#5861)Thomas Lively2023-08-091-3/+3
| | | | | Remove old, experimental instructions and type encodings that will not be shipped as part of WasmGC. Updating the encodings and text format to match the final spec is left as future work.
* [Wasm GC] Stop printing deprecated cast etc. instructions (#5852)Thomas Lively2023-08-021-1/+1
| | | | | | | | Stop printing `ref.as_i31`, `br_on_func`, etc. because they have been removed from the spec and are no longer supported by V8. #5614 already made this change for the binary format. Like that PR, leave reading unmodified in case someone is still using these instructions (even though they are useless). They will be fully removed in a future PR as we finalize things ahead of standardizing WasmGC.
* Vacuum code leading up to a trap in TrapsNeverHappen mode (#5228)Alon Zakai2023-05-171-2/+403
| | | | | | | | | | | | This adds two rules to vacuum in TNH mode: if (..) trap() => if (..) {} { stuff, trap() } => {} That is, we assume traps never happen so an if will not branch to one, and code right before a trap can be assumed to not execute. Together, we should be removing practically all possible code in TNH mode (though we could also add support for br_if etc.).
* Add a "mayNotReturn" effect (#5711)Alon Zakai2023-05-101-3/+10
| | | | | | | | | | | | | | | | This changes loops from having the effect "may trap (timeout)" to having "may not return." The only noticeable difference is in TrapsNeverHappen mode, which ignores the former but not the latter. So after this PR, in TNH mode we do not optimize away an infinite loop that seems to have no other side effects. We may also use this for other things in the future, like continuations/stack switching. There are upsides and downsides to allowing the optimizer to remove infinite loops (the C and C++ communities have had interesting discussions on that topic over the years...) but it seems safer to not optimize them out for now, to let the most code work properly. If a need comes up to optimize such code, we can look at various options then (like a flag to ignore infinite loops). See discussion in #5228
* [Wasm GC] Replace `HeapType::data` with `HeapType::struct_` (#5416)Thomas Lively2023-01-101-10/+0
| | | | | | `struct` has replaced `data` in the upstream spec, so update Binaryen's types to match. We had already supported `struct` as an alias for data, but now remove support for `data` entirely. Also remove instructions like `ref.is_data` that are deprecated and do not make sense without a `data` type.
* Represent ref.as_{func,data,i31} with RefCast (#5413)Thomas Lively2023-01-101-10/+0
| | | | | | | | | | | | | These operations are deprecated and directly representable as casts, so remove their opcodes in the internal IR and parse them as casts instead. For now, add logic to the printing and binary writing of RefCast to continue emitting the legacy instructions to minimize test changes. The few test changes necessary are because it is no longer valid to perform a ref.as_func on values outside the func type hierarchy now that ref.as_func is subject to the ref.cast validation rules. RefAsExternInternalize, RefAsExternExternalize, and RefAsNonNull are left unmodified. A future PR may remove RefAsNonNull as well, since it is also expressible with casts.
* Change the default type system to isorecursive (#5239)Thomas Lively2022-11-231-14/+14
| | | | | | | | | | This makes Binaryen's default type system match the WasmGC spec. Update the way type definitions without supertypes are printed to reduce the output diff for MVP tests that do not involve WasmGC. Also port some type-builder.cpp tests from test/example to test/gtest since they needed to be rewritten to work with isorecursive type anyway. A follow-on PR will remove equirecursive types completely.
* Vacuum: Ignore effects at the entire function scope when possible (#5053)Alon Zakai2022-09-191-3/+6
| | | | | | | | | | | | | | | Recently we added logic to ignore effects that don't "escape" past the function call. That is, e.g. local.set only affects the current function scope, and once the call stack is unwound it no longer matters as an effect. This moves that logic to a shared place, and uses it in the core Vacuum logic. The new constructor in EffectAnalyzer receives a function and then scans it as a whole. This works just like e.g. scanning a Block as a whole (if we see a break in the block, that has an effect only inside it, and the Block + children doesn't have a branch effect). Various tests are updated so they don't optimize away trivially, by adding new return values for them.
* Effects: Clarify trap effect meaning, and consider infinite loops to trap ↵Alon Zakai2022-09-161-31/+181
| | | | | | | | | | | | | | | | | | | | | due to timeout (#5039) I think this simplifies the logic behind what we consider to trap. Before we had kind of a hack in visitLoop that now has a more clear reasoning behind it: we consider as trapping things that trap in all VMs all the time, or will eventually. So a single allocation doesn't trap, but an unbounded amount can, and an infinite loop is considered to trap as well (a timeout in a VM will be hit eventually, somehow). This means we cannot optimize way a trivial infinite loop with no effects in it, while (1) {} But we can optimize it out in trapsNeverHappen mode. In any event, such a loop is not a realistic situation; an infinite loop with some other effect in it, like a call to an import, will not be optimized out, of course. Also clarify some other things regarding traps and trapsNeverHappen following recent discussions in https://github.com/emscripten-core/emscripten/issues/17732 Specifically, TNH will never be allowed to remove calls to imports.
* Effects.h: Fix RefAs (#4312)Alon Zakai2021-11-091-0/+17
| | | | | | | | | We marked that as only trapping if the input as nullable. But ref.as_func will trap if it isn't a func, for example. We could in theory try to check if a trap is possible, like checking if the input is already non-nullable or already a function, etc., but we have optimization passes to get rid of RefAs when they are not needed anyhow, so there is no point to duplicate that here.
* Use TrapsNeverHappen mode in more places in Vacuum (#4117)Alon Zakai2021-09-011-13/+50
| | | | | | | | | | | | | | We had already replaced the check on drop, but we can also use that mode on all the other things there, as the pass never does reorderings of things - it just removes them. For example, the pass can now remove part of a dropped thing, (drop (struct.get (foo))) => (drop (foo)) In this example the struct.get can be removed, even if the foo can't.
* TrapsNeverHappen mode (#4059)Alon Zakai2021-08-171-0/+74
The goal of this mode is to remove obviously-unneeded code like (drop (i32.load (local.get $x))) In general we can't remove it, as the load might trap - we'd be removing a side effect. This is fairly rare in general, but actually becomes quite annoying with wasm GC code where such patterns are more common, and we really need to remove them. Historically the IgnoreImplicitTraps option was meant to help here. However, in practice it did not quite work well enough for most production code, as mentioned e.g. in #3934 . TrapsNeverHappen mode is an attempt to fix that, based on feedback from @askeksa in that issue, and also I believe this implements an idea that @fitzgen mentioned a while ago (sorry, I can't remember where exactly...). So I'm hopeful this will be generally useful and not just for GC. The idea in TrapsNeverHappen mode is that traps are assumed to not actually happen at runtime. That is, if there is a trap in the code, it will not be reached, or if it is reached then it will not trap. For example, an (unreachable) would be assumed to never be reached, which means that the optimizer can remove it and any code that executes right before it: (if (..condition..) (block (..code that can be removed, if it does not branch out..) (..code that can be removed, if it does not branch out..) (..code that can be removed, if it does not branch out..) (unreachable))) And something like a load from memory is assumed to not trap, etc., which in particular would let us remove that dropped load from earlier. This mode should be usable in production builds with assertions disabled, if traps are seen as failing assertions. That might not be true of all release builds (maybe some use traps for other purposes), but hopefully in some. That is, if traps are like assertions, then enabling this new mode would be like disabling assertions in release builds and living with the fact that if an assertion would have been hit then that is "undefined behavior" and the optimizer might have removed the trap or done something weird. TrapsNeverHappen (TNH) is different from IgnoreImplicitTraps (IIT). The old IIT mode would just ignore traps when computing effects. That is a simple model, but a problem happens with a trap behind a condition, like this: if (x != 0) foo(1 / x); We won't trap on integer division by zero here only because of the guarding if. In IIT, we'd compute no side effects on 1 / x, and then we might end up moving it around, depending on other code in the area, and potentially out of the if - which would make it happen unconditionally, which would break. TNH avoids that problem because it does not simply ignore traps. Instead, there is a new hasUnremovableSideEffects() method that must be opted-in by passes. That checks if there are no side effects, or if there are, if we can remove them - and we know we can remove a trap if we are running under TrapsNeverHappen mode, as the trap won't happen by assumption. A pass must only use that method where it is safe, that is, where it would either remove the side effect (in which case, no problem), or if not, that it at least does not move it around (avoiding the above problem with IIT). This PR does not implement all optimizations possible with TNH, just a small initial set of things to get started. It is already useful on wasm GC code, including being as good as IIT on removing unnecessary casts in some cases, see the test suite updates here. Also, a significant part of the 18% speedup measured in #4052 (comment) is due to my testing with this enabled, as otherwise the devirtualization there leaves a lot of unneeded code.