diff options
author | Ryan Kelly <ryan@rfk.id.au> | 2014-01-23 22:18:57 +1100 |
---|---|---|
committer | Ryan Kelly <ryan@rfk.id.au> | 2014-01-23 22:37:31 +1100 |
commit | d21f2ea3adcd5c4f0d6e2ffaaa61f24dbb581737 (patch) | |
tree | 5519d6fc6902ca3c430099d02483ba7d6d9d9f1f | |
parent | 0bae95f2fc0f917b2ddf7343171c2353aa11a820 (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.js | 41 | ||||
-rw-r--r-- | tools/test-js-optimizer-asm-regs-harder-output.js | 28 |
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: |