diff options
-rw-r--r-- | src/analyzer.js | 37 | ||||
-rw-r--r-- | src/compiler.js | 3 | ||||
-rw-r--r-- | src/framework.js | 3 | ||||
-rw-r--r-- | src/intertyper.js | 25 | ||||
-rw-r--r-- | src/jsifier.js | 46 | ||||
-rw-r--r-- | src/parseTools.js | 4 | ||||
-rw-r--r-- | src/utility.js | 48 |
7 files changed, 67 insertions, 99 deletions
diff --git a/src/analyzer.js b/src/analyzer.js index 4aad192b..8f4ba95e 100644 --- a/src/analyzer.js +++ b/src/analyzer.js @@ -124,7 +124,7 @@ function analyzer(data, givenTypes) { if (['['].indexOf(type) != -1) return; data.types[type] = { name_: type, - fields: [ 'i32' ], // XXX + fields: [ 'i' + (QUANTUM_SIZE*8) ], // a single quantum size flatSize: 1, lineNum: '?' }; @@ -245,7 +245,7 @@ function analyzer(data, givenTypes) { func.variables[item.ident] = { ident: item.ident, type: item.value.type, - origin: item.value.intertype, // XXX should say something in the case of fastgetelementptrload + origin: item.intertype === 'assign' ? item.value.intertype : 'fastgetelementptrload', lineNum: item.lineNum, uses: parseInt(item.value.tokens.slice(-1)[0].item.tokens[0].text.split('=')[1]) }; @@ -292,8 +292,8 @@ function analyzer(data, givenTypes) { var pointedType = removePointing(variable.type); if (variable.origin == 'getelementptr') { // Use our implementation that emulates pointers etc. - // XXX Can we perhaps nativize some of these? However to do so, we need to discover their - // true types; we have '?' for them now, as they cannot be discovered in the intertyper. + // TODO Can we perhaps nativize some of these? However to do so, we need to discover their + // true types; we have '?' for them now, as they cannot be discovered in the intertyper. variable.impl = VAR_EMULATED; } else if (variable.origin == 'funcparam') { variable.impl = VAR_EMULATED; @@ -378,7 +378,7 @@ function analyzer(data, givenTypes) { } }); - var BRANCH_INVOKE = searchable('branch', 'invoke'); + var BRANCH_INVOKE = set('branch', 'invoke'); function operateOnLabels(line, func) { function process(item, id) { ['label', 'labelTrue', 'labelFalse', 'toLabel', 'unwindLabel', 'defaultLabel'].forEach(function(id) { @@ -513,13 +513,13 @@ function analyzer(data, givenTypes) { dprint('// ' + label.ident + ' :origOut : ' + JSON.stringify(label.originalOutLabels)); } - // Convert to searchables, for speed (we mainly do lookups here) and code clarity (x in Xlabels) + // Convert to set, for speed (we mainly do lookups here) and code clarity (x in Xlabels) // Also removes duplicates (which we can get in llvm switches) - // FIXME TODO XXX do we need all these? - label.outLabels = searchable(label.outLabels); - label.inLabels = searchable(label.inLabels); - label.allOutLabels = searchable(label.allOutLabels); - label.allInLabels = searchable(label.allInLabels); + // TODO do we need all these? + label.outLabels = set(label.outLabels); + label.inLabels = set(label.inLabels); + label.allOutLabels = set(label.allOutLabels); + label.allInLabels = set(label.allInLabels); }); } @@ -571,7 +571,7 @@ function analyzer(data, givenTypes) { calcLabelBranchingData(labels, labelsDict); - var s_entries = searchable(entries); + var s_entries = set(entries); dprint('relooping', 'makeBlock: ' + entries + ',' + labels.length + ' labels'); var entryLabels = entries.map(function(entry) { return labelsDict[entry] }); @@ -600,14 +600,9 @@ function analyzer(data, givenTypes) { var nextEntries = keys(entryLabel.outLabels); dprint('relooping', ' Creating simple emulated, outlabels: ' + nextEntries); - //if (nextEntries.length == 1) { - // replaceLabelLabels([entryLabel], set(nextEntries), 'BNOPP|XXX'); // remove unneeded branch XXX - this is dangerous, as we may - // // have 1 next entry, but 1 or more B-labels... - //} else { - nextEntries.forEach(function(nextEntry) { - replaceLabelLabels([entryLabel], set(nextEntry), 'BJSET|' + nextEntry); // Just SET __label__ - no break or continue or whatnot - }); - //} + nextEntries.forEach(function(nextEntry) { + replaceLabelLabels([entryLabel], set(nextEntry), 'BJSET|' + nextEntry); // Just SET __label__ - no break or continue or whatnot + }); return { type: 'emulated', id: blockId, @@ -648,7 +643,7 @@ function analyzer(data, givenTypes) { // We will be in a loop, |continue| gets us back to the entry entries.forEach(function(entry) { - replaceLabelLabels(internals, searchable(entries), 'BCONT|' + blockId); + replaceLabelLabels(internals, set(entries), 'BCONT|' + blockId); }); // To get to any of our (not our parents') exit labels, we will break. diff --git a/src/compiler.js b/src/compiler.js index bc53a5c2..1cdc0002 100644 --- a/src/compiler.js +++ b/src/compiler.js @@ -22,6 +22,7 @@ load('jsifier.js'); //=============================== // Override settings.js + var settings = JSON.parse(readline()); for (setting in settings) { this[setting] = settings[setting]; @@ -35,6 +36,7 @@ load('runtime.js'); assert(!(USE_TYPED_ARRAYS && SAFE_HEAP)); // Read llvm + var lines = []; var line; do { @@ -44,6 +46,7 @@ do { } while(true); // Do it + eval(preprocess(read('library.js'), CONSTANTS)); print(JSify(analyzer(intertyper(lines)))); diff --git a/src/framework.js b/src/framework.js index 8fd396b6..e9ff592e 100644 --- a/src/framework.js +++ b/src/framework.js @@ -128,8 +128,7 @@ Substrate.prototype = { if (DEBUG) print("Solving complete: no remaining items"); finalComment(); this.results.forEach(function(output) { - delete output.__result__; // Might recycle these - delete output.__uid__; + delete output.__uid__; // Might recycle these }); return this.results; } diff --git a/src/intertyper.js b/src/intertyper.js index f72d33a4..9897884b 100644 --- a/src/intertyper.js +++ b/src/intertyper.js @@ -67,7 +67,6 @@ function intertyper(data, parseFunctions, baseLineNum) { if (!parseFunctions) { var func = funcHeader.processItem(tokenizer.processItem({ lineText: currFunctionLines[0] }, true))[0]; unparsedFunctions.push({ - __result__: true, intertype: 'unparsedFunction', // We need this early, to know basic function info - ident, params, varargs ident: toNiceIdent(func.ident), @@ -276,7 +275,7 @@ function intertyper(data, parseFunctions, baseLineNum) { if (tokensLength >= 3 && token0Text == 'phi') return 'Phi'; } else if (item.indent === 0) { - if ((tokensLength >= 1 && token0Text.substr(-1) == ':') || // XXX LLVM 2.7 format, or llvm-gcc in 2.8 + if ((tokensLength >= 1 && token0Text.substr(-1) == ':') || // LLVM 2.7 format, or llvm-gcc in 2.8 (tokensLength >= 3 && token1Text == '<label>')) return 'Label'; if (tokensLength >= 4 && token0Text == 'declare') @@ -291,7 +290,7 @@ function intertyper(data, parseFunctions, baseLineNum) { } if (tokensLength >= 3 && (token0Text == 'call' || token1Text == 'call')) return 'Call'; - if (token0Text in searchable(';', 'target')) + if (token0Text in set(';', 'target')) return '/dev/null'; if (tokensLength >= 3 && token0Text == 'invoke') return 'Invoke'; @@ -320,7 +319,7 @@ function intertyper(data, parseFunctions, baseLineNum) { // Clang sometimes has |= i32| instead of |= { i32 }| fields = [item.tokens[3].text]; } else if (item.tokens[3].text != 'opaque') { - if (item.tokens[3].type == '<') { // type <{ i8 }> XXX - check spec + if (item.tokens[3].type == '<') { // type <{ i8 }> - TODO: check spec item.tokens[3] = tokenizer.processItem({ lineText: '{ ' + item.tokens[3].item.tokens[0].text + ' }' }, true).tokens[0]; } var subTokens = item.tokens[3].tokens; @@ -333,7 +332,6 @@ function intertyper(data, parseFunctions, baseLineNum) { } } return [{ - __result__: true, // XXX can remove these intertype: 'type', name_: item.tokens[0].text, fields: fields, @@ -350,7 +348,6 @@ function intertyper(data, parseFunctions, baseLineNum) { item.tokens.splice(2, 1); } var ret = { - __result__: true, intertype: 'globalVariable', ident: ident, type: item.tokens[2].text, @@ -366,7 +363,7 @@ function intertyper(data, parseFunctions, baseLineNum) { }); } } else { - if (item.tokens[3].type == '<') { // type <{ i8 }> XXX - check spec + if (item.tokens[3].type == '<') { // type <{ i8 }> TODO - check spec item.tokens[3] = item.tokens[3].item.tokens; } @@ -389,7 +386,6 @@ function intertyper(data, parseFunctions, baseLineNum) { return !(token.text in LLVM.LINKAGES || token.text in set('noalias', 'hidden', 'signext', 'zeroext', 'nounwind', 'define', 'inlinehint', '{', 'fastcc')); }); var ret = { - __result__: true, intertype: 'function', ident: item.tokens[1].text, returnType: item.tokens[0], @@ -411,7 +407,6 @@ function intertyper(data, parseFunctions, baseLineNum) { substrate.addActor('Label', { processItem: function(item) { return [{ - __result__: true, intertype: 'label', ident: item.tokens[0].text.substr(-1) == ':' ? '%' + item.tokens[0].text.substr(0, item.tokens[0].text.length-1) : @@ -551,7 +546,6 @@ function intertyper(data, parseFunctions, baseLineNum) { if (item.indent == 2) { // standalone call - not in assign item.standalone = true; - item.__result__ = true; return [item]; } this.forwardItem(item, 'Reintegrator'); @@ -576,7 +570,6 @@ function intertyper(data, parseFunctions, baseLineNum) { if (item.indent == 2) { // standalone call - not in assign item.standalone = true; - item.__result__ = true; return [item]; } this.forwardItem(item, 'Reintegrator'); @@ -621,7 +614,7 @@ function intertyper(data, parseFunctions, baseLineNum) { item.variant = item.tokens[1].text; item.tokens.splice(1, 1); } - if (item.tokens[1].text == 'exact') item.tokens.splice(1, 1); // XXX - do we need a check at runtime? + if (item.tokens[1].text == 'exact') item.tokens.splice(1, 1); // TODO: Implement trap values var segments = splitTokenList(item.tokens.slice(1)); for (var i = 1; i <= 4; i++) { if (segments[i-1]) { @@ -645,7 +638,6 @@ function intertyper(data, parseFunctions, baseLineNum) { if (item.tokens[0].text == 'volatile') item.tokens.shift(0); var segments = splitTokenList(item.tokens.slice(1)); var ret = { - __result__: true, intertype: 'store', valueType: item.tokens[1].text, value: parseLLVMSegment(segments[0]), // TODO: Make everything use this method, with finalizeLLVMParameter too @@ -662,14 +654,12 @@ function intertyper(data, parseFunctions, baseLineNum) { processItem: function(item) { if (item.tokens[1].text == 'label') { return [{ - __result__: true, intertype: 'branch', label: toNiceIdent(item.tokens[2].text), lineNum: item.lineNum }]; } else { return [{ - __result__: true, intertype: 'branch', ident: item.tokens[2].text, labelTrue: toNiceIdent(item.tokens[5].text), @@ -683,7 +673,6 @@ function intertyper(data, parseFunctions, baseLineNum) { substrate.addActor('Return', { processItem: function(item) { return [{ - __result__: true, intertype: 'return', type: item.tokens[1].text, value: item.tokens[2] ? parseLLVMSegment(item.tokens.slice(2)) : null, @@ -707,7 +696,6 @@ function intertyper(data, parseFunctions, baseLineNum) { return ret; } return [{ - __result__: true, intertype: 'switch', type: item.tokens[1].text, ident: item.tokens[2].text, @@ -721,7 +709,6 @@ function intertyper(data, parseFunctions, baseLineNum) { substrate.addActor('FuncEnd', { processItem: function(item) { return [{ - __result__: true, intertype: 'functionEnd', lineNum: item.lineNum }]; @@ -734,7 +721,6 @@ function intertyper(data, parseFunctions, baseLineNum) { item.tokens.splice(1, 1); } return [{ - __result__: true, intertype: 'functionStub', ident: item.tokens[2].text, returnType: item.tokens[1], @@ -747,7 +733,6 @@ function intertyper(data, parseFunctions, baseLineNum) { substrate.addActor('Unreachable', { processItem: function(item) { return [{ - __result__: true, intertype: 'unreachable', lineNum: item.lineNum }]; diff --git a/src/jsifier.js b/src/jsifier.js index 90f4ae86..85108b7d 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -9,7 +9,7 @@ function JSify(data, functionsOnly, givenTypes, givenFunctions) { // Now that analysis has completed, we can get around to handling unparsedFunctions (functionsOnly ? data.functions : data.unparsedFunctions.concat(data.functions)).forEach(function(func) { - // XXX Save just what we need, to save memory - whether there are varargs, and the # of parameters + // Save just what we need, to save memory - whether there are varargs, and the # of parameters FUNCTIONS[func.ident] = { hasVarArgs: func.hasVarArgs, numParams: func.params.length @@ -33,7 +33,6 @@ function JSify(data, functionsOnly, givenTypes, givenFunctions) { if (type.needsFlattening && !type.flatFactor) { item.JS += 'var ' + niceName + '___FLATTENER = ' + JSON.stringify(TYPES[item.name_].flatIndexes) + ';'; } - item.__result__ = true; return [item]; } }); @@ -172,7 +171,7 @@ function JSify(data, functionsOnly, givenTypes, givenFunctions) { return '0'; } else if (segment[1].text == 'zeroinitializer') { return makeEmptyStruct(segment[0].text); - } else if (segment[1].text in searchable('bitcast', 'inttoptr', 'ptrtoint')) { // TODO: Use parse/finalizeLLVMFunctionCall + } else if (segment[1].text in set('bitcast', 'inttoptr', 'ptrtoint')) { // TODO: Use parse/finalizeLLVMFunctionCall var type = segment[2].item.tokens.slice(-1)[0].text; // TODO: Use this? return handleSegment(segment[2].item.tokens.slice(0, -2)); } else if (segment[1].text in PARSABLE_LLVM_FUNCTIONS) { @@ -228,7 +227,6 @@ function JSify(data, functionsOnly, givenTypes, givenFunctions) { substrate.addActor('GlobalVariable', { processItem: function(item) { item.intertype = 'GlobalVariableStub'; - item.__result__ = true; var ret = [item]; if (item.ident == '_llvm_global_ctors') { item.JS = '\n__globalConstructor__ = function() {\n' + @@ -248,7 +246,6 @@ function JSify(data, functionsOnly, givenTypes, givenFunctions) { ret.push({ intertype: 'GlobalVariablePostSet', JS: 'IHEAP[' + item.ident + '+' + i + '] = ' + value + ';', - __result__: true }); constant[i] = '0'; } @@ -259,7 +256,6 @@ function JSify(data, functionsOnly, givenTypes, givenFunctions) { return ret.concat({ intertype: 'GlobalVariable', JS: item.ident + ' = ' + constant + ';', - __result__: true }); } } @@ -288,7 +284,6 @@ function JSify(data, functionsOnly, givenTypes, givenFunctions) { } else { item.JS = '// stub for ' + item.ident; } - item.__result__ = true; return [item]; } }); @@ -442,7 +437,6 @@ function JSify(data, functionsOnly, givenTypes, givenFunctions) { if (LABEL_DEBUG) func.JS += " INDENT = INDENT.substr(0, INDENT.length-2);\n"; func.JS += '}\n'; func.JS += func.ident + '.__index__ = Runtime.getFunctionIndex(' + func.ident + ', "' + func.ident + '");\n'; - func.__result__ = true; return func; } }); @@ -518,7 +512,7 @@ function JSify(data, functionsOnly, givenTypes, givenFunctions) { return substrate.addActor('Intertype:' + intertype, { processItem: function(item) { item.JS = func(item); - if (!item.JS) throw "XXX - no JS generated for " + dump(item); + if (!item.JS) throw "No JS generated for " + dump(item); this.forwardItem(item, 'FuncLineTriager'); } }); @@ -556,7 +550,7 @@ function JSify(data, functionsOnly, givenTypes, givenFunctions) { label = label.substr(1); if (label === 'entry') return '-1'; if (label === parseInt(label)) return label; // clang - //return '"' + label + '"'; // XXX debugging + //return '"' + label + '"'; // debugging label = toNiceIdent(label); if (label in LABEL_IDs) return LABEL_IDs[label]; return LABEL_IDs[label] = LABEL_ID_COUNTER ++; @@ -721,12 +715,12 @@ function JSify(data, functionsOnly, givenTypes, givenFunctions) { case 'sdiv': case 'udiv': return checkOverflow('Math.floor(' + ident1 + ' / ' + ident2 + ')'); case 'mul': return checkOverflow(ident1 + ' * ' + ident2); case 'urem': case 'srem': return 'Math.floor(' + ident1 + ' % ' + ident2 + ')'; - case 'or': return ident1 + ' | ' + ident2; // XXX this forces into a 32-bit int - add overflow-style checks? - case 'and': return ident1 + ' & ' + ident2; // XXX ^ - case 'xor': return ident1 + ' ^ ' + ident2; // XXX ^ - case 'shl': return ident1 + ' << ' + ident2; // XXX ^ - case 'ashr': return ident1 + ' >> ' + ident2; // XXX ^ - case 'lshr': return ident1 + ' >>> ' + ident2; // XXX ^ + case 'or': return ident1 + ' | ' + ident2; // TODO this forces into a 32-bit int - add overflow-style checks? also other bitops below us + case 'and': return ident1 + ' & ' + ident2; + case 'xor': return ident1 + ' ^ ' + ident2; + case 'shl': return ident1 + ' << ' + ident2; + case 'ashr': return ident1 + ' >> ' + ident2; + case 'lshr': return ident1 + ' >>> ' + ident2; case 'fadd': return ident1 + ' + ' + ident2; case 'fsub': return ident1 + ' - ' + ident2; case 'fdiv': return ident1 + ' / ' + ident2; @@ -746,8 +740,8 @@ function JSify(data, functionsOnly, givenTypes, givenFunctions) { } case 'fcmp': { switch (variant) { - // XXX 'o' ones should be 'ordered (no NaN) and', - // 'u' ones should be 'unordered or'. + // TODO 'o' ones should be 'ordered (no NaN) and', + // 'u' ones should be 'unordered or'. case 'uge': case 'oge': return ident1 + ' >= ' + ident2; case 'ule': case 'ole': return ident1 + ' <= ' + ident2; case 'ugt': case 'ogt': return ident1 + ' > ' + ident2; @@ -770,14 +764,8 @@ function JSify(data, functionsOnly, givenTypes, givenFunctions) { return '((' + ident1 + ') & ' + (Math.pow(2, bitsLeft)-1) + ')'; } case 'select': return ident1 + ' ? ' + ident2 + ' : ' + ident3; - case 'ptrtoint': { - //if (type != 'i8*') print('// XXX Warning: Risky ptrtoint operation on line ' + lineNum); - return ident1; - } - case 'inttoptr': { - //print('// XXX Warning: inttoptr operation on line ' + lineNum); - return ident1; - } + case 'ptrtoint': return ident1; + case 'inttoptr': return ident1; default: throw 'Unknown mathcmp op: ' + item.op; } } }); @@ -843,7 +831,7 @@ function JSify(data, functionsOnly, givenTypes, givenFunctions) { } } else { if (curr != 0) { - indexes.push(curr); // XXX QUANTUM_SIZE? + indexes.push(curr); } } if (!isNumber(curr) || parseInt(curr) < 0) { @@ -866,7 +854,7 @@ function JSify(data, functionsOnly, givenTypes, givenFunctions) { function finalizeLLVMFunctionCall(item) { switch(item.intertype) { - case 'getelementptr': // XXX finalizeLLVMParameter on the ident and the indexes? + case 'getelementptr': // TODO finalizeLLVMParameter on the ident and the indexes? return makePointer(makeGetSlab(item.ident, item.type), getGetElementPtrIndexes(item), null, item.type); case 'bitcast': case 'inttoptr': @@ -906,8 +894,6 @@ function JSify(data, functionsOnly, givenTypes, givenFunctions) { } makeFuncLineActor('bitcast', function(item) { - // XXX Don't we need to copy ptr - i.e. create new ones (at least if uses > just the next line)? - // XXX hardcoded ptr impl - as ptrs are ints, we don't need to copy var ident = toNiceIdent(item.ident); return ident; }); diff --git a/src/parseTools.js b/src/parseTools.js index 58b1ed71..a5a20939 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -163,7 +163,7 @@ function splitTokenList(tokens) { if (tokens.slice(-1)[0].text != ',') tokens.push({text:','}); var ret = []; var seg = []; - var SPLITTERS = searchable(',', 'to'); // 'to' can separate parameters as well... + var SPLITTERS = set(',', 'to'); // 'to' can separate parameters as well... for (var i = 0; i < tokens.length; i++) { var token = tokens[i]; if (token.text in SPLITTERS) { @@ -317,7 +317,7 @@ function cleanSegment(segment) { return segment; } -PARSABLE_LLVM_FUNCTIONS = searchable('getelementptr', 'bitcast', 'inttoptr', 'ptrtoint', 'mul', 'icmp', 'zext'); +PARSABLE_LLVM_FUNCTIONS = set('getelementptr', 'bitcast', 'inttoptr', 'ptrtoint', 'mul', 'icmp', 'zext'); // Parses a function call of form // TYPE functionname MODIFIERS (...) diff --git a/src/utility.js b/src/utility.js index ce726fbe..6973362d 100644 --- a/src/utility.js +++ b/src/utility.js @@ -1,4 +1,5 @@ -// General JS utilities +// General JS utilities - things that might be useful in any JS project. +// Nothing specific to Emscripten appears here. function safeQuote(x) { return x.replace(/"/g, '\\"') @@ -90,15 +91,6 @@ function zeros(size) { return ret; } -function searchable() { - if (typeof arguments[0] === 'object') arguments = arguments[0]; - var ret = {}; - for (var i = 0; i < arguments.length; i++) { - ret[arguments[i]] = 0; - } - return ret; -} - function walkJSON(item, func) { if (item.length) { for (var x = 0; x < item.length; x++) { @@ -204,9 +196,30 @@ function mergeInto(obj, other) { return obj; } +function isNumber(x) { + return x == parseFloat(x); +} + +function flatten(x) { + if (typeof x !== 'object') return x; + var ret = []; + for (var i = 0; i < x.length; i++) { + ret = ret.concat(flatten(x[i])); + } + return ret; +} + // Sets -set = searchable; // Create a 'set' +function set() { + if (typeof arguments[0] === 'object') arguments = arguments[0]; + var ret = {}; + for (var i = 0; i < arguments.length; i++) { + ret[arguments[i]] = 0; + } + return ret; +} + function setSub(x, y) { var ret = set(values(x)); for (yy in y) { @@ -228,16 +241,3 @@ function setIntersect(x, y) { return ret; } -function isNumber(x) { - return x == parseFloat(x); -} - -function flatten(x) { - if (typeof x !== 'object') return x; - var ret = []; - for (var i = 0; i < x.length; i++) { - ret = ret.concat(flatten(x[i])); - } - return ret; -} - |