summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/bisect_pair_lines.py63
-rw-r--r--tools/eliminator/asm-eliminator-test-output.js79
-rw-r--r--tools/eliminator/asm-eliminator-test.js73
-rw-r--r--tools/js-optimizer.js203
-rw-r--r--tools/shared.py6
-rw-r--r--tools/test-js-optimizer-asm-pre-output.js64
-rw-r--r--tools/test-js-optimizer-asm-pre.js66
-rw-r--r--tools/test-js-optimizer-asm-regs-harder-output.js5
-rw-r--r--tools/test-js-optimizer-asm-regs-harder.js8
-rw-r--r--tools/webidl_binder.py3
10 files changed, 532 insertions, 38 deletions
diff --git a/tools/bisect_pair_lines.py b/tools/bisect_pair_lines.py
new file mode 100644
index 00000000..f698ef2a
--- /dev/null
+++ b/tools/bisect_pair_lines.py
@@ -0,0 +1,63 @@
+'''
+Given two similar files, for example one with an additional optimization pass,
+and with different results, will bisect between them to find the smallest
+diff that makes the outputs different.
+Unlike bisect_pairs, this uses lines instead of diffs. We replace line by line. This assumes
+the programs differ on each line but lines have not been added or removed
+'''
+
+import os, sys, shutil
+from subprocess import Popen, PIPE, STDOUT
+
+__rootpath__ = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
+def path_from_root(*pathelems):
+ return os.path.join(__rootpath__, *pathelems)
+exec(open(path_from_root('tools', 'shared.py'), 'r').read())
+
+file1 = open(sys.argv[1]).read()
+file2 = open(sys.argv[2]).read()
+
+leftf = open('left', 'w')
+leftf.write(file1)
+leftf.close()
+
+rightf = open('right', 'w')
+rightf.write(file2)
+rightf.close()
+
+def run_code(name):
+ ret = run_js(name, stderr=PIPE, full_output=True)
+ # fix stack traces
+ ret = filter(lambda line: not line.startswith(' at ') and not name in line, ret.split('\n'))
+ return '\n'.join(ret)
+
+print 'running files'
+left_result = run_code('left')
+right_result = run_code('right') # right as in left-right, not as in correct
+assert left_result != right_result
+
+low = 0
+high = file1.count('\n')
+
+print 'beginning bisection, %d lines' % high
+
+left_lines = file1.split('\n')
+right_lines = file2.split('\n')
+
+while True:
+ mid = int((low + high)/2)
+ print low, high, ' current: %d' % mid,
+ open('middle', 'w').write('\n'.join(left_lines[:mid] + right_lines[mid:]))
+ shutil.copyfile('middle', 'middle' + str(mid))
+ result = run_code('middle')
+ print result == left_result, result == right_result#, 'XXX', left_result, 'YYY', result, 'ZZZ', right_result
+ if mid == low or mid == high: break
+ if result == right_result:
+ low = mid
+ elif result == left_result:
+ high = mid
+ else:
+ raise Exception('new result!?!?')
+
+print 'middle%d is like left, middle%d is like right' % (mid+1, mid)
+
diff --git a/tools/eliminator/asm-eliminator-test-output.js b/tools/eliminator/asm-eliminator-test-output.js
index 1a5dca55..ab4c13cc 100644
--- a/tools/eliminator/asm-eliminator-test-output.js
+++ b/tools/eliminator/asm-eliminator-test-output.js
@@ -24,7 +24,7 @@ function __Z11printResultPiS_j($needle, $haystack, $len) {
}
function _segment_holding($addr) {
$addr = $addr | 0;
- var $sp_0 = 0, $3 = 0, $12 = 0, $_0 = 0, label = 0;
+ var $sp_0 = 0, $3 = 0, $_0 = 0, label = 0;
$sp_0 = __gm_ + 444 | 0;
while (1) {
$3 = HEAP32[(($sp_0 | 0) & 16777215) >> 2] | 0;
@@ -35,13 +35,11 @@ function _segment_holding($addr) {
break;
}
}
- $12 = HEAP32[(($sp_0 + 8 | 0) & 16777215) >> 2] | 0;
- if (($12 | 0) == 0) {
+ $sp_0 = HEAP32[(($sp_0 + 8 | 0) & 16777215) >> 2] | 0;
+ if (($sp_0 | 0) == 0) {
$_0 = 0;
label = 1659;
break;
- } else {
- $sp_0 = $12;
}
}
if (label == 1659) {
@@ -818,7 +816,7 @@ function selfAssign() {
function elimOneLoopVar($argc, $argv) {
$argc = $argc | 0;
$argv = $argv | 0;
- var $arg$0 = 0, $call10 = Math_fround(0), $curri$012 = 0, $inc = 0, $j$010 = 0, $ok$0 = 0, $primes$011 = 0, $retval$0 = 0, $vararg_buffer1 = 0;
+ var $arg$0 = 0, $call10 = Math_fround(0), $curri$012 = 0, $j$010 = 0, $ok$0 = 0, $primes$011 = 0, $retval$0 = 0, $vararg_buffer1 = 0;
$curri$012 = 2;
$primes$011 = 0;
while (1) {
@@ -827,14 +825,12 @@ function elimOneLoopVar($argc, $argv) {
if ($call10 > Math_fround(+2)) {
$j$010 = 2;
while (1) {
- $inc = $j$010 + 1 | 0;
if ((($curri$012 | 0) % ($j$010 | 0) & -1 | 0) == 0) {
$ok$0 = 0;
break L15;
}
- if (Math_fround($inc | 0) < $call10) {
- $j$010 = $inc;
- } else {
+ $j$010 = $j$010 + 1 | 0;
+ if (!(Math_fround($j$010 | 0) < $call10)) {
$ok$0 = 1;
break;
}
@@ -898,10 +894,23 @@ function elimOneLoopVar4() {
}
}
function elimOneLoopVarStillUsed() {
+ var $call10 = Math_fround(0), $curri$012 = 0, $j$010 = 0, $retval$0 = 0;
+ while (1) {
+ if ((($curri$012 | 0) % ($j$010 | 0) & -1 | 0) == 0) {
+ break;
+ }
+ $j$010 = $j$010 + 1 | 0;
+ if (!(Math_fround($j$010 | 0) < $call10)) {
+ break;
+ }
+ }
+ return $retval$0 | 0;
+}
+function elimOneLoopVarStillUsedSE() {
var $call10 = Math_fround(0), $curri$012 = 0, $j$010 = 0, $retval$0 = 0, $j$010$looptemp = 0;
while (1) {
$j$010$looptemp = $j$010;
- $j$010 = $j$010 + 1 | 0;
+ $j$010 = $j$010 + sideeffect() | 0;
if ((($curri$012 | 0) % ($j$010$looptemp | 0) & -1 | 0) == 0) {
break;
}
@@ -911,4 +920,52 @@ function elimOneLoopVarStillUsed() {
}
return $retval$0 | 0;
}
+function elimOneLoopVar5() {
+ var $storemerge3$neg9 = 0, $18 = 0, $25 = 0, $26 = 0, $30 = 0, $jp = 0;
+ $storemerge3$neg9 = -1;
+ while (1) {
+ $25 = $jp + ($26 << 2) | 0;
+ HEAP32[$25 >> 2] = ($18 + $storemerge3$neg9 | 0) + (HEAP32[$25 >> 2] | 0) | 0;
+ $30 = $26 + 1 | 0;
+ if (($30 | 0) == 63) {
+ f($30);
+ break;
+ } else {
+ $storemerge3$neg9 = $18 ^ -1;
+ $26 = $30;
+ }
+ }
+}
+function loopVarWithContinue() {
+ var i = 0, i$looptemp = 0;
+ i = 0;
+ while (1) {
+ i$looptemp = i;
+ i = i + 1;
+ if (check()) {
+ i = i$looptemp + 1;
+ continue;
+ }
+ work(i);
+ work(i$looptemp);
+ work(i);
+ if (check()) {
+ break;
+ }
+ }
+}
+function helperExtraUse() {
+ var i = 0, i$looptemp = 0;
+ i = 0;
+ while (1) {
+ i$looptemp = i;
+ i = i + 1;
+ work(i$looptemp);
+ work(i);
+ if (check()) {
+ break;
+ }
+ }
+ return i;
+}
diff --git a/tools/eliminator/asm-eliminator-test.js b/tools/eliminator/asm-eliminator-test.js
index d5bbd8d5..7b949c44 100644
--- a/tools/eliminator/asm-eliminator-test.js
+++ b/tools/eliminator/asm-eliminator-test.js
@@ -1152,5 +1152,76 @@ function elimOneLoopVarStillUsed() {
}
return $retval$0 | 0;
}
-// EMSCRIPTEN_GENERATED_FUNCTIONS: ["asm", "__Z11printResultPiS_j", "_segment_holding", "__ZN5identC2EiPKcPci", "_vec2Length", "exc", "label", "confuusion", "tempDouble", "_org_apache_harmony_luni_util_NumberConverter_freeFormat__", "__ZN23b2EdgeAndPolygonContact8EvaluateEP10b2ManifoldRK11b2TransformS4_", "_java_nio_charset_Charset_forNameInternal___java_lang_String", "looop2", "looop3", "looop4", "looop5", "looop6", "looop7", "looop8", "multiloop", "multiloop2", "tempDouble2", "watIf", "select2", "binary", "cute", "selfAssign", "elimOneLoopVar", "elimOneLoopVar2", "elimOneLoopVar3", "elimOneLoopVar4", "elimOneLoopVarStillUsed"]
+function elimOneLoopVarStillUsedSE() {
+ var $0 = 0, $1 = 0, $arg$0 = 0, $arrayidx = 0, $call10 = Math_fround(0), $cmp = 0, $cmp11 = 0, $cmp119 = 0, $cmp12 = 0, $cmp7 = 0, $conv = 0, $conv8 = Math_fround(0), $conv9 = Math_fround(0), $curri$012 = 0, $inc = 0, $inc14$primes$0 = 0, $inc16 = 0, $j$010 = 0, $ok$0 = 0;
+ var $primes$011 = 0, $rem = 0, $retval$0 = 0, $sub = 0, $vararg_buffer1 = 0, label = 0, sp = 0;
+ while (1) {
+ $rem = ($curri$012 | 0) % ($j$010 | 0) & -1;
+ $cmp12 = ($rem | 0) == 0;
+ $inc = $j$010 + sideeffect() | 0; // side effect!
+ if ($cmp12) {
+ $ok$0 = 0;
+ break;
+ }
+ $conv8 = Math_fround($inc | 0);
+ $cmp11 = $conv8 < $call10;
+ if ($cmp11) {
+ $j$010 = $inc;
+ } else {
+ break;
+ }
+ }
+ return $retval$0 | 0;
+}
+function elimOneLoopVar5() {
+ var $storemerge3$neg9 = 0, $18 = 0, $25 = 0, $26 = 0, $30 = 0, $jp = 0;
+ $storemerge3$neg9 = -1;
+ while (1) {
+ $25 = $jp + ($26 << 2) | 0;
+ HEAP32[$25 >> 2] = ($18 + $storemerge3$neg9 | 0) + (HEAP32[$25 >> 2] | 0) | 0;
+ $30 = $26 + 1 | 0;
+ if (($30 | 0) == 63) {
+ f($30); // loop var used here, so cannot be easily optimized
+ break;
+ } else {
+ $storemerge3$neg9 = $18 ^ -1;
+ $26 = $30;
+ }
+ }
+}
+function loopVarWithContinue() {
+ var i = 0, inc = 0;
+ i = 0;
+ while (1) {
+ inc = i + 1;
+ if (check()) {
+ i = i + 1;
+ continue;
+ }
+ work(inc);
+ work(i);
+ work(inc);
+ if (check()) {
+ break;
+ } else {
+ i = inc;
+ }
+ }
+}
+function helperExtraUse() {
+ var i = 0, inc = 0;
+ i = 0;
+ while (1) {
+ inc = i + 1;
+ work(i);
+ work(inc);
+ if (check()) {
+ break;
+ } else {
+ i = inc;
+ }
+ }
+ return inc;
+}
+// EMSCRIPTEN_GENERATED_FUNCTIONS: ["asm", "__Z11printResultPiS_j", "_segment_holding", "__ZN5identC2EiPKcPci", "_vec2Length", "exc", "label", "confuusion", "tempDouble", "_org_apache_harmony_luni_util_NumberConverter_freeFormat__", "__ZN23b2EdgeAndPolygonContact8EvaluateEP10b2ManifoldRK11b2TransformS4_", "_java_nio_charset_Charset_forNameInternal___java_lang_String", "looop2", "looop3", "looop4", "looop5", "looop6", "looop7", "looop8", "multiloop", "multiloop2", "tempDouble2", "watIf", "select2", "binary", "cute", "selfAssign", "elimOneLoopVar", "elimOneLoopVar2", "elimOneLoopVar3", "elimOneLoopVar4", "elimOneLoopVarStillUsed", "elimOneLoopVarStillUsedSE", "elimOneLoopVar5", "helperExtraUse"]
diff --git a/tools/js-optimizer.js b/tools/js-optimizer.js
index 2914b6e8..2004efda 100644
--- a/tools/js-optimizer.js
+++ b/tools/js-optimizer.js
@@ -749,11 +749,74 @@ function simplifyExpressions(ast) {
});
}
+ function emitsBoolean(node) {
+ if (node[0] === 'num') {
+ return node[1] === 0 || node[1] === 1;
+ }
+ if (node[0] === 'binary') return node[1] in COMPARE_OPS;
+ if (node[0] === 'unary-prefix') return node[1] === '!';
+ if (node[0] === 'conditional') return emitsBoolean(node[2]) && emitsBoolean(node[3]);
+ 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
});
}
@@ -970,10 +1033,32 @@ function hasSideEffects(node) { // this is 99% incomplete!
}
return false;
}
+ case 'conditional': return hasSideEffects(node[1]) || hasSideEffects(node[2]) || hasSideEffects(node[3]);
default: return true;
}
}
+// checks if a node has just basic operations, nothing with side effects nor that can notice side effects, which
+// implies we can move it around in the code
+function triviallySafeToMove(node, asmData) {
+ var ok = true;
+ traverse(node, function(node, type) {
+ switch (type) {
+ case 'stat': case 'binary': case 'unary-prefix': case 'assign': case 'num':
+ break;
+ case 'name':
+ if (!(node[1] in asmData.vars) && !(node[1] in asmData.params)) ok = false;
+ break;
+ case 'call':
+ if (callHasSideEffects(node)) ok = false;
+ break;
+ default:
+ ok = false;
+ }
+ });
+ return ok;
+}
+
// Clear out empty ifs and blocks, and redundant blocks/stats and so forth
// Operates on generated functions only
function vacuum(ast) {
@@ -2152,18 +2237,30 @@ function registerizeHarder(ast) {
break;
case 'conditional':
isInExpr++;
- buildFlowGraph(node[1]);
- var jEnter = markJunction();
- var jExit = addJunction();
- if (node[2]) {
- buildFlowGraph(node[2]);
- }
- joinJunction(jExit);
- setJunction(jEnter);
- if (node[3]) {
- buildFlowGraph(node[3]);
+ // If the conditional has no side-effects, we can treat it as a single
+ // block, which might open up opportunities to remove it entirely.
+ if (!hasSideEffects(node)) {
+ buildFlowGraph(node[1]);
+ if (node[2]) {
+ buildFlowGraph(node[2]);
+ }
+ if (node[3]) {
+ buildFlowGraph(node[3]);
+ }
+ } else {
+ buildFlowGraph(node[1]);
+ var jEnter = markJunction();
+ var jExit = addJunction();
+ if (node[2]) {
+ buildFlowGraph(node[2]);
+ }
+ joinJunction(jExit);
+ setJunction(jEnter);
+ if (node[3]) {
+ buildFlowGraph(node[3]);
+ }
+ joinJunction(jExit);
}
- joinJunction(jExit);
isInExpr--;
break;
case 'while':
@@ -3525,13 +3622,13 @@ function eliminate(ast, memSafe) {
clearEmptyNodes(ifTrue[1]);
clearEmptyNodes(ifFalse[1]);
var flip = false;
- if (ifFalse[1][0] && ifFalse[1][0][0] === 'break') { // canonicalize break in the if
+ if (ifFalse[1][0] && ifFalse[1][ifFalse[1].length-1][0] === 'break') { // canonicalize break in the if-true
var temp = ifFalse;
ifFalse = ifTrue;
ifTrue = temp;
flip = true;
}
- if (ifTrue[1][0] && ifTrue[1][0][0] === 'break') {
+ if (ifTrue[1][0] && ifTrue[1][ifTrue[1].length-1][0] === 'break') {
var assigns = ifFalse[1];
clearEmptyNodes(assigns);
var loopers = [], helpers = [];
@@ -3568,6 +3665,17 @@ function eliminate(ast, memSafe) {
}
}
}
+ // remove loop vars that are used in the if
+ traverse(ifTrue, function(node, type) {
+ if (type === 'name') {
+ var index = loopers.indexOf(node[1]);
+ if (index < 0) index = helpers.indexOf(node[1]);
+ if (index >= 0) {
+ loopers.splice(index, 1);
+ helpers.splice(index, 1);
+ }
+ }
+ });
if (loopers.length === 0) return;
for (var l = 0; l < loopers.length; l++) {
var looper = loopers[l];
@@ -3591,21 +3699,57 @@ function eliminate(ast, memSafe) {
// if a loop variable is used after we assigned to the helper, we must save its value and use that.
// (note that this can happen due to elimination, if we eliminate an expression containing the
// loop var far down, past the assignment!)
- var temp = looper + '$looptemp';
- var looperUsed = false;
- assert(!(temp in asmData.vars));
+ // first, see if the looper and helper overlap
+ var firstLooperUsage = -1;
+ var lastLooperUsage = -1;
+ var firstHelperUsage = -1;
+ var lastHelperUsage = -1;
for (var i = found+1; i < stats.length; i++) {
var curr = i < stats.length-1 ? stats[i] : last[1]; // on the last line, just look in the condition
traverse(curr, function(node, type) {
- if (type === 'name' && node[1] === looper) {
- node[1] = temp;
- looperUsed = true;
+ if (type === 'name') {
+ if (node[1] === looper) {
+ if (firstLooperUsage < 0) firstLooperUsage = i;
+ lastLooperUsage = i;
+ } else if (node[1] === helper) {
+ if (firstHelperUsage < 0) firstHelperUsage = i;
+ lastHelperUsage = i;
+ }
}
});
}
- if (looperUsed) {
- asmData.vars[temp] = asmData.vars[looper];
- stats.splice(found, 0, ['stat', ['assign', true, ['name', temp], ['name', looper]]]);
+ if (firstLooperUsage >= 0) {
+ // the looper is used, we cannot simply merge the two variables
+ if ((firstHelperUsage < 0 || firstHelperUsage > lastLooperUsage) && lastLooperUsage+1 < stats.length && triviallySafeToMove(stats[found], asmData) &&
+ seenUses[helper] === namings[helper]) {
+ // the helper is not used, or it is used after the last use of the looper, so they do not overlap,
+ // and the last looper usage is not on the last line (where we could not append after it), and the
+ // helper is not used outside of the loop.
+ // just move the looper definition to after the looper's last use
+ stats.splice(lastLooperUsage+1, 0, stats[found]);
+ stats.splice(found, 1);
+ } else {
+ // they overlap, we can still proceed with the loop optimization, but we must introduce a
+ // loop temp helper variable
+ var temp = looper + '$looptemp';
+ assert(!(temp in asmData.vars));
+ for (var i = firstLooperUsage; i <= lastLooperUsage; i++) {
+ var curr = i < stats.length-1 ? stats[i] : last[1]; // on the last line, just look in the condition
+ traverse(curr, function looperToLooptemp(node, type) {
+ if (type === 'name') {
+ if (node[1] === looper) {
+ node[1] = temp;
+ }
+ } else if (type === 'assign' && node[2][0] === 'name') {
+ // do not traverse the assignment target, phi assignments to the loop variable must remain
+ traverse(node[3], looperToLooptemp);
+ return null;
+ }
+ });
+ }
+ asmData.vars[temp] = asmData.vars[looper];
+ stats.splice(found, 0, ['stat', ['assign', true, ['name', temp], ['name', looper]]]);
+ }
}
}
for (var l = 0; l < helpers.length; l++) {
@@ -3921,6 +4065,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 e7107443..fadec881 100644
--- a/tools/shared.py
+++ b/tools/shared.py
@@ -1904,7 +1904,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..5281b87c 100644
--- a/tools/test-js-optimizer-asm-pre-output.js
+++ b/tools/test-js-optimizer-asm-pre-output.js
@@ -538,4 +538,68 @@ 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();
+ }
+ print(((HEAP8[a] + HEAP8[b] + HEAP8[c] + HEAP8[d] + HEAP8[e] + HEAP8[f] | 0) > a % b % c % d ? 1 : $el) | $cheap > 0);
+ print(((HEAP8[a] + HEAP8[b] + HEAP8[c] + HEAP8[d] + HEAP8[e] + HEAP8[f] | 0) > a % b % c % d ? 1 : -1) | $cheap > 0);
+ print($cheap > 0 ? 1 : (HEAP8[a] + HEAP8[b] + HEAP8[c] + HEAP8[d] + HEAP8[e] + HEAP8[f] | 0) > a % b % c % d ? 1 : 0);
+ print(((HEAP8[a] + HEAP8[b] + HEAP8[c] + HEAP8[d] + HEAP8[e] + HEAP8[f] | 0) > a % b % c % d ? -1 : 1) | $cheap > 0);
+ 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..d48d736e 100644
--- a/tools/test-js-optimizer-asm-pre.js
+++ b/tools/test-js-optimizer-asm-pre.js
@@ -550,4 +550,68 @@ 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();
+ }
+ print( (((HEAP8[a] + HEAP8[b] + HEAP8[c] + HEAP8[d] + HEAP8[e] + HEAP8[f] | 0) > (a % b % c % d)) ? 1 : $el) | ($cheap > 0) ); // conditional does not always emit boolean
+ print( (((HEAP8[a] + HEAP8[b] + HEAP8[c] + HEAP8[d] + HEAP8[e] + HEAP8[f] | 0) > (a % b % c % d)) ? 1 : -1) | ($cheap > 0) );
+ print( (((HEAP8[a] + HEAP8[b] + HEAP8[c] + HEAP8[d] + HEAP8[e] + HEAP8[f] | 0) > (a % b % c % d)) ? 1 : 0) | ($cheap > 0) ); // this one is safe!
+ print( (((HEAP8[a] + HEAP8[b] + HEAP8[c] + HEAP8[d] + HEAP8[e] + HEAP8[f] | 0) > (a % b % c % d)) ? -1 : 1) | ($cheap > 0) );
+ 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"]
diff --git a/tools/test-js-optimizer-asm-regs-harder-output.js b/tools/test-js-optimizer-asm-regs-harder-output.js
index e1df42cb..c3b326f6 100644
--- a/tools/test-js-optimizer-asm-regs-harder-output.js
+++ b/tools/test-js-optimizer-asm-regs-harder-output.js
@@ -129,4 +129,9 @@ function linkedVars() {
}
return i2 + i1;
}
+function deadCondExpr(i2) {
+ i2 = i2 | 0;
+ var i1 = 0;
+ return i1 | 0;
+}
diff --git a/tools/test-js-optimizer-asm-regs-harder.js b/tools/test-js-optimizer-asm-regs-harder.js
index 0231a215..fa72aab8 100644
--- a/tools/test-js-optimizer-asm-regs-harder.js
+++ b/tools/test-js-optimizer-asm-regs-harder.js
@@ -149,5 +149,11 @@ function linkedVars() {
}
return outer1 + outer2;
}
-// EMSCRIPTEN_GENERATED_FUNCTIONS: ["asm", "_doit", "stackRestore", "switchey", "switchey2", "iffey", "labelledJump", "linkedVars']
+function deadCondExpr(input) {
+ input = input|0;
+ var dead = 0, temp = 0;
+ dead = (!input ? -1 : input)|0;
+ return temp|0;
+}
+// EMSCRIPTEN_GENERATED_FUNCTIONS: ["asm", "_doit", "stackRestore", "switchey", "switchey2", "iffey", "labelledJump", "linkedVars", "deadCondExpr"]
diff --git a/tools/webidl_binder.py b/tools/webidl_binder.py
index 0507cc78..168460fe 100644
--- a/tools/webidl_binder.py
+++ b/tools/webidl_binder.py
@@ -359,7 +359,8 @@ for name in names:
m.getExtendedAttribute('Value'),
(m.getExtendedAttribute('Operator') or [None])[0],
constructor,
- func_scope=m.parentScope.identifier.name)
+ func_scope=m.parentScope.identifier.name,
+ const=m.getExtendedAttribute('Const'))
mid_js += [';\n']
if constructor:
emit_constructor(name)