From b20cc12248336a7d53ebc2e8d07afe04ee56a22e Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Mon, 29 Apr 2019 16:27:29 -0700 Subject: [PATCH 1/5] optimize casts going into a store --- src/tools/wasm2js.cpp | 85 +++++++++++++++++++++++++++++---- test/wasm2js/emscripten.2asm.js | 3 ++ test/wasm2js/emscripten.wast | 12 +++++ 3 files changed, 91 insertions(+), 9 deletions(-) diff --git a/src/tools/wasm2js.cpp b/src/tools/wasm2js.cpp index 3d5f484da94..965c2897424 100644 --- a/src/tools/wasm2js.cpp +++ b/src/tools/wasm2js.cpp @@ -129,7 +129,7 @@ static void traversePost(Ref node, std::function visit) { } static void optimizeJS(Ref ast) { - // helpers + // Helpers auto isOrZero = [](Ref node) { return node->isArray() && !node->empty() && node[0] == BINARY && @@ -141,6 +141,11 @@ static void optimizeJS(Ref ast) { node[1] == PLUS; }; + auto isFround = [](Ref node) { + return node->isArray() && !node->empty() && node[0] == cashew::CALL && + node[1] == MATH_FROUND; + }; + auto isBitwise = [](Ref node) { if (node->isArray() && !node->empty() && node[0] == BINARY) { auto op = node[1]; @@ -150,6 +155,57 @@ static void optimizeJS(Ref ast) { return false; }; + auto removeOrZero = [&](Ref node) { + while (isOrZero(node)) { + node = node[2]; + } + return node; + }; + + auto removePlus = [&](Ref node) { + while (isPlus(node)) { + node = node[2]; + } + return node; + }; + + auto removePlusAndFround = [&](Ref node) { + while (1) { + if (isFround(node)) { + node = node[2][0]; + } else if (isPlus(node)) { + node = node[2]; + } else { + break; + } + } + return node; + }; + + auto getHeapFromAccess = [](Ref node) { + return node[1]->getIString(); + }; + + auto isIntegerHeap = [](IString heap) { + return heap == HEAP8 || heap == HEAPU8 || + heap == HEAP16 || heap == HEAPU16 || + heap == HEAP32 || heap == HEAPU32; + }; + + auto isFloatHeap = [](IString heap) { + return heap == HEAPF32 || heap == HEAPF64; + }; + + auto isHeapAccess = [&](Ref node) { + if (node->isArray() && !node->empty() && node[0] == SUB && node[1]->isString()) { + auto heap = getHeapFromAccess(node); + return isIntegerHeap(heap) || isFloatHeap(heap); + } + return false; + }; + + // Optimizations + // x >> 0 => x | 0 traversePost(ast, [](Ref node) { if (node->isArray() && !node->empty() && node[0] == BINARY && @@ -175,17 +231,28 @@ static void optimizeJS(Ref ast) { } // x | 0 going into a bitwise op => skip the | 0 else if (isBitwise(node)) { - while (isOrZero(node[2])) { - node[2] = node[2][2]; - } - while (isOrZero(node[3])) { - node[3] = node[3][2]; - } + node[2] = removeOrZero(node[2]); + node[3] = removeOrZero(node[3]); } // +(+x) => +x else if (isPlus(node)) { - while (isPlus(node[2])) { - node[2] = node[2][2]; + node[2] = removePlus(node[2]); + } else if (node->isAssign()) { + // Assignment into a heap coerces. + auto assign = node->asAssign(); + auto target = assign->target(); + if (isHeapAccess(target)) { + auto heap = getHeapFromAccess(target); + if (isIntegerHeap(heap)) { + assign->value() = removeOrZero(assign->value()); + } else { + assert(isFloatHeap(heap)); + if (heap == HEAPF32) { + assign->value() = removePlusAndFround(assign->value()); + } else { + assign->value() = removePlus(assign->value()); + } + } } } }); diff --git a/test/wasm2js/emscripten.2asm.js b/test/wasm2js/emscripten.2asm.js index 0b1d7ee67f7..27e74a2edb0 100644 --- a/test/wasm2js/emscripten.2asm.js +++ b/test/wasm2js/emscripten.2asm.js @@ -48,6 +48,9 @@ function asmFunc(global, env, buffer) { HEAP8[128 | 0]; HEAPU16[128 >> 1]; HEAP16[128 >> 1]; + HEAP32[16 >> 2] = 1 + 2; + HEAPF32[16 >> 2] = Math_fround(3.0) + Math_fround(4.0); + HEAPF64[16 >> 3] = 5.0 + 6.0; } function __growWasmMemory($0) { diff --git a/test/wasm2js/emscripten.wast b/test/wasm2js/emscripten.wast index 7305f0dc914..f60e763c25c 100644 --- a/test/wasm2js/emscripten.wast +++ b/test/wasm2js/emscripten.wast @@ -52,6 +52,18 @@ (i32.const 128) ) ) + (i32.store + (i32.const 16) + (i32.add (i32.const 1) (i32.const 2)) + ) + (f32.store + (i32.const 16) + (f32.add (f32.const 3) (f32.const 4)) + ) + (f64.store + (i32.const 16) + (f64.add (f64.const 5) (f64.const 6)) + ) ) (func $__growWasmMemory (param $0 i32) (result i32) (grow_memory From 0c5cbfad1ca41473418d5531116a3e84d609325c Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Mon, 29 Apr 2019 16:35:27 -0700 Subject: [PATCH 2/5] more --- src/tools/wasm2js.cpp | 24 +++++++++++++++++++++--- test/wasm2js/emscripten.2asm.js | 2 ++ test/wasm2js/emscripten.wast | 8 ++++++++ test/wasm2js/endianness.2asm.js | 2 +- test/wasm2js/left-to-right.2asm.js | 2 +- test/wasm2js/unaligned.2asm.js | 12 ++++++------ 6 files changed, 39 insertions(+), 11 deletions(-) diff --git a/src/tools/wasm2js.cpp b/src/tools/wasm2js.cpp index 965c2897424..123970767bb 100644 --- a/src/tools/wasm2js.cpp +++ b/src/tools/wasm2js.cpp @@ -155,6 +155,12 @@ static void optimizeJS(Ref ast) { return false; }; + auto isConstantAnd = [](Ref node, int num) { + return node->isArray() && !node->empty() && node[0] == BINARY && + node[1] == AND && node[3]->isNumber() && + node[3]->getNumber() == num; + }; + auto removeOrZero = [&](Ref node) { while (isOrZero(node)) { node = node[2]; @@ -237,14 +243,26 @@ static void optimizeJS(Ref ast) { // +(+x) => +x else if (isPlus(node)) { node[2] = removePlus(node[2]); - } else if (node->isAssign()) { - // Assignment into a heap coerces. + } + // Assignment into a heap coerces. + else if (node->isAssign()) { auto assign = node->asAssign(); auto target = assign->target(); if (isHeapAccess(target)) { auto heap = getHeapFromAccess(target); if (isIntegerHeap(heap)) { - assign->value() = removeOrZero(assign->value()); + if (heap == HEAP8 || heap == HEAPU8) { + while (isOrZero(assign->value()) || isConstantAnd(assign->value(), 255)) { + assign->value() = assign->value()[2]; + } + } else if (heap == HEAP16 || heap == HEAPU16) { + while (isOrZero(assign->value()) || isConstantAnd(assign->value(), 65535)) { + assign->value() = assign->value()[2]; + } + } else { + assert(heap == HEAP32 || heap == HEAPU32); + assign->value() = removeOrZero(assign->value()); + } } else { assert(isFloatHeap(heap)); if (heap == HEAPF32) { diff --git a/test/wasm2js/emscripten.2asm.js b/test/wasm2js/emscripten.2asm.js index 27e74a2edb0..52828f46e55 100644 --- a/test/wasm2js/emscripten.2asm.js +++ b/test/wasm2js/emscripten.2asm.js @@ -51,6 +51,8 @@ function asmFunc(global, env, buffer) { HEAP32[16 >> 2] = 1 + 2; HEAPF32[16 >> 2] = Math_fround(3.0) + Math_fround(4.0); HEAPF64[16 >> 3] = 5.0 + 6.0; + HEAP8[16 | 0] = 7 + 8; + HEAP16[16 >> 1] = 9 + 10; } function __growWasmMemory($0) { diff --git a/test/wasm2js/emscripten.wast b/test/wasm2js/emscripten.wast index f60e763c25c..8f797f8fcc6 100644 --- a/test/wasm2js/emscripten.wast +++ b/test/wasm2js/emscripten.wast @@ -64,6 +64,14 @@ (i32.const 16) (f64.add (f64.const 5) (f64.const 6)) ) + (i32.store8 + (i32.const 16) + (i32.add (i32.const 7) (i32.const 8)) + ) + (i32.store16 + (i32.const 16) + (i32.add (i32.const 9) (i32.const 10)) + ) ) (func $__growWasmMemory (param $0 i32) (result i32) (grow_memory diff --git a/test/wasm2js/endianness.2asm.js b/test/wasm2js/endianness.2asm.js index 3bd0c42a8d0..65a8d0f2d48 100644 --- a/test/wasm2js/endianness.2asm.js +++ b/test/wasm2js/endianness.2asm.js @@ -264,7 +264,7 @@ function asmFunc(global, env, buffer) { i64toi32_i32$0 = value$hi; i64toi32_i32$1 = 0; HEAP32[i64toi32_i32$1 >> 2] = value; - (wasm2js_i32$0 = i64toi32_i32$1, wasm2js_i32$1 = i64toi32_i32$0), ((HEAP8[wasm2js_i32$0 + 4 | 0] = wasm2js_i32$1 & 255, HEAP8[wasm2js_i32$0 + 5 | 0] = wasm2js_i32$1 >>> 8 & 255), HEAP8[wasm2js_i32$0 + 6 | 0] = wasm2js_i32$1 >>> 16 & 255), HEAP8[wasm2js_i32$0 + 7 | 0] = wasm2js_i32$1 >>> 24 & 255; + (wasm2js_i32$0 = i64toi32_i32$1, wasm2js_i32$1 = i64toi32_i32$0), ((HEAP8[wasm2js_i32$0 + 4 | 0] = wasm2js_i32$1, HEAP8[wasm2js_i32$0 + 5 | 0] = wasm2js_i32$1 >>> 8), HEAP8[wasm2js_i32$0 + 6 | 0] = wasm2js_i32$1 >>> 16), HEAP8[wasm2js_i32$0 + 7 | 0] = wasm2js_i32$1 >>> 24; i64toi32_i32$0 = i64_load_little(0); i64toi32_i32$1 = i64toi32_i32$HIGH_BITS; i64toi32_i32$HIGH_BITS = i64toi32_i32$1; diff --git a/test/wasm2js/left-to-right.2asm.js b/test/wasm2js/left-to-right.2asm.js index 681490ca78f..3e7c1b02190 100644 --- a/test/wasm2js/left-to-right.2asm.js +++ b/test/wasm2js/left-to-right.2asm.js @@ -950,7 +950,7 @@ function asmFunc(global, env, buffer) { $1 = i64toi32_i32$0; i64toi32_i32$0 = $0; HEAP32[i64toi32_i32$0 >> 2] = $1; - (wasm2js_i32$0 = i64toi32_i32$0, wasm2js_i32$1 = i64toi32_i32$1), ((HEAP8[wasm2js_i32$0 + 4 | 0] = wasm2js_i32$1 & 255, HEAP8[wasm2js_i32$0 + 5 | 0] = wasm2js_i32$1 >>> 8 & 255), HEAP8[wasm2js_i32$0 + 6 | 0] = wasm2js_i32$1 >>> 16 & 255), HEAP8[wasm2js_i32$0 + 7 | 0] = wasm2js_i32$1 >>> 24 & 255; + (wasm2js_i32$0 = i64toi32_i32$0, wasm2js_i32$1 = i64toi32_i32$1), ((HEAP8[wasm2js_i32$0 + 4 | 0] = wasm2js_i32$1, HEAP8[wasm2js_i32$0 + 5 | 0] = wasm2js_i32$1 >>> 8), HEAP8[wasm2js_i32$0 + 6 | 0] = wasm2js_i32$1 >>> 16), HEAP8[wasm2js_i32$0 + 7 | 0] = wasm2js_i32$1 >>> 24; return get() | 0; } diff --git a/test/wasm2js/unaligned.2asm.js b/test/wasm2js/unaligned.2asm.js index 51e4bf26936..6996fd1b944 100644 --- a/test/wasm2js/unaligned.2asm.js +++ b/test/wasm2js/unaligned.2asm.js @@ -84,19 +84,19 @@ function asmFunc(global, env, buffer) { function $4() { var wasm2js_i32$0 = 0, wasm2js_i32$1 = 0; - (wasm2js_i32$0 = 0, wasm2js_i32$1 = 0), ((HEAP8[wasm2js_i32$0 | 0] = wasm2js_i32$1 & 255, HEAP8[wasm2js_i32$0 + 1 | 0] = wasm2js_i32$1 >>> 8 & 255), HEAP8[wasm2js_i32$0 + 2 | 0] = wasm2js_i32$1 >>> 16 & 255), HEAP8[wasm2js_i32$0 + 3 | 0] = wasm2js_i32$1 >>> 24 & 255; + (wasm2js_i32$0 = 0, wasm2js_i32$1 = 0), ((HEAP8[wasm2js_i32$0 | 0] = wasm2js_i32$1, HEAP8[wasm2js_i32$0 + 1 | 0] = wasm2js_i32$1 >>> 8), HEAP8[wasm2js_i32$0 + 2 | 0] = wasm2js_i32$1 >>> 16), HEAP8[wasm2js_i32$0 + 3 | 0] = wasm2js_i32$1 >>> 24; } function $5() { var i64toi32_i32$1 = 0, wasm2js_i32$0 = 0, wasm2js_i32$1 = 0; i64toi32_i32$1 = 0; - (wasm2js_i32$0 = i64toi32_i32$1, wasm2js_i32$1 = 0), ((HEAP8[wasm2js_i32$0 | 0] = wasm2js_i32$1 & 255, HEAP8[wasm2js_i32$0 + 1 | 0] = wasm2js_i32$1 >>> 8 & 255), HEAP8[wasm2js_i32$0 + 2 | 0] = wasm2js_i32$1 >>> 16 & 255), HEAP8[wasm2js_i32$0 + 3 | 0] = wasm2js_i32$1 >>> 24 & 255; - (wasm2js_i32$0 = i64toi32_i32$1, wasm2js_i32$1 = 0), ((HEAP8[wasm2js_i32$0 + 4 | 0] = wasm2js_i32$1 & 255, HEAP8[wasm2js_i32$0 + 5 | 0] = wasm2js_i32$1 >>> 8 & 255), HEAP8[wasm2js_i32$0 + 6 | 0] = wasm2js_i32$1 >>> 16 & 255), HEAP8[wasm2js_i32$0 + 7 | 0] = wasm2js_i32$1 >>> 24 & 255; + (wasm2js_i32$0 = i64toi32_i32$1, wasm2js_i32$1 = 0), ((HEAP8[wasm2js_i32$0 | 0] = wasm2js_i32$1, HEAP8[wasm2js_i32$0 + 1 | 0] = wasm2js_i32$1 >>> 8), HEAP8[wasm2js_i32$0 + 2 | 0] = wasm2js_i32$1 >>> 16), HEAP8[wasm2js_i32$0 + 3 | 0] = wasm2js_i32$1 >>> 24; + (wasm2js_i32$0 = i64toi32_i32$1, wasm2js_i32$1 = 0), ((HEAP8[wasm2js_i32$0 + 4 | 0] = wasm2js_i32$1, HEAP8[wasm2js_i32$0 + 5 | 0] = wasm2js_i32$1 >>> 8), HEAP8[wasm2js_i32$0 + 6 | 0] = wasm2js_i32$1 >>> 16), HEAP8[wasm2js_i32$0 + 7 | 0] = wasm2js_i32$1 >>> 24; } function $6() { var wasm2js_i32$0 = 0, wasm2js_i32$1 = 0; - (wasm2js_i32$0 = 0, wasm2js_i32$1 = (wasm2js_scratch_store_f32(Math_fround(0.0)), wasm2js_scratch_load_i32(0))), ((HEAP8[wasm2js_i32$0 | 0] = wasm2js_i32$1 & 255, HEAP8[wasm2js_i32$0 + 1 | 0] = wasm2js_i32$1 >>> 8 & 255), HEAP8[wasm2js_i32$0 + 2 | 0] = wasm2js_i32$1 >>> 16 & 255), HEAP8[wasm2js_i32$0 + 3 | 0] = wasm2js_i32$1 >>> 24 & 255; + (wasm2js_i32$0 = 0, wasm2js_i32$1 = (wasm2js_scratch_store_f32(Math_fround(0.0)), wasm2js_scratch_load_i32(0))), ((HEAP8[wasm2js_i32$0 | 0] = wasm2js_i32$1, HEAP8[wasm2js_i32$0 + 1 | 0] = wasm2js_i32$1 >>> 8), HEAP8[wasm2js_i32$0 + 2 | 0] = wasm2js_i32$1 >>> 16), HEAP8[wasm2js_i32$0 + 3 | 0] = wasm2js_i32$1 >>> 24; } function $7() { @@ -104,8 +104,8 @@ function asmFunc(global, env, buffer) { wasm2js_scratch_store_f64(0.0); i64toi32_i32$0 = wasm2js_scratch_load_i32(1 | 0) | 0; i64toi32_i32$1 = 0; - (wasm2js_i32$0 = i64toi32_i32$1, wasm2js_i32$1 = wasm2js_scratch_load_i32(0 | 0) | 0), ((HEAP8[wasm2js_i32$0 | 0] = wasm2js_i32$1 & 255, HEAP8[wasm2js_i32$0 + 1 | 0] = wasm2js_i32$1 >>> 8 & 255), HEAP8[wasm2js_i32$0 + 2 | 0] = wasm2js_i32$1 >>> 16 & 255), HEAP8[wasm2js_i32$0 + 3 | 0] = wasm2js_i32$1 >>> 24 & 255; - (wasm2js_i32$0 = i64toi32_i32$1, wasm2js_i32$1 = i64toi32_i32$0), ((HEAP8[wasm2js_i32$0 + 4 | 0] = wasm2js_i32$1 & 255, HEAP8[wasm2js_i32$0 + 5 | 0] = wasm2js_i32$1 >>> 8 & 255), HEAP8[wasm2js_i32$0 + 6 | 0] = wasm2js_i32$1 >>> 16 & 255), HEAP8[wasm2js_i32$0 + 7 | 0] = wasm2js_i32$1 >>> 24 & 255; + (wasm2js_i32$0 = i64toi32_i32$1, wasm2js_i32$1 = wasm2js_scratch_load_i32(0 | 0) | 0), ((HEAP8[wasm2js_i32$0 | 0] = wasm2js_i32$1, HEAP8[wasm2js_i32$0 + 1 | 0] = wasm2js_i32$1 >>> 8), HEAP8[wasm2js_i32$0 + 2 | 0] = wasm2js_i32$1 >>> 16), HEAP8[wasm2js_i32$0 + 3 | 0] = wasm2js_i32$1 >>> 24; + (wasm2js_i32$0 = i64toi32_i32$1, wasm2js_i32$1 = i64toi32_i32$0), ((HEAP8[wasm2js_i32$0 + 4 | 0] = wasm2js_i32$1, HEAP8[wasm2js_i32$0 + 5 | 0] = wasm2js_i32$1 >>> 8), HEAP8[wasm2js_i32$0 + 6 | 0] = wasm2js_i32$1 >>> 16), HEAP8[wasm2js_i32$0 + 7 | 0] = wasm2js_i32$1 >>> 24; } function legalstub$1() { From 69526d1690d7f5c64240e535cad6f73a6f648fed Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Mon, 29 Apr 2019 16:36:46 -0700 Subject: [PATCH 3/5] todo --- src/tools/wasm2js.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/tools/wasm2js.cpp b/src/tools/wasm2js.cpp index 123970767bb..a09759f89d0 100644 --- a/src/tools/wasm2js.cpp +++ b/src/tools/wasm2js.cpp @@ -244,6 +244,10 @@ static void optimizeJS(Ref ast) { else if (isPlus(node)) { node[2] = removePlus(node[2]); } + // +(+x) => +x + else if (isFround(node)) { + node[2] = removePlusAndFround(node[2]); + } // Assignment into a heap coerces. else if (node->isAssign()) { auto assign = node->asAssign(); From 3c63f363e3482b21f0d54a18713f62aa71739086 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 30 Apr 2019 10:51:07 -0700 Subject: [PATCH 4/5] format --- src/tools/wasm2js.cpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/tools/wasm2js.cpp b/src/tools/wasm2js.cpp index a09759f89d0..885130b1174 100644 --- a/src/tools/wasm2js.cpp +++ b/src/tools/wasm2js.cpp @@ -125,7 +125,8 @@ static void traversePrePost(Ref node, } static void traversePost(Ref node, std::function visit) { - traversePrePost(node, [](Ref node) {}, visit); + traversePrePost( + node, [](Ref node) {}, visit); } static void optimizeJS(Ref ast) { @@ -157,8 +158,7 @@ static void optimizeJS(Ref ast) { auto isConstantAnd = [](Ref node, int num) { return node->isArray() && !node->empty() && node[0] == BINARY && - node[1] == AND && node[3]->isNumber() && - node[3]->getNumber() == num; + node[1] == AND && node[3]->isNumber() && node[3]->getNumber() == num; }; auto removeOrZero = [&](Ref node) { @@ -188,14 +188,11 @@ static void optimizeJS(Ref ast) { return node; }; - auto getHeapFromAccess = [](Ref node) { - return node[1]->getIString(); - }; + auto getHeapFromAccess = [](Ref node) { return node[1]->getIString(); }; auto isIntegerHeap = [](IString heap) { - return heap == HEAP8 || heap == HEAPU8 || - heap == HEAP16 || heap == HEAPU16 || - heap == HEAP32 || heap == HEAPU32; + return heap == HEAP8 || heap == HEAPU8 || heap == HEAP16 || + heap == HEAPU16 || heap == HEAP32 || heap == HEAPU32; }; auto isFloatHeap = [](IString heap) { @@ -203,7 +200,8 @@ static void optimizeJS(Ref ast) { }; auto isHeapAccess = [&](Ref node) { - if (node->isArray() && !node->empty() && node[0] == SUB && node[1]->isString()) { + if (node->isArray() && !node->empty() && node[0] == SUB && + node[1]->isString()) { auto heap = getHeapFromAccess(node); return isIntegerHeap(heap) || isFloatHeap(heap); } @@ -256,11 +254,13 @@ static void optimizeJS(Ref ast) { auto heap = getHeapFromAccess(target); if (isIntegerHeap(heap)) { if (heap == HEAP8 || heap == HEAPU8) { - while (isOrZero(assign->value()) || isConstantAnd(assign->value(), 255)) { + while (isOrZero(assign->value()) || + isConstantAnd(assign->value(), 255)) { assign->value() = assign->value()[2]; } } else if (heap == HEAP16 || heap == HEAPU16) { - while (isOrZero(assign->value()) || isConstantAnd(assign->value(), 65535)) { + while (isOrZero(assign->value()) || + isConstantAnd(assign->value(), 65535)) { assign->value() = assign->value()[2]; } } else { From 25d8848065d5e091c2a9f8059b2403475ee9211b Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 30 Apr 2019 12:28:14 -0700 Subject: [PATCH 5/5] format --- src/tools/wasm2js.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/tools/wasm2js.cpp b/src/tools/wasm2js.cpp index 885130b1174..6e465687881 100644 --- a/src/tools/wasm2js.cpp +++ b/src/tools/wasm2js.cpp @@ -125,8 +125,7 @@ static void traversePrePost(Ref node, } static void traversePost(Ref node, std::function visit) { - traversePrePost( - node, [](Ref node) {}, visit); + traversePrePost(node, [](Ref node) {}, visit); } static void optimizeJS(Ref ast) {