aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authoralon@honor <none@none>2010-10-15 19:59:59 -0700
committeralon@honor <none@none>2010-10-15 19:59:59 -0700
commit02818fb370ff1c5660b3245d4312418bdd3b17ef (patch)
tree49d4076b9e3c3167d41bf1b67ee4dfe6a43e241d /src
parentfca8d0a7e81070c251c8ecb81651c2ae15a9f9ee (diff)
BNOPP in some simple emulated blocks; 1% speedup
Diffstat (limited to 'src')
-rw-r--r--src/analyzer.js130
-rw-r--r--src/jsifier.js10
-rw-r--r--src/settings.js2
3 files changed, 87 insertions, 55 deletions
diff --git a/src/analyzer.js b/src/analyzer.js
index 6cb67578..d2d5103e 100644
--- a/src/analyzer.js
+++ b/src/analyzer.js
@@ -333,56 +333,55 @@ function analyzer(data) {
},
});
+ var BRANCH_INVOKE = searchable('branch', 'invoke');
+ function operateOnLabels(line, func) {
+ function process(item, id) {
+ ['label', 'labelTrue', 'labelFalse', 'toLabel', 'unwindLabel', 'defaultLabel'].forEach(function(id) {
+ if (item[id]) {
+ func(item, id);
+ }
+ });
+ }
+ if (line.intertype in BRANCH_INVOKE) {
+ process(line);
+ } else if (line.intertype == 'assign' && line.value.intertype == 'invoke') {
+ process(line.value);
+ } else if (line.intertype == 'switch') {
+ process(line);
+ line.switchLabels.forEach(process);
+ }
+ }
+
+ function replaceLabels(line, labelIds, toLabelId) {
+ var ret = [];
+ operateOnLabels(line, function process(item, id) {
+ if (item[id] in labelIds) {
+ ret.push(item[id]);
+ dprint('relooping', 'zz ' + id + ' replace ' + item[id] + ' with ' + toLabelId + '; old: ' + item['old_' + id]);
+ item[id] = toLabelId + '|' + item[id];
+ }
+ });
+ return ret;
+ }
+
+ function replaceLabelLabels(labels, labelIds, toLabelId) {
+ ret = [];
+ labels.forEach(function(label) {
+ ret = ret.concat(replaceLabels(label.lines[label.lines.length-1], labelIds, toLabelId));
+ });
+ return ret;
+ }
+
// ReLooper - reconstruct nice loops, as much as possible
substrate.addZyme('Relooper', {
processItem: function(item) {
var that = this;
function finish() {
- item.__finalResult__ = true;
- return [item];
+ that.forwardItem(item, 'LoopOptimizer');
}
// Tools
- var BRANCH_INVOKE = searchable('branch', 'invoke');
- function operateOnLabels(line, func) {
- function process(item, id) {
- ['label', 'labelTrue', 'labelFalse', 'toLabel', 'unwindLabel', 'defaultLabel'].forEach(function(id) {
- if (item[id]) {
- func(item, id);
- }
- });
- }
- if (line.intertype in BRANCH_INVOKE) {
- process(line);
- } else if (line.intertype == 'assign' && line.value.intertype == 'invoke') {
- process(line.value);
- } else if (line.intertype == 'switch') {
- process(line);
- line.switchLabels.forEach(process);
- }
- }
-
- function replaceLabels(line, labelIds, toLabelId) {
- var ret = [];
- operateOnLabels(line, function process(item, id) {
- if (item[id] in labelIds) {
- ret.push(item[id]);
- dprint('relooping', 'zz ' + id + ' replace ' + item[id] + ' with ' + toLabelId + '; old: ' + item['old_' + id]);
- item[id] = toLabelId + '|' + item[id];
- }
- });
- return ret;
- }
-
- function replaceLabelLabels(labels, labelIds, toLabelId) {
- ret = [];
- labels.forEach(function(label) {
- ret = ret.concat(replaceLabels(label.lines[label.lines.length-1], labelIds, toLabelId));
- });
- return ret;
- }
-
function calcLabelBranchingData(labels, labelsDict) {
item.functions.forEach(function(func) {
labels.forEach(function(label) {
@@ -390,11 +389,15 @@ function analyzer(data) {
label.inLabels = [];
label.hasReturn = false;
label.hasBreak = false;
+ if (!label.originalOutlabels) {
+ label.originalOutLabels = [];
+ label.needOriginalOutLabels = true;
+ }
});
});
// Find direct branchings
labels.forEach(function(label) {
- label.lines.forEach(function(line) {
+ [label.lines[label.lines.length-1]].forEach(function(line) {
operateOnLabels(line, function process(item, id) {
if (item[id][0] == 'B') { // BREAK, BCONT, BNOPP, BJSET
label.hasBreak = true;
@@ -402,8 +405,11 @@ function analyzer(data) {
label.outLabels.push(item[id]);
labelsDict[item[id]].inLabels.push(label.ident);
}
+ if (label.needOriginalOutLabels) {
+ label.originalOutLabels.push(item[id]);
+ }
});
-
+ label.needOriginalOutLabels = false;
label.hasReturn |= line.intertype == 'return';
});
});
@@ -440,6 +446,7 @@ function analyzer(data) {
dprint('// ' + label.ident + ' :in : ' + JSON.stringify(label.inLabels));
dprint('// ' + label.ident + ' :ALL out : ' + JSON.stringify(label.allOutLabels));
dprint('// ' + label.ident + ' :ALL in : ' + JSON.stringify(label.allInLabels));
+ dprint('// ' + label.ident + ' :origOut : ' + JSON.stringify(label.originalOutLabels));
}
// Convert to searchables, for speed (we mainly do lookups here) and code clarity (x in Xlabels)
@@ -689,10 +696,45 @@ function analyzer(data) {
},
});
- // TODO: LoopOptimizer. The Relooper generates native loop structures, that are
+ // LoopOptimizer. The Relooper generates native loop structures, that are
// logically correct. The LoopOptimizer works on that, doing further optimizations
// like switching to BNOPP when possible, etc.
+ substrate.addZyme('LoopOptimizer', {
+ processItem: function(item) {
+ var that = this;
+ function finish() {
+ item.__finalResult__ = true;
+ return [item];
+ }
+ if (!RELOOP) return finish();
+
+ function walkBlock(block) {
+ dprint('relooping', "// loopOptimizing block: " + block.type + ' : ' + block.entries);
+ if (block.type == 'emulated') {
+ if (block.labels.length == 1 && block.next) {
+ var label = block.labels[0];
+ dprint('relooping', '// simple emulated: ' + label.originalOutLabels + ' || ' + block.next.entries);
+ if (label.originalOutLabels.length == 1 && block.next.entries.length == 1) {
+ dprint('relooping', '// removing!');
+ replaceLabelLabels([label], set('BJSET|' + label.originalOutLabels[0] + '|' + label.originalOutLabels[0]), 'BNOPP');
+ }
+ }
+ } else if (block.type == 'reloop') {
+ } else if (block.type == 'multiple') {
+ } else {
+ throw "Walked into an invalid block type: " + block.type;
+ }
+ }
+
+ item.functions.forEach(function(func) {
+ dprint('relooping', "// loopOptimizing function: " + func.ident);
+ walkBlock(func.block);
+ });
+ return finish();
+ },
+ });
+
substrate.addItem({
items: data,
}, 'Sorter');
diff --git a/src/jsifier.js b/src/jsifier.js
index a4ea85d9..239792de 100644
--- a/src/jsifier.js
+++ b/src/jsifier.js
@@ -340,16 +340,6 @@ function JSify(data) {
ret += walkBlock(block.inner, indent + ' ');
ret += indent + '}\n';
ret += walkBlock(block.outer, indent);
- } else if (block.type == 'breakingif') {
- ret += walkBlock(block.check, indent);
- ret += indent + block.entry + ': do { if (' + block.ifVar + ') {\n';
- ret += walkBlock(block.ifTrue, indent + ' ');
- ret += indent + '} } while(0);\n';
- } else if (block.type == 'if') {
- ret += walkBlock(block.check, indent);
- ret += indent + 'if (' + block.ifVar + ') {\n';
- ret += walkBlock(block.ifTrue, indent + ' ');
- ret += indent + '}\n';
} else if (block.type == 'multiple') {
// TODO: Remove the loop here
var first = true;
diff --git a/src/settings.js b/src/settings.js
index 717bd334..3018a32f 100644
--- a/src/settings.js
+++ b/src/settings.js
@@ -34,7 +34,7 @@ EXCEPTION_DEBUG = 1; // Print out exceptions in emscriptened code
EXECUTION_TIMEOUT = -1; // Throw an exception after X seconds - useful to debug infinite loops
// Compiler debugging options
-DEBUG_TAGS_SHOWING = ['enzymatic'];
+DEBUG_TAGS_SHOWING = ['enzymatic', 'relooping'];
// Some useful items:
// gconst
// types