| Commit message (Collapse) | Author | Age | Files | Lines |
|
|
|
|
|
| |
* Don't emit "i31" or "data" if GC is not enabled, as only the GC feature adds those.
* Don't emit "any" without GC either. While it is allowed, fuzzer limitations prevent
this atm (see details in comment - it's fixable).
|
|
|
|
|
|
| |
In f124a11ca3 we removed support for the prototype nominal binary format
entirely, but that means that we can no longer parse older binary modules that
used that format. Fix this regression by restoring the ability to parse the
prototype binary format.
|
|
|
|
|
|
| |
If we do not remove a param, we can try to remove the return value. We can do that
on a per-function basis, and not only if we removed no params from anywhere.
Also simplify tail call logic.
|
| |
|
|
|
|
|
|
| |
Remove `Type::externref` and `HeapType::ext` and replace them with uses of
anyref and any, respectively, now that we have unified these types in the GC
proposal. For backwards compatibility, continue to parse `extern` and
`externref` and maintain their relevant C API functions.
|
|
|
|
|
|
| |
V8 requires that supertypes come before subtypes when it parses
isorecursive (i.e. standards-track) type definitions. Since 2268f2a we are
emitting nominal types using the standard isorecursive format, so respect the
ordering requirement.
|
|
|
|
|
| |
Without this Windows fails with:
'isdigit': is not a member of 'std'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
We assume a closed world atm in the GC space, but the call.without.effects
intrinsic sort of breaks that: that intrinsic looks like an import, but we really
need to care about what is sent to it even in a closed world:
(call $call-without-effects
(ref.func $target-keep)
)
That reference cannot be ignored, as logically it is called just as if there
were a call_ref there. This adds support for that, fixing the combination of
#4621 and using call.without.effects.
Also flip the vector of ref.func names to a set. I realized that in a very
large program we might see the same name many times.
|
|
|
|
|
|
|
|
|
|
| |
Print subtype declarations using the standards-track format with a vector of
supertypes followed by a normal type declaration rather than our interim nominal
format that used alternative versions of the func, struct, and array forms.
Desugar the nominal format to additionally emit all the types into a single
large recursion group. Currently V8 is performing this desugaring, but after
this change and a future change that fixes the order of nominal types to ensure
supertypes precede subtypes, it will no longer need to.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
in a function. (#4567)
* Lift the restriction in liveness-traversal.h that supported max 65535 locals in a function.
* Lint
* Fix typo
* Fix static
* Lint
* Lint
* Lint
* Add needed canRun function
* lint
* Use either a sparse or a dense matrix for tracking liveness copies, depending on the locals count.
* Lint
* Fix lint
* Lint
* Implement sparse_square_matrix class and use that as a backing.
* Lint
* Lint
* Lint #includes
* Lint
* Lint includes
* Remove unnecessary code
* Fix canonical accesses to copies matrix
* Lint
* Add missing variable update
* Remove canRun() function
* Address review
* Update expected test results
* Update test name
* Add asserts to sparse_square_matrix set and get functions that they are not out of bound.
* Lint includes
* Update test expectation
* Use .clear() + .resize() to reset totalCopies vector
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
If we see (ref.func $foo) that does not mean that $foo is reachable - we
must also see a (call_ref ..) of the proper type. Only after seeing both should
we mark the function as reachable, which this PR does.
This adds some complexity as we need to track intermediate state as we go,
since we could see the RefFunc before the CallRef or vice versa. We also
need to handle the case of a RefFunc without a CallRef properly: We cannot
remove the function, as the RefFunc must refer to it, but at least we can
empty out the body since we know it is never reached.
This removes an old wasm-opt test which is now superseded by a new lit
test.
On J2Wasm output this removes 3% of all functions, which account for
2.5% of total code size.
|
|
|
|
|
|
|
|
|
| |
parallel analysis (#4620)
Normally ParallelFunctionAnalysis is just an analysis, and has no effects. However, in
SignatureRefining we actually do have side effects, due to an internal limitation of the
helper code it runs. This adds a template parameter to the class so users can note that
they do modify the IR. The parameter is added in the middle as it is easier to add this
param than to add the last one (the map).
|
|
|
|
| |
* We implemented specialization of field types (the TypeRefining pass).
* LUBFinder now handles nulls, so we need nothing extra for it in TypeRefining.
|
|
|
|
|
|
| |
Previously we'd only try to remove functions from index 0, so we missed
some opportunities. With this change we still go through all the functions
if things go well, but we start from a deterministic random location in the
vector.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
We already assume the parent does not change,
binaryen/src/support/small_set.h
Lines 202 to 208 in 94d77ef
// std::set allows changes while iterating. For us here, though, it would
// be nontrivial to support that given we have two iterators that we
// generalize over (switching "in the middle" would not be easy or fast),
// so error on that.
if (usingFixed != other.usingFixed) {
Fatal() << "SmallSet does not support changes while iterating";
}
This also marks the parent as const to reflect that.
This fixed a weird C++ compilation error I had when working on
something unrelated, but seems worth landing independently.
|
|
|
|
|
|
|
|
|
| |
Casts can replace a type with a subtype, which normally has no downsides, but
in a corner case of struct types it can lead to us needing to refinalize higher up
too, see details in the comment.
We have avoided any Refinalize calls in OptimizeInstructions, but the case
handled here requires it sadly. I considered moving it to another pass, but this
is a peephole optimization so there isn't really a better place.
|
|
|
| |
This hits the fuzzer when it tries to call reference exports with a null.
|
|
|
|
|
|
|
|
|
|
|
| |
The cast instruction may be unreachable but the intended type for the cast
still needs to be collected. Otherwise we end up with problems both during
optimizations that look at heap types and in printing (which will use the heap
type in code but not declare it).
Diff without whitespace is much smaller: this just moves code around so
that we can use a template to avoid code duplication. The actual change
is just to scan ->intendedType unconditionally, and not ignore it if the
cast is unreachable.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
When a field has no reads, we remove all its writes, but we did this:
(struct.set $foo A B)
=>
(drop A) (drop B)
We also need to trap if A, the reference, is null, which this PR
fixes,
(struct.set $foo A B)
=>
(drop (ref.as_non_null A)) (drop B)
|
| |
|
|
|
|
|
|
| |
This fixes two bugs: First, we need to compare the nominal types of function
constants when looking for constants to "merge", not just their structure.
Second, when creating the new function we must use the proper type of
those constants, and not just another type.
|
|
|
|
| |
Randomly selecting a depth is ok for structural typing, but in nominal it
must match the actual hierarchy of types.
|
|
|
|
|
| |
The same module will have a different type after some transformations, even
though that is not observable, like --roundtrip. Basically, we should not be
comparing types between separate modules, which is what the fuzzer does.
|
| |
|
|
|
|
|
|
|
| |
Related: emscripten-core/emscripten#15893 (comment)
--pass-arg=asyncify-side-module option will be used not only from
side modules, but also from main modules.
|
|
|
| |
As proposed in https://github.com/WebAssembly/relaxed-simd/issues/52.
|
|
|
|
|
|
|
|
|
| |
We can preserve return_calls in inlined functions when the inlined call site is
itself a return_call, since the call result types must transitively match in
that case. This solves a problem where the previous inlining logic could
introduce stack exhaustion by downgrading recursive return_calls to normal
calls.
Fixes #4587.
|
|
|
|
| |
Other opcode ends with `Inxm` or `Fnxm` (where n and m are integers),
while `i8x16.swizzle`'s opcode name doesn't have an `I` in there.
|
|
|
| |
As proposed in https://github.com/WebAssembly/relaxed-simd/issues/40.
|
|
|
|
| |
Instead do a clear()+resize() (#4580)
|
|
|
|
|
|
|
|
| |
247f4c20a1 introduced a bug that caused expressions that refer to data segments
to be associated with the wrong segments in the presence of other segments that
have no referring expressions at all.
Fixes #4569.
Fixes #4571.
|
|
|
|
|
|
|
|
| |
CoalesceLocals (#4574)
Normally we just replace unreachable local.gets with a constant (0, or null), but if
the local is non-nullable we can't do that.
Fixes #4573
|
|
|
|
|
| |
Fixes #4562
Fixes #4564
|
|
|
|
|
|
|
|
|
|
|
| |
As we recently noted in #4555, that Feature::All and FeatureSet.setAll()
are different is potentially confusing...
I think the best thing is to make them identical. This does that, and adds a
new Feature::AllPossible which is everything possible and not just the
set of all features that are enabled by -all.
This undoes part of #4555 as now the old/simpler code works properly.
|
|
|
|
|
| |
#4555 fixed validation for such tuples, but we also did not handle
them in "stacky" code using pops etc., due to a logic bug in the
binary reading code.
|
|
|
|
|
|
|
| |
V8 used to incorrectly parse the segment index on bulk memory instructions as a
signed LEB rather than an unsigned LEB, which meant it only worked correctly
with up to 63 data segments. That bug has been fixed for over two years now, so
lift the maximum number of segments generated by memory packing from 63 to the
specified max, 100k.
|
|
|
|
|
|
| |
Apply the same logic to tuple fields as we do for all other fields,
when checking whether a non-nullable value is valid.
Fixes #4554
|
|
|
|
|
|
|
|
|
|
|
| |
The memory packing pass previously used vectors with a slot for each data
segment to easily map segment indices to lists of "referrers," i.e. bulk memory
expressions that referred to the segments. The parallel analysis pass to collect
these referrers allocated one of these vectors for each function in a module.
Unfortunately, for a particularly large module with over 200k functions and over
75k data segments, this resulted in hundreds of gigabytes of memory allocations.
The vast majority of functions contain no referrers, so using a
std::unordered_map makes much more sense than using a vector to perform this
mapping.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
(#4553)
Previously we'd remove a field from a type if that field has no uses in any
sub- or super-type. In that case we'd remove it from all the types at once.
However, there is a case where we can remove a field only from a parent
but not from its children, if the field is at the end: if A has fields {x, y, z}
and its subtype B has fields {x, y, z, w}, and A pointers only access
field y while B pointers access all the fields, then we can remove z
from A. Removing it from the end is safe, and then B will not only add
w as it did before but also add z. Note that we cannot remove x,
because it is not at the end: removing it from just A but not B would
shift the indexes, making them incompatible.
|
|
|
|
|
| |
This basically just adds a call to ParamUtils::applyConstantValues, however,
we also need to be careful to not optimize in the presence of imports or
exports, so this adds a boolean that indicates unoptimizability.
|
|
|
|
|
|
|
|
|
|
|
|
| |
This moves more logic from ConstantFieldPropagation into PossibleConstantValues,
that is, instead of handling the two cases of a Literal or a Name before calling
PossibleConstantValues, move that code into the helper class. That way all users of
PossibleConstantValues can benefit from it. In particular, this makes
DeadArgumentElimination now support optimizing immutable globals, as well as
ref.func and ref.null.
(Changes to test/lit/passes/dae-gc-refine-params.wast are to avoid the new
optimizations from kicking in, so that it still tests what it tested before.)
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
This adds a new signature-pruning pass that prunes parameters from
signature types where those parameters are never used in any function
that has that type. This is similar to DeadArgumentElimination but works
on a set of functions, and it can handle indirect calls.
Also move a little code from SignatureRefining into a shared place to
avoid duplication of logic to update signature types.
This pattern happens in j2wasm code, for example if all method functions
for some virtual method just return a constant and do not use the this
pointer.
|
| |
|
|
|
|
|
|
|
| |
DeadArgumentElimination (#4547)
Similar to #4544, this moves the code to a utility function, and also
slightly generalizes it to support a list of functions (and not just 1)
and also a list of call_refs (and not just calls).
|
|
|
|
| |
This just moves PossibleConstantValues to a new separate file
(as a preparation for other passes using it too).
|
|
|
|
|
|
|
|
|
|
|
|
| |
DeadArgumentElimination (#4544)
In preparation for removing dead arguments from all functions sharing a heap
type (which seems useful for j2wasm output), first this PR refactors that code
so it is reusable. This moves the code out of the pass into FunctionUtils, and
also generalizes it slightly by
supporting a set of functions and not just a single one, and
receiving a list of call_refs and not just calls
(no other changes to anything).
|
|
|
|
|
|
|
| |
I believe this old code was written before we had LocalGraph. It does a flow
analysis to see if the values arriving in parameters are actually used, but
there is no reason to do it manually since we have LocalGraph now which
makes that trivial, as it matches the values for each get, so we can just check
if any get can read the param's incoming value.
|
| |
|
|
|
| |
See https://github.com/WebAssembly/extended-const
|
|
|
|
|
|
|
| |
* use [[noreturn]] available since C++11 instead of compiler-specific attributes
* replace deprecated std::is_pod with is_trivial&&is_standard_layout (also available since C++11/14)
* explicitly capture this in [=] lambdas
* extra const functions in FeatureSet, fix implicit cast warning by using the features field directly
* Use CMAKE_CXX_STANDARD to ensure the C++ standard parameter is set on all targets, remove manual compiler flag workaround.
|