Giter Site home page Giter Site logo

webassembly / binaryen Goto Github PK

View Code? Open in Web Editor NEW
7.2K 175.0 712.0 128.85 MB

Optimizer and compiler/toolchain library for WebAssembly

License: Apache License 2.0

Shell 0.02% Python 1.22% C++ 28.50% C 0.85% JavaScript 7.00% CMake 0.12% WebAssembly 62.29% Assembly 0.01%
emscripten webassembly compilers c-plus-plus hacktoberfest

binaryen's People

Contributors

aardappel avatar aheejin avatar alexcrichton avatar ashleynh avatar brendandahl avatar bsalita avatar dcodeio avatar ddcc avatar dschuff avatar frank-emrich avatar froydnj avatar gkdn avatar jayphelps avatar jfbastien avatar jgravelle-google avatar jirutka avatar juj avatar kripken avatar martianboy avatar maxgraey avatar mbebenita avatar quantum5 avatar rongjiecomputer avatar sbc100 avatar sunfishcode avatar tlively avatar vouillon avatar walkingeyerobot avatar yurydelendik avatar zm2he avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

binaryen's Issues

Sort the local variable order with the most frequently referenced first.

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.

How to convert imported variables?

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?

Spec test fail on unoptimized build

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?

Cleaning up the s2wasm output.

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.

mapLocals logic needs work

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.

Use zero based local symbol naming

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.

wasm-as: incorrect local variable indexes

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) ; <<<<
    )
  )
)

assertion failed while running binaryen-shell

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_;
  }

Remove `br` at a block tail.

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.

Warning due to uninitialized value

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) {}

Unknown symbol: $__stack_pointer

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

Indirect function calls that occur as a top-level expression cause a crash

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?

Imports in native builds

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.

s2wasm globals parsing

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.

Possible mis-interpretation of import and export function names.

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.

s2wasm doesn't generate correct result type for call_indirect

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.

s2wasm doesn't output imports with the correct signature

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))

wasm-as: select operator arguments emitted in reverse order.

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.

Vanilla LLVM testing

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.

Test LLVM WebAssembly backend outputs, by executing them

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.

cc @sunfishcode, @jfbastien

asm2wasm: f64.const 18446744073709551616 ?

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)?

s2wasm outputs i32.neg

See pr35456.c.wast:

(i32.neg (get_local $$0))

i32.neg isn't currently a supported operation, as defined by the spec repo.

wasm-as: wrong opcodes for f64.convert_s/i32 and f64.convert_u/i32

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.

Merge emscripten .mem into wasm

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.

wasm-as: tableswitch has an incorrect number of targets in the encoding

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

Negative relocations

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

Eliminate unnecessary (if_else (i32.ne exp 0) ..) patterns.

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);

wasm-as: more locals than necessary.

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.

asm2wasm crah

Crash with the following command :

bin/asm2wasm noise.js

for:

(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

  • thread #1: tid = 0x303a, 0x00007fff83138866 libsystem_kernel.dylib`__pthread_kill + 10, queue = 'com.apple.main-thread', stop reason = signal SIGABRT
    • frame #0: 0x00007fff83138866 libsystem_kernel.dylib__pthread_kill + 10 frame #1: 0x00007fff8cdd835c libsystem_pthread.dylibpthread_kill + 92
      frame #2: 0x00007fff858e3b1a libsystem_c.dylibabort + 125 frame #3: 0x000000010000f04f asm2wasmcashew::Parser<cashew::Ref, cashew::DotZeroValueBuilder>::parseAfterKeyword(cashew::Parser<cashew::Ref, cashew::DotZeroValueBuilder>::Frag&, char_&, char const_) + 575
      frame #4: 0x000000010000e8df asm2wasmcashew::Parser<cashew::Ref, cashew::DotZeroValueBuilder>::parseElement(char*&, char const*) + 335 frame #5: 0x000000010000e481 asm2wasmcashew::Parser<cashew::Ref, cashew::DotZeroValueBuilder>::parseElementOrStatement(char_&, char const_) + 577
      frame #6: 0x000000010000e0df asm2wasmcashew::Parser<cashew::Ref, cashew::DotZeroValueBuilder>::parseBlock(char*&, char const*, cashew::IString, cashew::IString) + 463 frame #7: 0x0000000100012eff asm2wasmcashew::Parser<cashew::Ref, cashew::DotZeroValueBuilder>::parseBracketedBlock(char_&) + 287
      frame #8: 0x000000010001350a asm2wasmcashew::Parser<cashew::Ref, cashew::DotZeroValueBuilder>::parseFunction(char_&, char const_) + 922 frame #9: 0x000000010000e8df asm2wasmcashew::Parser<cashew::Ref, cashew::DotZeroValueBuilder>::parseElement(char_&, char const_) + 335
      frame #10: 0x000000010000e481 asm2wasmcashew::Parser<cashew::Ref, cashew::DotZeroValueBuilder>::parseElementOrStatement(char_&, char const_) + 577 frame #11: 0x000000010000e0df asm2wasmcashew::Parser<cashew::Ref, cashew::DotZeroValueBuilder>::parseBlock(char_&, char const_, cashew::IString, cashew::IString) + 463
      frame #12: 0x0000000100012eff asm2wasmcashew::Parser<cashew::Ref, cashew::DotZeroValueBuilder>::parseBracketedBlock(char_&) + 287 frame #13: 0x000000010001350a asm2wasmcashew::Parser<cashew::Ref, cashew::DotZeroValueBuilder>::parseFunction(char*&, char const*) + 922
      frame #14: 0x000000010000e8df asm2wasmcashew::Parser<cashew::Ref, cashew::DotZeroValueBuilder>::parseElement(char_&, char const_) + 335 frame #15: 0x000000010000e481 asm2wasmcashew::Parser<cashew::Ref, cashew::DotZeroValueBuilder>::parseElementOrStatement(char*&, char const*) + 577
      frame #16: 0x000000010000e0df asm2wasmcashew::Parser<cashew::Ref, cashew::DotZeroValueBuilder>::parseBlock(char_&, char const_, cashew::IString, cashew::IString) + 463 frame #17: 0x000000010000485f asm2wasmmain + 463
      frame #18: 0x00007fff8fcc15fd libdyld.dylib`start + 1

Hoist common sub-expressions expression lists from the two paths of if_else operations

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)))))

Take advantage of the wider range of expressions in wasm.

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.

  1. Can the (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.
  2. It seems possible to hoist the set_local $i3 repeated in each if_else branch out of the if_else.
  3. It might then be clearer that the set_local $i3 get_local $i3 can be eliminated.
  4. This would fee the $i3 local which could be removed.
  5. The block $topmost still seems unnecessary - see #32
  6. See a few uses of if_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)))

Memory size from emcc

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?

s2wasm has incorrect tableswitch output

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.

Implement binary format

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?

Mysterious intermittent error

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).

Add a binaryen-shell pass to fold load/store index offsets into the wasm load/store immediate offsets.

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.

Figure out wasm2asm testing

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?

wasm-as: br and br_fi require a result expression.

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.

build errors

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;
                      ^

asm2wasm not folding away some redundant type coercions

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))))

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.