aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/analyzer.js208
-rw-r--r--src/jsifier.js2
-rw-r--r--src/settings.js10
-rw-r--r--tests/runner.py7
-rw-r--r--tests/settings.py2
5 files changed, 18 insertions, 211 deletions
diff --git a/src/analyzer.js b/src/analyzer.js
index c991aca4..6cb67578 100644
--- a/src/analyzer.js
+++ b/src/analyzer.js
@@ -211,6 +211,8 @@ function analyzer(data) {
substrate.addZyme('VariableAnalyzer', {
processItem: function(item) {
item.functions.forEach(function(func) {
+ dprint('vars', 'Analyzing variables in ' + func.ident);
+
func.variables = {};
// LLVM is SSA, so we always have a single assignment/write. We care about
@@ -266,10 +268,10 @@ function analyzer(data) {
if (variable.origin == 'getelementptr') {
// Use our implementation that emulates pointers etc.
variable.impl = VAR_EMULATED;
- } else if ( variable.pointingLevels === 0 && !variable.hasAddrTaken ) {
+ } else if (OPTIMIZE && variable.pointingLevels === 0 && !variable.hasAddrTaken) {
// A simple int value, can be implemented as a native variable
variable.impl = VAR_NATIVE;
- } else if ( variable.pointingLevels === 1 && variable.origin === 'alloca' && !isStructPointerType(variable.type) && !variable.hasAddrTaken && !variable.hasValueTaken ) {
+ } else if (OPTIMIZE && variable.origin === 'alloca' && !variable.hasAddrTaken && !variable.hasValueTaken) {
// A pointer to a value which is only accessible through this pointer. Basically
// a local value on the stack, which nothing fancy is done on. So we can
// optimize away the pointing altogether, and just have a native variable
@@ -336,7 +338,8 @@ function analyzer(data) {
processItem: function(item) {
var that = this;
function finish() {
- that.forwardItem(item, 'Optimizer');
+ item.__finalResult__ = true;
+ return [item];
}
// Tools
@@ -690,205 +693,6 @@ function analyzer(data) {
// logically correct. The LoopOptimizer works on that, doing further optimizations
// like switching to BNOPP when possible, etc.
- // Optimizer
- // XXX: load, store and gep now have pointer/value/data from which we copy the ident into a toplevel ident.
- // However, we later read the non-toplevel ident in some cases, so optimizer changes can lead to bugs.
- // Need to remove the toplevel, work entirely with the non-toplevel. Single location.
- substrate.addZyme('Optimizer', {
- processItem: function(item) {
- var that = this;
- function finish() {
- item.__finalResult__ = true;
- return [item];
- }
- if (!OPTIMIZE) return finish();
-
- // Check if a line has side effects *aside* from an explicit assign if it has one
- function isLineSideEffecting(line) {
- if (line.intertype == 'assign' && line.value.intertype !== 'call') return false;
- if (['fastgetelementptrload'].indexOf(line.intertype) != -1) return false;
- return true;
- }
-
- function replaceVars(line, ident, replaceWith) {
- if (!replaceWith) {
- print('// Not replacing ' + dump(ident) + ' : ' + dump(replaceWith));
- return false;
- }
- var found = false;
- // assigns, loads, mathops
- var POSSIBLE_VARS = ['ident', 'ident2'];
- for (var i = 0; i < POSSIBLE_VARS.length; i++) {
- var possible = POSSIBLE_VARS[i];
- if (line[possible] == ident) {
- line[possible] = replaceWith;
- found = true;
- }
- if (line.value && line.value[possible] == ident) {
- line.value[possible] = replaceWith;
- found = true;
- }
- }
- // getelementptr, call params
- [line, line.value].forEach(function(element) {
- if (!element || !element.params) return;
- var params = element.params;
- for (var j = 0; j < params.length; j++) {
- var param = params[j];
- if (param.intertype == 'value' && param.ident == ident) {
- param.ident = replaceWith;
- found = true;
- }
- }
- });
- return found;
- }
-
- // Fast getelementptr loads
- item.functions.forEach(function(func) {
- for (var i = 0; i < func.lines.length-1; i++) {
- var a = func.lines[i];
- var b = func.lines[i+1];
- if (a.intertype == 'assign' && a.value.intertype == 'getelementptr' &&
- b.intertype == 'assign' && b.value.intertype == 'load' &&
- a.ident == b.value.ident && func.variables[a.ident].uses == 1) {
-// print("// LOADSUSPECT: " + i + ',' + (i+1) + ':' + a.ident + ':' + b.value.ident);
- a.intertype = 'fastgetelementptrload';
- a.value.valueType = b.value.valueType;
- a.ident = b.ident;
- b.intertype = null;
- i++;
- }
- }
- cleanFunc(func);
- });
-
- // Fast getelementptr stores
- item.functions.forEach(function(func) {
- for (var i = 0; i < func.lines.length-1; i++) {
- var a = func.lines[i];
- var b = func.lines[i+1];
- if (a.intertype == 'assign' && a.value.intertype == 'getelementptr' &&
- b.intertype == 'store' && b.value.text &&
- a.ident == b.ident && func.variables[a.ident].uses == 1) {
- //print("// STORESUSPECT: " + a.lineNum + ',' + b.lineNum);
- a.intertype = 'fastgetelementptrstore';
- a.ident = toNiceIdent(b.value.text);
- b.intertype = null;
- i++;
- }
- }
- cleanFunc(func);
- });
-
- // TODO: Use for all that can
- function optimizePairs(worker, minSlice, maxSlice) {
- minSlice = minSlice ? minSlice : 2;
- maxSlice = maxSlice ? maxSlice : 2;
- item.functions.forEach(function(func) {
- func.labels.forEach(function(label) {
- for (var i = 0; i < label.lines.length-1; i++) {
- for (var j = i+minSlice-1; j < Math.min(i+maxSlice+1, label.lines.length); j++) {
- if (worker(func, label.lines.slice(i, j+1))) {
- i += j-i;
- break; // stop working on this i
- }
- }
- }
- });
- cleanFunc(func);
- });
- }
-
- // Fast bitcast&something after them
- optimizePairs(function(func, lines) {
- var a = lines[0], b = lines[1];
- if (a.intertype == 'assign' && a.value.intertype == 'bitcast' &&
- func.variables[a.ident].uses == 1 && replaceVars(b, a.ident, a.value.ident)) {
- a.intertype = null;
- return true;
- }
- });
-
-/*
- // Remove unnecessary branches
- item.functions.forEach(function(func) {
- for (var i = 0; i < func.labels.length-1; i++) {
- var a = func.labels[i].lines.slice(-1)[0];
- var b = func.labels[i+1];
- if (a.intertype == 'branch' && a.label == b.ident) {
- a.intertype = null;
- }
- }
- cleanFunc(func);
- });
-*/
-
- // Remove temp variables around nativized
- item.functions.forEach(function(func) {
- // loads, mathops
- var worked = true;
- while (worked) {
- worked = false;
- for (var i = 0; i < func.lines.length-1; i++) {
- var a = func.lines[i];
- var b = func.lines[i+1];
- if (a.intertype == 'assign' && a.value.intertype == 'load' &&
- func.variables[a.value.ident] && // Not global
- func.variables[a.value.ident].impl === VAR_NATIVIZED) {
- //print('// ??zzzz ' + dump(a) + ',\n // ??zzbb' + dump(b));
- // If target is only used on next line - do not need it.
- if (func.variables[a.ident].uses == 1 &&
- replaceVars(b, a.ident, a.value.ident)) {
- a.intertype = null;
- i ++;
- worked = true;
- }
- }
- }
- cleanFunc(func);
- }
-
- // stores
- for (var i = 0; i < func.lines.length-1; i++) {
- var a = func.lines[i];
- var b = func.lines[i+1];
- if (b.intertype == 'store' &&
- func.variables[b.ident] && // Not global
- func.variables[b.ident].impl === VAR_NATIVIZED) {
- // If target is only used on prev line - do not need it.
- if (func.variables[b.value.ident] && func.variables[b.value.ident].uses == 1 &&
- ['assign', 'fastgetelementptrload'].indexOf(a.intertype) != -1 && a.ident == b.value.ident) {
- a.ident = b.ident;
- a.overrideSSA = true;
- b.intertype = null;
- i ++;
- }
- }
- }
- cleanFunc(func);
- });
-
- // Remove redundant vars - SLOW! XXX
- optimizePairs(function(func, lines) {
- // a - a line defining a var
- // b - a line defining a var that is identical to a
- // c - the only line using b, hopefully
- var a = lines[0], b = lines[lines.length-2], c = lines[lines.length-1];
- if (a.intertype == 'assign' && b.intertype == 'assign' &&
- func.variables[b.ident] && func.variables[b.ident].uses == 1 &&
- compareTokens(a.value, b.value) &&
- lines.slice(0,-1).filter(isLineSideEffecting).length == 0 &&
- replaceVars(c, b.ident, a.ident)) {
- b.intertype = null;
- return true;
- }
- }, 3, 12);
-
- return finish();
- },
- });
-
substrate.addItem({
items: data,
}, 'Sorter');
diff --git a/src/jsifier.js b/src/jsifier.js
index 38af855e..51e37d8a 100644
--- a/src/jsifier.js
+++ b/src/jsifier.js
@@ -457,7 +457,7 @@ function JSify(data) {
});
}
makeFuncLineZyme('store', function(item) {
- var value = finalizeLLVMParameter(item.value);
+ var value = indexizeFunctions(finalizeLLVMParameter(item.value));
if (pointingLevels(item.pointerType) == 1) {
value = parseNumerical(value, removePointing(item.pointerType));
}
diff --git a/src/settings.js b/src/settings.js
index 6b621770..717bd334 100644
--- a/src/settings.js
+++ b/src/settings.js
@@ -1,5 +1,5 @@
// Tuning
-QUANTUM_SIZE = 1; // This is the size of an individual field in a structure. 1 would
+QUANTUM_SIZE = 4; // This is the size of an individual field in a structure. 1 would
// lead to e.g. doubles and chars both taking 1 memory address. This
// is a form of 'compressed' memory, with shrinking and stretching
// according to the type, when compared to C/C++. On the other hand
@@ -8,10 +8,10 @@ QUANTUM_SIZE = 1; // This is the size of an individual field in a structure. 1 w
// the top address - the others are just empty, an 'alignment cost'
// of sorts.
//
- // llvm-gcc works with 1. However, clang uses llvm_memcpy for various
- // things, and the number of bytes it copies is hardcoded. A simple
- // way to prevent problems with that is to set QUANTUM_SIZE to 8.
- // See the 'copyop' automatic test.
+ // 1 is somewhat faster, but dangerous.
+ //
+ // TODO: Cleverly analyze malloc, memset, memcpy etc. operations in
+ // llvm, and replace with the proper values for us
GUARD_SIGNS = 1; // Whether we make sure to convert unsigned values to signed values.
// Decreases performance with additional runtime checks. Might not be
diff --git a/tests/runner.py b/tests/runner.py
index ad1f82e1..bc1fcd51 100644
--- a/tests/runner.py
+++ b/tests/runner.py
@@ -933,8 +933,11 @@ else:
os.remove(filename + '.cc.js')
except:
pass
- cc_output = Popen(['java', '-jar', CLOSURE_COMPILER, '--compilation_level', 'ADVANCED_OPTIMIZATIONS', '--formatting', 'PRETTY_PRINT',
- '--js', filename + '.o.js', '--js_output_file', filename + '.cc.js'], stdout=PIPE, stderr=STDOUT).communicate()[0]
+ cc_output = Popen(['java', '-jar', CLOSURE_COMPILER,
+ '--compilation_level', 'ADVANCED_OPTIMIZATIONS',
+ '--formatting', 'PRETTY_PRINT',
+ '--variable_map_output_file', filename + '.vars',
+ '--js', filename + '.o.js', '--js_output_file', filename + '.cc.js'], stdout=PIPE, stderr=STDOUT).communicate()[0]
assert('ERROR' not in cc_output)
# Run
diff --git a/tests/settings.py b/tests/settings.py
index 87601391..7ee0279b 100644
--- a/tests/settings.py
+++ b/tests/settings.py
@@ -13,7 +13,7 @@ COMPILERS = {
},
'llvm_gcc': {
'path': LLVM_GCC,
- 'quantum_size': 1,
+ 'quantum_size': 4,
}
}