aboutsummaryrefslogtreecommitdiff
path: root/src/analyzer.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/analyzer.js')
-rw-r--r--src/analyzer.js648
1 files changed, 362 insertions, 286 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