summaryrefslogtreecommitdiff
path: root/test/lit
Commit message (Collapse)AuthorAgeFilesLines
* Topological sorting of types in isorecursive output (#4492)Thomas Lively2022-02-021-0/+100
| | | | | | | | | | | | | | | | | | | Generally we try to order types by decreasing use count so that frequently used types get smaller indices. For the equirecursive and nominal systems, there are no contraints on the ordering of types, so we just have to sort them according to their use counts. For the isorecursive type system, however, there are a number of ordering constraints that have to be met for the type section to be valid. First, types in the same recursion group must be adjacent so they can be grouped together. Second, groups must be ordered topologically so that they only refer to types in themselves or prior groups. Update type ordering to produce a valid isorecursive output by performing a topological sort on the recursion groups. While performing the sort, prefer to visit and finish processing the most used groups first as a heuristic to improve the final ordering. Do not reorder types within groups, since doing so would change type identity and could affect the external interface of the module. Leave that reordering to an optimization pass (not yet implemented) that users can explicitly opt in to.
* Remove used wasm-emscripten-finalize option `--initial-stack-pointer` (#4490)Sam Clegg2022-02-011-3/+0
|
* [NFC] Refactor ModuleInstanceBase+RuntimeExpressionRunner into a single ↵Alon Zakai2022-01-281-0/+60
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | class (#4479) As recently discussed, the interpreter code is way too complex. Trying to add ctor-eval stuff I need, I got stuck and ended up spending some time to get rid of some of the complexity. We had a ModuleInstanceBase class which was basically an instance of a module, that is, an execution of it. And internally we have RuntimeExpressionRunner which is a runner that integrates with the ModuleInstanceBase - basically, it uses the runtime info to execute code. For example, the MIB has globals info, and the RER would read it from there. But these two classes are really just one functionality - an execution of a module. We get rid of some complexity by removing the separation between them, ending up with a class that can run a module. One set of problems we avoid is that we can now extend the single class in a simple way. Before, we would need to extend both - and inform each other of those changes. That gets "fun" with CRTP which we use everywhere. In other words, each of the two classes depended on the other / would need to be templated on the other. Specifically, MIB.callFunction would need to be given the RER to run with, and so that would need to be templated on it. This ends up leading to a bunch more templating all around - all complexity that we just don't need. See the simplification to the wasm-ctor-eval for some of that (and even worse complexity would have been needed without this PR in the next steps for that tool to eval GC stuff). The final single class is now called ModuleRunner. Also fixes a pre-existing issue uncovered by this PR. We had the delegate target on the runner, but it should be tied to a function scope. This happened to not be a problem if one always created a new runner for each scope, but this PR makes the runner longer-lived, so the stale data ended up mattering. The PR moves that data to the proper place. Note: Diff without whitespace is far, far smaller.
* Fuzzer: Fix a missing return of a trap (#4485)Alon Zakai2022-01-281-0/+14
| | | | | We emitted the right text to stdout to indicate a trap in one code path, but did not return a Trap from the function. As a result, we'd continue and hit the assert on the next line.
* wasm-emscripten-finalize: Remove legacy --new-pic-abi option (#4483)Sam Clegg2022-01-272-2/+29
|
* Remove NoExitRuntime pass (#4431)Alon Zakai2022-01-262-8/+0
| | | | After emscripten-core/emscripten#15905 lands Emscripten will no longer use it, and nothing else needs it AFAIK.
* [OptimizeInstructions] Combine some relational ops joined Or/And (Part 7-8) ↵Max Graey2022-01-261-0/+102
| | | | | | | | | | | (#4399) Final part of #4265 (i32(x) >= 0) & (i32(y) >= 0) ==> i32(x | y) >= 0 (i64(x) >= 0) & (i64(y) >= 0) ==> i64(x | y) >= 0 (i32(x) == -1) & (i32(y) == -1) ==> i32(x & y) == -1 (i64(x) == -1) & (i64(y) == -1) ==> i64(x & y) == -1
* Parse, create, and print isorecursive recursion groups (#4464)Thomas Lively2022-01-213-0/+93
| | | | | | | | | | | | | In `--hybrid` isorecursive mode, associate each defined type with a recursion group, represented as a `(rec ...)` wrapping the type definitions in the text format. Parse that text format, create the rec groups using a new TypeBuilder method, and print the rec groups in the printer. The only semantic difference rec groups currently make is that if one type in a rec group will be included in the output, all the types in that rec group will be included. This is because changing a rec group in any way (for example by removing a type) changes the identity of the types in that group in the isorecursive type system. Notably, rec groups do not yet participate in validation, so `--hybrid` is largely equivalent to `--nominal` for now.
* [OptimizeInstructions] Combine some relational ops joined Or/And (Part 5-6) ↵Max Graey2022-01-201-0/+102
| | | | | | | | | (#4372) (i32(x) >= 0) | (i32(y) >= 0) ==> i32(x & y) >= 0 (i64(x) >= 0) | (i64(y) >= 0) ==> i64(x & y) >= 0 (i32(x) != -1) | (i32(y) != -1) ==> i32(x & y) != -1 (i64(x) != -1) | (i64(y) != -1) ==> i64(x & y) != -1
* Add a `--hybrid` type system option (#4460)Thomas Lively2022-01-199-0/+36
| | | | | Eventually this will enable the isorecursive hybrid type system described in https://github.com/WebAssembly/gc/pull/243, but for now it just throws a fatal error if used.
* Add --no-emit-metadata option to wasm-emscripten-finalize (#4450)Sam Clegg2022-01-191-0/+3
| | | | | | This is useful for the case where we might want to finalize without extracting metadata. See: https://github.com/emscripten-core/emscripten/pull/15918
* Allow import mutable globals used in Asyncify pass (#4427)かめのこにょこにょこ2022-01-141-0/+106
| | | | | | | | | | | This PR is part of the solution to emscripten-core/emscripten#15594. emscripten Asyncify won't work properly in side modules, because the globals, __asyncify_state and __asyncify_data, are not synchronized between main-module and side-modules. A new pass arg, asyncify-side-module, is added to make __asyncify_state and __asyncify_data imported in the instrumented wasm.
* Revert "[OptimizeInstructions] Optimize zero sized bulk memory ops even ↵Thomas Lively2022-01-141-58/+24
| | | | | without "ignoreImplicitTraps" (#4295)" (#4459) This reverts commit 5cf3521708cfada341285414df2dc7366d7e5454.
* [OptimizeInstructions] Optimize zero sized bulk memory ops even without ↵Max Graey2022-01-121-24/+58
| | | | "ignoreImplicitTraps" (#4295)
* [ctor-eval] Add an option to keep some exports (#4441)Alon Zakai2022-01-111-0/+4
| | | | | | | | | | | | | | | | | | | | | | By default wasm-ctor-eval removes exports that it manages to completely eval (if it just partially evals then the export remains, but points to a function with partially-evalled contents). However, in some cases we do want to keep the export around even so, for example during fuzzing (as the fuzzer wants to call the same exports before and after wasm-ctor-eval runs) and also if there is an ABI we need to preserve (like if we manage to eval all of main()), or if the function returns a value (which we don't support yet, but this is a PR to prepare for that). Specifically, there is now a new option: --kept-exports foo,bar That is a list of exports to keep around. Note that when we keep around an export after evalling the ctor we make the export point to a new function. That new function just contains a nop, so that nothing happens when it is called. But the original function is kept around as it may have other callers, who we do not want to modify.
* Warn about and ignore empty local/param names in name section (#4426)Alon Zakai2022-01-072-0/+14
| | | | | | | Fixes the crash in #4418 Also replace the .at() there with better logic to handle imported functions. See WebAssembly/wabt#1799 for details on why wabt sometimes emits this.
* [ctor-eval] Add --ignore-external-input option (#4428)Alon Zakai2022-01-061-0/+3
| | | | | | | | | | | | This is meant to address one of the main limitations of wasm-ctor-eval in emscripten atm, that libc++ global ctors will read env vars, which means they call an import, which stops us from evalling, emscripten-core/emscripten#15403 (comment) To handle that, this adds an option to ignore external input. When set, we can assume that no env vars will be read, no reading from stdin, no arguments to main(), etc. Perhaps these could each be separate options, but I think keeping it simple for now might be good enough.
* Add categories to --help text (#4421)Alon Zakai2022-01-0512-698/+1900
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The general shape of the --help output is now: ======================== wasm-foo Does the foo operation ======================== wasm-foo opts: -------------- --foo-bar .. Tool opts: ---------- .. The options are now in categories, with the more specific ones - most likely to be wanted by the user - first. I think this makes the list a lot less confusing. In particular, in wasm-opt all the opt passes are now in their own category. Also add a script to make it easy to update the help tests.
* [GC] Move heap-types.wast out of lit/test/binary/ (#4424)Heejin Ahn2022-01-041-0/+0
| | | Apparently it is not a binary test?
* [EH] Fixup nested pops after reading stacky binary (#4420)Heejin Ahn2022-01-042-0/+66
| | | | | | When reading stacky code in the binary reader, we create `block`s to make it fit into Binaryen AST, within which `pop`s can be nested, making the resulting AST invalid. This PR runs the fixup function after reading each `Try` to fix this.
* Compare traps in ExecutionResults (#4405)Heejin Ahn2021-12-291-0/+55
| | | | | | | | We used to only compare return values, and in #4369 we started comparing whether an uncaught exception was thrown. This also adds whether a trap occurred to `ExecutionResults`. So in `--fuzz-exec`, if a program with a trap loses the trap or vice versa, it will error out saying the result has changed, unless either of `--ignore-implicit-traps` or `--trans-never-happen` is set.
* [EH][GC] Fix nested pop after removing ref.cast (#4407)Heejin Ahn2021-12-281-0/+58
| | | | | | | | | | | | | | | | `ref.cast` can be statically removed when the ref's type is a subtype of the intended RTT type and either of `--ignore-implicit-traps` or `--traps-never-happen` is given: https://github.com/WebAssembly/binaryen/blob/083ab9842ec3d4ca278c95e1a33112ae7cd4d9e5/src/passes/OptimizeInstructions.cpp#L1603-L1624 Some more context: https://github.com/WebAssembly/binaryen/pull/4097#discussion_r694456784 But this can create a block in which a `pop` is nested, which makes the `catch` invalid. The test in this PR is the same as the example given by @kripken in #4237. This calls the fixup function `EHUtils::handleBlockNestedPops` at the end of the pass to fix this. Also, because this pass creates a lot of blocks in other patterns, I think it is possible there can be other patterns to cause this kind of `pop` nesting.
* [EH] Handle nested pops after inlining (#4404)Heejin Ahn2021-12-201-3/+44
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Inlining creates additional `block`s at inlined call sites, which can be inside a `catch`. For example: ```wast (try (do) (catch $tag (call $callee (pop i32) ) ) ) ``` After inlining, this becomes ```wast (try (do) (catch $tag (block $__inlined_func$callee (local.set $0 (pop i32) ;; Invalid!! ) (nop) ) ) ) ``` Now the `pop` is nested in a `block`, which makes this invalid. This PR runs `EHUtils::handleBlockNestedPops` at the end to assign the `pop` to a local right after the `catch`, making the code valid again: ```wast (try (do) (catch $tag (local.set $new ;; New local to store `pop` result (pop i32) ) (block $__inlined_func$callee (local.set $0 (local.get $new) ) (nop) ) ) ) ```
* Add binary format parse checking for ref.as input type (#4389)Alon Zakai2021-12-162-0/+6
| | | | | | | If that type is not valid then we cannot even create and finalize the node, which means we'd hit an assertion inside finalize(), before we reach the validator. Fixes #4383
* [Wasm GC] Refine results in SignatureRefining (#4380)Alon Zakai2021-12-141-0/+134
| | | | | | Similar to what DeadArgumentElimination does for individual functions, this can refine the results of a set of functions all using the same heap type, when they all return something more specific. After this PR SignatureRefining can refine both params and results and is basically complete.
* [OptimizeInstructions] Combine some relational ops joined Or/And (Part 4) ↵Max Graey2021-12-141-0/+32
| | | | | | (#4339) (i32(x) < 0) & (i32(y) < 0) ==> i32(x & y) < 0 (i64(x) < 0) & (i64(y) < 0) ==> i64(x & y) < 0
* [Precompute][SIMD] Enable constant folding for simd (#4381)Max Graey2021-12-131-1/+14
|
* SimplifyGlobals: Handle nested read-only-to-write patterns (#4365)Alon Zakai2021-12-081-0/+269
| | | | | | | | | | | | | | | | | | | The general pattern is if (!global) { global = 1 } This PR generalizes that to handle nested appearances, if ({ if (!global) { global = 1 } !global }) { global = 1 } With this I can finally see no more "once" global operations on the hottest function in the currently slowest j2wasm benchmark ("filter"). Also added a failing testcase for something we do not handle yet.
* [EH] Make interpreter handle uncaught exceptions (#4369)Heejin Ahn2021-12-061-0/+64
| | | | | | | | | When a wasm exception is thrown and uncaught in the interpreter, it caused the whole interpreter to crash, rather than gracefully reporting it. This fixes the problem, and also compares whether an uncaught exception happened when comparing the results before and after optimizations in `--fuzz-exec`. To do that, when `--fuzz-exec` is given, we now compare results even when the function does not have return values. Logs for some existing test have changed because of this.
* [EH] Rename catch-pop-fixup.wast (#4371)Heejin Ahn2021-12-061-0/+0
| | | | All EH tests in test/lit/passes currently have the suffix `-eh`, so I think it's better be consistent for this one.
* [EH] Support try-delegate in EffectAnalyzer (#4368)Heejin Ahn2021-12-062-10/+173
| | | | | | | | | | | | | | | | This adds support for try-delegate in `EffectAnalyzer`. Without this support, the expresion below has been incorrectly classified as "cannot throw", because the previous code considered everything inside `try`-`catch_all` as "cannot throw". This is not the case when there is a `delegate` that can bypass the `catch_all`. ```wasm try $l0 try try throw $e delegate $l0 catch_all end end
* [OptimizeInstructions] Combine some relational ops joined Or/And (Part 3) ↵Max Graey2021-12-041-0/+85
| | | | | | | | (#4338) (i32(x) < 0) | (i32(y) < 0) ==> i32(x | y) < 0 (i32(x) != 0) | (i32(y) != 0) ==> i32(x | y) != 0 Likewise for i64.
* SimplifyGlobals: Ignore irrelevant effects in read-only-to-write (#4363)Alon Zakai2021-12-021-40/+189
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Previously this pass would see something like this and fail: if (foo() + global) { global = 1; } The call to foo() has side effects, so we did not optimize. However, in such a case the side effects are safe: they happen anyhow, regardless of the global that we are optimizing. That is, "global" is read only to be written, even though other things also influence the decision to write it. But "global" is not used in a way that is observable: we can remove it, and nothing will notice (except for things getting smaller/faster). In other words, this PR will let us optimize the above example, while it also needs to avoid optimizing the dangerous cases, like this: if (foo(global)) { global = 1; } Here "global" flows into a place that notices its value and may use it aside from deciding to write that global. A common case where we want to optimize is combined ifs, if (foo()) { if (global) { global = 1; } } which the optimizer turns into if (foo() & global) { global = 1; } With this PR we can handle those things too. This lets us optimize out some important globals in j2wasm like the initializer boolean for the Math object, reducing some total 0.5% of code size.
* Handle try in Flatten pass (#2567)Heejin Ahn2021-11-291-0/+234
| | | This adds handling of try in the Flatten pass.
* CoalesceLocals: Use ValueNumbering (#4355)Alon Zakai2021-11-242-20/+162
| | | | | | | | | | | | This removes the old hardcoded value numbering in that pass and makes it use the new code that was split into helper code. The immediate benefit of this is to make the code aware of identical constants: if two locals have the same constant then they do not interfere. Future improvements to numbering will also automatically help here. This changes some constants in existing tests so that they keep testing what they were testing before, and adds new tests for the new benefit here. This implements a proposed TODO from #4314
* SimplifyGlobals: If all writes write the initial value, they are unneeded ↵Alon Zakai2021-11-231-0/+143
| | | | (#4356)
* Add fixup function for nested pops in catch (#4348)Heejin Ahn2021-11-221-0/+396
| | | | | | | | | | | | | | | | | | | | | | | | | This adds `EHUtils::handleBlockNestedPops`, which can be called at the end of passes that has a possibility to put `pop`s inside `block`s. This method assumes there exists a `pop` in a first-descendant line, even though it can be nested within a block. This allows a `pop` to be nested within a `block` or a `try`, but not a `loop`, since that means the `pop` can run multile times. In case of `if`, `pop` can exist only in its condition; if a `pop` is in its true or false body, that's not in the first-descendant line. This can be useful when optimization passes create blocks to do transformations. Wrapping expressions wiith a block does not change semantics most of the time, but if pops happen to be inside a block generated by those passes, they can result in invalid binaries. To test this, this adds `passes/test_passes.cpp`, which is intended to contain multiple test passes that test a single (or more) utility functions separately. Without this kind of pass, it is hard to test various cases in which nested `pop`s can be generated in existing passes. This PR also adds `PassRegistry::registerTestPass`, which registers a pass that's intended only for internal testing and does not show up in `wasm-opt --help`. Fixes #4237.
* [Wasm GC] Signature Refining pass (#4326)Alon Zakai2021-11-192-0/+495
| | | | | | | | | | | | | | | | | | | This is fairly short and simple after the recent refactorings. This basically just finds all uses of each signature/function type, and then sees if it receives more specific types as params. It then rewrites the types if so. This just handles arguments so far, and not return types. This differs from DeadArgumentElimination's refineArguments() in that that pass modifies each function by itself, changing the type of the function as needed. That is only valid if the type is not observable, that is, if the function is called indirectly then DAE ignores it. This pass will work on the types themselves, so it considers all functions sharing a type as a whole, and when it upgrades that type it ends up affecting them all. This finds optimization opportunities on 4% of the total signature types in j2wasm. Those lead to some benefits in later opts, but the effect is not huge.
* Allow building basic HeapTypes in nominal mode (#4346)Thomas Lively2021-11-191-22/+21
| | | | | | | | | | | | | | | | As we work toward allowing nominal and structural types to coexist, any difference in how they can be built or used will be an inconvenient footgun that we will have to work around. In the spirit of reducing the differences between the type systems, allow TypeBuilder to construct basic HeapTypes in nominal mode just as it can in equirecursive mode. Although this change is a net increase in code complexity for not much benefit (wasm-opt never needs to build basic HeapTypes), it is also an incremental step toward getting rid of separate type system modes, so I expect it to simplify other PRs in the near future. This change also uncovered a bug in how the type fuzzer generated subtypes of basic HeapTypes. The generated subtypes did not necessarily have the intended `Kind`, which caused failures in nominal subtype validation in the fuzzer.
* [Wasm GC] Global Refining pass (#4344)Alon Zakai2021-11-182-0/+121
| | | | | | | | Fairly simple, this uses the existing infrastructure to find opportunities to refine the type of a global variable. This a common pattern in j2wasm for example, where a global begins as a null of $java.lang.Object (the least specific type) but it is in practice always assigned an object of some specific type.
* [Wasm GC] Update nulls to allow finding better LUBs (#4340)Alon Zakai2021-11-184-108/+607
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | It is common in GC code to have stuff like this: x = null; .. x = Data(); Nulls in wasm have a type, and if that initial null has say anyref then before this PR we would keep the type of x as anyref. However, while nulls have types, all null values are identical, and so we can in fact change x's type to a nullable reference of Data, by also changing the null's type to something more specific. LUBFinder now has an API that can return the best possible LUB so far, and that can be told to update nulls if we decide that the new LUB is worth using. This updates the passes using LUBFinder to use the new API. Note how TypeRefining becomes simpler because the special logic it had in a subclass of LUBFinder is now part of the main class (it used to remember if there was a null default; LUBFinder now handles both a null default as well as other nulls). This requires some changes to existing tests to avoid them from optimizing using nulls in ways that ends up not testing the original intent. Specifically the dae-gc-refine-params.wast now has calls to get a null of a type, instead of just having a ref.null of that type (which could be optimized now). And dae-gc-refine-return uses locals instead of ref.nulls.
* Small cleanups in type fuzzer (#4337)Thomas Lively2021-11-172-56/+34
| | | | | | | - Do not require defaultable types in function returns - Increase likelihood of `none` function return types - Correctly generate subtypes of basic types - Actually check output in tests - Print to cout instead of cerr
* [OptimizeInstructions] Combine some relational ops joined Or/And (Part 2) ↵Max Graey2021-11-162-6/+35
| | | | | | (#4336) (i32(x) != 0) | (i32(y) != 0) ==> i32(x | y) != 0 (i64(x) != 0) | (i64(y) != 0) ==> i64(x | y) != 0
* [OptimizeInstructions] Combine some relational ops joined Or/And (Part 1) ↵Max Graey2021-11-161-0/+31
| | | | | | (#4333) (i32(x) == 0) & (i32(y) == 0) ==> i32(x | y) == 0 (i64(x) == 0) & (i64(y) == 0) ==> i64(x | y) == 0
* Add a fuzzer specifically for types (#4328)Thomas Lively2021-11-152-0/+71
| | | | | | | | | | | | | | | Add a new fuzzer binary that repeatedly generates random types to find bugs in the type system implementation. Each iteration creates some number of root types followed by some number of subtypes thereof. Each built type can contain arbitrary references to other built types, regardless of their order of construction. Right now the fuzzer only finds fatal errors in type building (and in its own implementation), but it is meant to be extended to check other properties in the future, such as that LUB calculations work as expected. The logic for creating types is also intended to be integrated into the main fuzzer in a follow-on PR so that the main fuzzer can fuzz with arbitrarily more interesting GC types.
* [NFC] HeapRefining => TypeRefining (#4332)Alon Zakai2021-11-162-4/+4
|
* [NFC] Rename GlobalSubtyping => HeapRefining (#4331)Alon Zakai2021-11-162-4/+4
|
* Add support for relaxed-simd instructions (#4320)Ng Zhi An2021-11-151-0/+483
| | | | | | | | | | | | | | | | | | | | | This adds relaxed-simd instructions based on the current status of the proposal https://github.com/WebAssembly/relaxed-simd/blob/main/proposals/relaxed-simd/Overview.md. Binary opcodes are based on what is listed in https://github.com/WebAssembly/relaxed-simd/blob/main/proposals/relaxed-simd/Overview.md#binary-format. Text names are not fixed yet, and some sort sort of names that maps to the non-relaxed versions are chosen for this prototype. Support for these instructions have been added to LLVM via builtins, adding support here will allow Emscripten to successfully compile files that use those builtins. Interpreter support has also been added, and they delegate to the non-relaxed versions of the instructions. Most instructions are implemented in the interpreter the same way as the non-relaxed simd128 instructions, except for fma/fms, which is always fused.
* Directize: Fix handling of non-nullable locals and unreachability (#4330)Alon Zakai2021-11-151-4/+51
| | | | | The order of operations could allow us to add vars but then later decide not to do the optimization due to unreachability. And then we did not do a fixup for non-nullability for those args, leading to a fuzzer error.
* Fix vacuum on rtts with depth (#4327)Alon Zakai2021-11-151-0/+27
| | | | | | | | Found by the fuzzer. Calling makeZero on an rtt with depth will error because we try to create a zero Literal from it, and we can't do that - we don't know a list of super types to give it. We could work around it, but we don't want to: if the rtt has depth then we can't make a nice zero for it, we'd need some rtt.subs anyhow, so simply mark it as a type we can't make a zero for.