summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/emscripten-optimizer/simple_ast.cpp61
-rw-r--r--src/emscripten-optimizer/simple_ast.h9
-rw-r--r--src/tools/wasm2js.cpp125
-rw-r--r--test/wasm2js/br_table_to_loop.2asm.js6
-rw-r--r--test/wasm2js/fac.2asm.js8
-rw-r--r--test/wasm2js/i32.2asm.js2
-rw-r--r--test/wasm2js/i64-ctz.2asm.js2
-rw-r--r--test/wasm2js/i64.2asm.js6
-rw-r--r--test/wasm2js/int_exprs.2asm.js44
-rw-r--r--test/wasm2js/labels.2asm.js8
-rw-r--r--test/wasm2js/left-to-right.2asm.js4
-rw-r--r--test/wasm2js/loop.2asm.js10
-rw-r--r--test/wasm2js/stack-modified.2asm.js10
-rw-r--r--test/wasm2js/traps.2asm.js8
-rw-r--r--test/wasm2js/unary-ops.2asm.js4
15 files changed, 181 insertions, 126 deletions
diff --git a/src/emscripten-optimizer/simple_ast.cpp b/src/emscripten-optimizer/simple_ast.cpp
index d6dc5e51a..7575cc6f7 100644
--- a/src/emscripten-optimizer/simple_ast.cpp
+++ b/src/emscripten-optimizer/simple_ast.cpp
@@ -183,65 +183,4 @@ void dump(const char *str, Ref node, bool pretty) {
std::cerr << std::endl;
}
-// Traversals
-
-struct TraverseInfo {
- TraverseInfo() = default;
- TraverseInfo(Ref node) : node(node) {
- assert(node.get());
- if (node->isArray()) {
- for (size_t i = 0; i < node->size(); i++) {
- maybeAdd(node[i]);
- }
- } else if (node->isAssign()) {
- auto assign = node->asAssign();
- maybeAdd(assign->target());
- maybeAdd(assign->value());
- } else if (node->isAssignName()) {
- auto assign = node->asAssignName();
- maybeAdd(assign->value());
- } else {
- // no children
- }
- }
- Ref node;
- size_t index = -1;
- std::vector<Ref> children;
-
-private:
- void maybeAdd(Ref child) {
- if (child.get()) {
- children.push_back(child);
- }
- }
-};
-
-// Traverse, calling visit after the children
-void traversePost(Ref node, std::function<void (Ref)> visit) {
- std::vector<TraverseInfo> stack;
- stack.push_back(TraverseInfo(node));
- while (!stack.empty()) {
- TraverseInfo& back = stack.back();
- if (back.index == size_t(-1)) {
- // This is the first time we see this. Push its children.
- back.index = 0;
- for (auto child : back.children) {
- stack.emplace_back(child);
- }
- continue;
- }
- if (back.index < back.children.size()) {
- // Visit this child.
- back.index++;
- visit(back.children[back.index - 1]);
- continue;
- }
- assert(back.index == back.children.size());
- // Time to visit the node itself
- auto node = back.node;
- stack.pop_back();
- visit(node);
- }
-}
-
} // namespace cashew
diff --git a/src/emscripten-optimizer/simple_ast.h b/src/emscripten-optimizer/simple_ast.h
index 30ef42711..81d20e612 100644
--- a/src/emscripten-optimizer/simple_ast.h
+++ b/src/emscripten-optimizer/simple_ast.h
@@ -394,6 +394,10 @@ struct Value {
return arr->size();
}
+ bool empty() {
+ return size() == 0;
+ }
+
void setSize(size_t size) {
assert(isArray());
auto old = arr->size();
@@ -525,11 +529,6 @@ struct AssignName : public Value {
}
};
-// AST traversals
-
-// Traverse, calling visit after the children
-void traversePost(Ref node, std::function<void (Ref)> visit);
-
// JS printing support
struct JSPrinter {
diff --git a/src/tools/wasm2js.cpp b/src/tools/wasm2js.cpp
index 34ed2d9cb..84aa9f024 100644
--- a/src/tools/wasm2js.cpp
+++ b/src/tools/wasm2js.cpp
@@ -67,19 +67,79 @@ static void printJS(Ref ast, T& output) {
output << jser.buffer << std::endl;
}
+
+// Traversals
+
+struct TraverseInfo {
+ TraverseInfo() = default;
+ TraverseInfo(Ref node) : node(node) {
+ assert(node.get());
+ if (node->isArray()) {
+ for (size_t i = 0; i < node->size(); i++) {
+ maybeAdd(node[i]);
+ }
+ } else if (node->isAssign()) {
+ auto assign = node->asAssign();
+ maybeAdd(assign->target());
+ maybeAdd(assign->value());
+ } else if (node->isAssignName()) {
+ auto assign = node->asAssignName();
+ maybeAdd(assign->value());
+ } else {
+ // no children
+ }
+ }
+ Ref node;
+ bool scanned = false;
+ std::vector<Ref> children;
+
+private:
+ void maybeAdd(Ref child) {
+ if (child.get()) {
+ children.push_back(child);
+ }
+ }
+};
+
+// Traverse, calling visit after the children
+static void traversePrePost(Ref node, std::function<void (Ref)> visitPre, std::function<void (Ref)> visitPost) {
+ std::vector<TraverseInfo> stack;
+ stack.push_back(TraverseInfo(node));
+ while (!stack.empty()) {
+ TraverseInfo& back = stack.back();
+ if (!back.scanned) {
+ back.scanned = true;
+ // This is the first time we see this.
+ visitPre(back.node);
+ for (auto child : back.children) {
+ stack.emplace_back(child);
+ }
+ continue;
+ }
+ // Time to post-visit the node itself
+ auto node = back.node;
+ stack.pop_back();
+ visitPost(node);
+ }
+}
+
+static void traversePost(Ref node, std::function<void (Ref)> visit) {
+ traversePrePost(node, [](Ref node) {}, visit);
+}
+
static void optimizeJS(Ref ast) {
// helpers
auto isOrZero = [](Ref node) {
- return node->isArray() && node->size() > 0 && node[0] == BINARY && node[1] == OR && node[3]->isNumber() && node[3]->getNumber() == 0;
+ return node->isArray() && !node->empty() && node[0] == BINARY && node[1] == OR && node[3]->isNumber() && node[3]->getNumber() == 0;
};
auto isPlus = [](Ref node) {
- return node->isArray() && node->size() > 0 && node[0] == UNARY_PREFIX && node[1] == PLUS;
+ return node->isArray() && !node->empty() && node[0] == UNARY_PREFIX && node[1] == PLUS;
};
auto isBitwise = [](Ref node) {
- if (node->isArray() && node->size() > 0 && node[0] == BINARY) {
+ if (node->isArray() && !node->empty() && node[0] == BINARY) {
auto op = node[1];
return op == OR || op == AND || op == XOR || op == RSHIFT || op == TRSHIFT || op == LSHIFT;
}
@@ -88,7 +148,7 @@ static void optimizeJS(Ref ast) {
// x >> 0 => x | 0
traversePost(ast, [](Ref node) {
- if (node->isArray() && node->size() > 0 && node[0] == BINARY && node[1] == RSHIFT && node[3]->isNumber()) {
+ if (node->isArray() && !node->empty() && node[0] == BINARY && node[1] == RSHIFT && node[3]->isNumber()) {
if (node[3]->getNumber() == 0) {
node[1]->setString(OR);
}
@@ -124,6 +184,63 @@ static void optimizeJS(Ref ast) {
}
}
});
+
+ // Remove unnecessary break/continue labels, when referring to the top level.
+
+ // XXX IString invalid("__wasm2js$INVALID_LABEL__");
+ std::vector<Ref> breakCapturers;
+ std::vector<Ref> continueCapturers;
+ std::unordered_map<IString, Ref> labelToValue; // maps the label to the loop/etc.
+ std::unordered_set<Value*> labelled; // all things with a label on them.
+ Value INVALID;
+ traversePrePost(ast, [&](Ref node) {
+ if (node->isArray() && !node->empty()) {
+ if (node[0] == LABEL) {
+ auto label = node[1]->getIString();
+ labelToValue[label] = node[2];
+ labelled.insert(node[2].get());
+ } else if (node[0] == WHILE || node[0] == DO || node[0] == FOR) {
+ breakCapturers.push_back(node);
+ continueCapturers.push_back(node);
+ } else if (node[0] == cashew::BLOCK) {
+ if (labelled.count(node.get())) {
+ // Cannot break to a block without the label.
+ breakCapturers.push_back(Ref(&INVALID));
+ }
+ } else if (node[0] == SWITCH) {
+ breakCapturers.push_back(node);
+ }
+ }
+ }, [&](Ref node) {
+ if (node->isArray() && !node->empty()) {
+ if (node[0] == LABEL) {
+ auto label = node[1]->getIString();
+ labelToValue.erase(label);
+ labelled.erase(node[2].get());
+ } else if (node[0] == WHILE || node[0] == DO || node[0] == FOR) {
+ breakCapturers.pop_back();
+ continueCapturers.pop_back();
+ } else if (node[0] == cashew::BLOCK) {
+ if (labelled.count(node.get())) {
+ breakCapturers.pop_back();
+ }
+ } else if (node[0] == SWITCH) {
+ breakCapturers.pop_back();
+ } else if (node[0] == BREAK || node[0] == CONTINUE) {
+ if (!node[1]->isNull()) {
+ auto label = node[1]->getIString();
+ assert(labelToValue.count(label));
+ auto& capturers = node[0] == BREAK ? breakCapturers : continueCapturers;
+ assert(!capturers.empty());
+ if (capturers.back() == labelToValue[label]) {
+ // Success, the break/continue goes exactly where we would if we
+ // didn't have the label!
+ node[1]->setNull();
+ }
+ }
+ }
+ }
+ });
}
static void emitWasm(Module& wasm, Output& output, Wasm2JSBuilder::Flags flags, PassOptions options, Name name) {
diff --git a/test/wasm2js/br_table_to_loop.2asm.js b/test/wasm2js/br_table_to_loop.2asm.js
index 42f8081f2..408caf76e 100644
--- a/test/wasm2js/br_table_to_loop.2asm.js
+++ b/test/wasm2js/br_table_to_loop.2asm.js
@@ -28,7 +28,7 @@ function asmFunc(global, env, buffer) {
case 0:
break block;
case 1:
- continue loop;
+ continue;
default:
break block;
};
@@ -41,11 +41,11 @@ function asmFunc(global, env, buffer) {
loop : while (1) {
switch (1 | 0) {
case 0:
- continue loop;
+ continue;
case 1:
break block;
default:
- continue loop;
+ continue;
};
};
}
diff --git a/test/wasm2js/fac.2asm.js b/test/wasm2js/fac.2asm.js
index 9bc9896d6..58365051f 100644
--- a/test/wasm2js/fac.2asm.js
+++ b/test/wasm2js/fac.2asm.js
@@ -132,7 +132,7 @@ function asmFunc(global, env, buffer) {
$1$hi = i64toi32_i32$5;
}
}
- continue loop_in;
+ continue;
};
}
i64toi32_i32$5 = $2$hi;
@@ -179,7 +179,7 @@ function asmFunc(global, env, buffer) {
i$hi = i64toi32_i32$5;
}
}
- continue loop;
+ continue;
};
}
i64toi32_i32$5 = res$hi;
@@ -265,9 +265,9 @@ function asmFunc(global, env, buffer) {
}
}
if ($13) {
- continue loop_in
+ continue
}
- break loop_in;
+ break;
};
}
i64toi32_i32$2 = $1$hi;
diff --git a/test/wasm2js/i32.2asm.js b/test/wasm2js/i32.2asm.js
index 49c9c2f36..f3325de7e 100644
--- a/test/wasm2js/i32.2asm.js
+++ b/test/wasm2js/i32.2asm.js
@@ -208,7 +208,7 @@ function asmFunc(global, env, buffer) {
}
var$0 = var$0 & var$0 - 1;
var$1 = var$1 + 1 | 0;
- continue label$2;
+ continue;
};
}
return $5_1;
diff --git a/test/wasm2js/i64-ctz.2asm.js b/test/wasm2js/i64-ctz.2asm.js
index b135075b5..b95e2ebb5 100644
--- a/test/wasm2js/i64-ctz.2asm.js
+++ b/test/wasm2js/i64-ctz.2asm.js
@@ -236,7 +236,7 @@ function asmFunc(global, env, buffer) {
}
var$1 = i64toi32_i32$1;
var$1$hi = i64toi32_i32$4;
- continue label$2;
+ continue;
};
}
i64toi32_i32$4 = $5$hi;
diff --git a/test/wasm2js/i64.2asm.js b/test/wasm2js/i64.2asm.js
index 30dc5e536..28816af86 100644
--- a/test/wasm2js/i64.2asm.js
+++ b/test/wasm2js/i64.2asm.js
@@ -3357,9 +3357,9 @@ function asmFunc(global, env, buffer) {
var$7$hi = i64toi32_i32$3;
var$2 = var$2 + -1 | 0;
if (var$2) {
- continue label$15
+ continue
}
- break label$15;
+ break;
};
break label$13;
}
@@ -3556,7 +3556,7 @@ function asmFunc(global, env, buffer) {
}
var$1 = i64toi32_i32$1;
var$1$hi = i64toi32_i32$4;
- continue label$2;
+ continue;
};
}
i64toi32_i32$4 = $5$hi;
diff --git a/test/wasm2js/int_exprs.2asm.js b/test/wasm2js/int_exprs.2asm.js
index e5b4d8658..f12322311 100644
--- a/test/wasm2js/int_exprs.2asm.js
+++ b/test/wasm2js/int_exprs.2asm.js
@@ -1719,9 +1719,9 @@ function asmFunc(global, env, buffer) {
var$7$hi = i64toi32_i32$3;
var$2 = var$2 + -1 | 0;
if (var$2) {
- continue label$15
+ continue
}
- break label$15;
+ break;
};
break label$13;
}
@@ -2629,9 +2629,9 @@ function asmFunc(global, env, buffer) {
var$7$hi = i64toi32_i32$3;
var$2 = var$2 + -1 | 0;
if (var$2) {
- continue label$15
+ continue
}
- break label$15;
+ break;
};
break label$13;
}
@@ -3397,9 +3397,9 @@ function asmFunc(global, env, buffer) {
var$7$hi = i64toi32_i32$3;
var$2 = var$2 + -1 | 0;
if (var$2) {
- continue label$15
+ continue
}
- break label$15;
+ break;
};
break label$13;
}
@@ -4152,9 +4152,9 @@ function asmFunc(global, env, buffer) {
var$7$hi = i64toi32_i32$3;
var$2 = var$2 + -1 | 0;
if (var$2) {
- continue label$15
+ continue
}
- break label$15;
+ break;
};
break label$13;
}
@@ -4950,9 +4950,9 @@ function asmFunc(global, env, buffer) {
var$7$hi = i64toi32_i32$3;
var$2 = var$2 + -1 | 0;
if (var$2) {
- continue label$15
+ continue
}
- break label$15;
+ break;
};
break label$13;
}
@@ -5762,9 +5762,9 @@ function asmFunc(global, env, buffer) {
var$7$hi = i64toi32_i32$3;
var$2 = var$2 + -1 | 0;
if (var$2) {
- continue label$15
+ continue
}
- break label$15;
+ break;
};
break label$13;
}
@@ -6574,9 +6574,9 @@ function asmFunc(global, env, buffer) {
var$7$hi = i64toi32_i32$3;
var$2 = var$2 + -1 | 0;
if (var$2) {
- continue label$15
+ continue
}
- break label$15;
+ break;
};
break label$13;
}
@@ -7386,9 +7386,9 @@ function asmFunc(global, env, buffer) {
var$7$hi = i64toi32_i32$3;
var$2 = var$2 + -1 | 0;
if (var$2) {
- continue label$15
+ continue
}
- break label$15;
+ break;
};
break label$13;
}
@@ -8213,9 +8213,9 @@ function asmFunc(global, env, buffer) {
var$7$hi = i64toi32_i32$3;
var$2 = var$2 + -1 | 0;
if (var$2) {
- continue label$15
+ continue
}
- break label$15;
+ break;
};
break label$13;
}
@@ -9042,9 +9042,9 @@ function asmFunc(global, env, buffer) {
var$7$hi = i64toi32_i32$3;
var$2 = var$2 + -1 | 0;
if (var$2) {
- continue label$15
+ continue
}
- break label$15;
+ break;
};
break label$13;
}
@@ -9871,9 +9871,9 @@ function asmFunc(global, env, buffer) {
var$7$hi = i64toi32_i32$3;
var$2 = var$2 + -1 | 0;
if (var$2) {
- continue label$15
+ continue
}
- break label$15;
+ break;
};
break label$13;
}
diff --git a/test/wasm2js/labels.2asm.js b/test/wasm2js/labels.2asm.js
index e92791960..ded00aab1 100644
--- a/test/wasm2js/labels.2asm.js
+++ b/test/wasm2js/labels.2asm.js
@@ -42,7 +42,7 @@ function asmFunc(global, env, buffer) {
break exit;
}
}
- continue cont;
+ continue;
};
}
return $6_1 | 0;
@@ -55,7 +55,7 @@ function asmFunc(global, env, buffer) {
cont : while (1) {
i = i + 1 | 0;
if ((i | 0) == (5 | 0)) {
- continue cont
+ continue
}
if ((i | 0) == (8 | 0)) {
{
@@ -64,7 +64,7 @@ function asmFunc(global, env, buffer) {
}
}
i = i + 1 | 0;
- continue cont;
+ continue;
};
}
return $8_1 | 0;
@@ -99,7 +99,7 @@ function asmFunc(global, env, buffer) {
break exit;
}
}
- continue cont;
+ continue;
};
}
return $9_1 | 0;
diff --git a/test/wasm2js/left-to-right.2asm.js b/test/wasm2js/left-to-right.2asm.js
index 7f8a952d9..681490ca7 100644
--- a/test/wasm2js/left-to-right.2asm.js
+++ b/test/wasm2js/left-to-right.2asm.js
@@ -2045,9 +2045,9 @@ function asmFunc(global, env, buffer) {
var$7$hi = i64toi32_i32$3;
var$2 = var$2 + -1 | 0;
if (var$2) {
- continue label$15
+ continue
}
- break label$15;
+ break;
};
break label$13;
}
diff --git a/test/wasm2js/loop.2asm.js b/test/wasm2js/loop.2asm.js
index ab6a3b130..7bd07e083 100644
--- a/test/wasm2js/loop.2asm.js
+++ b/test/wasm2js/loop.2asm.js
@@ -210,7 +210,7 @@ function asmFunc(global, env, buffer) {
var $0 = 0, $1_1 = 0, $2_1 = 0, $3_1 = 0, $5_1 = 0;
$0 = 0;
$1_1 = $0;
- loop_in : while (1) continue loop_in;
+ loop_in : while (1) continue;
}
function fx() {
@@ -253,7 +253,7 @@ function asmFunc(global, env, buffer) {
i64toi32_i32$5 = i64toi32_i32$0 - i64toi32_i32$5 | 0;
$0 = $0 - i64toi32_i32$3 | 0;
$0$hi = i64toi32_i32$5;
- continue loop_in;
+ continue;
};
}
i64toi32_i32$5 = $1$hi;
@@ -293,7 +293,7 @@ function asmFunc(global, env, buffer) {
}
$2_1 = i64toi32_i32$4;
$2$hi = i64toi32_i32$5;
- continue loop_in;
+ continue;
};
}
i64toi32_i32$5 = $1$hi;
@@ -321,12 +321,12 @@ function asmFunc(global, env, buffer) {
}
$3_1 = Math_fround($3_1 + $2_1);
$2_1 = Math_fround($2_1 - Math_fround(2.0));
- continue loop_in72;
+ continue;
};
}
$3_1 = Math_fround($3_1 / $0);
$0 = Math_fround($0 - Math_fround(1.0));
- continue loop_in;
+ continue;
};
}
return Math_fround($3_1);
diff --git a/test/wasm2js/stack-modified.2asm.js b/test/wasm2js/stack-modified.2asm.js
index 84c59cadb..1514be5bd 100644
--- a/test/wasm2js/stack-modified.2asm.js
+++ b/test/wasm2js/stack-modified.2asm.js
@@ -62,7 +62,7 @@ function asmFunc(global, env, buffer) {
var$1$hi = i64toi32_i32$5;
}
}
- continue label$2;
+ continue;
};
}
i64toi32_i32$5 = var$2$hi;
@@ -109,7 +109,7 @@ function asmFunc(global, env, buffer) {
var$1$hi = i64toi32_i32$5;
}
}
- continue label$2;
+ continue;
};
}
i64toi32_i32$5 = var$2$hi;
@@ -156,7 +156,7 @@ function asmFunc(global, env, buffer) {
var$1$hi = i64toi32_i32$5;
}
}
- continue label$2;
+ continue;
};
}
i64toi32_i32$5 = var$2$hi;
@@ -203,7 +203,7 @@ function asmFunc(global, env, buffer) {
var$1$hi = i64toi32_i32$5;
}
}
- continue label$2;
+ continue;
};
}
i64toi32_i32$5 = var$2$hi;
@@ -250,7 +250,7 @@ function asmFunc(global, env, buffer) {
var$1$hi = i64toi32_i32$5;
}
}
- continue label$2;
+ continue;
};
}
i64toi32_i32$5 = var$2$hi;
diff --git a/test/wasm2js/traps.2asm.js b/test/wasm2js/traps.2asm.js
index 5ab7b0759..36fdb06ca 100644
--- a/test/wasm2js/traps.2asm.js
+++ b/test/wasm2js/traps.2asm.js
@@ -787,9 +787,9 @@ function asmFunc(global, env, buffer) {
var$7$hi = i64toi32_i32$3;
var$2 = var$2 + -1 | 0;
if (var$2) {
- continue label$15
+ continue
}
- break label$15;
+ break;
};
break label$13;
}
@@ -1686,9 +1686,9 @@ function asmFunc(global, env, buffer) {
var$7$hi = i64toi32_i32$3;
var$2 = var$2 + -1 | 0;
if (var$2) {
- continue label$15
+ continue
}
- break label$15;
+ break;
};
break label$13;
}
diff --git a/test/wasm2js/unary-ops.2asm.js b/test/wasm2js/unary-ops.2asm.js
index d0831c7e4..a8348ced1 100644
--- a/test/wasm2js/unary-ops.2asm.js
+++ b/test/wasm2js/unary-ops.2asm.js
@@ -469,7 +469,7 @@ function asmFunc(global, env, buffer) {
}
var$0 = var$0 & var$0 - 1;
var$1 = var$1 + 1 | 0;
- continue label$2;
+ continue;
};
}
return $5_1;
@@ -515,7 +515,7 @@ function asmFunc(global, env, buffer) {
}
var$1 = i64toi32_i32$1;
var$1$hi = i64toi32_i32$4;
- continue label$2;
+ continue;
};
}
i64toi32_i32$4 = $5$hi;