summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/analyzer.js648
-rw-r--r--src/compiler.js1
-rw-r--r--src/intertyper.js3
-rw-r--r--src/jsifier.js39
-rw-r--r--src/library.js8
-rw-r--r--src/modules.js2
-rw-r--r--src/parseTools.js157
-rw-r--r--src/runtime.js27
-rw-r--r--tests/cases/i64toi8star.ll2
-rw-r--r--tests/cases/inttoptr.ll2
-rw-r--r--tests/cases/lifetime.ll42
-rw-r--r--tests/cases/lifetime.py6
-rw-r--r--tests/lifetime.ll37
-rwxr-xr-xtests/runner.py68
-rwxr-xr-xtools/bindings_generator.py4
-rw-r--r--tools/shared.py1
16 files changed, 582 insertions, 465 deletions
diff --git a/src/analyzer.js b/src/analyzer.js
index 729d4607..1c643303 100644
--- a/src/analyzer.js
+++ b/src/analyzer.js
@@ -22,6 +22,7 @@ function cleanFunc(func) {
var BRANCH_INVOKE = set('branch', 'invoke');
var SIDE_EFFECT_CAUSERS = set('call', 'invoke', 'atomic');
+var UNUNFOLDABLE = set('value', 'type', 'phiparam');
// Analyzer
@@ -117,23 +118,16 @@ function analyzer(data, sidePass) {
// Currently we just legalize completely unrealistic types into bundles of i32s, and just
// the most common instructions that can be involved with such types: load, store, shifts,
// trunc and zext.
- //
- // TODO: Expand this also into legalization of i64 into i32,i32, which can then
- // replace our i64 mode 1 implementation. Legalizing i64s is harder though
- // as they can appear in function arguments and we would also need to implement
- // an unfolder (to uninline inline LLVM function calls, so that each LLVM line
- // has a single LLVM instruction).
substrate.addActor('Legalizer', {
processItem: function(data) {
// Legalization
if (USE_TYPED_ARRAYS == 2) {
function isIllegalType(type) {
- return getBits(type) > 64;
+ var bits = getBits(type);
+ return bits > 0 && (bits >= 64 || !isPowerOfTwo(bits));
}
function getLegalVars(base, bits) {
- if (isNumber(base)) {
- return getLegalLiterals(base, bits);
- }
+ assert(!isNumber(base));
var ret = new Array(Math.ceil(bits/32));
var i = 0;
while (bits > 0) {
@@ -154,48 +148,95 @@ function analyzer(data, sidePass) {
}
return ret;
}
- // Unfolds internal inline llvmfunc calls, for example x = load (bitcast y)
- // will become temp = y \n x = load temp
- // @return The index of the original line, after the unfolding. In the example
- // above, the index returned will be the new index of the line with `load',
- // that is, i+1.
- function unfold(lines, i, item, slot) {
- if (item[slot].intertype == 'value') return i;
- // TODO: unfold multiple slots at once
- var tempIdent = '$$emscripten$temp$' + i;
- item[slot].assignTo = tempIdent;
- item[slot].lineNum = lines[i].lineNum - 0.5;
- lines.splice(i, 0, item[slot]);
- item[slot] = { intertype: 'value', ident: tempIdent, type: item[slot].type };
- return i+1;
+ // Uses the right factor to multiply line numbers by so that they fit in between
+ // the line[i] and the line after it
+ function interpLines(lines, i, toAdd) {
+ var prev = i >= 0 ? lines[i].lineNum : -1;
+ var next = (i < lines.length-1) ? lines[i+1].lineNum : (lines[i].lineNum + 0.5);
+ var factor = (next - prev)/(4*toAdd.length+3);
+ for (var k = 0; k < toAdd.length; k++) {
+ toAdd[k].lineNum = prev + ((k+1)*factor);
+ }
}
function removeAndAdd(lines, i, toAdd) {
var item = lines[i];
- var interp = getInterp(lines, i, toAdd.length);
- for (var k = 0; k < toAdd.length; k++) {
- toAdd[k].lineNum = item.lineNum + (k*interp);
- }
+ interpLines(lines, i, toAdd);
Array.prototype.splice.apply(lines, [i, 1].concat(toAdd));
return toAdd.length;
}
- // Assuming we will replace the item at line i, with num items, returns
- // the right factor to multiply line numbers by so that they fit in between
- // the removed line and the line after it
- function getInterp(lines, i, num) {
- var next = (i < lines.length-1) ? lines[i+1].lineNum : (lines[i].lineNum + 0.5);
- return (next - lines[i].lineNum)/(3*num+2);
+ function legalizeFunctionParameters(params) {
+ var i = 0;
+ while (i < params.length) {
+ var param = params[i];
+ if (param.intertype == 'value' && isIllegalType(param.type)) {
+ var toAdd = getLegalVars(param.ident, getBits(param.type)).map(function(element) {
+ return {
+ intertype: 'value',
+ type: 'i' + element.bits,
+ ident: element.ident,
+ byval: 0
+ };
+ });
+ Array.prototype.splice.apply(params, [i, 1].concat(toAdd));
+ i += toAdd.length;
+ continue;
+ }
+ i++;
+ }
}
data.functions.forEach(function(func) {
+ // Legalize function params
+ legalizeFunctionParameters(func.params);
+ // Legalize lines in labels
+ var tempId = 0;
func.labels.forEach(function(label) {
var i = 0, bits;
while (i < label.lines.length) {
var item = label.lines[i];
- if (item.intertype == 'store') {
- if (isIllegalType(item.valueType)) {
- dprint('legalizer', 'Legalizing store at line ' + item.lineNum);
+ var value = item;
+ // Check if we need to legalize here, and do some trivial legalization along the way
+ var isIllegal = false;
+ walkInterdata(item, function(item) {
+ if (item.intertype == 'getelementptr' || (item.intertype == 'call' && item.ident in LLVM.INTRINSICS_32)) {
+ // Turn i64 args into i32
+ for (var i = 0; i < item.params.length; i++) {
+ if (item.params[i].type == 'i64') item.params[i].type = 'i32';
+ }
+ }
+ if (isIllegalType(item.valueType) || isIllegalType(item.type)) {
+ isIllegal = true;
+ }
+ });
+ if (!isIllegal) {
+ i++;
+ continue;
+ }
+ // Unfold this line. If we unfolded, we need to return and process the lines we just
+ // generated - they may need legalization too
+ var unfolded = [];
+ walkAndModifyInterdata(item, function(subItem) {
+ // Unfold all non-value interitems that we can, and also unfold all numbers (doing the latter
+ // makes it easier later since we can then assume illegal expressions are always variables
+ // accessible through ident$x, and not constants we need to parse then and there)
+ if (subItem != item && (!(subItem.intertype in UNUNFOLDABLE) ||
+ (subItem.intertype == 'value' && isNumber(subItem.ident) && isIllegalType(subItem.type)))) {
+ var tempIdent = '$$emscripten$temp$' + (tempId++);
+ subItem.assignTo = tempIdent;
+ unfolded.unshift(subItem);
+ return { intertype: 'value', ident: tempIdent, type: subItem.type };
+ }
+ });
+ if (unfolded.length > 0) {
+ interpLines(label.lines, i-1, unfolded);
+ Array.prototype.splice.apply(label.lines, [i, 0].concat(unfolded));
+ continue; // remain at this index, to unfold newly generated lines
+ }
+ // This is an illegal-containing line, and it is unfolded. Legalize it now
+ dprint('legalizer', 'Legalizing ' + item.intertype + ' at line ' + item.lineNum);
+ switch (item.intertype) {
+ case 'store': {
var toAdd = [];
bits = getBits(item.valueType);
- i = unfold(label.lines, i, item, 'value');
var elements;
elements = getLegalVars(item.value.ident, bits);
var j = 0;
@@ -228,238 +269,299 @@ function analyzer(data, sidePass) {
i += removeAndAdd(label.lines, i, toAdd);
continue;
}
- } else if (item.assignTo) {
- var value = item;
- switch (value.intertype) {
- case 'load': {
- if (isIllegalType(value.valueType)) {
- dprint('legalizer', 'Legalizing load at line ' + item.lineNum);
- bits = getBits(value.valueType);
- i = unfold(label.lines, i, value, 'pointer');
- var interp = getInterp(label.lines, i, Math.ceil(bits/32));
- label.lines.splice(i, 1);
- var elements = getLegalVars(item.assignTo, bits);
- var j = 0;
- elements.forEach(function(element) {
- var tempVar = '$st$' + i + '$' + j;
- label.lines.splice(i+j*2, 0, {
- intertype: 'getelementptr',
- assignTo: tempVar,
- ident: value.pointer.ident,
- type: '[0 x i32]*',
- params: [
- { intertype: 'value', ident: value.pointer.ident, type: '[0 x i32]*' }, // technically bitcast is needed in llvm, but not for us
- { intertype: 'value', ident: '0', type: 'i32' },
- { intertype: 'value', ident: j.toString(), type: 'i32' }
- ],
- lineNum: item.lineNum + (j*interp)
- });
- var actualSizeType = 'i' + element.bits; // The last one may be smaller than 32 bits
- label.lines.splice(i+j*2+1, 0, {
- intertype: 'load',
- assignTo: element.ident,
- pointerType: actualSizeType + '*',
- valueType: actualSizeType,
- type: actualSizeType, // XXX why is this missing from intertyper?
- pointer: { intertype: 'value', ident: tempVar, type: actualSizeType + '*' },
- ident: tempVar,
- pointerType: actualSizeType + '*',
- align: value.align,
- lineNum: item.lineNum + ((j+0.5)*interp)
- });
- j++;
- });
- Types.needAnalysis['[0 x i32]'] = 0;
- i += j*2;
- continue;
- }
- break;
+ // call, return: Return value is in an unlegalized array literal. Not fully optimal.
+ case 'call': case 'invoke': {
+ bits = getBits(value.type);
+ var elements = getLegalVars(item.assignTo, bits);
+ var toAdd = [value];
+ // legalize parameters
+ legalizeFunctionParameters(value.params);
+ if (value.assignTo) {
+ // legalize return value
+ var j = 0;
+ toAdd = toAdd.concat(elements.map(function(element) {
+ return {
+ intertype: 'value',
+ assignTo: element.ident,
+ type: 'i' + bits,
+ ident: value.assignTo + '[' + (j++) + ']'
+ };
+ }));
}
- case 'phi': {
- if (isIllegalType(value.type)) {
- dprint('legalizer', 'Legalizing phi at line ' + item.lineNum);
- bits = getBits(value.type);
- var toAdd = [];
- var elements = getLegalVars(item.assignTo, bits);
- var j = 0;
- elements.forEach(function(element) {
- toAdd.push({
- intertype: 'phi',
- assignTo: element.ident,
- type: 'i' + element.bits,
- params: value.params.map(function(param) {
- return {
- intertype: 'phiparam',
- label: param.label,
- value: { // TODO: unfolding
- intertype: 'value',
- ident: param.value.ident + '$' + j,
- type: 'i' + element.bits,
- }
- };
- })
- });
- j++;
- });
- i += removeAndAdd(label.lines, i, toAdd);
+ i += removeAndAdd(label.lines, i, toAdd);
+ continue;
+ }
+ case 'return': {
+ bits = getBits(item.type);
+ var elements = getLegalVars(item.value.ident, bits);
+ item.value.ident = '[' + elements.map(function(element) { return element.ident }).join(',') + ']';
+ i++;
+ continue;
+ }
+ case 'value': {
+ bits = getBits(value.type);
+ var elements = getLegalVars(item.assignTo, bits);
+ var values = getLegalLiterals(item.ident, bits);
+ var j = 0;
+ var toAdd = elements.map(function(element) {
+ return {
+ intertype: 'value',
+ assignTo: element.ident,
+ type: 'i' + bits,
+ ident: values[j++].ident
+ };
+ });
+ i += removeAndAdd(label.lines, i, toAdd);
+ continue;
+ }
+ case 'load': {
+ bits = getBits(value.valueType);
+ var elements = getLegalVars(item.assignTo, bits);
+ var j = 0;
+ var toAdd = [];
+ elements.forEach(function(element) {
+ var tempVar = '$st$' + i + '$' + j;
+ toAdd.push({
+ intertype: 'getelementptr',
+ assignTo: tempVar,
+ ident: value.pointer.ident,
+ type: '[0 x i32]*',
+ params: [
+ { intertype: 'value', ident: value.pointer.ident, type: '[0 x i32]*' }, // technically bitcast is needed in llvm, but not for us
+ { intertype: 'value', ident: '0', type: 'i32' },
+ { intertype: 'value', ident: j.toString(), type: 'i32' }
+ ]
+ });
+ var actualSizeType = 'i' + element.bits; // The last one may be smaller than 32 bits
+ toAdd.push({
+ intertype: 'load',
+ assignTo: element.ident,
+ pointerType: actualSizeType + '*',
+ valueType: actualSizeType,
+ type: actualSizeType, // XXX why is this missing from intertyper?
+ pointer: { intertype: 'value', ident: tempVar, type: actualSizeType + '*' },
+ ident: tempVar,
+ pointerType: actualSizeType + '*',
+ align: value.align
+ });
+ j++;
+ });
+ Types.needAnalysis['[0 x i32]'] = 0;
+ i += removeAndAdd(label.lines, i, toAdd);
+ continue;
+ }
+ case 'phi': {
+ bits = getBits(value.type);
+ var toAdd = [];
+ var elements = getLegalVars(item.assignTo, bits);
+ var j = 0;
+ elements.forEach(function(element) {
+ toAdd.push({
+ intertype: 'phi',
+ assignTo: element.ident,
+ type: 'i' + element.bits,
+ params: value.params.map(function(param) {
+ return {
+ intertype: 'phiparam',
+ label: param.label,
+ value: {
+ intertype: 'value',
+ ident: param.value.ident + '$' + j,
+ type: 'i' + element.bits,
+ }
+ };
+ })
+ });
+ j++;
+ });
+ i += removeAndAdd(label.lines, i, toAdd);
+ continue;
+ }
+ case 'bitcast': {
+ var inType = item.type2;
+ var outType = item.type;
+ if ((inType in Runtime.INT_TYPES && outType in Runtime.FLOAT_TYPES) ||
+ (inType in Runtime.FLOAT_TYPES && outType in Runtime.INT_TYPES)) {
+ i++;
+ continue; // special case, handled in processMathop
+ }
+ // fall through
+ }
+ case 'inttoptr': case 'ptrtoint': {
+ value = {
+ op: item.intertype,
+ param1: item.params[0]
+ };
+ // fall through
+ }
+ case 'mathop': {
+ var toAdd = [];
+ var sourceBits = getBits(value.param1.type);
+ // All mathops can be parametrized by how many shifts we do, and how big the source is
+ var shifts = 0;
+ var targetBits = sourceBits;
+ var processor = null;
+ var signed = false;
+ switch (value.op) {
+ case 'ashr': {
+ signed = true;
+ // fall through
+ }
+ case 'lshr': {
+ shifts = parseInt(value.param2.ident);
+ break;
+ }
+ case 'shl': {
+ shifts = -parseInt(value.param2.ident);
+ break;
+ }
+ case 'sext': {
+ signed = true;
+ // fall through
+ }
+ case 'trunc': case 'zext': case 'ptrtoint': {
+ targetBits = getBits(value.param2.ident);
+ break;
+ }
+ case 'inttoptr': {
+ targetBits = 32;
+ break;
+ }
+ case 'bitcast': {
+ break;
+ }
+ case 'select': {
+ sourceBits = targetBits = getBits(value.param2.type);
+ var otherElementsA = getLegalVars(value.param2.ident, sourceBits);
+ var otherElementsB = getLegalVars(value.param3.ident, sourceBits);
+ processor = function(result, j) {
+ return {
+ intertype: 'mathop',
+ op: 'select',
+ type: 'i' + otherElementsA[j].bits,
+ param1: value.param1,
+ param2: { intertype: 'value', ident: otherElementsA[j].ident, type: 'i' + otherElementsA[j].bits },
+ param3: { intertype: 'value', ident: otherElementsB[j].ident, type: 'i' + otherElementsB[j].bits }
+ };
+ };
+ break;
+ }
+ case 'or': case 'and': case 'xor': {
+ var otherElements = getLegalVars(value.param2.ident, sourceBits);
+ processor = function(result, j) {
+ return {
+ intertype: 'mathop',
+ op: value.op,
+ type: 'i' + otherElements[j].bits,
+ param1: result,
+ param2: { intertype: 'value', ident: otherElements[j].ident, type: 'i' + otherElements[j].bits }
+ };
+ };
+ break;
+ }
+ case 'add': case 'sub': case 'sdiv': case 'udiv': case 'mul': case 'urem': case 'srem':
+ case 'icmp':case 'uitofp': case 'sitofp': {
+ // We cannot do these in parallel chunks of 32-bit operations. We will handle these in processMathop
+ i++;
continue;
}
- break;
+ default: throw 'Invalid mathop for legalization: ' + [value.op, item.lineNum, dump(item)];
}
- case 'mathop': {
- if (isIllegalType(value.type)) {
- dprint('legalizer', 'Legalizing mathop at line ' + item.lineNum);
- var toAdd = [];
- assert(value.param1.intertype == 'value', 'TODO: unfolding');
- var sourceBits = getBits(value.param1.type);
- var sourceElements;
- if (sourceBits <= 64) {
- // The input is a legal type
- if (sourceBits <= 32) {
- sourceElements = [{ ident: value.param1.ident, bits: sourceBits }];
- } else if (sourceBits == 64 && I64_MODE == 1) {
- sourceElements = [{ ident: value.param1.ident + '[0]', bits: 32 },
- { ident: value.param1.ident + '[1]', bits: 32 }];
- // Add the source element as a param so that it is not eliminated as unneeded (the idents are not a simple ident here)
- toAdd.push({
- intertype: 'value', ident: ';', type: 'rawJS',
- params: [{ intertype: 'value', ident: value.param1.ident, type: 'i32' }]
- });
- } else {
- throw 'Invalid legal type as source of legalization ' + sourceBits;
- }
- } else {
- sourceElements = getLegalVars(value.param1.ident, sourceBits);
- }
- // All mathops can be parametrized by how many shifts we do, and how big the source is
- var shifts = 0;
- var targetBits;
- var processor = null;
- switch (value.op) {
- case 'lshr': {
- assert(value.param2.intertype == 'value', 'TODO: unfolding');
- shifts = parseInt(value.param2.ident);
- targetBits = sourceBits;
- break;
- }
- case 'shl': {
- assert(value.param2.intertype == 'value', 'TODO: unfolding');
- shifts = -parseInt(value.param2.ident);
- targetBits = sourceBits;
- break;
- }
- case 'trunc': case 'zext': {
- assert(value.param2.intertype == 'type' || value.param2.intertype == 'value', 'TODO: unfolding');
- targetBits = getBits(value.param2.ident);
- break;
- }
- case 'or': case 'and': case 'xor': {
- targetBits = sourceBits;
- var otherElements = getLegalVars(value.param2.ident, sourceBits);
- processor = function(result, j) {
- return {
- intertype: 'mathop',
- op: value.op,
- type: 'i' + otherElements[j].bits,
- param1: result,
- param2: { intertype: 'value', ident: otherElements[j].ident, type: 'i' + otherElements[j].bits }
- };
- };
- break;
- }
- default: throw 'Invalid mathop for legalization: ' + [value.op, item.lineNum, dump(item)];
- }
- // Do the legalization
- assert(isNumber(shifts), 'TODO: handle nonconstant shifts');
- var targetElements = getLegalVars(item.assignTo, targetBits);
- var sign = shifts >= 0 ? 1 : -1;
- var shiftOp = shifts >= 0 ? 'shl' : 'lshr';
- var shiftOpReverse = shifts >= 0 ? 'lshr' : 'shl';
- var whole = shifts >= 0 ? Math.floor(shifts/32) : Math.ceil(shifts/32);
- var fraction = Math.abs(shifts % 32);
- for (var j = 0; j < targetElements.length; j++) {
- var result = {
- intertype: 'value',
- ident: (j + whole >= 0 && j + whole < sourceElements.length) ? sourceElements[j + whole].ident : '0',
- type: 'i32',
- };
- if (fraction != 0) {
- var other = {
- intertype: 'value',
- ident: (j + sign + whole >= 0 && j + sign + whole < sourceElements.length) ? sourceElements[j + sign + whole].ident : '0',
- type: 'i32',
- };
- other = {
- intertype: 'mathop',
- op: shiftOp,
- type: 'i32',
- param1: other,
- param2: { intertype: 'value', ident: (32 - fraction).toString(), type: 'i32' }
- };
- result = {
- intertype: 'mathop',
- op: shiftOpReverse,
- type: 'i32',
- param1: result,
- param2: { intertype: 'value', ident: fraction.toString(), type: 'i32' }
- };
- result = {
- intertype: 'mathop',
- op: 'or',
- type: 'i32',
- param1: result,
- param2: other
- }
- }
- if (targetElements[j].bits < 32 && shifts < 0) {
- // truncate bits that fall off the end. This is not needed in most cases, can probably be optimized out
- result = {
- intertype: 'mathop',
- op: 'and',
- type: 'i32',
- param1: result,
- param2: { intertype: 'value', ident: (Math.pow(2, targetElements[j].bits)-1).toString(), type: 'i32' }
- }
- }
- if (processor) {
- result = processor(result, j);
- }
- result.assignTo = targetElements[j].ident;
- toAdd.push(result);
+ // Do the legalization
+ var sourceElements;
+ if (sourceBits <= 32) {
+ // The input is a legal type
+ sourceElements = [{ ident: value.param1.ident, bits: sourceBits }];
+ } else {
+ sourceElements = getLegalVars(value.param1.ident, sourceBits);
+ }
+ if (!isNumber(shifts)) {
+ // We can't statically legalize this, do the operation at runtime TODO: optimize
+ assert(sourceBits == 64, 'TODO: handle nonconstant shifts on != 64 bits');
+ value.intertype = 'value';
+ value.ident = 'Runtime.bitshift64(' + sourceElements[0].ident + ', ' +
+ sourceElements[1].ident + ',"' + value.op + '",' + value.param2.ident + '$0);' +
+ 'var ' + value.assignTo + '$0 = ' + value.assignTo + '[0], ' + value.assignTo + '$1 = ' + value.assignTo + '[1];';
+ i++;
+ continue;
+ }
+ var targetElements = getLegalVars(item.assignTo, targetBits);
+ var sign = shifts >= 0 ? 1 : -1;
+ var shiftOp = shifts >= 0 ? 'shl' : 'lshr';
+ var shiftOpReverse = shifts >= 0 ? 'lshr' : 'shl';
+ var whole = shifts >= 0 ? Math.floor(shifts/32) : Math.ceil(shifts/32);
+ var fraction = Math.abs(shifts % 32);
+ if (signed) {
+ var signedFill = '((' + sourceElements[sourceElements.length-1].ident + '|0) < 0 ? -1 : 0)';
+ var signedKeepAlive = { intertype: 'value', ident: sourceElements[sourceElements.length-1].ident, type: 'i32' };
+ }
+ for (var j = 0; j < targetElements.length; j++) {
+ var result = {
+ intertype: 'value',
+ ident: (j + whole >= 0 && j + whole < sourceElements.length) ? sourceElements[j + whole].ident : (signed ? signedFill : '0'),
+ param1: (signed && j + whole > sourceElements.length) ? signedKeepAlive : null,
+ type: 'i32',
+ };
+ if (fraction != 0) {
+ var other = {
+ intertype: 'value',
+ ident: (j + sign + whole >= 0 && j + sign + whole < sourceElements.length) ? sourceElements[j + sign + whole].ident : (signed ? signedFill : '0'),
+ param1: (signed && j + sign + whole > sourceElements.length) ? signedKeepAlive : null,
+ type: 'i32',
+ };
+ other = {
+ intertype: 'mathop',
+ op: shiftOp,
+ type: 'i32',
+ param1: other,
+ param2: { intertype: 'value', ident: (32 - fraction).toString(), type: 'i32' }
+ };
+ result = {
+ intertype: 'mathop',
+ // shifting in 1s from the top is a special case
+ op: (signed && shifts >= 0 && j + sign + whole >= sourceElements.length) ? 'ashr' : shiftOpReverse,
+ type: 'i32',
+ param1: result,
+ param2: { intertype: 'value', ident: fraction.toString(), type: 'i32' }
+ };
+ result = {
+ intertype: 'mathop',
+ op: 'or',
+ type: 'i32',
+ param1: result,
+ param2: other
}
- if (targetBits <= 64) {
- // We are generating a normal legal type here
- var legalValue;
- if (targetBits == 64 && I64_MODE == 1) {
- // Generate an i64-1 [low,high]. This will be unnecessary when we legalize i64s
- legalValue = {
- intertype: 'value',
- ident: '[' + targetElements[0].ident + ',' + targetElements[1].ident + ']',
- type: 'rawJS',
- // Add the target elements as params so that they are not eliminated as unneeded (the ident is not a simple ident here)
- params: targetElements.map(function(element) {
- return { intertype: 'value', ident: element.ident, type: 'i32' };
- })
- };
- } else if (targetBits <= 32) {
- legalValue = { intertype: 'value', ident: targetElements[0].ident, type: 'rawJS' };
- // truncation to smaller than 32 bits has already been done, if necessary
- } else {
- throw 'Invalid legal type as target of legalization ' + targetBits;
- }
- legalValue.assignTo = item.assignTo;
- toAdd.push(legalValue);
+ }
+ if (targetElements[j].bits < 32 && shifts < 0) {
+ // truncate bits that fall off the end. This is not needed in most cases, can probably be optimized out
+ result = {
+ intertype: 'mathop',
+ op: 'and',
+ type: 'i32',
+ param1: result,
+ param2: { intertype: 'value', ident: (Math.pow(2, targetElements[j].bits)-1).toString(), type: 'i32' }
}
- i += removeAndAdd(label.lines, i, toAdd);
- continue;
}
- break;
+ if (processor) {
+ result = processor(result, j);
+ }
+ result.assignTo = targetElements[j].ident;
+ toAdd.push(result);
+ }
+ if (targetBits <= 32) {
+ // We are generating a normal legal type here
+ legalValue = { intertype: 'value', ident: targetElements[0].ident, type: 'rawJS' };
+ // truncation to smaller than 32 bits has already been done, if necessary
+ legalValue.assignTo = item.assignTo;
+ toAdd.push(legalValue);
}
+ i += removeAndAdd(label.lines, i, toAdd);
+ continue;
}
}
- i++;
- continue;
+ assert(0, 'Could not legalize illegal line: ' + [item.lineNum, dump(item)]);
}
+ if (dcheck('legalizer')) dprint('zz legalized: \n' + dump(label.lines));
});
});
}
@@ -741,33 +843,7 @@ function analyzer(data, sidePass) {
//if (dcheck('vars')) dprint('analyzed variables: ' + dump(func.variables));
}
- // Filter out no longer used variables, collapsing more as we go
- while (true) {
- analyzeVariableUses();
-
- var recalc = false;
-
- keys(func.variables).forEach(function(vname) {
- var variable = func.variables[vname];
- if (variable.uses == 0 && variable.origin != 'funcparam') {
- // Eliminate this variable if we can
- var sideEffects = false;
- walkInterdata(func.lines[variable.rawLinesIndex], function(item) {
- if (item.intertype in SIDE_EFFECT_CAUSERS) sideEffects = true;
- });
- if (!sideEffects) {
- dprint('vars', 'Eliminating ' + vname);
- func.lines[variable.rawLinesIndex].intertype = 'noop';
- func.lines[variable.rawLinesIndex].assignTo = null;
- // in theory we can also null out some fields here to save memory
- delete func.variables[vname];
- recalc = true;
- }
- }
- });
-
- if (!recalc) break;
- }
+ analyzeVariableUses();
// Decision time
diff --git a/src/compiler.js b/src/compiler.js
index bf9d9c54..d37bc68b 100644
--- a/src/compiler.js
+++ b/src/compiler.js
@@ -138,6 +138,7 @@ EXPORTED_GLOBALS = set(EXPORTED_GLOBALS);
// Settings sanity checks
assert(!(USE_TYPED_ARRAYS === 2 && QUANTUM_SIZE !== 4), 'For USE_TYPED_ARRAYS == 2, must have normal QUANTUM_SIZE of 4');
+assert(!(USE_TYPED_ARRAYS !== 2 && I64_MODE === 1), 'i64 mode 1 is only supported with typed arrays mode 2');
// Output some info and warnings based on settings
diff --git a/src/intertyper.js b/src/intertyper.js
index 3dab220b..91ad15eb 100644
--- a/src/intertyper.js
+++ b/src/intertyper.js
@@ -539,9 +539,6 @@ function intertyper(data, sidePass, baseLineNums) {
params: params,
hasVarArgs: hasVarArgs(params),
lineNum: item.lineNum,
- paramIdents: params.map(function(param) {
- return (param.intertype == 'varargs') ? null : toNiceIdent(param.ident);
- }).filter(function(param) { return param != null; })
}];
}
});
diff --git a/src/jsifier.js b/src/jsifier.js
index 71533309..b830fc7c 100644
--- a/src/jsifier.js
+++ b/src/jsifier.js
@@ -497,16 +497,20 @@ function JSify(data, functionsOnly, givenFunctions) {
func.JS = '\n';
+ var paramIdents = func.params.map(function(param) {
+ return (param.intertype == 'varargs') ? null : toNiceIdent(param.ident);
+ }).filter(function(param) { return param != null; })
+
if (CLOSURE_ANNOTATIONS) {
func.JS += '/**\n';
- func.paramIdents.forEach(function(param) {
+ paramIdents.forEach(function(param) {
func.JS += ' * @param {number} ' + param + '\n';
});
func.JS += ' * @return {number}\n'
func.JS += ' */\n';
}
- func.JS += 'function ' + func.ident + '(' + func.paramIdents.join(', ') + ') {\n';
+ func.JS += 'function ' + func.ident + '(' + paramIdents.join(', ') + ') {\n';
if (PROFILE) {
func.JS += ' if (PROFILING) { '
@@ -1046,37 +1050,16 @@ function JSify(data, functionsOnly, givenFunctions) {
var hasVarArgs = isVarArgsFunctionType(type);
var normalArgs = (hasVarArgs && !useJSArgs) ? countNormalArgs(type) : -1;
- if (I64_MODE == 1 && ident in LLVM.INTRINSICS_32) {
- // Some LLVM intrinsics use i64 where it is not needed, and would cause much overhead
- params.forEach(function(param) { if (param.type == 'i64') param.type = 'i32' });
- }
-
params.forEach(function(param, i) {
var val = finalizeParam(param);
if (!hasVarArgs || useJSArgs || i < normalArgs) {
- if (param.type == 'i64' && I64_MODE == 1) {
- val = makeCopyI64(val); // Must copy [low, high] i64s, so they don't end up modified in the caller
- }
args.push(val);
argsTypes.push(param.type);
} else {
- if (!(param.type == 'i64' && I64_MODE == 1)) {
- varargs.push(val);
- varargs = varargs.concat(zeros(Runtime.getNativeFieldSize(param.type)-1));
- varargsTypes.push(param.type);
- varargsTypes = varargsTypes.concat(zeros(Runtime.getNativeFieldSize(param.type)-1));
- } else {
- // i64 mode 1. Write one i32 with type i64, and one i32 with type i32
- varargs.push(val + '[0]');
- varargs = varargs.concat(zeros(Runtime.getNativeFieldSize('i32')-1));
- ignoreFunctionIndexizing.push(varargs.length); // We will have a value there, but no type (the type is i64, but we write two i32s)
- varargs.push(val + '[1]');
- varargs = varargs.concat(zeros(Runtime.getNativeFieldSize('i32')-1));
- varargsTypes.push('i64');
- varargsTypes = varargsTypes.concat(zeros(Runtime.getNativeFieldSize('i32')-1));
- varargsTypes.push('i32');
- varargsTypes = varargsTypes.concat(zeros(Runtime.getNativeFieldSize('i32')-1));
- }
+ varargs.push(val);
+ varargs = varargs.concat(zeros(Runtime.getNativeFieldSize(param.type)-1));
+ varargsTypes.push(param.type);
+ varargsTypes = varargsTypes.concat(zeros(Runtime.getNativeFieldSize(param.type)-1));
}
});
@@ -1096,7 +1079,6 @@ function JSify(data, functionsOnly, givenFunctions) {
varargs.map(function(arg, i) {
var type = varargsTypes[i];
if (type == 0) return null;
- if (I64_MODE == 1 && type == 'i64') type = 'i32'; // We have [i64, 0, 0, 0, i32, 0, 0, 0] in the layout at this point
var ret = makeSetValue(getFastValue('tempInt', '+', offset), 0, arg, type, null, null, QUANTUM_SIZE, null, ',');
offset += Runtime.getNativeFieldSize(type);
return ret;
@@ -1190,6 +1172,7 @@ function JSify(data, functionsOnly, givenFunctions) {
print(postParts[0]);
// Print out global variables and postsets TODO: batching
+ legalizedI64s = false;
JSify(analyzer(intertyper(data.unparsedGlobalss[0].lines, true), true), true, Functions);
data.unparsedGlobalss = null;
diff --git a/src/library.js b/src/library.js
index cf28a73c..e0a38817 100644
--- a/src/library.js
+++ b/src/library.js
@@ -3481,11 +3481,17 @@ LibraryManager.library = {
___setErrNo(ERRNO_CODES.ERANGE);
}
+#if USE_TYPED_ARRAYS == 2
+ if (bits == 64) {
+ ret = [{{{ splitI64('ret') }}}];
+ }
+#else
#if I64_MODE == 1
if (bits == 64) {
ret = {{{ splitI64('ret') }}};
}
#endif
+#endif
return ret;
},
@@ -4377,7 +4383,7 @@ LibraryManager.library = {
ptrTV -= {{{ Runtime.QUANTUM_SIZE }}};
var TI = {{{ makeGetValue('ptrTV', '0', '*') }}};
do {
- if (TI == attemptedTI) return 1;
+ if (TI == attemptedTI) return ptr;
// Go to parent class
var type_infoAddr = {{{ makeGetValue('TI', '0', '*') }}} - {{{ Runtime.QUANTUM_SIZE*2 }}};
var type_info = {{{ makeGetValue('type_infoAddr', '0', '*') }}};
diff --git a/src/modules.js b/src/modules.js
index 52f14c2f..2896d632 100644
--- a/src/modules.js
+++ b/src/modules.js
@@ -161,7 +161,7 @@ var PreProcessor = {
// parameter to it will prevent nativization of the variable being cast (!)
for (var i = 0; i < lines.length; i++) {
var line = lines[i];
- if (/call void @llvm.lifetime.(start|end)\(i\d+ -1, i8\* %(\d+)\).*/.exec(line)) {
+ if (/call void @llvm.lifetime.(start|end)\(i\d+ -1,.*/.exec(line)) {
lines[i] = ';';
}
}
diff --git a/src/parseTools.js b/src/parseTools.js
index 3cc17cc4..1b48737e 100644
--- a/src/parseTools.js
+++ b/src/parseTools.js
@@ -129,9 +129,12 @@ function isIntImplemented(type) {
return type[0] == 'i' || isPointerType(type);
}
+// Note: works for iX types, not pointers (even though they are implemented as ints)
function getBits(type) {
if (!type || type[0] != 'i') return 0;
- return parseInt(type.substr(1));
+ var left = type.substr(1);
+ if (!isNumber(left)) return 0;
+ return parseInt(left);
}
function isVoidType(type) {
@@ -530,18 +533,27 @@ function makeI64(low, high) {
}
}
+// XXX Make all i64 parts signed
+
// Splits a number (an integer in a double, possibly > 32 bits) into an I64_MODE 1 i64 value.
-// Will suffer from rounding. margeI64 does the opposite.
-// TODO: optimize I64 calcs. For example, saving their parts as signed 32 as opposed to unsigned would help
+// Will suffer from rounding. mergeI64 does the opposite.
function splitI64(value) {
// We need to min here, since our input might be a double, and large values are rounded, so they can
// be slightly higher than expected. And if we get 4294967296, that will turn into a 0 if put into a
// HEAP32 or |0'd, etc.
- return makeInlineCalculation(makeI64('VALUE>>>0', 'Math.min(Math.floor(VALUE/4294967296), 4294967295)'), value, 'tempBigIntP');
+ if (legalizedI64s) {
+ return [value + '>>>0', 'Math.min(Math.floor(' + value + '/4294967296), 4294967295)'];
+ } else {
+ return makeInlineCalculation(makeI64('VALUE>>>0', 'Math.min(Math.floor(VALUE/4294967296), 4294967295)'), value, 'tempBigIntP');
+ }
}
function mergeI64(value) {
assert(I64_MODE == 1);
- return makeInlineCalculation(RuntimeGenerator.makeBigInt('VALUE[0]', 'VALUE[1]'), value, 'tempI64');
+ if (legalizedI64s) {
+ return RuntimeGenerator.makeBigInt(value + '$0', value + '$1');
+ } else {
+ return makeInlineCalculation(RuntimeGenerator.makeBigInt('VALUE[0]', 'VALUE[1]'), value, 'tempI64');
+ }
}
// Takes an i64 value and changes it into the [low, high] form used in i64 mode 1. In that
@@ -646,10 +658,11 @@ function parseI64Constant(str) {
if (!isNumber(str)) {
// This is a variable. Copy it, so we do not modify the original
- return makeCopyI64(str);
+ return legalizedI64s ? str : makeCopyI64(str);
}
var parsed = parseArbitraryInt(str, 64);
+ if (legalizedI64s) return parsed;
return '[' + parsed[0] + ',' + parsed[1] + ']';
}
@@ -888,11 +901,6 @@ function makeGetValue(ptr, pos, type, noNeedFirst, unsigned, ignore, align, noSa
if (i < bytes-1) ret += '|';
}
ret = '(' + makeSignOp(ret, type, unsigned ? 'un' : 're', true);
- } else {
- assert(bytes == 8);
- ret += 'tempBigInt=' + makeGetValue(ptr, pos, 'i32', noNeedFirst, true, ignore, align) + ',';
- ret += 'tempBigInt2=' + makeGetValue(ptr, getFastValue(pos, '+', Runtime.getNativeTypeSize('i32')), 'i32', noNeedFirst, true, ignore, align) + ',';
- ret += makeI64('tempBigInt', 'tempBigInt2');
}
} else {
if (type == 'float') {
@@ -906,11 +914,6 @@ function makeGetValue(ptr, pos, type, noNeedFirst, unsigned, ignore, align, noSa
}
}
- if (type == 'i64' && I64_MODE == 1) {
- return '[' + makeGetValue(ptr, pos, 'i32', noNeedFirst, 1, ignore) + ','
- + makeGetValue(ptr, getFastValue(pos, '+', Runtime.getNativeTypeSize('i32')), 'i32', noNeedFirst, 1, ignore) + ']';
- }
-
var offset = calcFastOffset(ptr, pos, noNeedFirst);
if (SAFE_HEAP && !noSafe) {
if (type !== 'null' && type[0] !== '#') type = '"' + safeQuote(type) + '"';
@@ -966,7 +969,8 @@ function makeSetValue(ptr, pos, value, type, noNeedFirst, ignore, align, noSafe,
makeSetValue(ptr, getFastValue(pos, '+', Runtime.getNativeTypeSize('i32')), 'tempDoubleI32[1]', 'i32', noNeedFirst, ignore, align, noSafe, ',') + ')';
}
- var needSplitting = isIntImplemented(type) && !isPowerOfTwo(getBits(type)); // an unnatural type like i24
+ var bits = getBits(type);
+ var needSplitting = bits > 0 && !isPowerOfTwo(bits); // an unnatural type like i24
if (USE_TYPED_ARRAYS == 2 && (align || needSplitting)) {
// Alignment is important here, or we need to split this up for other reasons.
var bytes = Runtime.getNativeTypeSize(type);
@@ -978,16 +982,12 @@ function makeSetValue(ptr, pos, value, type, noNeedFirst, ignore, align, noSafe,
ret += 'tempBigInt=' + value + sep;
ret += makeSetValue(ptr, pos, 'tempBigInt&0xffff', 'i16', noNeedFirst, ignore, 2) + sep;
ret += makeSetValue(ptr, getFastValue(pos, '+', 2), 'tempBigInt>>16', 'i16', noNeedFirst, ignore, 2);
- } else if (bytes != 8) {
+ } else {
ret += 'tempBigInt=' + value + sep;
for (var i = 0; i < bytes; i++) {
ret += makeSetValue(ptr, getFastValue(pos, '+', i), 'tempBigInt&0xff', 'i8', noNeedFirst, ignore, 1);
if (i < bytes-1) ret += sep + 'tempBigInt>>=8' + sep;
}
- } else { // bytes == 8, specific optimization
- ret += 'tempPair=' + ensureI64_1(value) + sep;
- ret += makeSetValue(ptr, pos, 'tempPair[0]', 'i32', noNeedFirst, ignore, align) + sep;
- ret += makeSetValue(ptr, getFastValue(pos, '+', Runtime.getNativeTypeSize('i32')), 'tempPair[1]', 'i32', noNeedFirst, ignore, align);
}
} else {
ret += makeSetValue('tempDoublePtr', 0, value, type, noNeedFirst, ignore, 8) + sep;
@@ -997,11 +997,6 @@ function makeSetValue(ptr, pos, value, type, noNeedFirst, ignore, align, noSafe,
}
}
- if (type == 'i64' && I64_MODE == 1) {
- return '(' + makeSetValue(ptr, pos, value + '[0]', 'i32', noNeedFirst, ignore) + ','
- + makeSetValue(ptr, getFastValue(pos, '+', Runtime.getNativeTypeSize('i32')), value + '[1]', 'i32', noNeedFirst, ignore) + ')';
- }
-
value = indexizeFunctions(value, type);
var offset = calcFastOffset(ptr, pos, noNeedFirst);
if (SAFE_HEAP && !noSafe) {
@@ -1530,6 +1525,8 @@ function isSignedOp(op, variant) {
return op in SIGNED_OP || (variant && variant[0] == 's');
}
+var legalizedI64s = USE_TYPED_ARRAYS == 2; // We do not legalize globals, but do legalize function lines. This will be true in the latter case
+
function processMathop(item) {
var op = item.op;
var variant = item.variant;
@@ -1539,7 +1536,7 @@ function processMathop(item) {
if (item['param'+i]) {
paramTypes[i-1] = item['param'+i].type || type;
item['ident'+i] = finalizeLLVMParameter(item['param'+i]);
- if (!isNumber(item['ident'+i])) {
+ if (!isNumber(item['ident'+i]) && !isNiceIdent(item['ident'+i])) {
item['ident'+i] = '(' + item['ident'+i] + ')'; // we may have nested expressions. So enforce the order of operations we want
}
} else {
@@ -1570,8 +1567,24 @@ function processMathop(item) {
if ((type == 'i64' || paramTypes[0] == 'i64' || paramTypes[1] == 'i64' || ident2 == '(i64)') && I64_MODE == 1) {
var warnI64_1 = function() {
- warnOnce('Arithmetic on 64-bit integers in mode 1 is rounded and flaky, like mode 0, but much slower!');
+ warnOnce('Arithmetic on 64-bit integers in mode 1 is rounded and flaky, like mode 0!');
};
+ // In ops that can be either legalized or not, we need to differentiate how we access low and high parts
+ var low1 = ident1 + (legalizedI64s ? '$0' : '[0]');
+ var high1 = ident1 + (legalizedI64s ? '$1' : '[1]');
+ var low2 = ident2 + (legalizedI64s ? '$0' : '[0]');
+ var high2 = ident2 + (legalizedI64s ? '$1' : '[1]');
+ function finish(result) {
+ // If this is in legalization mode, steal the assign and assign into two vars
+ if (legalizedI64s) {
+ assert(item.assignTo);
+ var ret = 'var ' + item.assignTo + '$0 = ' + result[0] + '; var ' + item.assignTo + '$1 = ' + result[1] + ';';
+ item.assignTo = null;
+ return ret;
+ } else {
+ return result;
+ }
+ }
switch (op) {
// basic integer ops
case 'or': {
@@ -1587,7 +1600,7 @@ function processMathop(item) {
case 'ashr':
case 'lshr': {
if (!isNumber(ident2)) {
- return 'Runtime.bitshift64(' + ident1 + ',"' + op + '",' + stripCorrections(ident2) + '[0]|0)';
+ return 'Runtime.bitshift64(' + ident1 + '[0], ' + ident1 + '[1],"' + op + '",' + stripCorrections(ident2) + '[0]|0)';
}
bits = parseInt(ident2);
var ander = Math.pow(2, bits)-1;
@@ -1623,38 +1636,28 @@ function processMathop(item) {
}
}
}
- case 'uitofp': case 'sitofp': return ident1 + '[0] + ' + ident1 + '[1]*4294967296';
- case 'fptoui': case 'fptosi': return splitI64(ident1);
+ case 'uitofp': case 'sitofp': return low1 + ' + ' + high1 + '*4294967296';
+ case 'fptoui': case 'fptosi': return finish(splitI64(ident1));
case 'icmp': {
switch (variant) {
- case 'uge': return ident1 + '[1] >= ' + ident2 + '[1] && (' + ident1 + '[1] > ' + ident2 + '[1] || ' +
- ident1 + '[0] >= ' + ident2 + '[0])';
- case 'sge': return '(' + ident1 + '[1]|0) >= (' + ident2 + '[1]|0) && ((' + ident1 + '[1]|0) > (' + ident2 + '[1]|0) || ' +
- '(' + ident1 + '[0]|0) >= (' + ident2 + '[0]|0))';
- case 'ule': return ident1 + '[1] <= ' + ident2 + '[1] && (' + ident1 + '[1] < ' + ident2 + '[1] || ' +
- ident1 + '[0] <= ' + ident2 + '[0])';
- case 'sle': return '(' + ident1 + '[1]|0) <= (' + ident2 + '[1]|0) && ((' + ident1 + '[1]|0) < (' + ident2 + '[1]|0) || ' +
- '(' + ident1 + '[0]|0) <= (' + ident2 + '[0]|0))';
- case 'ugt': return ident1 + '[1] > ' + ident2 + '[1] || (' + ident1 + '[1] == ' + ident2 + '[1] && ' +
- ident1 + '[0] > ' + ident2 + '[0])';
- case 'sgt': return '(' + ident1 + '[1]|0) > (' + ident2 + '[1]|0) || ((' + ident1 + '[1]|0) == (' + ident2 + '[1]|0) && ' +
- '(' + ident1 + '[0]|0) > (' + ident2 + '[0]|0))';
- case 'ult': return ident1 + '[1] < ' + ident2 + '[1] || (' + ident1 + '[1] == ' + ident2 + '[1] && ' +
- ident1 + '[0] < ' + ident2 + '[0])';
- case 'slt': return '(' + ident1 + '[1]|0) < (' + ident2 + '[1]|0) || ((' + ident1 + '[1]|0) == (' + ident2 + '[1]|0) && ' +
- '(' + ident1 + '[0]|0) < (' + ident2 + '[0]|0))';
- case 'ne': case 'eq': {
- // We must sign them, so we do not compare -1 to 255 (could have unsigned them both too)
- // since LLVM tells us if <=, >= etc. comparisons are signed, but not == and !=.
- assert(paramTypes[0] == paramTypes[1]);
- ident1 = makeSignOp(ident1, paramTypes[0], 're');
- ident2 = makeSignOp(ident2, paramTypes[1], 're');
- if (variant === 'eq') {
- return ident1 + '[0] == ' + ident2 + '[0] && ' + ident1 + '[1] == ' + ident2 + '[1]';
- } else {
- return ident1 + '[0] != ' + ident2 + '[0] || ' + ident1 + '[1] != ' + ident2 + '[1]';
- }
- }
+ case 'uge': return high1 + ' >= ' + high2 + ' && (' + high1 + ' > ' + high + ' || ' +
+ low1 + ' >= ' + low2 + ')';
+ case 'sge': return '(' + high1 + '|0) >= (' + high2 + '|0) && ((' + high1 + '|0) > (' + high2 + '|0) || ' +
+ '(' + low1 + '|0) >= (' + low2 + '|0))';
+ case 'ule': return high1 + ' <= ' + high2 + ' && (' + high1 + ' < ' + high2 + ' || ' +
+ low1 + ' <= ' + low2 + ')';
+ case 'sle': return '(' + high1 + '|0) <= (' + high2 + '|0) && ((' + high1 + '|0) < (' + high2 + '|0) || ' +
+ '(' + low1 + '|0) <= (' + low2 + '|0))';
+ case 'ugt': return high1 + ' > ' + high2 + ' || (' + high1 + ' == ' + high2 + ' && ' +
+ low1 + ' > ' + low2 + ')';
+ case 'sgt': return '(' + high1 + '|0) > (' + high2 + '|0) || ((' + high1 + '|0) == (' + high2 + '|0) && ' +
+ '(' + low1 + '|0) > (' + low2 + '|0))';
+ case 'ult': return high1 + ' < ' + high2 + ' || (' + high1 + ' == ' + high2 + ' && ' +
+ low1 + ' < ' + low2 + ')';
+ case 'slt': return '(' + high1 + '|0) < (' + high2 + '|0) || ((' + high1 + '|0) == (' + high2 + '|0) && ' +
+ '(' + low1 + '|0) < (' + low2 + '|0))';
+ case 'ne': return low1 + ' != ' + low2 + ' || ' + high1 + ' != ' + high2 + '';
+ case 'eq': return low1 + ' == ' + low2 + ' && ' + high1 + ' == ' + high2 + '';
default: throw 'Unknown icmp variant: ' + variant;
}
}
@@ -1667,11 +1670,11 @@ function processMathop(item) {
case 'ptrtoint': return makeI64(ident1, 0);
case 'inttoptr': return '(' + ident1 + '[0])'; // just directly truncate the i64 to a 'pointer', which is an i32
// Dangerous, rounded operations. TODO: Fully emulate
- case 'add': warnI64_1(); return handleOverflow(splitI64(mergeI64(ident1) + '+' + mergeI64(ident2)), bits);
- case 'sub': warnI64_1(); return handleOverflow(splitI64(mergeI64(ident1) + '-' + mergeI64(ident2)), bits);
- case 'sdiv': case 'udiv': warnI64_1(); return splitI64(makeRounding(mergeI64(ident1) + '/' + mergeI64(ident2), bits, op[0] === 's'));
- case 'mul': warnI64_1(); return handleOverflow(splitI64(mergeI64(ident1) + '*' + mergeI64(ident2)), bits);
- case 'urem': case 'srem': warnI64_1(); return splitI64(mergeI64(ident1) + '%' + mergeI64(ident2));
+ case 'add': warnI64_1(); return finish(splitI64(mergeI64(ident1) + '+' + mergeI64(ident2)));
+ case 'sub': warnI64_1(); return finish(splitI64(mergeI64(ident1) + '-' + mergeI64(ident2)));
+ case 'sdiv': case 'udiv': warnI64_1(); return finish(splitI64(makeRounding(mergeI64(ident1) + '/' + mergeI64(ident2), bits, op[0] === 's')));
+ case 'mul': warnI64_1(); return finish(splitI64(mergeI64(ident1) + '*' + mergeI64(ident2)));
+ case 'urem': case 'srem': warnI64_1(); return finish(splitI64(mergeI64(ident1) + '%' + mergeI64(ident2)));
case 'bitcast': {
// Pointers are not 64-bit, so there is really only one possible type of bitcast here, int to float or vice versa
assert(USE_TYPED_ARRAYS == 2, 'Can only bitcast ints <-> floats with typed arrays mode 2');
@@ -1831,6 +1834,7 @@ function walkInterdata(item, pre, post, obj) {
var originalObj = obj;
if (obj && obj.replaceWith) obj = obj.replaceWith; // allow pre to replace the object we pass to all its children
if (item.value && walkInterdata(item.value, pre, post, obj)) return true;
+ // TODO if (item.pointer && walkInterdata(item.pointer, pre, post, obj)) return true;
if (item.dependent && walkInterdata(item.dependent, pre, post, obj)) return true;
var i;
for (i = 1; i <= 4; i++) {
@@ -1851,6 +1855,29 @@ function walkInterdata(item, pre, post, obj) {
return post && post(item, originalObj, obj);
}
+// Separate from walkInterdata so that the former is as fast as possible
+// If the callback returns a value, we replace the current item with that
+// value, and do *not* walk the children.
+function walkAndModifyInterdata(item, pre) {
+ if (!item || !item.intertype) return false;
+ var ret = pre(item);
+ if (ret) return ret;
+ var repl;
+ if (item.value && (repl = walkAndModifyInterdata(item.value, pre))) item.value = repl;
+ if (item.pointer && (repl = walkAndModifyInterdata(item.pointer, pre))) item.pointer = repl;
+ if (item.dependent && (repl = walkAndModifyInterdata(item.dependent, pre))) item.dependent = repl;
+ var i;
+ for (i = 1; i <= 4; i++) {
+ if (item['param'+i] && (repl = walkAndModifyInterdata(item['param'+i], pre))) item['param'+i] = repl;
+ }
+ if (item.params) {
+ for (i = 0; i <= item.params.length; i++) {
+ if (repl = walkAndModifyInterdata(item.params[i], pre)) item.params[i] = repl;
+ }
+ }
+ // Ignore possibleVars because we can't replace them anyhow
+}
+
function parseBlockAddress(segment) {
return { intertype: 'blockaddress', func: toNiceIdent(segment[2].item.tokens[0].text), label: toNiceIdent(segment[2].item.tokens[2].text), type: 'i32' };
}
diff --git a/src/runtime.js b/src/runtime.js
index b5663045..852d08d8 100644
--- a/src/runtime.js
+++ b/src/runtime.js
@@ -79,9 +79,10 @@ var RuntimeGenerator = {
// Rounding is inevitable if the number is large. This is a particular problem for small negative numbers
// (-1 will be rounded!), so handle negatives separately and carefully
makeBigInt: function(low, high, unsigned) {
- return '(' + unsigned +
- ' ? (' + makeSignOp(low, 'i32', 'un', 1, 1) + '+(' + makeSignOp(high, 'i32', 'un', 1, 1) + '*4294967296))' +
- ' : (' + makeSignOp(low, 'i32', 'un', 1, 1) + '+(' + makeSignOp(high, 'i32', 're', 1, 1) + '*4294967296)))';
+ var unsignedRet = '(' + makeSignOp(low, 'i32', 'un', 1, 1) + '+(' + makeSignOp(high, 'i32', 'un', 1, 1) + '*4294967296))';
+ var signedRet = '(' + makeSignOp(low, 'i32', 'un', 1, 1) + '+(' + makeSignOp(high, 'i32', 're', 1, 1) + '*4294967296))';
+ if (typeof unsigned === 'string') return '(' + unsigned + ' ? ' + unsignedRet + ' : ' + signedRet + ')';
+ return unsigned ? unsignedRet : signedRet;
}
};
@@ -122,34 +123,34 @@ var Runtime = {
FLOAT_TYPES: set('float', 'double'),
// Mirrors processMathop's treatment of constants (which we optimize directly)
- bitshift64: function(value, op, bits) {
+ bitshift64: function(low, high, op, bits) {
var ander = Math.pow(2, bits)-1;
if (bits < 32) {
switch (op) {
case 'shl':
- return [value[0] << bits, (value[1] << bits) | ((value[0]&(ander << (32 - bits))) >>> (32 - bits))];
+ return [low << bits, (high << bits) | ((low&(ander << (32 - bits))) >>> (32 - bits))];
case 'ashr':
- return [(((value[0] >>> bits ) | ((value[1]&ander) << (32 - bits))) >> 0) >>> 0, (value[1] >> bits) >>> 0];
+ return [(((low >>> bits ) | ((high&ander) << (32 - bits))) >> 0) >>> 0, (high >> bits) >>> 0];
case 'lshr':
- return [((value[0] >>> bits) | ((value[1]&ander) << (32 - bits))) >>> 0, value[1] >>> bits];
+ return [((low >>> bits) | ((high&ander) << (32 - bits))) >>> 0, high >>> bits];
}
} else if (bits == 32) {
switch (op) {
case 'shl':
- return [0, value[0]];
+ return [0, low];
case 'ashr':
- return [value[1], (value[1]|0) < 0 ? ander : 0];
+ return [high, (high|0) < 0 ? ander : 0];
case 'lshr':
- return [value[1], 0];
+ return [high, 0];
}
} else { // bits > 32
switch (op) {
case 'shl':
- return [0, value[0] << (bits - 32)];
+ return [0, low << (bits - 32)];
case 'ashr':
- return [(value[1] >> (bits - 32)) >>> 0, (value[1]|0) < 0 ? ander : 0];
+ return [(high >> (bits - 32)) >>> 0, (high|0) < 0 ? ander : 0];
case 'lshr':
- return [value[1] >>> (bits - 32) , 0];
+ return [high >>> (bits - 32) , 0];
}
}
abort('unknown bitshift64 op: ' + [value, op, bits]);
diff --git a/tests/cases/i64toi8star.ll b/tests/cases/i64toi8star.ll
index 53a31d02..d4a39340 100644
--- a/tests/cases/i64toi8star.ll
+++ b/tests/cases/i64toi8star.ll
@@ -27,6 +27,6 @@ entry:
%"alloca point" = bitcast i32 0 to i32 ; [#uses=0]
%5 = call i32 @PyLong_FromVoidPtr(i8* null) nounwind ; [#uses=0]
%13 = call i32 @PyLong_FromVoidPtr(i8* inttoptr (i64 1 to i8*)) nounwind ; [#uses=0]
- %0 = call i32 bitcast (i32 (i8*)* @puts to i32 (i32*)*)(i8* getelementptr inbounds ([14 x i8]* @.str, i32 0, i32 0)) ; [#uses=0]
+ %1 = call i32 bitcast (i32 (i8*)* @puts to i32 (i32*)*)(i8* getelementptr inbounds ([14 x i8]* @.str, i32 0, i32 0)) ; [#uses=0]
ret i32 0
}
diff --git a/tests/cases/inttoptr.ll b/tests/cases/inttoptr.ll
index c70904c8..b0711672 100644
--- a/tests/cases/inttoptr.ll
+++ b/tests/cases/inttoptr.ll
@@ -15,6 +15,6 @@ entry:
%"alloca point" = bitcast i32 0 to i32 ; [#uses=0]
%sz.i7 = inttoptr i32 64 to i32* ; [#uses=1 type=i32*]
store i32 184, i32* %sz.i7, align 8, !tbaa !1610
- %0 = call i32 bitcast (i32 (i8*)* @puts to i32 (i32*)*)(i8* getelementptr inbounds ([14 x i8]* @.str, i32 0, i32 0)) ; [#uses=0]
+ %1 = call i32 bitcast (i32 (i8*)* @puts to i32 (i32*)*)(i8* getelementptr inbounds ([14 x i8]* @.str, i32 0, i32 0)) ; [#uses=0]
ret i32 0
}
diff --git a/tests/cases/lifetime.ll b/tests/cases/lifetime.ll
deleted file mode 100644
index dc6d471d..00000000
--- a/tests/cases/lifetime.ll
+++ /dev/null
@@ -1,42 +0,0 @@
-; ModuleID = '/tmp/emscripten/tmp/src.cpp.o'
-target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:32:32-n8:16:32"
-target triple = "i386-pc-linux-gnu"
-
-%struct.vec2 = type { float, float }
-
-@.str = private unnamed_addr constant [15 x i8] c"hello, world!\0A\00" ; [#uses=1]
-
-; [#uses=1]
-declare i32 @printf(i8* noalias, ...)
-
-define linkonce_odr float @vec2Length(%struct.vec2* %this) nounwind align 2 {
-entry:
- %__first.addr.i = alloca %struct.b2Pair.5*, align 4 ; [#uses=3 type=%struct.b2Pair.5**]
- %__last.addr.i = alloca %struct.b2Pair.5*, align 4 ; [#uses=3 type=%struct.b2Pair.5**]
- %__comp.addr.i = alloca %struct.b2Pair.5*, align 4 ; [#uses=2 type=%struct.b2Pair.5**]
- %13 = bitcast %struct.vec2** %__first.addr.i to i8* ; [#uses=1 type=i8*]
- call void @llvm.lifetime.start(i64 -1, i8* %13)
- %14 = bitcast %struct.vec2** %__last.addr.i to i8* ; [#uses=1 type=i8*]
- call void @llvm.lifetime.start(i64 -1, i8* %14)
- %15 = bitcast i1 (%struct.vec2*, %struct.vec2*)** %__comp.addr.i to i8* ; [#uses=1 type=i8*]
- call void @llvm.lifetime.start(i64 -1, i8* %15)
- store %struct.vec2* %10, %struct.vec2** %__first.addr.i, align 4
- store %struct.vec2* %add.ptr, %struct.vec2** %__last.addr.i, align 4
- %18 = bitcast %struct.vec2** %__first.addr.i to i8* ; [#uses=1 type=i8*]
- call void @llvm.lifetime.end(i64 -1, i8* %18)
- %19 = bitcast %struct.vec2** %__last.addr.i to i8* ; [#uses=1 type=i8*]
- call void @llvm.lifetime.end(i64 -1, i8* %19)
- %20 = bitcast i1 (%struct.vec2*, %struct.vec2*)** %__comp.addr.i to i8* ; [#uses=1 type=i8*]
- call void @llvm.lifetime.end(i64 -1, i8* %20)
-}
-
-define i32 @main() {
-entry:
- %retval = alloca i32, align 4 ; [#uses=1]
- store i32 0, i32* %retval
- %b = getelementptr inbounds i32* %retval, i32 0, i32 1 ; [#uses=1] ; force __stackBase__ to appear!
- %call = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([15 x i8]* @.str, i32 0, i32 0)) ; [#uses=0]
- call i32 (i32)* @nonexistant(i32 %b) ; keep %b alive
- ret i32 0
-}
-
diff --git a/tests/cases/lifetime.py b/tests/cases/lifetime.py
deleted file mode 100644
index 3bb9cbac..00000000
--- a/tests/cases/lifetime.py
+++ /dev/null
@@ -1,6 +0,0 @@
-if Settings.MICRO_OPTS:
- assert '__stackBase__' in generated, 'There should be some stack activity (without which, we cannot do the next checks)'
- assert '__stackBase__+4' not in generated, 'All variables should have been nativized'
- assert '__stackBase__+8' not in generated, 'All variables should have been nativized'
- assert 'comp_addr' not in generated, 'This variable should have been eliminated during analysis'
-
diff --git a/tests/lifetime.ll b/tests/lifetime.ll
new file mode 100644
index 00000000..058d6b4a
--- /dev/null
+++ b/tests/lifetime.ll
@@ -0,0 +1,37 @@
+; ModuleID = '/tmp/emscripten/tmp/src.cpp.o'
+target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:32:32-n8:16:32"
+target triple = "i386-pc-linux-gnu"
+
+%struct.vec2 = type { float, float }
+
+@.str = private unnamed_addr constant [15 x i8] c"hello, world!\0A\00" ; [#uses=1]
+
+; [#uses=1]
+declare i32 @printf(i8* noalias, ...)
+
+define linkonce_odr i32 @vec2Length(%struct.vec2* %this) nounwind align 2 {
+entry:
+ %__first.addr.i = alloca %struct.vec2*, align 4 ; [#uses=3 type=%struct.vec2**]
+ %__last.addr.i = alloca %struct.vec2*, align 4 ; [#uses=3 type=%struct.vec2**]
+ %__comp.addr.i = alloca %struct.vec2*, align 4 ; [#uses=2 type=%struct.vec2**]
+ %a13 = bitcast %struct.vec2** %__first.addr.i to i8* ; [#uses=1 type=i8*]
+ call void @llvm.lifetime.start(i64 -1, i8* %a13)
+ %a14 = bitcast %struct.vec2** %__last.addr.i to i8* ; [#uses=1 type=i8*]
+ call void @llvm.lifetime.start(i64 -1, i8* %a14)
+ %a18 = bitcast %struct.vec2** %__first.addr.i to i8* ; [#uses=1 type=i8*]
+ call void @llvm.lifetime.end(i64 -1, i8* %a18)
+ %a19 = bitcast %struct.vec2** %__last.addr.i to i8* ; [#uses=1 type=i8*]
+ call void @llvm.lifetime.end(i64 -1, i8* %a19)
+ ret i32 0
+}
+
+define i32 @main() {
+entry:
+ %retval = alloca i32, align 4 ; [#uses=1]
+ %call = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([15 x i8]* @.str, i32 0, i32 0)) ; [#uses=0]
+ ret i32 0
+}
+
+declare void @llvm.lifetime.start(i64, i8*)
+declare void @llvm.lifetime.end(i64, i8*)
+
diff --git a/tests/runner.py b/tests/runner.py
index 1cd94111..ac422e9e 100755
--- a/tests/runner.py
+++ b/tests/runner.py
@@ -428,6 +428,8 @@ if 'benchmark' not in str(sys.argv) and 'sanity' not in str(sys.argv):
self.do_run(src, output, force_c=True)
def test_i64(self):
+ if Settings.USE_TYPED_ARRAYS != 2: return self.skip('i64 mode 1 requires ta2')
+
for i64_mode in [0,1]:
if i64_mode == 0 and Settings.USE_TYPED_ARRAYS != 0: continue # Typed arrays truncate i64
if i64_mode == 1 and Settings.QUANTUM_SIZE == 1: continue # TODO: i64 mode 1 for q1
@@ -1547,6 +1549,25 @@ if 'benchmark' not in str(sys.argv) and 'sanity' not in str(sys.argv):
self.do_run(src, '*11,74,32,1012*\n*11*\n*22*')
def test_dynamic_cast(self):
+ src = r'''
+ #include <stdio.h>
+
+ struct Support {
+ virtual void f() {
+ printf("f()\n");
+ }
+ };
+
+ struct Derived : Support {
+ };
+
+ int main() {
+ Support * p = new Derived;
+ dynamic_cast<Derived*>(p)->f();
+ }
+ '''
+ self.do_run(src, 'f()\n')
+
src = '''
#include <stdio.h>
@@ -3290,6 +3311,7 @@ at function.:blag
self.do_run(src, expected)
def test_parseInt(self):
+ if Settings.USE_TYPED_ARRAYS != 2: return self.skip('i64 mode 1 requires ta2')
if Settings.QUANTUM_SIZE == 1: return self.skip('Q1 and I64_1 do not mix well yet')
Settings.I64_MODE = 1 # Necessary to prevent i64s being truncated into i32s, but we do still get doubling
# FIXME: The output here is wrong, due to double rounding of i64s!
@@ -3298,7 +3320,7 @@ at function.:blag
self.do_run(src, expected)
def test_printf(self):
- if Settings.QUANTUM_SIZE == 1: return self.skip('Q1 and I64_1 do not mix well yet')
+ if Settings.USE_TYPED_ARRAYS != 2: return self.skip('i64 mode 1 requires ta2')
Settings.I64_MODE = 1
self.banned_js_engines = [NODE_JS, V8_ENGINE] # SpiderMonkey and V8 do different things to float64 typed arrays, un-NaNing, etc.
src = open(path_from_root('tests', 'printf', 'test.c'), 'r').read()
@@ -3869,15 +3891,14 @@ def process(filename):
self.do_run(src, "1 2 3")
def test_readdir(self):
-
add_pre_run = '''
def process(filename):
src = open(filename, 'r').read().replace(
- '// {{PRE_RUN_ADDITIONS}}',
- "FS.createFolder('', 'test', true, true);\\nFS.createLazyFile( 'test', 'some_file', 'http://localhost/some_file', true, false);\\nFS.createFolder('test', 'some_directory', true, true);"
+ '// {{PRE_RUN_ADDITIONS}}',
+ "FS.createFolder('', 'test', true, true);\\nFS.createLazyFile( 'test', 'some_file', 'http://localhost/some_file', true, false);\\nFS.createFolder('test', 'some_directory', true, true);"
)
open(filename, 'w').write(src)
- '''
+'''
src = '''
#include <dirent.h>
@@ -4674,17 +4695,31 @@ def process(filename):
'hello python world!\n[0, 2, 4, 6]\n5\n22\n5.470000',
args=['-S', '-c' '''print "hello python world!"; print [x*2 for x in range(4)]; t=2; print 10-3-t; print (lambda x: x*2)(11); print '%f' % 5.47'''])
+ def test_lifetime(self):
+ if self.emcc_args is None: return self.skip('test relies on emcc opts')
+
+ try:
+ os.environ['EMCC_LEAVE_INPUTS_RAW'] = '1'
+
+ self.do_ll_run(path_from_root('tests', 'lifetime.ll'), 'hello, world!\n')
+ if '-O1' in self.emcc_args or '-O2' in self.emcc_args:
+ assert 'a18' not in open(os.path.join(self.get_dir(), 'src.cpp.o.js')).read(), 'lifetime stuff and their vars must be culled'
+ else:
+ assert 'a18' in open(os.path.join(self.get_dir(), 'src.cpp.o.js')).read(), "without opts, it's there"
+
+ finally:
+ del os.environ['EMCC_LEAVE_INPUTS_RAW']
+
# Test cases in separate files. Note that these files may contain invalid .ll!
# They are only valid enough for us to read for test purposes, not for llvm-as
# to process.
def test_cases(self):
- try:
- self.banned_js_engines = [NODE_JS] # node issue 1669, exception causes stdout not to be flushed
+ if Building.LLVM_OPTS: return self.skip("Our code is not exactly 'normal' llvm assembly")
+ try:
os.environ['EMCC_LEAVE_INPUTS_RAW'] = '1'
-
+ self.banned_js_engines = [NODE_JS] # node issue 1669, exception causes stdout not to be flushed
Settings.CHECK_OVERFLOWS = 0
- if Building.LLVM_OPTS: return self.skip("Our code is not exactly 'normal' llvm assembly")
for name in glob.glob(path_from_root('tests', 'cases', '*.ll')):
shortname = name.replace('.ll', '')
@@ -5563,6 +5598,9 @@ TT = %s
del T # T is just a shape for the specific subclasses, we don't test it itself
class other(RunnerCore):
+ def test_reminder(self):
+ assert 0, 'find appearances of i64 in src/, most are now unneeded'
+
def test_emcc(self):
emcc_debug = os.environ.get('EMCC_DEBUG')
@@ -5725,12 +5763,12 @@ Options that are modified or new in %s include:
for params, test, text in [
(['-s', 'INLINING_LIMIT=0'], lambda generated: 'function _dump' in generated, 'no inlining without opts'),
(['-O1', '-s', 'INLINING_LIMIT=0'], lambda generated: 'function _dump' not in generated, 'inlining'),
- (['-s', 'USE_TYPED_ARRAYS=0'], lambda generated: 'new Int32Array' not in generated, 'disable typed arrays'),
- (['-s', 'USE_TYPED_ARRAYS=1'], lambda generated: 'IHEAPU = ' in generated, 'typed arrays 1 selected'),
+ (['-s', 'USE_TYPED_ARRAYS=0', '-s', 'I64_MODE=0'], lambda generated: 'new Int32Array' not in generated, 'disable typed arrays'),
+ (['-s', 'USE_TYPED_ARRAYS=1', '-s', 'I64_MODE=0'], lambda generated: 'IHEAPU = ' in generated, 'typed arrays 1 selected'),
([], lambda generated: 'Module["_dump"]' not in generated, 'dump is not exported by default'),
(['-s', 'EXPORTED_FUNCTIONS=["_main", "_dump"]'], lambda generated: 'Module["_dump"]' in generated, 'dump is now exported'),
- (['--typed-arrays', '0'], lambda generated: 'new Int32Array' not in generated, 'disable typed arrays'),
- (['--typed-arrays', '1'], lambda generated: 'IHEAPU = ' in generated, 'typed arrays 1 selected'),
+ (['--typed-arrays', '0', '-s', 'I64_MODE=0'], lambda generated: 'new Int32Array' not in generated, 'disable typed arrays'),
+ (['--typed-arrays', '1', '-s', 'I64_MODE=0'], lambda generated: 'IHEAPU = ' in generated, 'typed arrays 1 selected'),
(['--typed-arrays', '2'], lambda generated: 'new Uint16Array' in generated and 'new Uint32Array' in generated, 'typed arrays 2 selected'),
(['--llvm-opts', '1'], lambda generated: '_puts(' in generated, 'llvm opts requested'),
]:
@@ -5867,7 +5905,7 @@ f.close()
clear()
output = Popen([EMCC, path_from_root('tests', 'hello_world_gles.c'), '-o', 'something.html',
'-DHAVE_BUILTIN_SINCOS',
- '-s', 'USE_TYPED_ARRAYS=0',
+ '-s', 'USE_TYPED_ARRAYS=0', '-s', 'I64_MODE=0',
'--shell-file', path_from_root('tests', 'hello_world_gles_shell.html')],
stdout=PIPE, stderr=PIPE).communicate()
assert len(output[0]) == 0, output[0]
@@ -6079,7 +6117,7 @@ elif 'benchmark' in str(sys.argv):
'''
self.do_benchmark(src, [], 'final: 720.')
- def test_files(self):
+ def zzztest_files(self):
src = r'''
#include<stdio.h>
#include<stdlib.h>
diff --git a/tools/bindings_generator.py b/tools/bindings_generator.py
index bdb3e755..e1c1ab4b 100755
--- a/tools/bindings_generator.py
+++ b/tools/bindings_generator.py
@@ -180,8 +180,8 @@ for classname, clazz in classes.iteritems():
method['name'] = 'op_comp'
method['operator'] = ' return arg0 == arg1;' if len(method['parameters'][0]) == 2 else ' return *self == arg0;'
else:
- print 'zz unknown operator:', method['name']
- 1/0.
+ print 'zz unknown operator:', method['name'], ', ignoring'
+ method['ignore'] = True
# Fill in some missing stuff
method['returns_text'] = method['returns_text'].replace('&', '').replace('*', '')
diff --git a/tools/shared.py b/tools/shared.py
index d830627c..b5ae1ae1 100644
--- a/tools/shared.py
+++ b/tools/shared.py
@@ -333,7 +333,6 @@ class Settings:
Settings.CORRECT_SIGNS = 0
Settings.CORRECT_OVERFLOWS = 0
Settings.CORRECT_ROUNDINGS = 0
- Settings.I64_MODE = 0
Settings.DOUBLE_MODE = 0
if noisy: print >> sys.stderr, 'Warning: Applying some potentially unsafe optimizations! (Use -O2 if this fails.)'