diff options
-rw-r--r-- | src/analyzer.js | 52 | ||||
-rw-r--r-- | src/jsifier.js | 22 | ||||
-rw-r--r-- | src/parseTools.js | 10 | ||||
-rw-r--r-- | tests/runner.py | 26 | ||||
-rwxr-xr-x | tools/emmaken.py | 15 |
5 files changed, 101 insertions, 24 deletions
diff --git a/src/analyzer.js b/src/analyzer.js index 1195c68b..6cfb2b6d 100644 --- a/src/analyzer.js +++ b/src/analyzer.js @@ -621,19 +621,15 @@ function analyzer(data) { // we need __lastLabel__. func.needsLastLabel = false; func.labels.forEach(function(label) { - var phis = []; + var phis = [], phi; label.lines.forEach(function(line) { - if (line.value && line.value.intertype == 'phi') { - for (var i = 0; i < line.value.params.length; i++) { - var remarkableLabelId = line.value.params[i].label; - var remarkableLabel = func.labelsDict[remarkableLabelId]; - assert(remarkableLabel); - var lastLine = remarkableLabel.lines.slice(-1)[0]; - if (lastLine.intertype === 'assign') { - lastLine.value.currLabelId = remarkableLabelId; - } else { - lastLine.currLabelId = remarkableLabelId; - } + if ((phi = line.value) && phi.intertype == 'phi') { + for (var i = 0; i < phi.params.length; i++) { + var sourceLabelId = phi.params[i].label; + var sourceLabel = func.labelsDict[sourceLabelId]; + var lastLine = sourceLabel.lines.slice(-1)[0]; + assert(lastLine.intertype == 'branch', 'Only branches can lead to labels with phis'); + lastLine.currLabelId = sourceLabelId; } phis.push(line); func.needsLastLabel = true; @@ -661,8 +657,36 @@ function analyzer(data) { } } }); - } else { // MICRO_OPTS - assert(0, 'TODO'); + } else { + // MICRO_OPTS == 1: Properly implement phis, by pushing them back into the branch + // that leads to here. We will only have the |var| definition in this location. + + // First, push phis back + func.labels.forEach(function(label) { + label.lines.forEach(function(line) { + var phi; + if ((phi = line.value) && phi.intertype == 'phi') { + for (var i = 0; i < phi.params.length; i++) { + var param = phi.params[i]; + var sourceLabelId = param.label; + var sourceLabel = func.labelsDict[sourceLabelId]; + var lastLine = sourceLabel.lines.slice(-1)[0]; + assert(lastLine.intertype == 'branch', 'Only branches can lead to labels with phis'); + if (!lastLine.phi) { + // We store the phi assignments in the branch's params (which are otherwise unused) + lastLine.phi = true; + assert(!lastLine.params); + lastLine.params = []; + }; + lastLine.params.push({ + intertype: 'phiassign', + ident: line.ident, + value: param.value + }); + } + } + }); + }); } }); this.forwardItem(item, 'StackAnalyzer'); diff --git a/src/jsifier.js b/src/jsifier.js index 604e8b8c..d158a9b9 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -671,7 +671,7 @@ function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) { function makeBranch(label, lastLabel, labelIsVariable) { var pre = ''; - if (lastLabel) { + if (!MICRO_OPTS && lastLabel) { pre = '__lastLabel__ = ' + getLabelId(lastLabel) + '; '; } if (label[0] == 'B') { @@ -819,16 +819,20 @@ function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) { }); makeFuncLineActor('phi', function(item) { var params = item.params; - function makeOne(i) { - if (i === params.length-1) { - return finalizeLLVMParameter(params[i].value); + if (!MICRO_OPTS) { + function makeOne(i) { + if (i === params.length-1) { + return finalizeLLVMParameter(params[i].value); + } + return '__lastLabel__ == ' + getLabelId(params[i].label) + ' ? ' + + finalizeLLVMParameter(params[i].value) + ' : (' + makeOne(i+1) + ')'; } - return '__lastLabel__ == ' + getLabelId(params[i].label) + ' ? ' + - finalizeLLVMParameter(params[i].value) + ' : (' + makeOne(i+1) + ')'; + var ret = makeOne(0); + if (item.postSet) ret += item.postSet; + return ret; + } else { // MICRO_OPTS == 1 + assert(0, 'TODO'); } - var ret = makeOne(0); - if (item.postSet) ret += item.postSet; - return ret; }); makeFuncLineActor('mathop', processMathop); diff --git a/src/parseTools.js b/src/parseTools.js index d7514ef5..591e6add 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -1339,6 +1339,7 @@ function getGetElementPtrIndexes(item) { } function handleOverflow(text, bits) { + // TODO: handle overflows of i64s if (!bits) return text; var correct = correctOverflows(); warn(!correct || bits <= 32, 'Cannot correct overflows of this many bits: ' + bits + ' at line ' + Framework.currItem.lineNum); @@ -1393,6 +1394,10 @@ function finalizeLLVMParameter(param, noIndexizeFunctions) { } function makeSignOp(value, type, op, force) { + if (I64_MODE == 1 && type == 'i64') { + return '(tempPair=' + value + ',[' + makeSignOp('tempPair[0]', 'i32', op, force) + ',' + makeSignOp('tempPair[1]', 'i32', op, force) + '])'; + } + if (isPointerType(type)) type = 'i32'; // Pointers are treated as 32-bit ints if (!value) return value; var bits, full; @@ -1430,6 +1435,8 @@ function makeSignOp(value, type, op, force) { } function makeRounding(value, bits, signed) { + // TODO: handle roundings of i64s + // C rounds to 0 (-5.5 to -5, +5.5 to 5), while JS has no direct way to do that. // With 32 bits and less, and a signed value, |0 will round it like C does. if (bits && bits <= 32 && signed) return '(('+value+')|0)'; @@ -1531,7 +1538,8 @@ function processMathop(item) { with(item) { default: throw 'Unknown icmp variant: ' + variant; } } - case 'zext': case 'sext': return makeI64(ident1, 0); + case 'zext': return makeI64(ident1, 0); + case 'sext': return '(tempInt=' + ident1 + ',' + makeI64('tempInt', 'tempInt<0 ? 4294967295 : 0') + ')'; case 'trunc': { return '((' + ident1 + '[0]) & ' + (Math.pow(2, bitsLeft)-1) + ')'; } diff --git a/tests/runner.py b/tests/runner.py index 75d087bd..ced640df 100644 --- a/tests/runner.py +++ b/tests/runner.py @@ -396,6 +396,7 @@ if 'benchmark' not in str(sys.argv): # Stuff that only works in i64_mode = 1 Settings.I64_MODE = 1 + src = r''' #include <time.h> #include <stdio.h> @@ -458,6 +459,31 @@ if 'benchmark' not in str(sys.argv): '*18446744073709552000*\n*576460752303423500*\n' + 'm1: 127\n*123*\n*127*\n') + Settings.CORRECT_SIGNS = 1 + + src = r''' + #include <stdio.h> + #include <stdint.h> + + int main() + { + // i32 vs i64 + int32_t small = -1; + int64_t large = -1; + printf("*%d*\n", small == large); + small++; + printf("*%d*\n", small == large); + uint32_t usmall = -1; + uint64_t ularge = -1; + printf("*%d*\n", usmall == ularge); + usmall++; + printf("*%d*\n", usmall == ularge); + return 0; + } + ''' + + self.do_run(src, '*1*\n*0*\n*1*\n*0*') + def test_unaligned(self): if Settings.QUANTUM_SIZE == 1: return self.skip('No meaning to unaligned addresses in q1') if Settings.USE_TYPED_ARRAYS != 2: return self.skip('No meaning to unaligned addresses without t2') diff --git a/tools/emmaken.py b/tools/emmaken.py index 8e2144b2..a509b940 100755 --- a/tools/emmaken.py +++ b/tools/emmaken.py @@ -51,6 +51,21 @@ Example uses: SET(CMAKE_AR "PATH/emmaken.py") SET(CMAKE_RANLIB "PATH/emmaken.py") + * For SCons the shared.py can be imported like so: + __file__ = str(Dir('#/project_path_to_emscripten/dummy/dummy')) + __rootpath__ = os.path.abspath(os.path.dirname(os.path.dirname(__file__))) + def path_from_root(*pathelems): + return os.path.join(__rootpath__, *pathelems) + exec(open(path_from_root('tools', 'shared.py'), 'r').read()) + + For using the Emscripten compilers/linkers/etc. you can do: + env = Environment() + ... + env.Append(CCFLAGS = COMPILER_OPTS) + env.Replace(LINK = LLVM_LD) + env.Replace(LD = LLVM_LD) + TODO: Document all relevant setup changes + After setting that up, run your build system normally. It should generate LLVM instead of the normal output, and end up with .ll files that you can give to Emscripten. Note that this tool doesn't run Emscripten itself. Note |