| Commit message (Collapse) | Author | Age | Files | Lines |
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
|
|
| |
Use the new capability in a new test of RTT behavior that will be fixed in #4284,
|
| |
|
|
|
| |
This sets the C++ standard variable in the build to C++17, and makes use of std::optional (a C++17 library feature) in one place, to test that it's working.
|
| |
|
| |
|
| |
|
|
|
|
|
|
|
| |
The upstream name of the command in LLVM is FileCheck, but we use a Python
package called filecheck instead and using `FileCheck` in lit tests will not
work. To make catching this common error easier, add a warning about it in
scripts/update_lit_checks.py. This warning also applies to other uses of pipes,
which are not supported in this script.
|
|
|
|
| |
Adds the part of the spec test suite that this passes (without table.set we
can't do it all).
|
|
|
|
|
|
|
| |
While making clang-tidy CI only check for src/, #4193 accidentally
overrided the existing default regex that checks only c/cpp/h... files:
https://github.com/llvm/llvm-project/blob/8971b99c8387f3daf2e802956f2688b3b77335a4/clang-tools-extra/clang-tidy/tool/clang-tidy-diff.py#L132
This fixes the problem by appending all those extensions after `src/`.
|
| |
|
|
|
|
|
|
|
|
|
| |
This clang-formats c/cpp files in test/ directory, and updates
clang-format-diff.sh so that it does not ignore test/ directory anymore.
bigswitch.cpp is excluded from formatting, because there are big
commented-out code blocks, and apparently clang-format messes up
formatting in them. Also to make matters worse, different clang-format
versions do different things on those commented-out code blocks.
|
|
|
|
| |
We don't keep files within test/ clang-tidy compliant, so including this
directory can generate CI errors when test files change.
|
|
|
|
|
|
|
|
|
| |
Fuzzer shows the initial contents and prompts the user if they want to
proceed after #4173, but when the fuzzer is used within a script called
from `wasm-reduce`, we shouldn't pause for the user input. This shows
the prompt only when there is no seed given.
To do that, we now initialize the important initial contents from
`main`. We used to assign those variables before we start `main`.
|
|
|
|
|
|
|
|
|
| |
See #4149
This modifies the test added in #4163 which used static casts on
dynamically-created structs and arrays. That was technically not
valid (as we won't want users to "mix" the two forms). This makes that
test 100% static, which both fixes the test and gives test coverage
to the new instructions added here.
|
|
|
|
|
|
|
|
|
| |
This is another attempt to address #4073. Instead of relying on the
timestamp, this examines git log to gather the list of test files added
or modified within some fixed number of days. The number of days is
currently set to 30 (= 1 month) but can be changed. This will be enabled
by `--auto-initial-contents`, which is now disabled by default.
Hopefully fixes #4073.
|
|
|
|
|
|
|
|
|
|
|
|
| |
We added an optional ReFinalize in OptimizeInstructions at some point,
but that is not valid: The ReFinalize only updates types when all other
works is done, but the pass works incrementally. The bug the fuzzer found
is that a child is changed to be unreachable, and then the parent is
optimized before finalize() is called on it, which led to an assertion being
hit (as the child was unreachable but not the parent, which should also
be).
To fix this, do not change types in this pass. Emit an extra block with a
declared type when necessary. Other passes can remove the extra block.
|
|
|
|
|
|
|
|
|
|
|
|
| |
These variants take a HeapType that is the type we intend to cast to,
and do not take an RTT.
These are intended to be more statically optimizable. For now though
this PR just implements the minimum to get them parsing and to get
through the optimizer without crashing.
Spec: https://docs.google.com/document/d/1afthjsL_B9UaMqCA5ekgVmOm75BVFu6duHNsN9-gnXw/edit#
See #4149
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
This PR helps with functions like this:
function foo(x) {
if (x) {
..
lots of work here
..
}
}
If "lots of work" is large enough, then we won't inline such a
function. However, we may end up calling into the function
only to get a false on that if and immediately exit. So it is useful
to partially inline this function, basically by creating a split
of it into a condition part that is inlineable
function foo$inlineable(x) {
if (x) {
foo$outlined();
}
}
and an outlined part that is not inlineable:
function foo$outlined(x) {
..
lots of work here
..
}
We can then inline the inlineable part. That means that a call
like
foo(param);
turns into
if (param) {
foo$outlined();
}
In other words, we end up replacing a call and then a check with
a check and then a call. Any time that the condition is false, this
will be a speedup.
The cost here is increased size, as we duplicate the condition
into the callsites. For that reason, only do this when heavily
optimizing for size.
This is a 10% speedup on j2cl. This helps two types of functions
there: Java class inits, which often look like "have I been
initialized before? if not, do all this work", and also assertion
methods which look like "if the input is null, throw an
exception".
|
|
|
|
|
|
| |
Avoids a crash in calling getHeapType when there isn't one.
Also add the relevant lit test (and a few others) to the list of files to
fuzz more heavily.
|
|
|
|
|
|
|
|
|
|
|
|
| |
tablify() attempts to turns a sequence of br_ifs into a single
br_table. This PR adds some flexibility to the specific pattern it
looks for, specifically:
* Accept i32.eqz as a comparison to zero, and not just to look
for i32.eq against a constant.
* Allow the first condition to be a tee. If it is, compare later
conditions to local.get of that local.
This will allow more br_tables to be emitted in j2cl output.
|
|
|
|
|
|
|
| |
array.init is like array.new_with_rtt except that it takes
as arguments the values to initialize the array with (as opposed to
a size and an optional initial value).
Spec: https://docs.google.com/document/d/1afthjsL_B9UaMqCA5ekgVmOm75BVFu6duHNsN9-gnXw/edit#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Some functions run only once with this pattern:
function foo() {
if (foo$ran) return;
foo$ran = 1;
...
}
If that global is not ever set to 0, then the function's payload (after the
initial if and return) will never execute more than once. That means we
can optimize away dominated calls:
foo();
foo(); // we can remove this
To do this, we find which globals are "once", which means they can
fit in that pattern, as they are never set to 0. If a function looks like the
above pattern, and it's global is "once", then the function is "once" as
well, and we can perform this optimization.
This removes over 8% of static calls in j2cl.
|
|
|
|
| |
NFC (#4090)
|
|
|
|
|
| |
If extra data is found in this section simply propagate it.
Also, remove some dead code from wasm-binary.cpp.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
When we catches "Output must be deterministic" we can't see any details. This PR fix
this and now we can see diff of b1.wasm and b2.wasm files.
Example output:
Output must be deterministic.
Diff:
--- expected
+++ actual
@@ -2072,9 +2072,7 @@
)
(drop
(block $label$16 (result funcref)
- (local.set $10
- (ref.null func)
- )
+ (nop)
(drop
(call $22
(f64.const 0.296)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Technically this is not a new pass, but it is a rewrite almost from scratch.
Local Common Subexpression Elimination looks for repeated patterns,
stuff like this:
x = (a + b) + c
y = a + b
=>
temp = a + b
x = temp + c
y = temp
The old pass worked on flat IR, which is inefficient, and was overly
complicated because of that. The new pass uses a new algorithm that
I think is pretty simple, see the detailed comment at the top.
This keeps the pass enabled only in -O4, like before - right after
flattening the IR. That is to make this as minimal a change as possible.
Followups will enable the pass in the main pipeline, that is, we will
finally be able to run it by default. (Note that to make the pass work
well after flatten, an extra simplify-locals is added - the old pass used
to do part of simplify-locals internally, which was one source of
complexity. Even so, some of the -O4 tests have changes, due to
minor factors - they are just minor orderings etc., which can be
seen by inspecting the outputs before and after using e.g.
--metrics)
This plus some followup work leads to large wins on wasm GC output.
On j2cl there is a common pattern of repeated struct.gets, so common
that this pass removes 85% of all struct.gets, which makes the total
binary 15% smaller. However, on LLVM-emitted code the benefit is
minor, less than 1%.
|
| |
|
|
|
| |
fix #3985
|
|
|
|
|
|
|
|
| |
This adds calls to imports around every struct load and store, to
note their values, and also to arrays (where it also notes the
index).
This has been very useful in debugging LowerGC (lowering of Wasm
GC to wasm MVP).
|
|
|
|
|
|
|
| |
Now that the features section adds on top of the commandline arguments,
it means the way we test if initial contents are ok to use will not work if
the wasm has a features section - as it will enable a feature, even if
we wanted to see if the wasm can work without that feature. To fix this,
strip the features section there.
|
|
|
|
|
|
| |
This works around the issue with wasm gc types sometimes getting
truncated (as the default names can be very long or even infinitely
recursive). If the truncation leads to name collision, the wast is not
valid.
|
|
|
|
|
|
|
|
|
|
| |
The features section is additive since #3960. For the fuzzer to know which features
are used, it therefore needs to also scan the features section. To do this,
run --print-features to get the total features used from both flags + the
features section.
A result of this is that we now have a list of enabled features instead of
"enable all, then disable". This is actually clearer I think, but it does require
inverting the logic in some places.
|
|
|
|
|
|
| |
Emscripten stopped emitting shell support code by default (as most users
run node.js, but here we are literally fuzzing d8).
Fixes #3967
|
| |
|
|
|
|
|
|
| |
Filter out tests using --metrics, --emit-{js,spec}-wrapper, --fuzz-exec,
--print-stack-ir, --dwarfdump, etc. because they have ouput that will not be
captured in the automatically generated checks. Also filter based on the list of
passes rather than the test file in case the test uses a .passes file.
|
|
|
| |
And use it to port the very simple untee test.
|
|
|
|
|
|
| |
In conjunction with the `foreach` tool, allows autogenerating checks for lit
tests containing multiple modules. Supporting this will help automatically port
existing bespoke wast tests to be lit tests, since many of those tests contain
multiple modules per file.
|
|
|
|
| |
Decompose the code into more functions and make other simplifying changes to
prepare for multi-module support introduced in #3962.
|
|
|
|
|
|
|
|
| |
Add an --all-items flag to update_lit_checks.py to emit checks for all module
items, not just those that match items in the input. Update two tests to use
generated input with the new flag.
Also, to improve readability, insert an empty line between consecutive checks
for different items.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Instead of only generating checks for functions, generate checks for all named top-level module items, such as types, tags, tables, and memories. Because module items can be in different orders in the input and the output but FileCheck checks must follow the order of the output, we need to be slightly clever about when we emit the checks. Consider these types in the input file:
```
(type $A (...))
(type $B (...))
```
If their order is reversed in the output file, then the checks for $B need to be emitted before the checks for $A, so the resulting module will look like this:
```
;; CHECK: (type $B (...))
;; CHECK: (type $A (...))
(type $A (...))
(type $B (...))
```
Rather than this, which looks nicer but would be incorrect:
```
;; CHECK: (type $A (...))
(type $A (...))
;; CHECK: (type $B (...))
(type $B (...))
```
|
|
|
|
|
|
|
| |
The major drawback of lit tests is that so far they have only supported a single
module per test file. This commit adds a new utility script that splits an input
file into multiple files and runs a command on each of them, giving lit tests a
simple way to test multiple modules per file.
|
|
|
|
|
|
|
|
|
|
| |
This is the same as rtt.sub, but creates a "new" rtt each time. See
https://docs.google.com/document/d/1DklC3qVuOdLHSXB5UXghM_syCh-4cMinQ50ICiXnK3Q/edit#
The old Literal implementation of rtts becomes a little more complex here,
as it was designed for the original spec where only structure matters. It may
be worth a complete redesign there, but for now as the spec is in flux I think
the approach here is good enough.
|
|
|
|
|
|
|
| |
The support code there emits "low high" as the result, for example, 25 0 would
be 25 (as the high bits are all 0). This is different than how numbers are reported
in other things we fuzz, so this caused an error.
Fixes #3915
|
|
|
|
|
|
| |
They are basically the flip versions. The only interesting part in the impl is that their
returned typed and sent types are different.
Spec: https://docs.google.com/document/d/1DklC3qVuOdLHSXB5UXghM_syCh-4cMinQ50ICiXnK3Q/edit
|
|
|
|
|
|
|
|
| |
Spec for it is here:
https://docs.google.com/document/d/1DklC3qVuOdLHSXB5UXghM_syCh-4cMinQ50ICiXnK3Q/edit#
Also reorder some things in wasm.h that were not in the canonical order (that has
no effect, but it is confusing to read).
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
If we allocate some GC data, and do not let the reference escape, then we can
replace the allocation with locals, one local for each field in the allocation
basically. This avoids the allocation, and also allows us to optimize the locals
further.
On the Dart DeltaBlue benchmark, this is a 24% speedup (making it faster than
the JS version, incidentially), and also a 6% reduction in code size.
The tests are not the best way to show what this does, as the pass assumes
other passes will clean up after. Here is an example to clarify. First, in pseudocode:
ref = new Int(42)
do {
ref.set(ref.get() + 1)
} while (import(ref.get())
That is, we allocate an int on the heap and use it as a counter. Unnecessarily,
as it could be a normal int on the stack.
Wat:
(module
;; A boxed integer: an entire struct just to hold an int.
(type $boxed-int (struct (field (mut i32))))
(import "env" "import" (func $import (param i32) (result i32)))
(func "example"
(local $ref (ref null $boxed-int))
;; Allocate a boxed integer of 42 and save the reference to it.
(local.set $ref
(struct.new_with_rtt $boxed-int
(i32.const 42)
(rtt.canon $boxed-int)
)
)
;; Increment the integer in a loop, looking for some condition.
(loop $loop
(struct.set $boxed-int 0
(local.get $ref)
(i32.add
(struct.get $boxed-int 0
(local.get $ref)
)
(i32.const 1)
)
)
(br_if $loop
(call $import
(struct.get $boxed-int 0
(local.get $ref)
)
)
)
)
)
)
Before this pass, the optimizer could do essentially nothing with this.
Even with this pass, running -O1 has no effect, as the pass is only
used in -O2+. However, running --heap2local -O1 leads to this:
(func $0
(local $0 i32)
(local.set $0
(i32.const 42)
)
(loop $loop
(br_if $loop
(call $import
(local.tee $0
(i32.add
(local.get $0)
(i32.const 1)
)
)
)
)
)
)
All the GC heap operations have been removed, and we just
have a plain int now, allowing a bunch of other opts to run. That
output is basically the optimal code, I think.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
We only ignored known issues if the process failed. However, some things
do not bring the process down, but are still necessary to ignore, which this
fixes.
Another approach might be to make all the things we need to ignore fail
the entire process. However, that could be annoying for other debugging:
we don't want a host limit on say hitting a VM limit on recursion to bring
down the entire process, as those limits manifest as traps, and we can
still run after them (and do need to test that). The specific host limit that
made me fix this was the trap on OOM when trying to allocate an array
of size 4GB.
|