diff options
author | Alon Zakai <alonzakai@gmail.com> | 2013-06-08 09:14:22 -0700 |
---|---|---|
committer | Alon Zakai <alonzakai@gmail.com> | 2013-06-08 09:55:41 -0700 |
commit | 430cfefc1612c00c481e5343b3be4ddc514fd415 (patch) | |
tree | b5eaa77c1923c00a400d1972a1509a610e541fe7 /tools/js-optimizer.js | |
parent | 0f382355e385e94f933f9962bf8b7703614b7c16 (diff) |
optimize away bitcasts to variables that will only be used in an assign to the parallel heap type
Diffstat (limited to 'tools/js-optimizer.js')
-rw-r--r-- | tools/js-optimizer.js | 127 |
1 files changed, 94 insertions, 33 deletions
diff --git a/tools/js-optimizer.js b/tools/js-optimizer.js index ee056c33..c598fb81 100644 --- a/tools/js-optimizer.js +++ b/tools/js-optimizer.js @@ -405,7 +405,7 @@ function removeUnneededLabelSettings(ast) { function simplifyExpressionsPre(ast) { // Look for (x&A)<<B>>B and replace it with X&A if possible. function simplifySignExtends(ast) { - traverseGenerated(ast, function(node, type) { + traverse(ast, function(node, type) { if (type == 'binary' && node[1] == '>>' && node[3][0] == 'num' && node[2][0] == 'binary' && node[2][1] == '<<' && node[2][3][0] == 'num' && node[3][1] == node[2][3][1]) { var innerNode = node[2][2]; @@ -433,7 +433,7 @@ function simplifyExpressionsPre(ast) { var rerun = true; while (rerun) { rerun = false; - traverseGenerated(ast, function process(node, type, stack) { + traverse(ast, function process(node, type, stack) { if (type == 'binary' && node[1] == '|') { if (node[2][0] == 'num' && node[3][0] == 'num') { return ['num', node[2][1] | node[3][1]]; @@ -481,7 +481,7 @@ function simplifyExpressionsPre(ast) { var hasTempDoublePtr = false; - traverseGenerated(ast, function(node, type) { + traverse(ast, function(node, type) { if (type == 'name') { if (node[1] == 'tempDoublePtr') hasTempDoublePtr = true; } else if (type == 'binary' && node[1] == '&' && node[3][0] == 'num') { @@ -574,10 +574,71 @@ function simplifyExpressionsPre(ast) { } } }); + + // finally, wipe out remaining ones by finding cases where all assignments to X are bitcasts, and all uses are writes to + // the other heap type, then eliminate the bitcast + var bitcastVars = {}; + traverse(ast, function(node, type) { + if (type == 'assign' && node[1] === true && node[2][0] == 'name') { + var value = node[3]; + if (value[0] == 'seq' && value[1][0] == 'assign' && value[1][2][0] == 'sub' && value[1][2][1][0] == 'name' && + (value[1][2][1][1] == 'HEAP32' || value[1][2][1][1] == 'HEAPF32') && + value[1][2][2][0] == 'binary' && value[1][2][2][2][0] == 'name' && value[1][2][2][2][1] == 'tempDoublePtr') { + var name = node[2][1]; + if (!bitcastVars[name]) bitcastVars[name] = { + define_HEAP32: 0, define_HEAPF32: 0, use_HEAP32: 0, use_HEAPF32: 0, bad: false, namings: 0, defines: [], uses: [] + }; + bitcastVars[name]['define_' + value[1][2][1][1]]++; + bitcastVars[name].defines.push(node); + } + } + }); + traverse(ast, function(node, type) { + if (type == 'name' && bitcastVars[node[1]]) { + bitcastVars[node[1]].namings++; + } else if (type == 'assign' && node[1] === true) { + var value = node[3]; + if (value[0] == 'name') { + var name = value[1]; + if (bitcastVars[name]) { + var target = node[2]; + if (target[0] == 'sub' && target[1][0] == 'name' && (target[1][1] == 'HEAP32' || target[1][1] == 'HEAPF32')) { + bitcastVars[name]['use_' + target[1][1]]++; + bitcastVars[name].uses.push(node); + } + } + } + } + }); + var asmData = normalizeAsm(ast); + for (var v in bitcastVars) { + var info = bitcastVars[v]; + // good variables define only one type, use only one type, have definitions and uses, and define as a different type than they use + if (info.define_HEAP32*info.define_HEAPF32 == 0 && info.use_HEAP32*info.use_HEAPF32 == 0 && + info.define_HEAP32+info.define_HEAPF32 > 0 && info.use_HEAP32+info.use_HEAPF32 > 0 && + info.define_HEAP32*info.use_HEAP32 == 0 && info.define_HEAPF32*info.use_HEAPF32 == 0 && + v in asmData.vars && info.namings == info.define_HEAP32+info.define_HEAPF32+info.use_HEAP32+info.use_HEAPF32) { + var correct = info.use_HEAP32 ? 'HEAPF32' : 'HEAP32'; + info.defines.forEach(function(define) { + define[3] = define[3][1][3]; + if (correct == 'HEAP32') { + define[3] = ['binary', '|', define[3], ['num', 0]]; + } else { + define[3] = ['unary-prefix', '+', define[3]]; + } + // do we want a simplifybitops on the new values here? + }); + info.uses.forEach(function(use) { + use[2][1][1] = correct; + }); + asmData.vars[v] = 1 - asmData.vars[v]; + } + } + denormalizeAsm(ast, asmData); } // optimize num >> num, in asm we need this here since we do not run optimizeShifts - traverseGenerated(ast, function(node, type) { + traverse(ast, function(node, type) { if (type == 'binary' && node[1] == '>>' && node[2][0] == 'num' && node[3][0] == 'num') { node[0] = 'num'; node[1] = node[2][1] >> node[3][1]; @@ -593,7 +654,7 @@ function simplifyExpressionsPre(ast) { var rerun = true; while (rerun) { rerun = false; - traverseGenerated(ast, function(node, type) { + traverse(ast, function(node, type) { if (type == 'binary' && node[1] == '+') { if (node[2][0] == 'num' && node[3][0] == 'num') { rerun = true; @@ -616,7 +677,7 @@ function simplifyExpressionsPre(ast) { // if (x == 0) can be if (!x), etc. function simplifyZeroComp(ast) { - traverseGenerated(ast, function(node, type) { + traverse(ast, function(node, type) { var binary; if (type == 'if' && (binary = node[1])[0] == 'binary') { if ((binary[1] == '!=' || binary[1] == '!==') && binary[3][0] == 'num' && binary[3][1] == 0) { @@ -630,40 +691,40 @@ function simplifyExpressionsPre(ast) { }); } - function asmOpts(ast) { + function asmOpts(fun) { // 1. Add final returns when necessary // 2. Remove unneeded coercions on function calls that have no targets (eliminator removed it) - traverseGeneratedFunctions(ast, function(fun) { - var returnType = null; - traverse(fun, function(node, type) { - if (type == 'return' && node[1]) { - returnType = detectAsmCoercion(node[1]); - } else if (type == 'stat') { - var inner = node[1]; - if ((inner[0] == 'binary' && inner[1] in ASSOCIATIVE_BINARIES && inner[2][0] == 'call' && inner[3][0] == 'num') || - (inner[0] == 'unary-prefix' && inner[1] == '+' && inner[2][0] == 'call')) { - node[1] = inner[2]; - } - } - }); - // Add a final return if one is missing. - if (returnType !== null) { - var stats = getStatements(fun); - var last = stats[stats.length-1]; - if (last[0] != 'return') { - var returnValue = ['num', 0]; - if (returnType == ASM_DOUBLE) returnValue = ['unary-prefix', '+', returnValue]; - stats.push(['return', returnValue]); + var returnType = null; + traverse(fun, function(node, type) { + if (type == 'return' && node[1]) { + returnType = detectAsmCoercion(node[1]); + } else if (type == 'stat') { + var inner = node[1]; + if ((inner[0] == 'binary' && inner[1] in ASSOCIATIVE_BINARIES && inner[2][0] == 'call' && inner[3][0] == 'num') || + (inner[0] == 'unary-prefix' && inner[1] == '+' && inner[2][0] == 'call')) { + node[1] = inner[2]; } } }); + // Add a final return if one is missing. + if (returnType !== null) { + var stats = getStatements(fun); + var last = stats[stats.length-1]; + if (last[0] != 'return') { + var returnValue = ['num', 0]; + if (returnType == ASM_DOUBLE) returnValue = ['unary-prefix', '+', returnValue]; + stats.push(['return', returnValue]); + } + } } - simplifySignExtends(ast); - simplifyBitops(ast); - joinAdditions(ast); - // simplifyZeroComp(ast); TODO: investigate performance - if (asm) asmOpts(ast); + traverseGeneratedFunctions(ast, function(func) { + simplifySignExtends(func); + simplifyBitops(func); + joinAdditions(func); + // simplifyZeroComp(func); TODO: investigate performance + if (asm) asmOpts(func); + }); } // In typed arrays mode 2, we can have |