aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRyan Kelly <ryan@rfk.id.au>2014-01-23 22:18:57 +1100
committerRyan Kelly <ryan@rfk.id.au>2014-01-23 22:37:31 +1100
commitd21f2ea3adcd5c4f0d6e2ffaaa61f24dbb581737 (patch)
tree5519d6fc6902ca3c430099d02483ba7d6d9d9f1f
parent0bae95f2fc0f917b2ddf7343171c2353aa11a820 (diff)
Simplify handling of switch statements in registerizeHarder.
It now assumes they're of the very restricted for that's actually produced by emscripten, which both simplified the code and uncovered opportunities for further register reduction in a testcase.
-rw-r--r--tools/js-optimizer.js41
-rw-r--r--tools/test-js-optimizer-asm-regs-harder-output.js28
2 files changed, 26 insertions, 43 deletions
diff --git a/tools/js-optimizer.js b/tools/js-optimizer.js
index 78676681..abb854c6 100644
--- a/tools/js-optimizer.js
+++ b/tools/js-optimizer.js
@@ -2460,55 +2460,40 @@ function registerizeHarder(ast) {
buildFlowGraph(node[2]);
break;
case 'switch':
- // This is horrific. It need to capture the default flow-through
- // logic of sequential case bodies, as well as the theoretical
- // sequential evaluation of each case clause.
- // TODO: simplify based on asmjs switch-statement restrictions.
+ // Emscripten generates switch statements of a very limited
+ // form: all case clauses are numeric literals, and all
+ // case bodies end with a break. So it's basically equivalent
+ // to a multi-way 'if' statement.
isInExpr++;
buildFlowGraph(node[1]);
isInExpr--;
var jCheckExit = markJunction();
var jExit = addJunction();
pushActiveLabels(null, jExit);
- // Process all cases as a sequential chain of checks.
- // Process all case bodies as one big flow-through statement.
- // They might break themselves out of it but this implements the
- // default fall-through case logic.
var hasDefault = false;
- var jPrevCaseExit = jCheckExit;
- var jPrevBodyExit = jCheckExit;
for (var i=0; i<node[2].length; i++) {
- // In the general case we'll need a basic block for the case clause.
- // Try to avoid it for common, simple, non-var-using cases.
+ setJunction(jCheckExit);
if (!node[2][i][0]) {
hasDefault = true;
} else {
if (node[2][i][0][0] !== 'num') {
- setJunction(jPrevCaseExit);
- isInExpr++;
- buildFlowGraph(node[2][i][0]);
- isInExpr--;
- jPrevCaseExit = markJunction();
+ if (node[2][i][0][0] !== 'unary-prefix' || node[2][i][0][2][0] !== 'num') {
+ assert(false, 'non-numeric switch case clause');
+ }
}
- }
- // The next case body flows from the exit of the prev one,
- // or may be entered directly from the case statement exit.
- setJunction(jPrevCaseExit);
- if (jPrevBodyExit !== jCheckExit) {
- joinJunction(jPrevBodyExit);
+ addPreCondTrue(['binary', '==', node[1], node[2][i][0]]);
}
for (var j = 0; j < node[2][i][1].length; j++) {
buildFlowGraph(node[2][i][1][j]);
}
- jPrevBodyExit = markJunction();
+ if (currEntryJunction !== null, 'switch case body did not break');
}
- markJunction(jExit);
// If there was no default case, we also need an empty block
- // linking straight from entry to exit.
- if (!hasDefault && jCheckExit !== jPrevBodyExit) {
+ // linking straight from the test evaluation to the exit.
+ if (!hasDefault) {
setJunction(jCheckExit);
- joinJunction(jExit);
}
+ markJunction(jExit);
popActiveLabels()
break;
case 'return':
diff --git a/tools/test-js-optimizer-asm-regs-harder-output.js b/tools/test-js-optimizer-asm-regs-harder-output.js
index 710018bb..448fb67a 100644
--- a/tools/test-js-optimizer-asm-regs-harder-output.js
+++ b/tools/test-js-optimizer-asm-regs-harder-output.js
@@ -37,31 +37,29 @@ function switchey(d1, i2) {
}
}
function switchey2() {
- var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, d7 = +0, d8 = +0;
+ var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, d6 = +0, d7 = +0;
i2 = STACKTOP;
STACKTOP = STACKTOP + 8 | 0;
- i6 = 1;
- while (1) switch (i6 | 0) {
+ i3 = 1;
+ while (1) switch (i3 | 0) {
case 1:
i1 = i2 | 0;
__ZN6RandomC1Ev(i1);
i4 = 0;
- i3 = 0;
- i6 = 2;
+ i5 = 0;
+ i3 = 2;
break;
case 2:
- d8 = +__ZN6Random3getEf(8, +1);
- d7 = +__ZN6Random3getEf(i1, +1);
- _printf(24, (tempInt = STACKTOP, STACKTOP = STACKTOP + 16 | 0, HEAPF64[CHECK_ALIGN_8(tempInt | 0) >> 3] = d8, HEAPF64[CHECK_ALIGN_8(tempInt + 8 | 0) >> 3] = d7, tempInt) | 0);
- i5 = (d8 != d7 & 1) + i3 | 0;
- i6 = i4 + 1 | 0;
- if ((i6 | 0) < 100) {
- i4 = i6;
- i3 = i5;
- i6 = 2;
+ d7 = +__ZN6Random3getEf(8, +1);
+ d6 = +__ZN6Random3getEf(i1, +1);
+ _printf(24, (tempInt = STACKTOP, STACKTOP = STACKTOP + 16 | 0, HEAPF64[CHECK_ALIGN_8(tempInt | 0) >> 3] = d7, HEAPF64[CHECK_ALIGN_8(tempInt + 8 | 0) >> 3] = d6, tempInt) | 0);
+ i5 = (d7 != d6 & 1) + i5 | 0;
+ i4 = i4 + 1 | 0;
+ if ((i4 | 0) < 100) {
+ i3 = 2;
break;
} else {
- i6 = 3;
+ i3 = 3;
break;
}
case 3: