diff options
-rw-r--r-- | src/tools/wasm2js.cpp | 78 | ||||
-rw-r--r-- | test/wasm2js/emscripten.2asm.js | 8 | ||||
-rw-r--r-- | test/wasm2js/emscripten.2asm.js.opt | 8 | ||||
-rw-r--r-- | test/wasm2js/emscripten.wast | 10 |
4 files changed, 78 insertions, 26 deletions
diff --git a/src/tools/wasm2js.cpp b/src/tools/wasm2js.cpp index 611b00803..00ea23e7d 100644 --- a/src/tools/wasm2js.cpp +++ b/src/tools/wasm2js.cpp @@ -155,9 +155,26 @@ static void optimizeJS(Ref ast) { return false; }; - auto isConstantAnd = [](Ref node, int num) { + auto isUnary = [](Ref node, IString op) { + return node->isArray() && !node->empty() && node[0] == UNARY_PREFIX && + node[1] == op; + }; + + auto isConstantBitwise = [](Ref node, IString op, int num) { return node->isArray() && !node->empty() && node[0] == BINARY && - node[1] == AND && node[3]->isNumber() && node[3]->getNumber() == num; + node[1] == op && node[3]->isNumber() && node[3]->getNumber() == num; + }; + + auto isWhile = [](Ref node) { + return node->isArray() && !node->empty() && node[0] == WHILE; + }; + + auto isDo = [](Ref node) { + return node->isArray() && !node->empty() && node[0] == DO; + }; + + auto isIf = [](Ref node) { + return node->isArray() && !node->empty() && node[0] == IF; }; auto removeOrZero = [&](Ref node) { @@ -211,35 +228,40 @@ static void optimizeJS(Ref ast) { return false; }; + auto optimizeBoolean = [&](Ref node) { + // x ^ 1 => !x + if (isConstantBitwise(node, XOR, 1)) { + node[0]->setString(UNARY_PREFIX); + node[1]->setString(L_NOT); + node[3]->setNull(); + } + return node; + }; + // Optimizations - // x >> 0 => x | 0 - traversePost(ast, [](Ref node) { - if (node->isArray() && !node->empty() && node[0] == BINARY && - node[1] == RSHIFT && node[3]->isNumber()) { - if (node[3]->getNumber() == 0) { - node[1]->setString(OR); - } + // Pre-simplification + traversePost(ast, [&](Ref node) { + // x >> 0 => x | 0 + if (isConstantBitwise(node, RSHIFT, 0)) { + node[1]->setString(OR); } }); traversePost(ast, [&](Ref node) { - // x | 0 | 0 => x | 0 - if (isOrZero(node)) { - while (isOrZero(node[2])) { - node[2] = node[2][2]; - } - if (isBitwise(node[2])) { - auto child = node[2]; - node[1] = child[1]; - node[2] = child[2]; - node[3] = child[3]; - } - } - // x | 0 going into a bitwise op => skip the | 0 - else if (isBitwise(node)) { + if (isBitwise(node)) { + // x | 0 going into a bitwise op => skip the | 0 node[2] = removeOrZero(node[2]); node[3] = removeOrZero(node[3]); + // x | 0 | 0 => x | 0 + if (isOrZero(node)) { + if (isBitwise(node[2])) { + auto child = node[2]; + node[1] = child[1]; + node[2] = child[2]; + node[3] = child[3]; + } + } // A load into an & may allow using a simpler heap, e.g. HEAPU8[..] & 1 // (a load of a boolean) may be HEAP8[..] & 1. The signed heaps are more // commonly used, so it compresses better, and also they seem to have @@ -247,7 +269,7 @@ static void optimizeJS(Ref ast) { // smallint). if (node[1] == AND && isHeapAccess(node[2])) { auto heap = getHeapFromAccess(node[2]); - if (isConstantAnd(node, 1)) { + if (isConstantBitwise(node, AND, 1)) { if (heap == HEAPU8) { setHeapOnAccess(node[2], HEAP8); } else if (heap == HEAPU16) { @@ -263,6 +285,8 @@ static void optimizeJS(Ref ast) { // +(+x) => +x else if (isFround(node)) { node[2] = removePlusAndFround(node[2]); + } else if (isUnary(node, L_NOT)) { + node[2] = optimizeBoolean(node[2]); } // Assignment into a heap coerces. else if (node->isAssign()) { @@ -273,12 +297,12 @@ static void optimizeJS(Ref ast) { if (isIntegerHeap(heap)) { if (heap == HEAP8 || heap == HEAPU8) { while (isOrZero(assign->value()) || - isConstantAnd(assign->value(), 255)) { + isConstantBitwise(assign->value(), AND, 255)) { assign->value() = assign->value()[2]; } } else if (heap == HEAP16 || heap == HEAPU16) { while (isOrZero(assign->value()) || - isConstantAnd(assign->value(), 65535)) { + isConstantBitwise(assign->value(), AND, 65535)) { assign->value() = assign->value()[2]; } } else { @@ -294,6 +318,8 @@ static void optimizeJS(Ref ast) { } } } + } else if (isWhile(node) || isDo(node) || isIf(node)) { + node[1] = optimizeBoolean(node[1]); } }); diff --git a/test/wasm2js/emscripten.2asm.js b/test/wasm2js/emscripten.2asm.js index 339429be0..91838daf9 100644 --- a/test/wasm2js/emscripten.2asm.js +++ b/test/wasm2js/emscripten.2asm.js @@ -93,6 +93,14 @@ function asmFunc(global, env, buffer) { bools((HEAP16[0 >> 1] | 0) & 1 | 0 | 0) | 0; bools((HEAP32[0 >> 2] | 0) & 1 | 0 | 0) | 0; bools((HEAPU8[0 >> 0] | 0) & 2 | 0 | 0) | 0; + bools(x ^ 1 | 0 | 0) | 0; + if (x ^ 1 | 0) { + bools(2 | 0) | 0 + } + if (x ^ 2 | 0) { + bools(2 | 0) | 0 + } + bools(!(x ^ 1 | 0) | 0) | 0; abort(); } diff --git a/test/wasm2js/emscripten.2asm.js.opt b/test/wasm2js/emscripten.2asm.js.opt index 315279a56..bb4569b7f 100644 --- a/test/wasm2js/emscripten.2asm.js.opt +++ b/test/wasm2js/emscripten.2asm.js.opt @@ -74,6 +74,14 @@ function asmFunc(global, env, buffer) { bools(HEAP16[0 >> 1] & 1); bools(HEAP32[0 >> 2] & 1); bools(HEAPU8[0 | 0] & 2); + bools($0 ^ 1); + if (!$0) { + bools(2) + } + if ($0 ^ 2) { + bools(2) + } + bools(!!$0); abort(); } diff --git a/test/wasm2js/emscripten.wast b/test/wasm2js/emscripten.wast index 07caf4f87..05c290fb9 100644 --- a/test/wasm2js/emscripten.wast +++ b/test/wasm2js/emscripten.wast @@ -106,6 +106,16 @@ (drop (call $bools (i32.and (i32.load16_s (i32.const 0)) (i32.const 1)))) (drop (call $bools (i32.and (i32.load (i32.const 0)) (i32.const 1)))) (drop (call $bools (i32.and (i32.load8_u (i32.const 0)) (i32.const 2)))) + (drop (call $bools (i32.xor (local.get $x) (i32.const 1)))) + (if + (i32.xor (local.get $x) (i32.const 1)) + (drop (call $bools (i32.const 2))) + ) + (if + (i32.xor (local.get $x) (i32.const 2)) + (drop (call $bools (i32.const 2))) + ) + (drop (call $bools (i32.eqz (i32.xor (local.get $x) (i32.const 1))))) (unreachable) ) ) |