summaryrefslogtreecommitdiff
path: root/src
Commit message (Collapse)AuthorAgeFilesLines
* [Outlining] StringifyWalker (#5772)Ashley Nelson2023-06-302-0/+207
| | | StringifyWalker is a new Walker with UnifiedExpressionVisitor. This walker performs a shallow visit of control-flow (try, if, block, loop) expressions and their simple expression siblings before then visiting the children of each control-flow expression in postorder. As a result, this walker un-nests nested control flow structures, so the expression visit order does not correspond to a normal postorder traversal of the function.
* [NFC] Add a helper to get function DCE names in wasm-metadce (#5793)Alon Zakai2023-06-301-30/+15
|
* [wasm-metadce] Note ref.func connections + fix rooting of segment offsets ↵Jérôme Vouillon2023-06-291-13/+28
| | | | (#5791)
* Dynamic Sized Bitvector Powerset Lattice for Static Analysis (#5784)Bruce He2023-06-295-171/+234
| | | This change introduces a finite-height powerset lattice FinitePowersetLattice where each element's height is determined when constructed in runtime. This is implemented using a vector of `bools. This change also modifies BlockState and MonotoneCFGAnalyzer to be templated on a generic lattice type instead of using a hardcoded lattice. It additionally fixes an iterator bug in MonotoneCFGAnalyzer::fromCFG which assigned a temporary iterator object as predecessor and successor pointers to BlockStates instead of pointers to actual BlockState objects.
* Limit printing of Literal[s] in a general way (#5792)Alon Zakai2023-06-281-16/+49
| | | | | | | | Previously we limited printing in a single Literals. But we can have infinitely recursive GC literals, or just huge graphs even without infinite recursion where no single Literals is that big (but we still get exponential blowup). This PR adds a general limit on how much we print once we start to print a Literal or Literals.
* Fix opt/shrink levels when running the optimizer multiple times, Part 2 (#5787)Alon Zakai2023-06-273-41/+39
| | | | | | | | | | | This is a followup to #5333 . That fixed the selection of which passes to run, but forgot to also fix the global state of the current optimize/shrink levels. This PR fixes that. As a result, running -O3 -Oz will now work as expected: the first -O3 will run the right passes (as #5333 fixed) and while running them, the global optimize/shrinkLevels will be -O3 (and not -Oz), which this PR fixes. A specific result of this is that -O3 -Oz used to inline less, since the invocation of inlining during -O3 thought we were optimizing for size. The new test verifies that we do fully inline in the first -O3 now.
* Liveness Analysis Proof of Concept (#5771)Bruce He2023-06-237-0/+410
| | | This introduces a limited monotone flow-sensitive liveness analysis on local indices as an initial proof of concept for the creation of a monotone flow-sensitive static analysis framework. Tests are included in test/gtest/cfg.cpp.
* PostEmscripten: Preserve __em_js__ exports in side modules (#5780)Sam Clegg2023-06-231-4/+10
|
* Fuzzing for Try and Throw (#5776)Alon Zakai2023-06-213-3/+79
|
* Limit literal printing to a reasonable limit (#5779)Alon Zakai2023-06-211-0/+8
| | | | | | | | | Without this, a massive GC array for example can end up being printed as a huge amount of output, which is a problem in the fuzzer. I noticed this because a testcase was taking minutes to run. Perhaps we should add an option (BINARYEN_PRINT_FULL=1?) to disable this limit, but let's see if we ever need that.
* Fix pop assertion (#5777)Alon Zakai2023-06-201-1/+1
| | | Subtypes are allowed as well, not just exact matches, in the pop value's type.
* [NFC] Simplify `Tuple` by making it an alias of `TypeList` (#5775)Thomas Lively2023-06-206-65/+41
| | | | | | | Rather than wrap a `TypeList`, make `Tuple` an alias of `TypeList`. This means removing `Tuple::toString`, but that had no callers and was of limited use for debugging anyway. In return, the use of tuples becomes much less verbose. In the future, it may make sense to remove one of `Tuple` and `TypeList`.
* [EH] Add pass to remove EH instructions (#5770)Heejin Ahn2023-06-154-0/+81
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | This pass strips all EH stuff, including EH instructions and tags, from the input module and disables the EH feature from the features section. 1. This removes `catch` and `catch_all` blocks from the code. So ```wast (try (do (some code) ) (catch ... ) ) ``` becomes just `(some code)`. Note that all `rethrow`s will be removed with `catch`es. Note that all `rethrow`s will be removed with `catch`es. 2. This converts 'throw (...)` into `unreachable`. Note that `rethrows 3. This removes all tags from the module, which are unused anyway after 1 and 2. 4. This removes exception handling feature from the features section. You can use the pass with ```console $ wasm-opt --enable-exception-handling --strip-eh INPUT -o OUTPUT ``` This is not an optimization pass, so it is not run unless you specify the pass explicitly. This is in effect similar to Clang's `-fignore-exceptions`, in which you can throw but it will result in a crash and we compile away all landing pads. This can be used for people who don't (or can't) use `-fignore-exceptions` in their build settings or who want to compile away `catch` blocks later. Closes emscripten-core/emscripten#19585.
* [NFC] Rewrite isorecursive canonicalization (#5774)Thomas Lively2023-06-152-341/+159
| | | | | | | Rewrite the type canonicalization algorithm to fully canonicalize a single rec group at a time rather than canonicalizing multiple rec groups at once in multiple stages. The previous code was useful when it had to be shared with equirecursive and nominal canonicalization, but was much more complicated than necessary for just isorecursive canonicalization, which is all we support today.
* EffectAnalyzer: Assume we execute the two things whose effects we compare ↵Alon Zakai2023-06-131-6/+45
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | (#5764) EffectAnalyzer::canReorder/invalidate now assume that the things from whom we generated the effects both execute (or, rather, that if the first of them doesn't transfer control flow then they execute). If they both execute then we can do more work in TrapsNeverHappen mode, since we can then reorder this for example: (global.set ..) (i32.load ..) The load may trap, but in TNH mode we assume it won't. So we can reorder those two. However, if they did not both execute then we could be in this situation: (global.set ..) (br_if ..) (i32.load) Reordering the load and the set here would be invalid, because we could make the load execute when it didn't execute before, and it could now start to actually trap at runtime. This new assumption seems obvious, since we don't compare the effects of things unless they are adjacent and with no control flow between them - otherwise, why compare them? To be sure, I manually reviewed every single use of EffectAnalyzer::canReorder/invalidate in the entire codebase. I've also been fuzzing this for several days (hundreds of thousands of iterations), and have not seen any problem. This was motivated by seeing that #5744 should be able to do more work in TNH mode, but it wasn't. New tests show the benefits there in OptimizeCasts as well as in SimplifyLocals.
* [NFC] Simplify the HeapTypeStore (#5765)Thomas Lively2023-06-131-107/+38
| | | | | | | | | | | | | Now that we support only isorecursive typing, which canonicalizes heap types by the rec group rather than individually, we no longer need a canonicalizing store for heap types. Simplify the `Store` implementation, which was previously generic over both `HeapType`s and `Type`s, to instead work only for `Type`s. Replace `globalHeapTypeStore` with a simple vector to keep canonicalized `HeapTypeInfo`s alive. Also simplify global canonicalization to not replace heap type uses, since that is already done separately as part of isorecursive rec group canonicalization. This simplification does require adding new information to `CanonicalizationState`, but further work will simplify that away as well.
* Remove BinaryenIRToBinaryWriter::visit (#5766)Heejin Ahn2023-06-131-4/+0
| | | | This is not used. We use the parent's `visit` method instead: https://github.com/WebAssembly/binaryen/blob/585af93ec6a22feb8954bc118f0bff997d1fc165/src/wasm-stack.h#L233-L262
* Rename WasmBinaryBuilder to WasmBinaryReader (NFC) (#5767)Heejin Ahn2023-06-137-212/+204
| | | | | | We have `WasmBinaryBuilder` that read binary into Binaryen IR and `WasmBinaryWriter` that writes Binaryen IR to binary. To me `WasmBinaryBuilder` sounds similar to `WasmBinaryWriter`, which builds binary. How about renaming it to `WasmBinaryReader`?
* DeadArgumentElimination: Do not error on bottom types in result refining (#5763)Alon Zakai2023-06-121-1/+6
| | | | More generally, the LUB computation that code relies on did not handle bottom types properly.
* ConstantFieldPropagation: Track copied values properly (#5761)Alon Zakai2023-06-121-24/+56
| | | | The logic ignored copied values, which was fine for struct.get operations but not for struct.new.
* Update br_on_cast binary and text format (#5762)Thomas Lively2023-06-126-46/+61
| | | | | | | | | | | | The final versions of the br_on_cast and br_on_cast_fail instructions have two reference type annotations: one for the input type and one for the cast target type. In the binary format, this is represented as a flags byte followed by two encoded heap types. Upgrade all of the tests at once to use the new versions of the instructions and drop support for the old instructions from the text parser. Keep support in the binary parser to avoid breaking users, though. Drop some binary tests of deprecated instruction encodings that would be more effort to update than they're worth. Re-land with fixes of #5734
* Remove handleBranchForVisitBlock (#5760)Heejin Ahn2023-06-091-15/+0
| | | | This method doesn't seem to be used anymore. It was added in #1771 and its uses were removed in #2492.
* Validate tag param types (#5759)Alon Zakai2023-06-081-0/+5
| | | | | We already validated function params, but were missing tags. Without this the fuzzer can get confused if a type is only used in a tag.
* Strings: Add initial validation checks (#5758)Alon Zakai2023-06-081-0/+91
| | | | | | | | | This is far from comprehensive, but it checks strings being enabled for all the instructions. Without this, the fuzzer can get confused because it checks if code validates and then proceeds under that assumption, so any missing validation checks can cause problems (specifically, if we have a string.const without strings enabled then we error during writing of the string, since we don't do the initial pass to find all strings to deduplicate them).
* TypeRefining: Fix a bug with chains of StructGets (#5757)Alon Zakai2023-06-081-1/+23
| | | | | | | | | | | | | If we have (struct.get $A (struct.get $B then if both types end up refined we may have a problem. If the inner one is refined to emit nullref then the outer one no longer knows what type it is, since it depends on the type of the ref child for that in our IR. We can't just skip updating it, as the outside may depend on its new refined type to validate. To avoid errors here, just make this code that is effectively unreachable also actually unreachable.
* [Strings] Fix non-nullable string emitting in the binary format (#5756)Alon Zakai2023-06-071-3/+9
| | | Related to #5737 which did something similar for other types.
* [NFC] Remove redundant code from EffectAnalyzer (#5754)Alon Zakai2023-06-061-5/+0
| | | | | | | | | | | | | | | | This PR removes a check for transfersControlFlow() && other.trap which is already checked higher up in the code, here: transfersControlFlow() && other.hasSideEffects() In binaryen/src/ir/effects.h , lines 223 to 224 That last code handles the first code because trapping is part of hasSideEffects().
* Move casts which are immediate children of local.gets to earlier local.gets ↵Bruce He2023-06-061-16/+324
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | (#5744) In the OptimizeCasts pass, it is useful to move more refined casts as early as possible without causing side-effects. This will allow such casts to potentially trap earlier, and will allow the OptimizeCasts pass to use more refined casts earlier. This change allows a more refined cast to be duplicated at an earlier local.get expression. The later instance of the cast will then be eliminated in a later optimization pass. For example, if we have the following instructions: (drop (local.get $x) ) (drop (ref.cast $A (local.get $x) ) (drop (ref.cast $B (local.get $x) ) ) Where $B is a sublcass of $A, we can convert this to: (drop (ref.cast $B (local.get $x) ) ) (drop (ref.cast $A (local.get $x) ) (drop (ref.cast $B (local.get $x) ) ) Concretely we will save the first cast to a local and use it in the other local.gets.
* Fix emitting of function reference types without GC (#5737)Thomas Lively2023-06-051-14/+17
| | | | | | | | | We previously had logic to emit GC types used in the IR as their corresponding top types when GC was not enabled (so e.g. nullfuncref would be emitted as funcref), but the logic was not robust enough and non-null function references were not properly emitted as funcref. Refactor the relevant code to be more robust and future-proof, and add a test demonstrating that the lowering works as intended.
* StackIR: Remove nops (#5746)Alon Zakai2023-05-301-0/+17
| | | | | | | No nop instruction is necessary in wasm, so in StackIR we can simply remove them all. Fixes #5745
* wasm-merge: Preserve imports when copying module items (#5743)Jérôme Vouillon2023-05-261-0/+4
| | | | The import information of Tags and Memories was not preserved.
* Revert "Update br_on_cast binary and text format (#5734)" (#5740)Alon Zakai2023-05-236-40/+46
| | | | | | | This reverts commit b7b1d0df29df14634d2c680d1d2c351b624b4fbb. See comment at the end of #5734: It turns out that dropping the old opcodes causes problems for current users, so let's revert this for now, and later we can figure out how best to do the update.
* Fuzzer: Limit ArrayNew sizes most of the time (#5738)Alon Zakai2023-05-221-2/+11
|
* TypeSSA: Handle collisions by adding a hash to ensure a fresh rec group (#5724)Alon Zakai2023-05-192-22/+100
| | | Fixes #5720
* Update br_on_cast binary and text format (#5734)Thomas Lively2023-05-196-46/+40
| | | | | | | | | | The final versions of the br_on_cast and br_on_cast_fail instructions have two reference type annotations: one for the input type and one for the cast target type. In the binary format, this is represented as a flags byte followed by two encoded heap types. Since these instructions have been in flux for a while, do not attempt to maintain backward compatibility with older versions of the instructions. Instead, upgrade all of the tests at once to use the new versions of the instructions. Drop some binary tests of deprecated instruction encodings that would be more effort to update than they're worth.
* Improve TODO docs in OptimizeCasts (#5732)Alon Zakai2023-05-181-7/+17
|
* Vacuum code leading up to a trap in TrapsNeverHappen mode (#5228)Alon Zakai2023-05-171-1/+79
| | | | | | | | | | | | 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.).
* avoid incomplete type in a vector (#5730)walkingeyerobot2023-05-171-17/+17
| | | | | Swap the order of struct declarations to avoid using an incomplete type in a vector. In C++20, using std::vector with an incomplete type often becomes a build failure due to increased usage of constexpr for vector members.
* Print function types on function imports in the text format (#5727)Alon Zakai2023-05-171-0/+4
| | | | The function type should be printed there just like for non-imported functions.
* EffectAnalyzer: Do not clear break targets before walk()/visit() (#5723)Alon Zakai2023-05-171-7/+0
| | | | | | We depend on repeated calls to walk/visit accumulating effects, so this was a bug; if we want to clear stuff then we create a new EffectAnalyzer. Removing that fixes the attached testcase. Also added a unit test.
* Reintroduce wasm-merge (#5709)Alon Zakai2023-05-163-6/+631
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | We used to have a wasm-merge tool but removed it for a lack of use cases. Recently use cases have been showing up in the wasm GC space and elsewhere, as people are using more diverse toolchains together, for example a project might build some C++ code alongside some wasm GC code. Merging those wasm files together can allow for nice optimizations like inlining and better DCE etc., so it makes sense to have a tool for merging. Background: * Removal: #1969 * Requests: * wasm-merge - why it has been deleted #2174 * Compiling and linking wat files #2276 * wasm-link? #2767 This PR is a compete rewrite of wasm-merge, not a restoration of the original codebase. The original code was quite messy (my fault), and also, since then we've added multi-memory and multi-table which makes things a lot simpler. The linking semantics are as described in the "wasm-link" issue #2767 : all we do is merge normal wasm files together and connect imports and export. That is, we have a graph of modules and their names, and each import to a module name can be resolved to that module. Basically, like a JS bundler would do for JS, or, in other words, we do the same operations as JS code would do to glue wasm modules together at runtime, but at compile time. See the README update in this PR for a concrete example. There are no plans to do more than that simple bundling, so this should not really overlap with wasm-ld's use cases. This should be fairly fast as it works in linear time on the total input code. However, it won't be as fast as wasm-ld, of course, as it does build Binaryen IR for each module. An advantage to working on Binaryen IR is that we can easily do some global DCE after merging, and further optimizations are possible later.
* [NFC] Optimize ArrayNew zero construction (#5722)Alon Zakai2023-05-151-1/+2
| | | | | | | | | | All array elements have the same type, so we can construct a single zero and just copy it. This makes ArrayNew of large arrays 2x faster. I also experimented with putting Literal::makeZero in a header, in hopes of inlining leading to licm helping here, but that did not help at all unfortunately, at least not in gcc.
* [Strings] Adopt new instruction binary encoding (#5714)Jérôme Vouillon2023-05-1210-118/+129
| | | | | | | | | | | See WebAssembly/stringref#46. This format is already adopted by V8: https://chromium-review.googlesource.com/c/v8/v8/+/3892695. The text format is left unchanged (see #5607 for a discussion on the subject). I have also added support for string.encode_lossy_utf8 and string.encode_lossy_utf8 array (by allowing the replace policy for Binaryen's string.encode_wtf8 instruction).
* [analysis] Add a new iterable CFG utility (#5712)Thomas Lively2023-05-126-0/+351
| | | | | | | | | | | | | | | | | | | | Add a new "analysis" source directory that will contain the source for a new static program analysis framework. To start the framework, add a CFG utility that provides convenient iterators for iterating through the basic blocks of the CFG as well as the predecessors, successors, and contents of each block. The new CFGs are constructed using the existing CFGWalker, but they are different in that the new utility is meant to provide a usable representation of a CFG whereas CFGWalker is meant to allow collecting arbitrary information about each basic block in a CFG. For testing and debugging purposes, add `print` methods to CFGs and basic blocks. This requires exposing the ability to print expression contents excluding children, which was something we previously did only for StackIR. Also add a new gtest file with a test for constructing and printing a CFG. The test reveals some strange properties of the current CFG construction, including empty blocks and strange placement of `loop` instructions, but fixing these problems is left as future work.
* Extend drop.h and use it in Directize (#5713)Alon Zakai2023-05-103-53/+48
| | | | | | | | | | | | | | | | | | | | | This adds an option to ignore effects in the parent in getDroppedChildrenAndAppend. With that, this becomes usable in more places, like Directize, basically in situations where we know we can ignore effects in the parent (since we've inferred they are not needed). This lets us get rid of some boilerplate code in Directize. Diff without whitespace is a lot smaller. A large other part of the diff is a rename of curr => parent which I think it makes it more readable as then parent/children is a clear contrast, and then the new parameter "ignore/ notice parent effects" is obviously connected to "parent". The top comment in drop.cpp is removed as it just duplicated the top comment in the header drop.h. This is basically NFC but using drop.h does bring the advantage of emitting less code, see the test changes, so it is noticeable in the IR. This is a refactoring PR in preparation for a larger improvement to Directize that will also benefit from this new drop capability.
* Gate all partial inlining behind the partial-inlining-ifs flag (#5710)Alon Zakai2023-05-101-6/+10
| | | | | | | | | #4191 meant to do that, I think, but only did so for "pattern B". This does it for all patterns, and adds assertions. In theory this could regress code that benefits from partial inlining of "pattern A" (since this PR stops doing it by default), but I did not see a significant difference on any benchmarks, and it is easy to re-enable that behavior by doing --partial-inlining-ifs=1.
* Add a "mayNotReturn" effect (#5711)Alon Zakai2023-05-101-11/+5
| | | | | | | | | | | | | | | | 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
* Remove TypeUpdater in Vacuum and always ReFinalize (#5707)Alon Zakai2023-05-091-48/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | TypeUpdater::remove must be called after removing a thing from the tree. If not, then we can get confused by something like this: (block $b (br $b) ) If we first call TypeUpdater::remove then we see that the block's only br is going away, so it becomes unreachable. But when we then remove the br then the block should have type none. Removing the br first from the IR, and then calling TypeUpdater::remove, is the safe way to do it. However, changing that order in Vacuum is not trivial. After looking into this, I realized that it is just simpler to remove TypeUpdater entirely. Instead, we can ReFinalize at the end unconditionally. This has the downside that we do not propagate type updates "as we go", but that should be very rare. Another downside is that TypeUpdater tracks the number of brs, which can help remove code like in the one test that regresses here (see comment there). But I'm not sure that removal was valid - Vacuum should not really be doing it, and it looks like its related to this bug actually. Instead, we have a dedicated pass for removing unused brs - RemoveUnusedBrs - so leave things for it. This PR's benefit, aside from now handling the fuzz testcase, is that it makes the code simpler and faster. I see a 10-25% speedup on the Vacuum pass on various binaries I tested on. (Vacuum is one of our faster passes anyhow, though, so the runtime of -O1 is not much improved.) Another minor benefit might be that running ReFinalize more often can propagate type info more quickly, thanks to #5704 etc. But that is probably very minor.
* Fix optimizeAddedConstants on GC-introduced unreachability (#5706)Alon Zakai2023-05-091-3/+8
|
* [Wasm GC] wasm-ctor-eval: Handle cycles of data (#5685)Alon Zakai2023-05-052-57/+377
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | A cycle of data is something we can't just naively emit as wasm globals. If at runtime we end up, for example, with an object A that refers to itself, then we can't just emit (global $A (struct.new $A (global.get $A))) The struct.get is of this very global, and such a self-reference is invalid. So we need to break such cycles as we emit them. The simple idea used here is to find paths in the cycle that are nullable and mutable, and replace the initial value with a null that is fixed up later in the start function: (global $A (struct.new $A (ref.null $A))) (func $start (struct.set (global.get $A) (global.get $A))) ) This is not optimal in terms of breaking cycles, but it is fast (linear time) and simple, and does well in practice on j2wasm (where cycles in fact occur).