aboutsummaryrefslogtreecommitdiff
path: root/tools/js-optimizer.js
diff options
context:
space:
mode:
Diffstat (limited to 'tools/js-optimizer.js')
-rw-r--r--tools/js-optimizer.js105
1 files changed, 28 insertions, 77 deletions
diff --git a/tools/js-optimizer.js b/tools/js-optimizer.js
index 48139e82..7b489b33 100644
--- a/tools/js-optimizer.js
+++ b/tools/js-optimizer.js
@@ -372,8 +372,7 @@ function optimizeShiftsInternal(ast, conservative) {
uses: 0,
timesShifted: [0, 0, 0, 0], // zero shifts of size 0, 1, 2, 3
benefit: 0,
- primaryShift: -1,
- replaceOriginal: false
+ primaryShift: -1
};
}
}
@@ -447,16 +446,8 @@ function optimizeShiftsInternal(ast, conservative) {
if (funFinished[name]) continue;
// We have one shift size (and possible unshifted uses). Consider replacing this variable with a shifted clone. If
// the estimated benefit is >0, we will do it
- data.replaceOriginal = false; // Let later passes remove unneeded new variables. The only case where that might not
- // work perfectly is with parameters, but inlining can fix even that
- if (data.replaceOriginal) {
- assert(0);
- //data.benefit = totalTimesShifted - ((data.uses-totalTimesShifted) + data.defs + (data.param ? 1 : 0));
- } else {
- // We keep the original around, so there is some additional cost for each def, but none for unshifted uses
- if (data.defs == 1) {
- data.benefit = totalTimesShifted - 2*(data.defs + (data.param ? 1 : 0));
- }
+ if (data.defs == 1) {
+ data.benefit = totalTimesShifted - 2*(data.defs + (data.param ? 1 : 0));
}
if (conservative) data.benefit = 0;
if (data.benefit > 0) {
@@ -485,11 +476,7 @@ function optimizeShiftsInternal(ast, conservative) {
var data = vars[name];
if (needsShift(name)) {
if (data.param) {
- if (data.replaceOriginal) {
- fun[3].unshift(['stat', ['assign', '>>', ['name', name], ['num', data.primaryShift]]]);
- } else {
- fun[3].unshift(['var', [[name + '$s' + data.primaryShift, ['binary', '>>', ['name', name], ['num', data.primaryShift]]]]]);
- }
+ fun[3].unshift(['var', [[name + '$s' + data.primaryShift, ['binary', '>>', ['name', name], ['num', data.primaryShift]]]]]);
} else {
fun[3].unshift(['var', [[name + '$s' + data.primaryShift]]]);
}
@@ -500,22 +487,17 @@ function optimizeShiftsInternal(ast, conservative) {
if (node[0] == 'assign' && node[1] === true && node[2][0] == 'name' && needsShift(node[2][1]) && !node[2][2]) {
var name = node[2][1];
var data = vars[name];
- if (data.replaceOriginal) {
- node[3] = ['binary', '>>', node[3], ['num', vars[name].primaryShift]];
- return node;
+ var parent = stack[stack.length-3];
+ var parentIndex;
+ if (parent[0] == 'defun') {
+ parentIndex = 3;
+ } else if (parent[0] == 'block') {
+ parentIndex = 1;
} else {
- var parent = stack[stack.length-3];
- var parentIndex;
- if (parent[0] == 'defun') {
- parentIndex = 3;
- } else if (parent[0] == 'block') {
- parentIndex = 1;
- } else {
- throw 'Invalid parent for assign-shift: ' + dump(parent);
- }
- var i = parent[parentIndex].indexOf(stack[stack.length-2]);
- parent[parentIndex].splice(i+1, 0, ['stat', ['assign', true, ['name', name + '$s' + data.primaryShift], ['binary', '>>', ['name', name, true], ['num', data.primaryShift]]]]);
+ throw 'Invalid parent for assign-shift: ' + dump(parent);
}
+ var i = parent[parentIndex].indexOf(stack[stack.length-2]);
+ parent[parentIndex].splice(i+1, 0, ['stat', ['assign', true, ['name', name + '$s' + data.primaryShift], ['binary', '>>', ['name', name, true], ['num', data.primaryShift]]]]);
} else if (node[0] == 'var') {
var args = node[1];
for (var i = 0; i < args.length; i++) {
@@ -523,74 +505,43 @@ function optimizeShiftsInternal(ast, conservative) {
var name = arg[0];
var data = vars[name];
if (arg[1] && needsShift(name)) {
- if (data.replaceOriginal) {
- arg[1] = ['binary', '>>', arg[1], ['num', data.primaryShift]];
- } else {
- args.splice(i+1, 0, [name + '$s' + data.primaryShift, ['binary', '>>', ['name', name, true], ['num', data.primaryShift]]]);
- }
+ args.splice(i+1, 0, [name + '$s' + data.primaryShift, ['binary', '>>', ['name', name, true], ['num', data.primaryShift]]]);
}
}
return node;
}
}, null, []);
cleanNotes();
- traverse(fun, function(node, type, stack) { // replace name with unshifted name, making everything valid again by balancing the assign changes
+ traverse(fun, function(node, type, stack) { // replace shifted name with new variable
stack.push(node);
- if (node[0] == 'name' && !node[2] && needsShift(node[1]) &&
- !((stack[stack.length-2][0] == 'assign' && stack[stack.length-2][2] == node) || // ignore changing VAR in |VAR = something|
- (stack[stack.length-2][0] == 'binary' && stack[stack.length-3][0] == 'assign' && // ignore changing name$sX = name >> X;
- stack[stack.length-3][2][0] == 'name' && stack[stack.length-3][2][1] == node[1] + '$s' + vars[node[1]].primaryShift) ||
- (stack[stack.length-2][0] == 'binary' && // ignore changing name$sX = name >> X;
- stack[stack.length-3][0] == node[1] + '$s' + vars[node[1]].primaryShift) )) {
- var name = node[1];
+ if (node[0] == 'binary' && node[1] == '>>' && node[2][0] == 'name' && needsShift(node[2][1]) && node[3][0] == 'num') {
+ var name = node[2][1];
var data = vars[name];
- node[2] = true;
- if (!data.replaceOriginal) {
- node[1] += '$s' + data.primaryShift; // When this node is shifted, the collapse will get to the optimal case. But when it is
- // unshifted, we just added an (un)shift. We remove that later.
+ var parent = stack[stack.length-2];
+ // Don't modify in |x$sN = x >> 2|, in normal assigns and in var assigns
+ if (parent[0] == 'assign' && parent[2][0] == 'name' && parent[2][1] == name + '$s' + data.primaryShift) return;
+ if (parent[0] == name + '$s' + data.primaryShift) return;
+ if (node[3][1] == data.primaryShift) {
+ return ['name', name + '$s' + data.primaryShift];
}
- return ['binary', '<<', node, ['num', data.primaryShift]];
}
}, null, []);
cleanNotes();
var SIMPLE_SHIFTS = set('<<', '>>');
var more = true;
- while (more) { // collapse shifts and unshifts, completing the optimization
+ while (more) { // combine shifts in the same direction as an optimization
more = false;
traverse(fun, function(node, type) {
- if (node[0] == 'binary' && node[1] in SIMPLE_SHIFTS && node[2][0] == 'binary' && node[2][1] in SIMPLE_SHIFTS &&
- node[3][0] == 'num' && node[2][3][0] == 'num' && // do not turn a << b << c into a << b + c; while logically identical, it is slower
- Math.abs(node[3][1]) <= MAX_SHIFTS && Math.abs(node[2][3][1]) <= MAX_SHIFTS) { // do not modify things like x << 24 >> 24 (which is reSign)
+ if (node[0] == 'binary' && node[1] in SIMPLE_SHIFTS && node[2][0] == 'binary' && node[2][1] == node[1] &&
+ node[3][0] == 'num' && node[2][3][0] == 'num') { // do not turn a << b << c into a << b + c; while logically identical, it is slower
more = true;
- var combinedShift = '>>';
- var sign1 = node[1] == '>>' ? 1 : -1;
- var sign2 = node[2][1] == '>>' ? 1 : -1;
- var total = 0;
- total = ['num', sign1*node[3][1] + sign2*node[2][3][1]];
- if (total[1] < 0) {
- combinedShift = '<<';
- total[1] *= -1;
- }
- if (total[1] == 0) {
- // XXX this may be wrong, if we removed a |0 that assumed we had this >> which |0's anyhow!
- return node[2][2];
- }
- return ['binary', combinedShift, node[2][2], total];
+ return ['binary', node[1], node[2][2], ['num', node[3][1] + node[2][3][1]]];
}
});
}
- traverse(fun, function(node, type) { // collapse name$sX << X into name
- if (type == 'binary' && node[1] == '<<' && node[2][0] == 'name' && node[3][0] == 'num') {
- var shifts = node[3][1];
- var full = node[2][1]
- var raw = full.substr(0, full.length-3);
- if (raw + '$s' + shifts == full) {
- return ['name', raw];
- }
- }
- });
// Before recombining, do some additional optimizations
traverse(fun, function(node, type) {
+ // Apply constant shifts onto constants
if (type == 'binary' && node[1] == '>>' && node[2][0] == 'num' && node[3][0] == 'num' && node[3][1] <= MAX_SHIFTS) {
var subNode = node[2];
var shifts = node[3][1];