| Commit message (Collapse) | Author | Age | Files | Lines |
|
|
|
| |
As the name of a class, uppercase seems better here.
|
|
|
|
| |
If we wanted to switch types in such cases we'd need to refinalize (which is likely
worth doing, though other passes should refine globals anyhow).
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
SimplifyGlobals already does this, so this is a subset of that pass, and does not
add anything new. It is useful for testing, however.
In particular it allows testing that we propagate subsequent globals in a single
pass, that is if one global reads from another and becomes constant, then it
can be propagated as well. SimplifyGlobals runs multiple passes so this always
worked, but with this pass we can test that we do it efficiently in one pass.
This will also be useful for comparing stringref to imported strings, as it
allows gathered strings to be propagated to other globals (possible with
stringref, but not imported strings) but not anywhere else (which might have
downsides as it could lead to more allocations).
Also add an additional test for simplify-globals that we do not get confused by
an unoptimizable global.get in the middle (see last part).
|
|
|
|
|
| |
globals (#6285)
Before we propagated to the top level, but not to anything interior.
|
|
|
|
|
|
|
|
|
|
| |
This reverts commit 9090ce56fcc67e15005aeedc59c6bc6773220f11.
This has the effect of once more propagating string constants from
globals to other places (and from non-globals too), which is useful
for various optimizations even if it isn't useful in the final output.
To fix the final output problem, #6257 added a pass that is run at the
end to collect string.const to globals, which allows us to once more
propagate strings in the optimizer, now without a downside.
|
|
|
|
|
| |
This causes overhead atm since in VMs executing a string.const will actually allocate a
string, and more copies means more allocations. For now, just do not add more. This
required changes to two passes: SimplifyGlobals and Precompute.
|
|
|
|
|
|
|
| |
We already applied such globals to other globals, but can do the same to offsets
of data and element segments.
Suggested in #6220
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
For example,
(global $a (struct.new $A))
(global $b (struct.new $B (global.get $A)))
=>
(global $b (struct.new $B (struct.new $A)))
and the global $a is now unused. This is valid if $a has no other uses.
This saves a little in code size, but should not really help otherwise, as we
already look through immutable global.get operations in important
optimizations. But the code size may matter if there are many such single-
use globals.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The pass was written before we had relevant code in module locations, but now
with GC we can have global.gets of more things.
The scanner did not run on global code in a way that is not a problem yet, but
will be for a later PR I'll open. It will be tested there. That is, right now there is no
optimization that is confused by the fact that we did not scan code at the module
level, but the next PR will do that.
The use modifier did not run on global code either, which was an actual missed
optimization opportunity: There are cases where we want to modify a global.get
to point to another one, and such a get might be in global code, not just in a
function. A test is added for that.
|
|
|
|
|
|
|
|
| |
This fixes some outdated comments and typos in Asyncify and improves
some other comments. This tries to make code comments more readable by
making them more accurate and also by using the three state (normal,
unwinding, and rewinding) consistently.
Drive-by fix: Typo fixes in SimplifyGlobals and wasm-reduce option.
|
|
|
|
|
|
|
| |
Followup to #5860, this does the same for SimplifyGlobals as for SimplifyLocals.
As there, this is valid because it's ok if we branch away. This part of the pass
applies a global value to a global.get based on a dominating global.set, so any
dominance is good enough for us.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
This fixes a TODO.
There is a runtime cost to this in higher opt levels, as passing through -O3
makes nested optimization work take longer. But it can lead to better results.
For now, this PR moves us from 0 before to a maximum of 1, as a compromise.
1 does not regress compile times, but there may be further benefits to allowing
2 and 3 in the future.
Also fix a fuzzer bug that becomes uncovered by tihs PR: Now that we actually
optimize in simplify-globals, we need to handle the case of the optimizer there
seeing a call with the effects of writing to a global (we had an assert on that
never happening, but with function effects that can happen, and so a GlobalSet
is not the only thing that can set a global).
Aside from the opt and shrink levels this passes through all other options,
like trapsNeverHappen.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
|
|
|
| |
(#4356)
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Similar to what we do with structs, if a global is immutable then we know it
cannot interact with calls.
This changes the JS API for getSideEffects(). That was actually broken,
as passing in the optional module param would just pass it along to the
compiled C code, so it was coerced to 0 or 1, and not a pointer to a module.
To fix that, this now does module.ptr to actually get the pointer, and this is
now actually tested as without a module we cannot compute the effects of a
global. This PR also makes the module param mandatory in the JS API,
as again, without a module we can't compute global effects. (The module
param has already been mandatory in the C++ API for some time.)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
We already detected code that looks like
if (foo == 0) {
foo = 1;
}
That "read only to write" pattern occurs also in functions, like this:
function bar() {
if (foo == 0) return;
foo = 1;
}
This PR detects that pattern. It moves code around to share almost
all the logic with the previous pattern (the git diff is not that useful
there, sadly, but looking at them side by side that should be
obvious).
This helps in j2cl on some common clinits, where the clinit function
ends up empty, which is exactly this pattern.
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Knowing the module will allow us to do more analysis in the
effect analyzer. For now, this just refactors the code to allow
providing a module instead of features, and to infer the
features from the module. This actually shortens the code in
most places which is nice (just pass module instead of
module->features).
This modifies basically all callers to use the new module
form, except for the fallthrough logic. That would require
some more refactoring, so to keep this PR reasonably small
that is not yet done.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
themselves (#4070)
If the only uses of a global are
if (global == 0) {
global = 1;
}
Then we do not need that global: while it has both reads and
writes, the value in the global does not cause anything observable.
It is read, but only to write to itself, and nothing else.
This happens in real-world code from j2cl quite a lot, as they have
an initialization pattern with globals, and in some cases we can
optimize away the work done in the initialization, leaving only the
globals in this pattern.
|
| |
|
| |
|
|
|
|
| |
We shouldn't actually nop, we forgot that the value may have
side effects, so just drop it (opts will remove it later, if possible).
|
|
|
|
| |
Based on freedback in #2741 it looks like we can use the existing
`simplify-globals-optimizing` pass to trigger this cleanups we need.
|
|
|
|
|
| |
Since the global is never read, we know that any write operation
will be unobservable.
|
|
|
|
|
|
|
| |
Since it wasn't easy to support tuples in Asyncify's call support
using temporary functions, we decided to allow tuple-typed globals
after all. This PR adds support for parsing, printing, lowering, and
interpreting tuple globals and also adds validation ensuring that
imported and exported globals do not have tuple types.
|
|
|
|
|
|
| |
The meaning we intend is "constant", and not the "Const"
node (which contains a number). So I think the full
name is less confusing.
|
|
|
|
| |
Updates the interpreter to properly flow vectors of values, including
at function boundaries. Adds a small spec test for multivalue return.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
This adds EH support to `EffectAnalyzer`. Before `throw` and `rethrow`
conservatively set property. Now `EffectAnalyzer` has a new property
`throws` to represent an expression that can throw, and expression that
can throw sets `throws` correctly.
When EH is enabled, any calls can throw too, so we cannot reorder them
with another expression with any side effects, meaning all calls should
be treated in the same way as branches when evaluating `invalidate`.
This prevents many reorderings, so this patch sets `throws` for calls
only when the exception handling features is enabled. This is also why I
passed `--disable-exception-handling` to `wasm2js` tests. Most of code
changes outside of `EffectAnalyzer` class was made in order to pass
`FeatureSet` to it.
`throws` isn't always set whenever an expression contains a throwable
instruction. When an throwable instruction is within an inner try, it
will be caught by the corresponding inner catch, so it does not set
`throws`.
|
|
|
|
|
|
|
|
|
|
|
|
| |
This adds support for the reference type proposal. This includes support
for all reference types (`anyref`, `funcref`(=`anyfunc`), and `nullref`)
and four new instructions: `ref.null`, `ref.is_null`, `ref.func`, and
new typed `select`. This also adds subtype relationship support between
reference types.
This does not include table instructions yet. This also does not include
wasm2js support.
Fixes #2444 and fixes #2447.
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
This optimizes stuff like
(global.set $x (i32.const 123))
(global.get $x)
into
(global.set $x (i32.const 123))
(i32.const 123)
This doesn't help much with LLVM output as it's rare to use globals (except for the stack pointer, and that's already well optimized), but it may help on general wasm. It can also help with Asyncify that does use globals extensively.
|
|
|
|
|
|
|
|
|
|
|
| |
(global $g1 (mut i32) (i32.const 42))
(global $g2 i32 (global.get $g1))
can be optimized to
(global $g1 (mut i32) (i32.const 42))
(global $g2 i32 (i32.const 42))
even though $g1 is mutable - because it can't be mutated during module instantiation.
|
|
|
|
|
|
|
|
|
| |
(#2242)
Main change here is in pass.h, everything else is changes to work with the new API.
The add("name") remains as before, while the weird variadic add(..) which constructed the pass now just gets a std::unique_ptr of a pass. This also makes the memory management internally fully automatic. And it makes it trivial to parallelize WalkerPass::run on parallel passes.
As a benefit, this allows removing a lot of code since in many cases there is no need to create a new pass runner, and running a pass can be just a single line.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
- 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.
|
|
If a global is marked mutable but not assigned to, make it immutable.
If an immutable global is a copy of another, use the original, so we can remove the duplicates.
Fixes #2011
|