webassembly / binaryen Goto Github PK
View Code? Open in Web Editor NEWOptimizer and compiler/toolchain library for WebAssembly
License: Apache License 2.0
Optimizer and compiler/toolchain library for WebAssembly
License: Apache License 2.0
From the output of asm2wasm, I find it just simply delete the imported variables statements, such as "var i = env.STACKTOP | 0; ". Without the support of imported variables, can this tool support all asm.js?
readFunctions()
asserts that functions are named, but only imports and exports are required to be named.
There is a proposal for a wasm binary format, links in the design repo.
We should implement it in a new header (wasm-binary.h
perhaps), and add tests. Might use the tests from the v8-native repo, although that's been merged to upstream v8, so maybe we'd need to look there. Or, maybe we'd just use our existing tests and see we can translate them to binary and back?
Seeing common expressions in the branches of if_else
operations. Seems appropriate to hoist them out. Added the pass 'hoist-if-else-common-block-expressions' to hoist out common tail sequences of expressions.
For example:
(if_else (i32.eq (i32.and (get_local $i42) (i32.const 512)) (i8.const 0))
(block (set_local $i283 (i8.const 0))
(set_local $i284 (get_local $i287))
(set_local $i285 (i8.const 0))
(set_local $i286 (get_local $i289)))
(block (i32.store8 (get_local $i3) (get_local $i288))
(i32.store8 (i32.add (get_local $i3) (i8.const 1))
(i32.shr_u (get_local $i288) (i8.const 8)))
(i32.store (i32.add (get_local $i5) (i8.const 24))
(call_function $_crc32 (i32.load (i32.add (get_local $i5) (i8.const 24)))
(get_local $i3) (i8.const 2)))
(set_local $i283 (i8.const 0))
(set_local $i284 (get_local $i287))
(set_local $i285 (i8.const 0))
(set_local $i286 (get_local $i289))))
=>
(block
(if_else
(i32.eq (i32.and (get_local $i42) (i32.const 512)) (i8.const 0)) (nop)
(block (i32.store8 (get_local $i3) (get_local $i288))
(i32.store8 (i32.add (get_local $i3) (i8.const 1))
(i32.shr_u (get_local $i288) (i8.const 8)))
(i32.store (i32.add (get_local $i5) (i8.const 24))
(call_function $_crc32
(i32.load (i32.add (get_local $i5) (i8.const 24))) (get_local $i3)
(i8.const 2)))))
(set_local $i283 (i8.const 0))
(set_local $i284 (get_local $i287))
(set_local $i285 (i8.const 0))
(set_local $i286 (get_local $i289)))))
See 20030714-1.c.wast from torture-tests:
(type $FUNCSIG_ii (func (param i32)))
(table $RenderBox_isTableCell)
(func $RenderBox_setStyle (param $$0 i32) (param $$1 i32)
...
(br_if
(call_indirect $FUNCSIG_ii
(i32.load offset=28 align=4
(get_local $$0)
)
(get_local $$0)
)
$BB0_6
)
...
(func $RenderBox_isTableCell (param $$0 i32) (result i32)
...
br_if requires its first argument to be of type i32, but $FUNCSIG_ii
has a result type of void. Note that it must be calling $RenderBox_isTableCell
which has a result type of i32 as well.
Seeing a off-by-one issue in the tableswitch output. The following also loses the default case when round-tipping wasm-as and wasm-dis - not sure if related.
(module
(memory 0 0)
(func $f1 (param $x i32) (result i32)
(block $topmost
(tableswitch $switch$0
(i32.sub
(get_local $x)
(i32.const 1)
)
(table (case $switch-case$1) (case $switch-case$2)) (case $switch-case$1)
(case $switch-case$1
(br $topmost
(i32.const 1)
)
)
(case $switch-case$2
(br $topmost
(i32.const 2)
)
)
)
(i32.const 0)
)
)
)
Looking at the encoding demonstrates the problem:
sexp-prototype:
0000012: 08 ; OPCODE_TABLESWITCH
0000013: 0200 ; num cases
0000015: 0300 ; num targets <<<<
0000017: 0000 ; case index
0000019: 0100 ; case index
000001b: 0000 ; case index
000001d: 41 ; OPCODE_I32_SUB
wasm-as:
08
0200
0200 ; num targets <<<< wrong
0000
0100
41
The asm2wasm output labels the locals with symbols using the pattern $i<n>
starting with $i1
. The wast spec allows these to be named by index, starting at zero. If the naming also started at $i0
then the index would match, and this might be handy when comparing it to the encoded files.
The spec repo has tests that we should get wasm2asm working on. But it has multiple modules per file and a special assert syntax. Should we support that, or create something simpler?
See 20000112-1.c.s.wast for example:
(module
(memory 0 4294967295)
(import $exit "env" "exit")
(export "main" $main)
(func $main (result i32)
(call_import $exit
(i32.const 0)
)
(unreachable)
)
)
;; METADATA: { "asmConsts": {},"staticBump": 0 }
It should be (import $exit "env" "exit" (param i32))
see pr42691.c.wast in the gcc torture tests:
(block
(br_if
(f64.ne
(get_local $$3)
(f64.const inf)
)
$BB0_4
)
It should be infinity
not inf
See the nesting blow out and it looks likely to be caused by br
. Both br
and br_if
require a result expression in the v8 encoding, even if a nop
needs to be used, they have a fixed number of arguments.
The following demonstrates some bad numbering of local variable indexes. The reference to $i3
is emitted as index 0.
(module
(memory 0 0)
(func $f1 (param $i1 i32) (param $i2 i32) (param $i3 i32) (result i32)
(block $topmost
(get_local $i3)
)))
This can be seen using wasm-dis which also loses the result type.
(module
(memory 0)
(type $0 (func (param i32 i32 i32) (result i32)))
(func $f1 (param $var$0 i32) (param $var$1 i32) (param $var$2 i32)
(block $label$0
(get_local $var$0) ; <<<<
)
)
)
To give a canonical ordering for experimenting with the encoding efficiency it might help to sort each functions local variables with the most frequently referenced first. This way an encoding optimizing for small local variable indexes might do best, such as the polyfill-prototype-1. I assume similar encoding optimizations will be used in the MVP too because it appears quite effective.
I have not yet used "WebAssembly binaryen -> asm2wasm". I wonder if asm2wasm can understand ECMAScript 6?
Example:
(module
(memory 0 0)
(func $f1 (param $i1 i32) (result i32)
(i32.select
(i32.lt_s
(get_local $i1)
(i32.const 0)
)
(i32.sub
(i32.const 0)
(get_local $i1)
)
(get_local $i1)
)
(i32.const 0))
)
sexp-wasm emits the select
operator arguments in the wast order.
0000010: 05 ; OPCODE_SELECT
0000011: 4f ; OPCODE_I32_LT_S
0000012: 0e ; OPCODE_GET_LOCAL
0000013: 00 ; remapped local index
0000014: 09 ; OPCODE_I8_CONST
0000015: 00 ; u8 literal
0000016: 41 ; OPCODE_I32_SUB
0000017: 09 ; OPCODE_I8_CONST
0000018: 00 ; u8 literal
0000019: 0e ; OPCODE_GET_LOCAL
000001a: 00 ; remapped local index
000001b: 0e ; OPCODE_GET_LOCAL
000001c: 00 ; remapped local index
000001d: 09 ; OPCODE_I8_CONST
000001e: 00 ; u8 literal
Interestingly wasm-as emits them in the opposite order, that is the i32.sub first then the i32.lt_s.
See pr35456.c.wast:
(i32.neg (get_local $$0))
i32.neg isn't currently a supported operation, as defined by the spec repo.
Spotted at lot of (i32.shr_u <exp> 0)
operations. Most are probably a remnant of asm.js style and should be removed?
For example: (i32.gt_u (i32.shr_u (get_local $i3) (i32.const 0)) (i32.shr_u (get_local $i1) (i32.const 0))))
Not sure if the intention was to address this case, but s2wasm seems to generate this following redundant pattern.
(module
(memory 0 4294967295)
(export "add" $add)
(func $add (param $$0 i32) (param $$1 i32) (result i32)
(block $fake_return_waka123
(block
(br $fake_return_waka123
(i32.add
(get_local $$1)
(get_local $$0)))))))
binaryen-shell -print-after -remove-unused-brs -remove-unused-names -merge-blocks add.wast
(module
(memory 0 18446744073709551615)
(export "add" $add)
(func $add (param $$0 i32) (param $$1 i32) (result i32)
(block $fake_return_waka123
(br $fake_return_waka123
(i32.add
(get_local $$1)
(get_local $$0)
)))))
Could still optimize away the block br
. An extension for follow tailing expressions and remove br
's from them too.
We currently apply the memory inside a wasm module into emscripten's memory, careful to merge them properly. This is used in the wasm-backend path in emscripten, where the LLVM wasm backend gives us a module, containing memory data. At runtime, emscripten creates memory, and then we instantiate the wasm, and combine the memories. However, when running asm2wasm, the LLVM asm.js backend gave us a .mem file separately, and we currently keep it separate.
We could merge it into the wasm module directly. A downside is that currently all our wasm is in .wast code, and so binary data is not efficiently encoded. This could be annoying for testing on large codebases. So perhaps it makes sense to wait on this until we have binary format support.
It looks like s2wasm fails on the following GCC torture tests because of negative relocations:
20060905-1.c.s # $s-384
pr58209.c.s $buf-4
The problem occurs here:
ret->fullType = getFunctionType(astStackHelper.getParent(), ret->operands);
astStackHelper.getParent()
is null for a top-level expression, which causes getFunctionType
to crash.
Instead of calling astStackHelper.getParent()
, shouldn't it try to determine the return type of the functions in the specified function table?
We need to pass the memory size info from emscripten to the memory section of the wasm module. Perhaps we should parse it out of the js file?
Seeing bad code detected as missing a name on an import.
Seeing code that could eliminate uses of intermediate local variables. These might be an effect of the conversion from asm.js to wasm given that wasm supports a wider range of expressions. Perhaps the llvm backend will do a better job here, or perhaps it also needs some help. Just filing this to put it on the radar, plus some other potential simplifications.
(eq <> 0)
be remove, flipping the order of the if_else
branches, or is there locality or likely path semantics to preserve? See a few of these in the code.set_local $i3
repeated in each if_else
branch out of the if_else
.set_local $i3
get_local $i3
can be eliminated.$i3
local which could be removed.block $topmost
still seems unnecessary - see #32if_else
with a (i32.const 0)
branch. Could/does if
return 0 when not taken? If so then this code could be further simplified to use just if
and remove the (i32.const 0)
branch.(func $_wctomb (param $i1 i32) (param $i2 i32)
(result i32)
(local $i3 i32)
(block $topmost
(if_else (i32.eq (get_local $i1) (i32.const 0))
(set_local $i3 (i32.const 0))
(set_local $i3 (call $_wcrtomb (get_local $i1) (get_local $i2) (i32.const 0))))
(get_local $i3)))`
Could be simplified to:
(func $_wctomb (param $i1 i32) (param $i2 i32)
(result i32)
(if_else (get_local $i1)
(call $_wcrtomb (get_local $i1) (get_local $i2) (i32.const 0))
(i32.const 0)))
We already fixed emscripten_asm_const
to be type-signatured, but looks like the same happens for cxa_find_matching_catch
. Not sure if the best fix is in emscripten or here.
Noticed that asm2wasm has not worked for a few days. Seems due to the significant changes to blocks and labels.
s2wasm outputs tableswitch using blocks instead of cases, see switch-1.c.wast in torture-tests:
(block $BB1_13
(block $BB1_12
(block $BB1_11
(block $BB1_9
(block $BB1_7
(block $BB1_5
(tableswitch
(get_local $$2)
(table (case $BB1_5) (case $BB1_14) (case $BB1_7) (case $BB1_14) (case $BB1_14) (case $BB1_9) (case $BB1_14) (case $BB1_11)) (case $BB1_5)
)
)
...
It looks like this may be changed soon in the spec repo, so maybe it's not worth fixing here, however.
The encoding supports names for functions, and notes imports and exports. It does not appear to prohibit names on other functions, but imports and exports have both an external name and an internal label name which can be different but there is only support for one name - I expect it needs to be interpreted as the external name and that there is no support for naming the internal labels.
For example, in the following sexpr-wasm-prototype emits the "myfunc" name in the encoding, but wasm-as emits "f1" which would not be correct.
(module
(memory 0 0)
(export "myfunc" $f1)
(func $f1 (param $x i32) (result i32)
(i32.const 0)))
I suggest changing wasm-as to only emit names for the imports and exports and to use the external name string rather than the labels, and to wait until there is some debug support for naming the internal labels.
The .s
format isn't final, but some things it appears to just take the "normal" assembly syntax notation for, like how it writes globals. Currently s2wasm is very hackish there, as I'm not that familiar with what those things mean in typical assembly, so it just ignores things like .lcomm
, .section
. etc., which I'm not sure matter.
The code is in parseType, parseObject
. Someone familiar with assembly formats could probably easily make it more reasonable.
Some of the spec tests fail randomly. This is very odd as there is nothing random in the interpreter, nor the test. I seem to only see it on a 32-bit machine.
To see it, I just run ./check
and stop after the spec tests, then keep doing that until it fails.
Valgrind finds nothing.
Looks somehow float rounding or signaling nan related, based on the error (we fail the spec test due to a nan having or not having the signaling bit).
Seeing many unused block
s, not just the $topmost
, produced via asm2wasm.
We now have testing in check.py
of s2wasm outputs on the torture tests. That means we are getting output from the wasm backend, and run main() in hopes of it not hitting an abort() or some internal error.
Looks like 70% or so pass. The known failures are in test/s2wasm_known_binaryen_shell_test_failures.txt
. It would be good to go through those and see what causes them, as in principle they all should pass. This might be finding bugs in the wasm backend, in particular, as it's the first large-scale test of executing its outputs AFAIK.
Consider:
(module
(memory 0 0)
(func $f1 (param $i1 i32) (result f64)
(block $topmost
(f64.add
(f64.convert_s/i32 (get_local $i1))
(f64.convert_u/i32 (get_local $i1))
))))
wasm-as emits opcode 0x9e
for f64.convert_s/i32
and opcode a0
for f64.convert_u/i32
, whereas sexpr-wasm-prototype emits opcodes 0xae
and 0xaf
respectively.
Seeing this asm.js _frexp(d1 * 18446744073709551616.0, i2)
converted into (f64.mul (get_local $d1) (f64.const 18446744073709551616))
.
The integer 18446744073709551616
is 0x10000000000000000
and is outside the range of a u64, and might this be unexpected?
Perhaps it should have been (f64.const 1.844674407370955e19)
or (f64.const 4895412794951729152)
?
Seeing wasm-as encode more local variables than necessary. For example: in emcc_O2_hello_world.wast the second function $_free
has 36 i32 local variables, but emcc_O2_hello_world.wast.fromBinary has 127.
I get this on OS X when I build with my cmake build:
../src/s2wasm.h:957:65: warning: reference 'o' is not yet bound to a value when used here [-Wuninitialized]
AsmConstWalker(S2WasmBuilder* parent) : parent(parent), o(o) {}
The logic in mapLocals looks incomplete. Not all locals appear to being added. Can be seen in the test 'fromBinary' files, and note that many of the $var$0
instances in the output do not refer to the correct variable in the source wast files. Would be nice if missing names could have flagged an error at lookup too.
Crash with the following command :
bin/asm2wasm noise.js
(i0 = 0; (((i0 | 0) < 2) | 0); i0 = (((i0 | 0) + 1) | 0)) {
HEAP32[dsp + 0 + ((i0 | 0) << 2) >> 2] = 0;
Abort trap: 6
Noise.js file content is :
/* ------------------------------------------------------------
author: "Grame"
copyright: "(c)GRAME 2009"
license: "BSD"
name: "Noise"
version: "1.1"
Code generated with Faust 2.0.a41 (http://faust.grame.fr)
------------------------------------------------------------ */
function mydspModule(global, foreign, buffer) {
'use asm';
var HEAP32 = new global.Int32Array(buffer);
var HEAPF32 = new global.Float32Array(buffer);
var imul = global.Math.imul;
var log = global.Math.log;
function fmodf(x, y) { x = +x; y = +y; return +(x % y); }
function log10f(a) { a = +a; return +(+log(a) / +log(10.)); }
function getNumInputs(dsp) {
dsp = dsp | 0;
return 0;
}
function getNumOutputs(dsp) {
dsp = dsp | 0;
return 1;
}
function classInit(dsp, samplingFreq) {
dsp = dsp | 0;
samplingFreq = samplingFreq | 0;
}
function instanceInit(dsp, samplingFreq) {
dsp = dsp | 0;
samplingFreq = samplingFreq | 0;
var i0 = 0;
HEAP32[dsp + 12 >> 2] = (samplingFreq | 0);
HEAPF32[dsp + 8 >> 2] = +(0.);
for (i0 = 0; (((i0 | 0) < 2) | 0); i0 = (((i0 | 0) + 1) | 0)) {
HEAP32[dsp + 0 + ((i0 | 0) << 2) >> 2] = 0;
}
}
function init(dsp, samplingFreq) {
dsp = dsp | 0;
samplingFreq = samplingFreq | 0;
classInit(dsp, samplingFreq);
instanceInit(dsp, samplingFreq);
}
function setValue(dsp, offset, value) {
dsp = dsp | 0;
offset = offset | 0;
value = +value;
HEAPF32[dsp + offset >> 2] = value;
}
function getValue(dsp, offset) {
dsp = dsp | 0;
offset = offset | 0;
return +HEAPF32[dsp + offset >> 2];
}
function compute(dsp, count, inputs, outputs) {
dsp = dsp | 0;
count = count | 0;
inputs = inputs | 0;
outputs = outputs | 0;
var output0 = 0;
var fSlow0 = 0.;
var i = 0;
output0 = (HEAP32[outputs + (0 << 2) >> 2] | 0);
fSlow0 = +(4.65661e-10 * +(+(HEAPF32[dsp + 8 >> 2])));
for (i = 0; (((i | 0) < (count | 0)) | 0); i = (((i | 0) + 1) | 0)) {
HEAP32[dsp + 0 + (0 << 2) >> 2] = ((12345 + (imul(1103515245, (HEAP32[dsp + 0 + (1 << 2) >> 2] | 0)) | 0)) | 0);
HEAPF32[output0 + ((i | 0) << 2) >> 2] = +(+(+(fSlow0) * +((HEAP32[dsp + 0 + (0 << 2) >> 2] | 0))));
HEAP32[dsp + 0 + (1 << 2) >> 2] = (HEAP32[dsp + 0 + (0 << 2) >> 2] | 0);
}
}
return { getNumInputs : getNumInputs, getNumOutputs : getNumOutputs, classInit : classInit, instanceInit : instanceInit, init : init, setValue : setValue, getValue : getValue, compute : compute };
}
function getSizemydsp() {
return 16;
}
function getPathTablemydsp() {
var pathTable = [];
pathTable["/0x00/Volume"] = 8;
return pathTable;
}
function getJSONmydsp() {
return "{ "name": "Noise", "outputs": "1", "meta": [ { "author": "Grame" }, { "copyright": "(c)GRAME 2009" }, { "license": "BSD" }, { "name": "Noise" }, { "version": "1.1" } ], "ui": [ { "type": "vgroup", "label": "0x00", "items": [ { "type": "vslider", "label": "Volume", "address": "/0x00/Volume", "meta": [ { "style": "knob" } ], "init": "0", "min": "0", "max": "1", "step": "0.1" } ] } ] } ";
}
function metadatamydsp(m) {
m.declare("author", "Grame");
m.declare("copyright", "(c)GRAME 2009");
m.declare("license", "BSD");
m.declare("name", "Noise");
m.declare("version", "1.1");
}
Crash log is :
bt
__pthread_kill + 10 frame #1: 0x00007fff8cdd835c libsystem_pthread.dylib
pthread_kill + 92abort + 125 frame #3: 0x000000010000f04f asm2wasm
cashew::Parser<cashew::Ref, cashew::DotZeroValueBuilder>::parseAfterKeyword(cashew::Parser<cashew::Ref, cashew::DotZeroValueBuilder>::Frag&, char_&, char const_) + 575cashew::Parser<cashew::Ref, cashew::DotZeroValueBuilder>::parseElement(char*&, char const*) + 335 frame #5: 0x000000010000e481 asm2wasm
cashew::Parser<cashew::Ref, cashew::DotZeroValueBuilder>::parseElementOrStatement(char_&, char const_) + 577cashew::Parser<cashew::Ref, cashew::DotZeroValueBuilder>::parseBlock(char*&, char const*, cashew::IString, cashew::IString) + 463 frame #7: 0x0000000100012eff asm2wasm
cashew::Parser<cashew::Ref, cashew::DotZeroValueBuilder>::parseBracketedBlock(char_&) + 287cashew::Parser<cashew::Ref, cashew::DotZeroValueBuilder>::parseFunction(char_&, char const_) + 922 frame #9: 0x000000010000e8df asm2wasm
cashew::Parser<cashew::Ref, cashew::DotZeroValueBuilder>::parseElement(char_&, char const_) + 335cashew::Parser<cashew::Ref, cashew::DotZeroValueBuilder>::parseElementOrStatement(char_&, char const_) + 577 frame #11: 0x000000010000e0df asm2wasm
cashew::Parser<cashew::Ref, cashew::DotZeroValueBuilder>::parseBlock(char_&, char const_, cashew::IString, cashew::IString) + 463cashew::Parser<cashew::Ref, cashew::DotZeroValueBuilder>::parseBracketedBlock(char_&) + 287 frame #13: 0x000000010001350a asm2wasm
cashew::Parser<cashew::Ref, cashew::DotZeroValueBuilder>::parseFunction(char*&, char const*) + 922cashew::Parser<cashew::Ref, cashew::DotZeroValueBuilder>::parseElement(char_&, char const_) + 335 frame #15: 0x000000010000e481 asm2wasm
cashew::Parser<cashew::Ref, cashew::DotZeroValueBuilder>::parseElementOrStatement(char*&, char const*) + 577cashew::Parser<cashew::Ref, cashew::DotZeroValueBuilder>::parseBlock(char_&, char const_, cashew::IString, cashew::IString) + 463 frame #17: 0x000000010000485f asm2wasm
main + 463See 20020227-1.c.wast:
...
(block $BB2_4
(br_if
(f32.ne
(f32.reinterpreti32
(i32.or
(i32.shl
...
Should be f32.reinterpret/i32
It looks like 112 many of the torture tests are now failing with:
Unknown symbol: $__stack_pointer
There already were a few failures before about unknown symbols, but __stack_pointer
wasn't one of them.
Did things regress, or did error detection improve? If the later then could we just add that to the list of known failures until it's fixed?
The tests are:
20000412-2.c.s 20000801-1.c.s 20001228-1.c.s 20010116-1.c.s 20010518-2.c.s 20010915-1.c.s 20020406-1.c.s 20020413-1.c.s 20021120-3.c.s 20021219-1.c.s 20030218-1.c.s 20030221-1.c.s 20030222-1.c.s 20030313-1.c.s 20030916-1.c.s 20031012-1.c.s 20031201-1.c.s 20040218-1.c.s 20041019-1.c.s 20041124-1.c.s 20041126-1.c.s 20050121-1.c.s 20050203-1.c.s 20050502-1.c.s 20050502-2.c.s 20060420-1.c.s 20070201-1.c.s 20070212-1.c.s 20070517-1.c.s 20071029-1.c.s 20071030-1.c.s 20071202-1.c.s 20071219-1.c.s 20080502-1.c.s 20080604-1.c.s 20090207-1.c.s 20100708-1.c.s 20101013-1.c.s 20111208-1.c.s 20111212-1.c.s 20120105-1.c.s 20120808-1.c.s 20120919-1.c.s 20121108-1.c.s 20131127-1.c.s 20140425-1.c.s 920411-1.c.s 920501-9.c.s 921110-1.c.s 930513-1.c.s 930622-2.c.s 930930-2.c.s 941014-2.c.s 950710-1.c.s 960215-1.c.s 960327-1.c.s 960513-1.c.s 980605-1.c.s 990513-1.c.s 990531-1.c.s 991228-1.c.s alloca-1.c.s builtin-prefetch-2.c.s cbrt.c.s conversion.c.s fprintf-1.c.s gofast.c.s memcpy-1.c.s pr15262.c.s pr15296.c.s pr20527-1.c.s pr27073.c.s pr27285.c.s pr29006.c.s pr33142.c.s pr33992.c.s pr34176.c.s pr35472.c.s pr36339.c.s pr36343.c.s pr37573.c.s pr38212.c.s pr38236.c.s pr39120.c.s pr41239.c.s pr42614.c.s pr42691.c.s pr43236.c.s pr43835.c.s pr44202-1.c.s pr44852.c.s pr45070.c.s pr49218.c.s pr49279.c.s pr51466.c.s pr52760.c.s pr52979-1.c.s pr52979-2.c.s pr54471.c.s pr54985.c.s pr56799.c.s pr57124.c.s pr57131.c.s pr59229.c.s pr59358.c.s pr60960.c.s printf-1.c.s regstack-1.c.s string-opt-17.c.s string-opt-18.c.s string-opt-5.c.s
Program aborts while running bin/binaryen-shell test/dot_s/switch.wast
on GNU/Linux. Here's backtrace I got
* frame #0: 0x00007ffff7221cc9 libc.so.6`gsignal + 57
frame #1: 0x00007ffff72250d8 libc.so.6`abort + 328
frame #2: 0x00007ffff721ab86 libc.so.6`??? + 294
frame #3: 0x00007ffff721ac32 libc.so.6`__assert_fail + 66
frame #4: 0x000000000040b630 binaryen-shell`wasm::Element::list(this=0x0000000000677020) + 48 at wasm-s-parser.h:49
frame #5: 0x000000000040b659 binaryen-shell`wasm::Element::operator[](this=0x0000000000677020, i=0) + 31 at wasm-s-parser.h:54
frame #6: 0x000000000040449a binaryen-shell`main(argc=2, argv=0x00007fffffffded8) + 2533 at binaryen-shell.cpp:280
frame #7: 0x00007ffff720cec5 libc.so.6`__libc_start_main + 245
frame #8: 0x0000000000402c19 binaryen-shell
codes that failed:
List& list() {
assert(isList_);
return list_;
}
The reference interpreter lacks module importing support, so we Nop imports in native builds, so that we can validate them in the reference interpreter. Perhaps we should find a better workaround that would still check the imports.
Looking at the output of s2wasm strncmp-1.c.s
shows wast code such as the following
(block $BB1_5
(br_if (i32.eq (get_local $$0) (i32.const 0)) $BB1_5)
(loop $BB1_4 ...))
which appears to be
(if (i32.eq (get_local $$0) (i32.const 0))
(loop ...))
Are there any plans to clean up the output? Would this be a job on the llvm side? It looks more than just a pattern matching exercise, and might need some understanding of the CFG? Perhaps the block structure will help here and lead to some simpler strategies.
After emscripten-core/emscripten#4013 , we can test emcc+vanilla LLVM on our wasm-backend tests in this repo. That is, it would be nice if we detected we have emcc, and then run the full emcc tests using the wasm backend, and then optionally run the asm2wasm etc. tests that require a non-vanilla LLVM with the asm.js backend. To do that, we'd need to know emscripten's LLVM is vanilla, and if so, not run the asm.js tests, but still run the wasm-backend tests.
writeFunctionTable()
needs to write an index into functions excluding the imports - subtly difference compared to the index used for call_function
.
Seeing a few (if_else (i32.ne exp 0) ..) style patterns in the asm2wasm output. These are in the original asm.js, but were they needed there for some reason and should they be eliminated in the conversion, or just artifacts that can be ignored? These turn up in br_if and if_else in the zlib benchmark. Some are not direct but deeper in expressions that return a value to a predicate argument.
Example asm.js, but not sure if this generated the above pattern on conversion.
do {
i11 = i11 + -2 | 0;
i9 = HEAPU16[i11 >> 1] | 0;
HEAP16[i11 >> 1] = i9 >>> 0 < i2 >>> 0 ? 0 : i9 - i2 & 65535;
i10 = i10 + -1 | 0;
} while ((i10 | 0) != 0);
CMake?
In most cases it is fine to fold an asm.js load/store offset into the wasm load/store offset. It will fail on some rare code when the pre-offset index is a signed value (wasm interprets it as unsigned with infinite precision), but to help us get some benchmarks out and develop the binary encoding could this be a command line option that defaults to off?
You might recall a big sage a year ago in emscripten with this being rejected there as 'not wanted', and I had to maintain an emscripten fork with this support, but perhaps people have conceded it's worth the burden now, or that at least it could help us get some testing done until the llvm wasm backend pipeline is more useful. The rebased emscripten patches are still at https://github.com/JSStats/emscripten if they are of any use.
I am having errors when building the project.
drom@drom:~/work/github/WebAssembly/wasm-emscripten> ./build.sh
building asm2wasm
building interpreter/js
./build.sh: line 4: em++: command not found
building wasm shell
In file included from src/wasm-s-parser.h:9:0,
from src/wasm-shell.cpp:8:
src/wasm.h:996:22: error: ‘ReturnType wasm::WasmVisitor<ReturnType>::visitBlock(wasm::Block*) [with ReturnType = wasm::ModuleInstance::callFunction(cashew::IString, wasm::ModuleInstance::LiteralList&)::Flow]’, declared using local type ‘wasm::ModuleInstance::callFunction(cashew::IString, wasm::ModuleInstance::LiteralList&)::Flow’, is used but never defined [-fpermissive]
virtual ReturnType visitBlock(Block *curr) = 0;
^
src/wasm.h:997:22: error: ‘ReturnType wasm::WasmVisitor<ReturnType>::visitIf(wasm::If*) [with ReturnType = wasm::ModuleInstance::callFunction(cashew::IString, wasm::ModuleInstance::LiteralList&)::Flow]’, declared using local type ‘wasm::ModuleInstance::callFunction(cashew::IString, wasm::ModuleInstance::LiteralList&)::Flow’, is used but never defined [-fpermissive]
virtual ReturnType visitIf(If *curr) = 0;
^
src/wasm.h:998:22: error: ‘ReturnType wasm::WasmVisitor<ReturnType>::visitLoop(wasm::Loop*) [with ReturnType = wasm::ModuleInstance::callFunction(cashew::IString, wasm::ModuleInstance::LiteralList&)::Flow]’, declared using local type ‘wasm::ModuleInstance::callFunction(cashew::IString, wasm::ModuleInstance::LiteralList&)::Flow’, is used but never defined [-fpermissive]
virtual ReturnType visitLoop(Loop *curr) = 0;
^
src/wasm.h:999:22: error: ‘ReturnType wasm::WasmVisitor<ReturnType>::visitLabel(wasm::Label*) [with ReturnType = wasm::ModuleInstance::callFunction(cashew::IString, wasm::ModuleInstance::LiteralList&)::Flow]’, declared using local type ‘wasm::ModuleInstance::callFunction(cashew::IString, wasm::ModuleInstance::LiteralList&)::Flow’, is used but never defined [-fpermissive]
virtual ReturnType visitLabel(Label *curr) = 0;
^
src/wasm.h:1000:22: error: ‘ReturnType wasm::WasmVisitor<ReturnType>::visitBreak(wasm::Break*) [with ReturnType = wasm::ModuleInstance::callFunction(cashew::IString, wasm::ModuleInstance::LiteralList&)::Flow]’, declared using local type ‘wasm::ModuleInstance::callFunction(cashew::IString, wasm::ModuleInstance::LiteralList&)::Flow’, is used but never defined [-fpermissive]
virtual ReturnType visitBreak(Break *curr) = 0;
^
src/wasm.h:1001:22: error: ‘ReturnType wasm::WasmVisitor<ReturnType>::visitSwitch(wasm::Switch*) [with ReturnType = wasm::ModuleInstance::callFunction(cashew::IString, wasm::ModuleInstance::LiteralList&)::Flow]’, declared using local type ‘wasm::ModuleInstance::callFunction(cashew::IString, wasm::ModuleInstance::LiteralList&)::Flow’, is used but never defined [-fpermissive]
virtual ReturnType visitSwitch(Switch *curr) = 0;
^
src/wasm.h:1002:22: error: ‘ReturnType wasm::WasmVisitor<ReturnType>::visitCall(wasm::Call*) [with ReturnType = wasm::ModuleInstance::callFunction(cashew::IString, wasm::ModuleInstance::LiteralList&)::Flow]’, declared using local type ‘wasm::ModuleInstance::callFunction(cashew::IString, wasm::ModuleInstance::LiteralList&)::Flow’, is used but never defined [-fpermissive]
virtual ReturnType visitCall(Call *curr) = 0;
^
src/wasm.h:1003:22: error: ‘ReturnType wasm::WasmVisitor<ReturnType>::visitCallImport(wasm::CallImport*) [with ReturnType = wasm::ModuleInstance::callFunction(cashew::IString, wasm::ModuleInstance::LiteralList&)::Flow]’, declared using local type ‘wasm::ModuleInstance::callFunction(cashew::IString, wasm::ModuleInstance::LiteralList&)::Flow’, is used but never defined [-fpermissive]
virtual ReturnType visitCallImport(CallImport *curr) = 0;
^
src/wasm.h:1004:22: error: ‘ReturnType wasm::WasmVisitor<ReturnType>::visitCallIndirect(wasm::CallIndirect*) [with ReturnType = wasm::ModuleInstance::callFunction(cashew::IString, wasm::ModuleInstance::LiteralList&)::Flow]’, declared using local type ‘wasm::ModuleInstance::callFunction(cashew::IString, wasm::ModuleInstance::LiteralList&)::Flow’, is used but never defined [-fpermissive]
virtual ReturnType visitCallIndirect(CallIndirect *curr) = 0;
^
src/wasm.h:1005:22: error: ‘ReturnType wasm::WasmVisitor<ReturnType>::visitGetLocal(wasm::GetLocal*) [with ReturnType = wasm::ModuleInstance::callFunction(cashew::IString, wasm::ModuleInstance::LiteralList&)::Flow]’, declared using local type ‘wasm::ModuleInstance::callFunction(cashew::IString, wasm::ModuleInstance::LiteralList&)::Flow’, is used but never defined [-fpermissive]
virtual ReturnType visitGetLocal(GetLocal *curr) = 0;
^
src/wasm.h:1006:22: error: ‘ReturnType wasm::WasmVisitor<ReturnType>::visitSetLocal(wasm::SetLocal*) [with ReturnType = wasm::ModuleInstance::callFunction(cashew::IString, wasm::ModuleInstance::LiteralList&)::Flow]’, declared using local type ‘wasm::ModuleInstance::callFunction(cashew::IString, wasm::ModuleInstance::LiteralList&)::Flow’, is used but never defined [-fpermissive]
virtual ReturnType visitSetLocal(SetLocal *curr) = 0;
^
src/wasm.h:1007:22: error: ‘ReturnType wasm::WasmVisitor<ReturnType>::visitLoad(wasm::Load*) [with ReturnType = wasm::ModuleInstance::callFunction(cashew::IString, wasm::ModuleInstance::LiteralList&)::Flow]’, declared using local type ‘wasm::ModuleInstance::callFunction(cashew::IString, wasm::ModuleInstance::LiteralList&)::Flow’, is used but never defined [-fpermissive]
virtual ReturnType visitLoad(Load *curr) = 0;
^
src/wasm.h:1008:22: error: ‘ReturnType wasm::WasmVisitor<ReturnType>::visitStore(wasm::Store*) [with ReturnType = wasm::ModuleInstance::callFunction(cashew::IString, wasm::ModuleInstance::LiteralList&)::Flow]’, declared using local type ‘wasm::ModuleInstance::callFunction(cashew::IString, wasm::ModuleInstance::LiteralList&)::Flow’, is used but never defined [-fpermissive]
virtual ReturnType visitStore(Store *curr) = 0;
^
src/wasm.h:1009:22: error: ‘ReturnType wasm::WasmVisitor<ReturnType>::visitConst(wasm::Const*) [with ReturnType = wasm::ModuleInstance::callFunction(cashew::IString, wasm::ModuleInstance::LiteralList&)::Flow]’, declared using local type ‘wasm::ModuleInstance::callFunction(cashew::IString, wasm::ModuleInstance::LiteralList&)::Flow’, is used but never defined [-fpermissive]
virtual ReturnType visitConst(Const *curr) = 0;
^
src/wasm.h:1010:22: error: ‘ReturnType wasm::WasmVisitor<ReturnType>::visitUnary(wasm::Unary*) [with ReturnType = wasm::ModuleInstance::callFunction(cashew::IString, wasm::ModuleInstance::LiteralList&)::Flow]’, declared using local type ‘wasm::ModuleInstance::callFunction(cashew::IString, wasm::ModuleInstance::LiteralList&)::Flow’, is used but never defined [-fpermissive]
virtual ReturnType visitUnary(Unary *curr) = 0;
^
src/wasm.h:1011:22: error: ‘ReturnType wasm::WasmVisitor<ReturnType>::visitBinary(wasm::Binary*) [with ReturnType = wasm::ModuleInstance::callFunction(cashew::IString, wasm::ModuleInstance::LiteralList&)::Flow]’, declared using local type ‘wasm::ModuleInstance::callFunction(cashew::IString, wasm::ModuleInstance::LiteralList&)::Flow’, is used but never defined [-fpermissive]
virtual ReturnType visitBinary(Binary *curr) = 0;
^
src/wasm.h:1012:22: error: ‘ReturnType wasm::WasmVisitor<ReturnType>::visitCompare(wasm::Compare*) [with ReturnType = wasm::ModuleInstance::callFunction(cashew::IString, wasm::ModuleInstance::LiteralList&)::Flow]’, declared using local type ‘wasm::ModuleInstance::callFunction(cashew::IString, wasm::ModuleInstance::LiteralList&)::Flow’, is used but never defined [-fpermissive]
virtual ReturnType visitCompare(Compare *curr) = 0;
^
src/wasm.h:1013:22: error: ‘ReturnType wasm::WasmVisitor<ReturnType>::visitConvert(wasm::Convert*) [with ReturnType = wasm::ModuleInstance::callFunction(cashew::IString, wasm::ModuleInstance::LiteralList&)::Flow]’, declared using local type ‘wasm::ModuleInstance::callFunction(cashew::IString, wasm::ModuleInstance::LiteralList&)::Flow’, is used but never defined [-fpermissive]
virtual ReturnType visitConvert(Convert *curr) = 0;
^
src/wasm.h:1014:22: error: ‘ReturnType wasm::WasmVisitor<ReturnType>::visitSelect(wasm::Select*) [with ReturnType = wasm::ModuleInstance::callFunction(cashew::IString, wasm::ModuleInstance::LiteralList&)::Flow]’, declared using local type ‘wasm::ModuleInstance::callFunction(cashew::IString, wasm::ModuleInstance::LiteralList&)::Flow’, is used but never defined [-fpermissive]
virtual ReturnType visitSelect(Select *curr) = 0;
^
src/wasm.h:1015:22: error: ‘ReturnType wasm::WasmVisitor<ReturnType>::visitHost(wasm::Host*) [with ReturnType = wasm::ModuleInstance::callFunction(cashew::IString, wasm::ModuleInstance::LiteralList&)::Flow]’, declared using local type ‘wasm::ModuleInstance::callFunction(cashew::IString, wasm::ModuleInstance::LiteralList&)::Flow’, is used but never defined [-fpermissive]
virtual ReturnType visitHost(Host *curr) = 0;
^
src/wasm.h:1016:22: error: ‘ReturnType wasm::WasmVisitor<ReturnType>::visitNop(wasm::Nop*) [with ReturnType = wasm::ModuleInstance::callFunction(cashew::IString, wasm::ModuleInstance::LiteralList&)::Flow]’, declared using local type ‘wasm::ModuleInstance::callFunction(cashew::IString, wasm::ModuleInstance::LiteralList&)::Flow’, is used but never defined [-fpermissive]
virtual ReturnType visitNop(Nop *curr) = 0;
^
When building with -O2, the spec tests pass, but if building with -O0 then I see a failure. This is on 32-bit, so perhaps float related.
Maybe related to #10?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.