| Commit message (Collapse) | Author | Age | Files | Lines |
|
|
|
|
| |
Remove `SExpressionParser`, `SExpressionWasmBuilder`, and `cashew::Parser`.
Simplify gen-s-parser.py. Remove the --new-wat-parser and
--deprecated-wat-parser flags.
|
| |
|
|
|
|
| |
This code predates our adoption of C++14 and can now be removed in favor of
`std::make_unique`, which should be more efficient.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Previously only WalkerPasses had access to the `getPassRunner` and
`getPassOptions` methods. Move those methods to `Pass` so all passes can use
them. As a result, the `PassRunner` passed to `Pass::run` and
`Pass::runOnFunction` is no longer necessary, so remove it.
Also update `Pass::create` to return a unique_ptr, which is more efficient than
having it return a raw pointer only to have the `PassRunner` wrap that raw
pointer in a `unique_ptr`.
Delete the unused template `PassRunner::getLast()`, which looks like it was
intended to enable retrieving previous analyses and has been in the code base
since 2015 but is not implemented anywhere.
|
|
|
|
|
|
|
| |
This PR removes the single memory restriction in IR, adding support for a single module to reference multiple memories. To support this change, a new memory name field was added to 13 memory instructions in order to identify the memory for the instruction.
It is a goal of this PR to maintain backwards compatibility with existing text and binary wasm modules, so memory indexes remain optional for memory instructions. Similarly, the JS API makes assumptions about which memory is intended when only one memory is present in the module. Another goal of this PR is that existing tests behavior be unaffected. That said, tests must now explicitly define a memory before invoking memory instructions or exporting a memory, and memory names are now printed for each memory instruction in the text format.
There remain quite a few places where a hardcoded reference to the first memory persist (memory flattening, for example, will return early if more than one memory is present in the module). Many of these call-sites, particularly within passes, will require us to rethink how the optimization works in a multi-memories world. Other call-sites may necessitate more invasive code restructuring to fully convert away from relying on a globally available, single memory pointer.
|
| |
|
|
|
|
|
| |
Add a new OptimizeForJS pass which contains rewriting rules specific to JavaScript.
LLVM usually lowers x != 0 && (x & (x - 1)) == 0 (isPowerOf2) to popcnt(x) == 1 which is ok for wasm and other targets but is quite expensive for JavaScript. In this PR we lower the popcnt pattern back to the isPowerOf2 pattern.
|
|
|
|
|
|
|
|
|
| |
As found in #3682, the current implementation of type ordering is not correct,
and although the immediate issue would be easy to fix, I don't think the current
intended comparison algorithm is correct in the first place. Rather than try to
switch to using a correct algorithm (which I am not sure I know how to
implement, although I have an idea) this PR removes Type ordering entirely. In
places that used Type ordering with std::set or std::map because they require
deterministic iteration order, this PR uses InsertOrdered{Set,Map} instead.
|
| |
|
|
|
|
|
| |
Adds an IR profile to each function so the validator can determine
which validation rules to apply and adds a flag to have the wast
parser set the profile to Poppy for testing purposes.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
As a follow-up to https://github.com/WebAssembly/binaryen/pull/3012#pullrequestreview-459686171 this PR prepares for the new compound Signature, Struct and Array types that are single but not basic.
This includes:
* Renames `Type::getSingle` to `Type::getBasic` (NFC). Previously, its name was not representing its implementation (`isSingle` excluded `none` and `unreachable` while `getSingle` didn't, i.e. `getSingle` really was `getBasic`). Note that a hypothetical `Type::getSingle` cannot return `ValueType` anyway (new compound types are single but don't map to `ValueType`), so I figured it's best to skip implementing it until we actually need it.
* Marks locations where we are (still) assuming that all single types are basic types, as suggested in https://github.com/WebAssembly/binaryen/pull/3012#discussion_r465356708, but using a macro, so we get useful errors once we start implementing the new types and can quickly traverse the affected locations.
The macro is added where
* there used to be a `switch (type.getSingle())` or similar that handled any basic type (NFC), but in the future will also have to handle single types that are not basic types.
* we are not dealing with `Unary`, `Binary`, `Load`, `Store` or `AtomicXY` instructions, since these don't deal with compound types anyway.
|
|
|
|
|
|
| |
wasm2js does not have full call_indirect support as we don't trap if
the type is incorrect, which wasm does. Therefore the StubUnsupportedJSOps
pass needs to remove those operations so that the fuzzer doesn't find
spurious issues.
|
|
|
|
|
|
|
|
| |
This doesn't lower them - it just replaces the unsupported operation
with a drop. This will be useful for fuzzing, where to compare JS to the
correct semantics we must avoid operations where JS is not always
accurate.
Also fully document the i64 -> f32 conversion issue in JS.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
That code originally used memory location 1024 to save 64 bits of
data (as that is what rust does apparently). We refactored it
manually to instead use a scratch memory helper, which is safer.
However, that 64-bit function ends up legalized, which actually
changes the interface between the module and the outside,
which is confusing and causes problems with optimizations
that can remove the getTempRet0 imports, see
emscripten-core/emscripten#11456
Instead, just use a global i64 to stash those bits. This requires
adding support for copying globals from the intrinsics module,
but otherwise seems simpler overall.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Adds a special helper functions for data.drop etc., as unlike most
wasm instructions these are too big to emit inline.
Track passive segments at runtime in var memorySegments
whose indexes are the segment indexes.
Emit var bufferView even if the memory exists even without
memory segments, as we do still need the view in order to
operate on it.
Also adds a few constants for atomics that will be useful in future
PRs (as this PR updates the constant lists anyhow).
|
|
|
|
|
|
|
|
|
|
| |
* Remove implicit conversion operators from Type
Now types must be explicitly converted to uint32_t with Type::getID or
to ValueType with Type::getVT. This fixes #2572 for switches that use
Type::getVT.
* getVT => getSingle
|
| |
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
- Reflected new renamed instruction names in code and tests:
- `get_local` -> `local.get`
- `set_local` -> `local.set`
- `tee_local` -> `local.tee`
- `get_global` -> `global.get`
- `set_global` -> `global.set`
- `current_memory` -> `memory.size`
- `grow_memory` -> `memory.grow`
- Removed APIs related to old instruction names in Binaryen.js and added
APIs with new names if they are missing.
- Renamed `typedef SortedVector LocalSet` to `SetsOfLocals` to prevent
name clashes.
- Resolved several TODO renaming items in wasm-binary.h:
- `TableSwitch` -> `BrTable`
- `I32ConvertI64` -> `I32WrapI64`
- `I64STruncI32` -> `I64SExtendI32`
- `I64UTruncI32` -> `I64UExtendI32`
- `F32ConvertF64` -> `F32DemoteI64`
- `F64ConvertF32` -> `F64PromoteF32`
- Renamed `BinaryenGetFeatures` and `BinaryenSetFeatures` to
`BinaryenModuleGetFeatures` and `BinaryenModuleSetFeatures` for
consistency.
|
|
|
| |
Applies the changes in #2065, and temprarily disables the hook since it's too slow to run on a change this large. We should re-enable it in a later commit.
|
|
|
| |
Mass change to apply clang-format to everything. We are applying this in a PR by me so the (git) blame is all mine ;) but @aheejin did all the work to get clang-format set up and all the manual work to tidy up some things to make the output nicer in #2048
|
|
|
|
|
|
|
| |
This replaces all uses of __tempMemory__, the old scratch space location, with calls to function imports for scratch memory access. This lets us then implement those in a way that does not use the same heap as main memory. This avoids possible bugs with scratch memory overwriting something, or just in general that it has observable side effects, which can confuse fuzzing etc.
The intrinsics are currently implemented in the glue. We could perhaps emit them inline instead (but that might limit asm.js optimizations, so I wanted to keep our options open for now - easy to change later).
Also fixes some places where we used 0 as the scratch space address.
|
|
|
|
|
|
| |
* Don't assume function types exist in legalize-js-interface.
* Properly handle (ignore) imports in RemoveNonJSOps - do not try to recurse into them.
* Run legalize-js-interface and remove-unused-module-elements in wasm2js, the first is necessary, the last is nice to have.
|
|
|
|
|
|
|
|
| |
* I64ToI32Lowering - don't assume address 0 is a hardcoded location for scratch memory. Import __tempMemory__ for that.
* RemoveNonJSOps - also use __tempMemory__. Oddly here the address was a hardcoded 1024 (perhaps where the rust program put a static global?).
* Support imported ints in wasm2js, coercing them as needed.
* Add "env" import support in the tests, since now we emit imports from there.
* Make wasm2js tests split out multi-module tests using split_wast which is more robust and avoids emitting multiple outputs in one file (which makes no sense for ES6 modules)
|
|
|
|
|
|
|
| |
Minus multi-memory which we don't support yet.
Improve validator.
Fix some minor validation issues in our tests.
|
|
|
|
|
|
|
| |
* Finds functions whose return value is always dropped, and removes the return.
* Run multiple iterations of the pass, as one can enable others.
* Do not run DeadArgumentElimination at all if debug info is present (with these improvements, it became much more likely to destroy debug info).
Saves 2.5% on hello world, because of some simple libc calls.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
This adds a new IR, "Stack IR". This represents wasm at a very low level, as a simple stream of instructions, basically the same as wasm's binary format. This is unlike Binaryen IR which is structured and in a tree format.
This gives some small wins on binary sizes, less than 1% in most cases, usually 0.25-0.50% or so. That's not much by itself, but looking forward this prepares us for multi-value, which we really need an IR like this to be able to optimize well. Also, it's possible there is more we can do already - currently there are just a few stack IR optimizations implemented,
DCE
local2stack - check if a set_local/get_local pair can be removed, which keeps the set's value on the stack, which if the stars align it can be popped instead of the get.
Block removal - remove any blocks with no branches, as they are valid in wasm binary format.
Implementation-wise, the IR is defined in wasm-stack.h. A new StackInst is defined, representing a single instruction. Most are simple reflections of Binaryen IR (an add, a load, etc.), and just pointers to them. Control flow constructs are expanded into multiple instructions, like a block turns into a block begin and end, and we may also emit extra unreachables to handle the fact Binaryen IR has unreachable blocks/ifs/loops but wasm does not. Overall, all the Binaryen IR differences with wasm vanish on the way to stack IR.
Where this IR lives: Each Function now has a unique_ptr to stack IR, that is, a function may have stack IR alongside the main IR. If the stack IR is present, we write it out during binary writing; if not, we do the same binaryen IR => wasm binary process as before (this PR should not affect speed there). This design lets us use normal Passes on stack IR, in particular this PR defines 3 passes:
Generate stack IR
Optimize stack IR (might be worth splitting out into separate passes eventually)
Print stack IR for debugging purposes
Having these as normal passes is convenient as then they can run in parallel across functions and all the other conveniences of our current Pass system. However, a downside of keeping the second IR as an option on Functions, and using normal Passes to operate on it, means that we may get out of sync: if you generate stack IR, then modify binaryen IR, then the stack IR may no longer be valid (for example, maybe you removed locals or modified instructions in place etc.). To avoid that, Passes now define if they modify Binaryen IR or not; if they do, we throw away the stack IR.
Miscellaneous notes:
Just writing Stack IR, then writing to binary - no optimizations - is 20% slower than going directly to binary, which is one reason why we still support direct writing. This does lead to some "fun" C++ template code to make that convenient: there is a single StackWriter class, templated over the "mode", which is either Binaryen2Binary (direct writing), Binaryen2Stack, or Stack2Binary. This avoids a lot of boilerplate as the 3 modes share a lot of code in overlapping ways.
Stack IR does not support source maps / debug info. We just don't use that IR if debug info is present.
A tiny text format comment (if emitting non-minified text) indicates stack IR is present, if it is ((; has Stack IR ;)). This may help with debugging, just in case people forget. There is also a pass to print out the stack IR for debug purposes, as mentioned above.
The sieve binaryen.js test was actually not validating all along - these new opts broke it in a more noticeable manner. Fixed.
Added extra checks in pass-debug mode, to verify that if stack IR should have been thrown out, it was. This should help avoid any confusion with the IR being invalid.
Added a comment about the possible future of stack IR as the main IR, depending on optimization results, following some discussion earlier today.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
* Import `abort` from the environment
* Add passing spec tests
* Bind the abort function
* wasm2asm: Fix name collisions
Currently function names and local names can collide in namespaces, causing
buggy results when a function intends to call another function but ends up using
a local value as the target!
This fix was required to enable the `fac` spec test
* wasm2asm: Get multiple modules in one file working
The spec tests seem to have multiple modules defined in some tests and the
invocations all use the most recently defined module. This commit updates the
`--allow-asserts` mode of wasm2asm to work with this mode of tests, enabling us
to enable more spec tests for wasm2asm.
* wasm2asm: Enable the float_literals spec test
This needed to be modified to account for how JS engines don't work with NaN
bits the same way, but it's otherwise largely the same test. Additionally it
turns out that asm.js doesn't accept either `Infinity` or `NaN` ambient globals
so they needed to get imported through the `global` variable rather than defined
as literals in code
* wasm2asm: Fix function pointer invocations
This commit fixes invocations of functions through function pointers as
previously the table names on lookup and definition were mismatched. Both tables
now go through signature-based namification rather than athe name of the type
itself.
Overall this enables a slew of spec tests
* wasm2asm: Enable the left-to-right spec test
There were two small bugs in the order of evaluation of operators with
wasm2asm. The `select` instruction would sometimes evaluate the condition first
when it was supposed to be last. Similarly a `call_indirect` instruction would
evaluate the function pointer first when it was supposed to be evaluated last.
The `select` instruction case was a relatively small fix but the one for
`call_indirect` was a bit more pessimized to generate some temporaries.
Hopefully if this becomes up a problem it can be tightened up.
* wasm2asm: Fix signed load promotions of 64-bit ints
This commit enables the `endianness` spec test which revealed a bug in 64-bit
loads from smaller sizes which were signed. Previously the upper bits of the
64-bit number were all set to zero but the fix was for signed loads to have all
the upper bits match the highest bit of the low 32 bits that we load.
* wasm2asm: Enable the `stack` spec test
Internally the spec test uses a mixture of the s-expression syntax and the wat
syntax, so this is copied over into the `wasm2asm` folder after going through
`wat2wasm` to ensure it's consistent for binaryen.
* wasm2asm: Fix unaligned loads/stores of floats
Replace these operations in `RemoveNonJSOps` by using reinterpretation to
translate floats to integers and then use the existing code for unaligned
loads/stores of integers.
* wasm2asm: Fix a tricky grow_memory codegen bug
This commit fixes a tricky codegen bug found in the `grow_memory` instruction.
Specifically if you stored the result of `grow_memory` immediately into memory
it would look like:
HEAP32[..] = __wasm_grow_memory(..);
Here though it looks like JS evaluates the destination *before* the grow
function is called, but the grow function will invalidate the destination!
Furthermore this is actually generalizable to all function calls:
HEAP32[..] = foo(..);
Because any function could transitively call `grow_memory`. This commit fixes
the issue by ensuring that store instructions are always considered statements,
unconditionally evaluating the value into a temporary and then storing that into
the destination. While a bit of a pessmimization for now it should hopefully fix
the bug here.
* wasm2asm: Handle offsets in tables
This commit fixes initializing tables whose elements have an initial offset.
This should hopefully help fix some more Rust code which has all function
pointers offset by default!
* Update tests
* Tweak * location on types
* Rename entries of NameScope and document fromName
* Comment on lowercase names
* Update compiled JS
* Update js test output expectation
* Rename NameScope::Global to NameScope::Top
* Switch to `enum class`
* Switch to `Fatal()`
* Add TODO for when asm.js is no longer generated
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
* wasm2asm: Finish i64 lowering operations
This commit finishes out lowering i64 operations to JS with implementations of
division and remainder for JS. The primary change here is to have these compiled
from Rust to wasm and then have them "linked in" via intrinsics. The
`RemoveNonJSOps` pass has been updated to include some of what
`I64ToI32Lowering` was previously doing, basically replacing some instructions
with calls to intrinsics. The intrinsics are now all tracked in one location.
Hopefully the intrinsics don't need to be regenerated too much, but for
posterity the source currently [lives in a gist][gist], although I suspect that
gist won't continue to compile and work as-is for all of time.
[gist]: https://gist.github.com/alexcrichton/e7ea67bcdd17ce4b6254e66f77165690
|
|
|