aboutsummaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/js-optimizer.js75
-rw-r--r--tools/shared.py6
-rw-r--r--tools/test-js-optimizer-asm-pre-output.js60
-rw-r--r--tools/test-js-optimizer-asm-pre.js62
4 files changed, 201 insertions, 2 deletions
diff --git a/tools/js-optimizer.js b/tools/js-optimizer.js
index 2914b6e8..f38ff08c 100644
--- a/tools/js-optimizer.js
+++ b/tools/js-optimizer.js
@@ -749,11 +749,71 @@ function simplifyExpressions(ast) {
});
}
+ function emitsBoolean(node) {
+ if (node[0] === 'binary') return node[1] in COMPARE_OPS;
+ if (node[0] === 'unary-prefix') return node[1] === '!';
+ if (node[0] === 'conditional') return true;
+ return false;
+ }
+
+ // expensive | expensive can be turned into expensive ? 1 : expensive, and
+ // expensive | cheap can be turned into cheap ? 1 : expensive,
+ // so that we can avoid the expensive computation, if it has no side effects.
+ function conditionalize(ast) {
+ var MIN_COST = 7;
+ traverse(ast, function(node, type) {
+ if (node[0] === 'binary' && (node[1] === '|' || node[1] === '&') && node[3][0] !== 'num' && node[2][0] !== 'num') {
+ // logical operator on two non-numerical values
+ var left = node[2];
+ var right = node[3];
+ if (!emitsBoolean(left) || !emitsBoolean(right)) return;
+ var leftEffects = hasSideEffects(left);
+ var rightEffects = hasSideEffects(right);
+ if (leftEffects && rightEffects) return; // both must execute
+ // canonicalize with side effects, if any, happening on the left
+ if (rightEffects) {
+ if (measureCost(left) < MIN_COST) return; // avoidable code is too cheap
+ var temp = left;
+ left = right;
+ right = temp;
+ } else if (leftEffects) {
+ if (measureCost(right) < MIN_COST) return; // avoidable code is too cheap
+ } else {
+ // no side effects, reorder based on cost estimation
+ var leftCost = measureCost(left);
+ var rightCost = measureCost(right);
+ if (Math.max(leftCost, rightCost) < MIN_COST) return; // avoidable code is too cheap
+ // canonicalize with expensive code on the right
+ if (leftCost > rightCost) {
+ var temp = left;
+ left = right;
+ right = temp;
+ }
+ }
+ // worth it, perform conditionalization
+ var ret;
+ if (node[1] === '|') {
+ ret = ['conditional', left, ['num', 1], right];
+ } else { // &
+ ret = ['conditional', left, right, ['num', 0]];
+ }
+ if (left[0] === 'unary-prefix' && left[1] === '!') {
+ ret[1] = flipCondition(left);
+ var temp = ret[2];
+ ret[2] = ret[3];
+ ret[3] = temp;
+ }
+ return ret;
+ }
+ });
+ }
+
traverseGeneratedFunctions(ast, function(func) {
simplifyIntegerConversions(func);
simplifyBitops(func);
joinAdditions(func);
simplifyNotComps(func);
+ conditionalize(func);
// simplifyZeroComp(func); TODO: investigate performance
});
}
@@ -3921,6 +3981,21 @@ function measureSize(ast) {
return size;
}
+function measureCost(ast) {
+ var size = 0;
+ traverse(ast, function(node, type) {
+ if (type === 'num' || type === 'unary-prefix') size--;
+ else if (type === 'binary') {
+ if (node[3][0] === 'num' && node[3][1] === 0) size--;
+ else if (node[1] === '/' || node[1] === '%') size += 2;
+ }
+ else if (type === 'call' && !callHasSideEffects(node)) size -= 2;
+ else if (type === 'sub') size++;
+ size++;
+ });
+ return size;
+}
+
function aggressiveVariableEliminationInternal(func, asmData) {
// This removes as many variables as possible. This is often not the best thing because it increases
// code size, but it is far preferable to the risk of split functions needing to do more spilling, so
diff --git a/tools/shared.py b/tools/shared.py
index 826baa83..5305d46b 100644
--- a/tools/shared.py
+++ b/tools/shared.py
@@ -1836,7 +1836,11 @@ def unsuffixed_basename(name):
return os.path.basename(unsuffixed(name))
def safe_move(src, dst):
- if os.path.abspath(src) == os.path.abspath(dst):
+ src = os.path.abspath(src)
+ dst = os.path.abspath(dst)
+ if os.path.isdir(dst):
+ dst = os.path.join(dst, os.path.basename(src))
+ if src == dst:
return
shutil.move(src, dst)
diff --git a/tools/test-js-optimizer-asm-pre-output.js b/tools/test-js-optimizer-asm-pre-output.js
index c9746e78..31b9cfd7 100644
--- a/tools/test-js-optimizer-asm-pre-output.js
+++ b/tools/test-js-optimizer-asm-pre-output.js
@@ -538,4 +538,64 @@ function fcomp() {
if (5 >= ($b | 0)) return 5;
if (5 >= 5) return 5;
}
+function conditionalizeMe() {
+ if (x > 1 ? x + y + z + w > 12 : 0) {
+ b();
+ }
+ if (a() > 1 ? x + y + z + w > 12 : 0) {
+ b();
+ }
+ if (x > 1 & x + y + z + k() > 12) {
+ b();
+ }
+ if (a() > 1 & x + y + z + k() > 12) {
+ b();
+ }
+ if (x > 1 ? 1 : x + y + z + w > 12) {
+ b();
+ }
+ if (a() > 1 ? 1 : x + y + z + w > 12) {
+ b();
+ }
+ if (x > 1 | x + y + z + k() > 12) {
+ b();
+ }
+ if (a() > 1 | x + y + z + k() > 12) {
+ b();
+ }
+ if (x > 1 ? 1 : x + y + z + w > 12) {
+ b();
+ }
+ if (a() > 1 ? 1 : x + y + z + w > 12) {
+ b();
+ }
+ if (x + y + z + k() > 12 | x > 1) {
+ b();
+ }
+ if (x + y + z + k() > 12 | a() > 1) {
+ b();
+ }
+ while (x > 1 ? x + y + z + w > 12 : 0) {
+ b();
+ }
+ while (a() > 1 ? x + y + z + w > 12 : 0) {
+ b();
+ }
+ while (x > 1 & x + y + z + k() > 12) {
+ b();
+ }
+ while (a() > 1 & x + y + z + k() > 12) {
+ b();
+ }
+ if (!($sub$i480 >= Math_fround(+0)) | !($sub4$i483 >= Math_fround(+0))) {
+ b();
+ }
+ if ($sub$i480 >= Math_fround(+0) ? !($sub4$i483 >= Math_fround(HEAPF32[x + y | 0])) : 1) {
+ b();
+ }
+ if (x > 10 | HEAP[20] + 2 > 5) {
+ b();
+ }
+ return (((((Math_imul(i6 + 1, i7) | 0) + 17 | 0) % 5 | 0) == 0 ? 1 : ((((Math_imul(i7 + 1, i7) | 0) + 11 | 0) >>> 0) % 3 | 0) == 0) | 0) == 0;
+}
diff --git a/tools/test-js-optimizer-asm-pre.js b/tools/test-js-optimizer-asm-pre.js
index 00ebd7d7..2a6ea4a9 100644
--- a/tools/test-js-optimizer-asm-pre.js
+++ b/tools/test-js-optimizer-asm-pre.js
@@ -550,4 +550,64 @@ function fcomp() {
if (!(5 < ($b|0))) return 5;
if (!(5 < 5)) return 5;
}
-// EMSCRIPTEN_GENERATED_FUNCTIONS: ["a", "b", "rett", "ret2t", "retf", "i32_8", "tempDoublePtr", "boxx", "_main", "badf", "badf2", "fcomp"]
+function conditionalizeMe() {
+ if ((x > 1) & (x+y+z+w > 12)) {
+ b();
+ }
+ if ((a() > 1) & (x+y+z+w > 12)) {
+ b();
+ }
+ if ((x > 1) & (x+y+z+k() > 12)) {
+ b();
+ }
+ if ((a() > 1) & (x+y+z+k() > 12)) {
+ b();
+ }
+ if ((x > 1) | (x+y+z+w > 12)) {
+ b();
+ }
+ if ((a() > 1) | (x+y+z+w > 12)) {
+ b();
+ }
+ if ((x > 1) | (x+y+z+k() > 12)) {
+ b();
+ }
+ if ((a() > 1) | (x+y+z+k() > 12)) {
+ b();
+ }
+ if ((x+y+z+w > 12) | (x > 1)) {
+ b();
+ }
+ if ((x+y+z+w > 12) | (a() > 1)) {
+ b();
+ }
+ if ((x+y+z+k() > 12) | (x > 1)) {
+ b();
+ }
+ if ((x+y+z+k() > 12) | (a() > 1)) {
+ b();
+ }
+ while ((x > 1) & (x+y+z+w > 12)) {
+ b();
+ }
+ while ((a() > 1) & (x+y+z+w > 12)) {
+ b();
+ }
+ while ((x > 1) & (x+y+z+k() > 12)) {
+ b();
+ }
+ while ((a() > 1) & (x+y+z+k() > 12)) {
+ b();
+ }
+ if (!($sub$i480 >= Math_fround(+0)) | !($sub4$i483 >= Math_fround(+0))) {
+ b();
+ }
+ if (!($sub$i480 >= Math_fround(+0)) | !($sub4$i483 >= Math_fround(HEAPF32[x+y|0]))) {
+ b();
+ }
+ if (x > 10 | (HEAP[20] + 2) > 5) {
+ b();
+ }
+ return ((((Math_imul(i6+1, i7) | 0) + 17 | 0) % 5 | 0 | 0) == 0 | ((((Math_imul(i7+1, i7) | 0) + 11 | 0) >>> 0) % 3 | 0 | 0) == 0 | 0) == 0;
+}
+// EMSCRIPTEN_GENERATED_FUNCTIONS: ["a", "b", "rett", "ret2t", "retf", "i32_8", "tempDoublePtr", "boxx", "_main", "badf", "badf2", "fcomp", "conditionalizeMe"]