aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--tests/test_other.py3
-rw-r--r--tools/js-optimizer.js106
-rw-r--r--tools/test-js-optimizer-si-output.js34
-rw-r--r--tools/test-js-optimizer-si.js52
4 files changed, 164 insertions, 31 deletions
diff --git a/tests/test_other.py b/tests/test_other.py
index 4a62384c..0c597e9f 100644
--- a/tests/test_other.py
+++ b/tests/test_other.py
@@ -2591,6 +2591,7 @@ int main()
main = src[src.find('function _main'):src.find('\n}', src.find('function _main'))]
actual_ifs = main.count('if (')
assert ifs == actual_ifs, main + ' : ' + str([ifs, actual_ifs])
+ #print main
test(r'''
#include <stdio.h>
@@ -2617,5 +2618,5 @@ int main()
}
return 0;
}
- ''', [8, 6, 6])
+ ''', [8, 5, 5])
diff --git a/tools/js-optimizer.js b/tools/js-optimizer.js
index e57bab0f..c38b51d5 100644
--- a/tools/js-optimizer.js
+++ b/tools/js-optimizer.js
@@ -838,38 +838,86 @@ function simplifyExpressions(ast) {
function simplifyIfs(ast) {
- traverse(ast, function(node, type) {
- // simplify if (x) { if (y) { .. } } to if (x ? y : 0) { .. }
- if (type === 'if') {
- var body = node[2];
- // recurse to handle chains
- while (body[0] === 'block') {
- var stats = body[1];
- if (stats.length === 0) break;
- var other = stats[stats.length-1];
- if (other[0] !== 'if') break;
- // we can handle elses, but must be fully identical
- if (!astCompare(node[3], other[3])) break;
- if (stats.length > 1) {
- // try to commaify - turn everything between the ifs into a comma operator inside the second if
- var ok = true;
- for (var i = 0; i < stats.length-1; i++) {
- var curr = stats[i];
- if (curr[0] === 'stat') curr = curr[1];
- if (!(curr[0] in COMMABLE)) ok = false;
- }
- if (!ok) break;
- for (var i = stats.length-2; i >= 0; i--) {
- var curr = stats[i];
- if (curr[0] === 'stat') curr = curr[1];
- other[1] = ['seq', curr, other[1]];
+ traverseGeneratedFunctions(ast, function(func) {
+ var simplifiedAnElse = false;
+
+ traverse(func, function(node, type) {
+ // simplify if (x) { if (y) { .. } } to if (x ? y : 0) { .. }
+ if (type === 'if') {
+ var body = node[2];
+ // recurse to handle chains
+ while (body[0] === 'block') {
+ var stats = body[1];
+ if (stats.length === 0) break;
+ var other = stats[stats.length-1];
+ if (other[0] !== 'if') break;
+ // we can handle elses, but must be fully identical
+ if (!astCompare(node[3], other[3])) break;
+ if (stats.length > 1) {
+ // try to commaify - turn everything between the ifs into a comma operator inside the second if
+ var ok = true;
+ for (var i = 0; i < stats.length-1; i++) {
+ var curr = stats[i];
+ if (curr[0] === 'stat') curr = curr[1];
+ if (!(curr[0] in COMMABLE)) ok = false;
+ }
+ if (!ok) break;
+ for (var i = stats.length-2; i >= 0; i--) {
+ var curr = stats[i];
+ if (curr[0] === 'stat') curr = curr[1];
+ other[1] = ['seq', curr, other[1]];
+ }
+ stats = body[1] = [other];
}
- stats = body[1] = [other];
+ if (stats.length !== 1) break;
+ if (node[3]) simplifiedAnElse = true;
+ node[1] = ['conditional', node[1], other[1], ['num', 0]];
+ body = node[2] = other[2];
}
- if (stats.length !== 1) break;
- node[1] = ['conditional', node[1], other[1], ['num', 0]];
- body = node[2] = other[2];
}
+ });
+
+ if (simplifiedAnElse) {
+ // there may be fusing opportunities
+ traverse(func, function(node, type) {
+ var stats = getStatements(node);
+ if (stats) {
+ for (var i = 0; i < stats.length-1; i++) {
+ var pre = stats[i];
+ var post = stats[i+1];
+ if (pre[0] === 'if' && pre[3] && post[0] === 'if' && !post[3]) {
+ var postCond = post[1];
+ if (postCond[0] === 'binary' && postCond[1] === '==' &&
+ postCond[2][0] === 'binary' && postCond[2][1] === '|' &&
+ postCond[2][2][0] === 'name' && postCond[2][2][1] === 'label' &&
+ postCond[2][3][0] === 'num' && postCond[2][3][1] === 0 &&
+ postCond[3][0] === 'num') {
+ var postValue = postCond[3][1];
+ var preElse = pre[3];
+ if (preElse[0] === 'block' && preElse[1] && preElse[1].length === 1) {
+ var preStat = preElse[1][0];
+ if (preStat[0] === 'stat' && preStat[1][0] === 'assign' &&
+ preStat[1][1] === true && preStat[1][2][0] === 'name' && preStat[1][2][1] === 'label' &&
+ preStat[1][3][0] === 'num' && preStat[1][3][1] === postValue) {
+ // Conditions match, just need to make sure the post clears label
+ if (post[2][0] === 'block' && post[2][1] && post[2][1].length > 0) {
+ var postStat = post[2][1][0];
+ if (postStat[0] === 'stat' && postStat[1][0] === 'assign' &&
+ postStat[1][1] === true && postStat[1][2][0] === 'name' && postStat[1][2][1] === 'label' &&
+ postStat[1][3][0] === 'num' && postStat[1][3][1] === 0) {
+ // Everything lines up, do it
+ pre[3] = post[2];
+ pre[3][1].splice(0, 1); // remove the label clearing
+ stats.splice(i+1, 1); // remove the post entirely
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ });
}
});
}
diff --git a/tools/test-js-optimizer-si-output.js b/tools/test-js-optimizer-si-output.js
index 97d7fe83..a6e8f53e 100644
--- a/tools/test-js-optimizer-si-output.js
+++ b/tools/test-js-optimizer-si-output.js
@@ -103,5 +103,39 @@ function a() {
} else {
label = 5;
}
+ fuseElses();
+ if (x ? y : 0) {
+ f();
+ } else {
+ a();
+ }
+ if (x ? y : 0) {
+ f();
+ } else {
+ label = 5;
+ }
+ if ((label | 0) == 6) {
+ label = 0;
+ a();
+ }
+ if (x ? y : 0) {
+ f();
+ } else {
+ label = 5;
+ }
+ if ((label | 0) == 5) {
+ a();
+ }
+}
+function b() {
+ if (x) {
+ a();
+ } else {
+ label = 5;
+ }
+ if ((label | 0) == 5) {
+ label = 0;
+ a();
+ }
}
diff --git a/tools/test-js-optimizer-si.js b/tools/test-js-optimizer-si.js
index def2b5d9..78683d6c 100644
--- a/tools/test-js-optimizer-si.js
+++ b/tools/test-js-optimizer-si.js
@@ -125,5 +125,55 @@ function a() {
} else {
label = 5;
}
+ fuseElses();
+ if (x) {
+ if (y) {
+ f();
+ } else {
+ label = 5;
+ }
+ } else {
+ label = 5;
+ }
+ if ((label|0) == 5) {
+ label = 0;
+ a();
+ }
+ if (x) {
+ if (y) {
+ f();
+ } else {
+ label = 5;
+ }
+ } else {
+ label = 5;
+ }
+ if ((label|0) == 6) {
+ label = 0;
+ a();
+ }
+ if (x) {
+ if (y) {
+ f();
+ } else {
+ label = 5;
+ }
+ } else {
+ label = 5;
+ }
+ if ((label|0) == 5) {
+ a();
+ }
+}
+function b() {
+ if (x) { // will not be fused, since we did not eliminate with elses
+ a();
+ } else {
+ label = 5;
+ }
+ if ((label|0) == 5) {
+ label = 0;
+ a();
+ }
}
-
+// EMSCRIPTEN_GENERATED_FUNCTIONS: ["a", "b"]