summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlon Zakai <azakai@google.com>2019-05-15 17:50:49 -0700
committerGitHub <noreply@github.com>2019-05-15 17:50:49 -0700
commitf86375ac2121db5fec236f4e35f73adde9318a8c (patch)
tree5f6cf343615df7e97c988c719ad5a3d214e13f9d
parentcff4b756e61dad01aa1965ceb4d76a24de7413c5 (diff)
downloadbinaryen-f86375ac2121db5fec236f4e35f73adde9318a8c.tar.gz
binaryen-f86375ac2121db5fec236f4e35f73adde9318a8c.tar.bz2
binaryen-f86375ac2121db5fec236f4e35f73adde9318a8c.zip
wasm2js: more coercion optimization (#2109)
-rw-r--r--src/tools/wasm2js.cpp57
-rw-r--r--test/wasm2js/br_table_temp.2asm.js.opt2
-rw-r--r--test/wasm2js/emscripten.2asm.js42
-rw-r--r--test/wasm2js/emscripten.2asm.js.opt42
-rw-r--r--test/wasm2js/emscripten.wast85
5 files changed, 209 insertions, 19 deletions
diff --git a/src/tools/wasm2js.cpp b/src/tools/wasm2js.cpp
index b3f8068e2..731efbee0 100644
--- a/src/tools/wasm2js.cpp
+++ b/src/tools/wasm2js.cpp
@@ -145,9 +145,20 @@ static void replaceInPlaceIfPossible(Ref target, Ref value) {
static void optimizeJS(Ref ast) {
// Helpers
- auto isOrZero = [](Ref node) {
+ auto isBinary = [](Ref node, IString op) {
return node->isArray() && !node->empty() && node[0] == BINARY &&
- node[1] == OR && node[3]->isNumber() && node[3]->getNumber() == 0;
+ node[1] == op;
+ };
+
+ auto isConstantBinary = [&](Ref node, IString op, int num) {
+ return isBinary(node, op) && node[3]->isNumber() &&
+ node[3]->getNumber() == num;
+ };
+
+ auto isOrZero = [&](Ref node) { return isConstantBinary(node, OR, 0); };
+
+ auto isTrshiftZero = [&](Ref node) {
+ return isConstantBinary(node, TRSHIFT, 0);
};
auto isPlus = [](Ref node) {
@@ -174,11 +185,6 @@ static void optimizeJS(Ref ast) {
node[1] == op;
};
- auto isConstantBitwise = [](Ref node, IString op, int num) {
- return node->isArray() && !node->empty() && node[0] == BINARY &&
- node[1] == op && node[3]->isNumber() && node[3]->getNumber() == num;
- };
-
auto isWhile = [](Ref node) {
return node->isArray() && !node->empty() && node[0] == WHILE;
};
@@ -243,11 +249,14 @@ static void optimizeJS(Ref ast) {
};
auto optimizeBoolean = [&](Ref node) {
- // x ^ 1 => !x
- if (isConstantBitwise(node, XOR, 1)) {
+ if (isConstantBinary(node, XOR, 1)) {
+ // x ^ 1 => !x
node[0]->setString(UNARY_PREFIX);
node[1]->setString(L_NOT);
node[3]->setNull();
+ } else if (isOrZero(node) || isTrshiftZero(node)) {
+ // Just being different from 0 is enough, casts don't matter.
+ return node[2];
}
return node;
};
@@ -257,7 +266,7 @@ static void optimizeJS(Ref ast) {
// Pre-simplification
traversePost(ast, [&](Ref node) {
// x >> 0 => x | 0
- if (isConstantBitwise(node, RSHIFT, 0)) {
+ if (isConstantBinary(node, RSHIFT, 0)) {
node[1]->setString(OR);
}
});
@@ -270,10 +279,7 @@ static void optimizeJS(Ref ast) {
// 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];
+ replaceInPlace(node, node[2]);
}
}
if (isHeapAccess(node[2])) {
@@ -284,7 +290,7 @@ static void optimizeJS(Ref ast) {
if (isIntegerHeap(heap)) {
replacementHeap = heap;
}
- } else if (isConstantBitwise(node, TRSHIFT, 0)) {
+ } else if (isTrshiftZero(node)) {
// For signed or unsigned loads smaller than 32 bits, doing an | 0
// was safe either way - they aren't in the range an | 0 can affect.
// For >>> 0 however, a negative value would change, so we still
@@ -308,7 +314,7 @@ static void optimizeJS(Ref ast) {
// better performance (perhaps since HEAPU32 is at risk of not being a
// smallint).
if (node[1] == AND) {
- if (isConstantBitwise(node, AND, 1)) {
+ if (isConstantBinary(node, AND, 1)) {
if (heap == HEAPU8) {
setHeapOnAccess(node[2], HEAP8);
} else if (heap == HEAPU16) {
@@ -348,6 +354,21 @@ static void optimizeJS(Ref ast) {
} else if (isUnary(node, L_NOT)) {
node[2] = optimizeBoolean(node[2]);
}
+ // Add/subtract can merge coercions up.
+ else if (isBinary(node, PLUS) || isBinary(node, MINUS)) {
+ auto left = node[2];
+ auto right = node[3];
+ if (isOrZero(left) && isOrZero(right)) {
+ auto op = node[1]->getIString();
+ // Add a coercion on top.
+ node[1]->setString(OR);
+ node[2] = left;
+ node[3] = ValueBuilder::makeNum(0);
+ // Add/subtract the inner uncoerced values.
+ left[1]->setString(op);
+ left[3] = right[2];
+ }
+ }
// Assignment into a heap coerces.
else if (node->isAssign()) {
auto assign = node->asAssign();
@@ -357,12 +378,12 @@ static void optimizeJS(Ref ast) {
if (isIntegerHeap(heap)) {
if (heap == HEAP8 || heap == HEAPU8) {
while (isOrZero(assign->value()) ||
- isConstantBitwise(assign->value(), AND, 255)) {
+ isConstantBinary(assign->value(), AND, 255)) {
assign->value() = assign->value()[2];
}
} else if (heap == HEAP16 || heap == HEAPU16) {
while (isOrZero(assign->value()) ||
- isConstantBitwise(assign->value(), AND, 65535)) {
+ isConstantBinary(assign->value(), AND, 65535)) {
assign->value() = assign->value()[2];
}
} else {
diff --git a/test/wasm2js/br_table_temp.2asm.js.opt b/test/wasm2js/br_table_temp.2asm.js.opt
index 5620f829f..4633a99e3 100644
--- a/test/wasm2js/br_table_temp.2asm.js.opt
+++ b/test/wasm2js/br_table_temp.2asm.js.opt
@@ -12662,7 +12662,7 @@ function asmFunc(global, env, buffer) {
function $63($0) {
$0 = $0 | 0;
- if ($0 - 1 | 0) {
+ if ($0 - 1) {
$0 = 9
} else {
$0 = 8
diff --git a/test/wasm2js/emscripten.2asm.js b/test/wasm2js/emscripten.2asm.js
index 3cbb33a35..6304e9b9d 100644
--- a/test/wasm2js/emscripten.2asm.js
+++ b/test/wasm2js/emscripten.2asm.js
@@ -90,6 +90,48 @@ function asmFunc(global, env, buffer) {
if ((HEAPU8[144 >> 0] | 0) >>> 0 < 3 >>> 0) {
bar()
}
+ if ((bools(314159 | 0) | 0) >>> 7 | 0) {
+ bar()
+ }
+ if ((bools(314159 | 0) | 0) >> 8 | 0) {
+ bar()
+ }
+ if (~~Math_fround(getf32()) >>> 0) {
+ bar()
+ }
+ if (~~Math_fround(getf32())) {
+ bar()
+ }
+ if (~~+getf64() >>> 0) {
+ bar()
+ }
+ if (~~+getf64()) {
+ bar()
+ }
+ if (((geti32() | 0) + (geti32() | 0) | 0) + (geti32() | 0) | 0) {
+ bar()
+ }
+ if ((geti32() | 0) + ((geti32() | 0) + (geti32() | 0) | 0) | 0) {
+ bar()
+ }
+ if (((geti32() | 0) + (geti32() | 0) | 0) + ((geti32() | 0) + (geti32() | 0) | 0) | 0) {
+ bar()
+ }
+ if ((((geti32() | 0) + (geti32() | 0) | 0) + ((geti32() | 0) + (geti32() | 0) | 0) | 0) + (((geti32() | 0) + (geti32() | 0) | 0) + ((geti32() | 0) + (geti32() | 0) | 0) | 0) | 0) {
+ bar()
+ }
+ }
+
+ function geti32() {
+ return geti32() | 0 | 0;
+ }
+
+ function getf32() {
+ return Math_fround(Math_fround(getf32()));
+ }
+
+ function getf64() {
+ return +(+getf64());
}
function __growWasmMemory($0) {
diff --git a/test/wasm2js/emscripten.2asm.js.opt b/test/wasm2js/emscripten.2asm.js.opt
index 682daaf85..69251d9bb 100644
--- a/test/wasm2js/emscripten.2asm.js.opt
+++ b/test/wasm2js/emscripten.2asm.js.opt
@@ -83,6 +83,48 @@ function asmFunc(global, env, buffer) {
if (HEAPU8[144] < 3) {
bar()
}
+ if (bools(314159) >>> 7) {
+ bar()
+ }
+ if (bools(314159) >> 8) {
+ bar()
+ }
+ if (~~getf32()) {
+ bar()
+ }
+ if (~~getf32()) {
+ bar()
+ }
+ if (~~getf64()) {
+ bar()
+ }
+ if (~~getf64()) {
+ bar()
+ }
+ if ((geti32() + geti32() | 0) + geti32()) {
+ bar()
+ }
+ if (geti32() + (geti32() + geti32() | 0)) {
+ bar()
+ }
+ if (geti32() + geti32() + (geti32() + geti32())) {
+ bar()
+ }
+ if (geti32() + geti32() + (geti32() + geti32()) + (geti32() + geti32() + (geti32() + geti32()))) {
+ bar()
+ }
+ }
+
+ function geti32() {
+ return geti32();
+ }
+
+ function getf32() {
+ return getf32();
+ }
+
+ function getf64() {
+ return getf64();
}
function __growWasmMemory($0) {
diff --git a/test/wasm2js/emscripten.wast b/test/wasm2js/emscripten.wast
index f6ad7aae7..5b1b81507 100644
--- a/test/wasm2js/emscripten.wast
+++ b/test/wasm2js/emscripten.wast
@@ -110,6 +110,91 @@
(if (i32.lt_u (i32.load8_u (i32.const 144)) (i32.const 3))
(call $bar)
)
+ (if (i32.shr_u (call $bools (i32.const 314159)) (i32.const 7))
+ (call $bar)
+ )
+ (if (i32.shr_s (call $bools (i32.const 314159)) (i32.const 8))
+ (call $bar)
+ )
+ (if (i32.trunc_f32_u (call $getf32))
+ (call $bar)
+ )
+ (if (i32.trunc_f32_s (call $getf32))
+ (call $bar)
+ )
+ (if (i32.trunc_f64_u (call $getf64))
+ (call $bar)
+ )
+ (if (i32.trunc_f64_s (call $getf64))
+ (call $bar)
+ )
+ (if
+ (i32.add
+ (i32.add
+ (call $geti32)
+ (call $geti32)
+ )
+ (call $geti32)
+ )
+ (call $bar)
+ )
+ (if
+ (i32.add
+ (call $geti32)
+ (i32.add
+ (call $geti32)
+ (call $geti32)
+ )
+ )
+ (call $bar)
+ )
+ (if
+ (i32.add
+ (i32.add
+ (call $geti32)
+ (call $geti32)
+ )
+ (i32.add
+ (call $geti32)
+ (call $geti32)
+ )
+ )
+ (call $bar)
+ )
+ (if
+ (i32.add
+ (i32.add
+ (i32.add
+ (call $geti32)
+ (call $geti32)
+ )
+ (i32.add
+ (call $geti32)
+ (call $geti32)
+ )
+ )
+ (i32.add
+ (i32.add
+ (call $geti32)
+ (call $geti32)
+ )
+ (i32.add
+ (call $geti32)
+ (call $geti32)
+ )
+ )
+ )
+ (call $bar)
+ )
+ )
+ (func $geti32 (result i32)
+ (call $geti32)
+ )
+ (func $getf32 (result f32)
+ (call $getf32)
+ )
+ (func $getf64 (result f64)
+ (call $getf64)
)
(func $__growWasmMemory (param $0 i32) (result i32)
(grow_memory