diff options
author | alon@honor <none@none> | 2010-10-13 22:24:06 -0700 |
---|---|---|
committer | alon@honor <none@none> | 2010-10-13 22:24:06 -0700 |
commit | 5efa5e467476859cdfb55a3a9dd22bf4584f670e (patch) | |
tree | b08d44f39989df6ac1ffdba6ebbf38849fee2013 | |
parent | d276be7499faff9814dc3cad07c2685284645106 (diff) |
aggressively nativize variables; stop doing optimizations that are no longer needed; fix some uncovered bugs; 49% speedup
-rw-r--r-- | src/analyzer.js | 208 | ||||
-rw-r--r-- | src/jsifier.js | 2 | ||||
-rw-r--r-- | src/settings.js | 10 | ||||
-rw-r--r-- | tests/runner.py | 7 | ||||
-rw-r--r-- | tests/settings.py | 2 |
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, } } |