aboutsummaryrefslogtreecommitdiff
path: root/src/analyzer.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/analyzer.js')
-rw-r--r--src/analyzer.js167
1 files changed, 134 insertions, 33 deletions
diff --git a/src/analyzer.js b/src/analyzer.js
index 014579f4..0ad3e017 100644
--- a/src/analyzer.js
+++ b/src/analyzer.js
@@ -19,7 +19,7 @@ function recomputeLines(func) {
var BRANCH_INVOKE = set('branch', 'invoke');
var SIDE_EFFECT_CAUSERS = set('call', 'invoke', 'atomic');
-var UNUNFOLDABLE = set('value', 'type', 'phiparam');
+var UNUNFOLDABLE = set('value', 'structvalue', 'type', 'phiparam');
// Analyzer
@@ -120,12 +120,14 @@ function analyzer(data, sidePass) {
processItem: function(data) {
// Legalization
if (USE_TYPED_ARRAYS == 2) {
- function getLegalVars(base, bits) {
- assert(!isNumber(base));
+ function getLegalVars(base, bits, allowLegal) {
+ if (allowLegal && bits <= 32) return [{ ident: base, bits: bits }];
+ if (isNumber(base)) return getLegalLiterals(base, bits);
var ret = new Array(Math.ceil(bits/32));
var i = 0;
+ if (base == 'zeroinitializer' || base == 'undef') base = 0;
while (bits > 0) {
- ret[i] = { ident: base + '$' + i, bits: Math.min(32, bits) };
+ ret[i] = { ident: base ? base + '$' + i : '0', bits: Math.min(32, bits) };
bits -= 32;
i++;
}
@@ -142,6 +144,23 @@ function analyzer(data, sidePass) {
}
return ret;
}
+ function getLegalStructuralParts(value) {
+ return value.params.slice(0);
+ }
+ function getLegalParams(params, bits) {
+ return params.map(function(param) {
+ var value = param.value || param;
+ if (isNumber(value.ident)) {
+ return getLegalLiterals(value.ident, bits);
+ } else if (value.intertype == 'structvalue') {
+ return getLegalStructuralParts(value).map(function(part) {
+ return { ident: part.ident, bits: part.type.substr(1) };
+ });
+ } else {
+ return getLegalVars(value.ident, bits);
+ }
+ });
+ }
// 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) {
@@ -191,6 +210,7 @@ function analyzer(data, sidePass) {
// Legalize lines in labels
var tempId = 0;
func.labels.forEach(function(label) {
+ if (dcheck('legalizer')) dprint('zz legalizing: \n' + dump(label.lines));
var i = 0, bits;
while (i < label.lines.length) {
var item = label.lines[i];
@@ -207,8 +227,12 @@ function analyzer(data, sidePass) {
if (isIllegalType(item.valueType) || isIllegalType(item.type)) {
isIllegal = true;
}
+ if ((item.intertype == 'load' || item.intertype == 'store') && isStructType(item.valueType)) {
+ isIllegal = true; // storing an entire structure is illegal
+ }
});
if (!isIllegal) {
+ //if (dcheck('legalizer')) dprint('no need to legalize \n' + dump(item));
i++;
continue;
}
@@ -222,10 +246,10 @@ function analyzer(data, sidePass) {
if (subItem != item && (!(subItem.intertype in UNUNFOLDABLE) ||
(subItem.intertype == 'value' && isNumber(subItem.ident) && isIllegalType(subItem.type)))) {
if (item.intertype == 'phi') {
- assert(subItem.intertype == 'value', 'We can only unfold illegal constants in phis');
+ assert(subItem.intertype == 'value' || subItem.intertype == 'structvalue', 'We can only unfold illegal constants in phis');
// we must handle this in the phi itself, if we unfold normally it will not be pushed back with the phi
} else {
- var tempIdent = '$$emscripten$temp$' + (tempId++);
+ var tempIdent = '$$etemp$' + (tempId++);
subItem.assignTo = tempIdent;
unfolded.unshift(subItem);
fixUnfolded(subItem);
@@ -234,7 +258,7 @@ function analyzer(data, sidePass) {
} else if (subItem.intertype == 'switch' && isIllegalType(subItem.type)) {
subItem.switchLabels.forEach(function(switchLabel) {
if (switchLabel.value[0] != '$') {
- var tempIdent = '$$emscripten$temp$' + (tempId++);
+ var tempIdent = '$$etemp$' + (tempId++);
unfolded.unshift({
assignTo: tempIdent,
intertype: 'value',
@@ -258,8 +282,7 @@ function analyzer(data, sidePass) {
case 'store': {
var toAdd = [];
bits = getBits(item.valueType);
- var elements;
- elements = getLegalVars(item.value.ident, bits);
+ var elements = getLegalParams([item.value], bits)[0];
var j = 0;
elements.forEach(function(element) {
var tempVar = '$st$' + i + '$' + j;
@@ -290,32 +313,43 @@ function analyzer(data, sidePass) {
i += removeAndAdd(label.lines, i, toAdd);
continue;
}
- // call, return: Return value is in an unlegalized array literal. Not fully optimal.
+ // call, return: Return the first 32 bits, the rest are in temp
case 'call': {
bits = getBits(value.type);
var elements = getLegalVars(item.assignTo, bits);
var toAdd = [value];
// legalize parameters
legalizeFunctionParameters(value.params);
- if (value.assignTo) {
+ if (value.assignTo && isIllegalType(item.type)) {
// legalize return value
- var j = 0;
- toAdd = toAdd.concat(elements.map(function(element) {
- return {
+ value.assignTo = elements[0].ident;
+ for (var j = 1; j < elements.length; j++) {
+ var element = elements[j];
+ toAdd.push({
intertype: 'value',
assignTo: element.ident,
- type: 'i' + bits,
- ident: value.assignTo + '[' + (j++) + ']'
- };
- }));
+ type: element.bits,
+ ident: 'tempRet' + (j - 1)
+ });
+ assert(j<10); // TODO: dynamically create more than 10 tempRet-s
+ }
}
i += removeAndAdd(label.lines, i, toAdd);
continue;
}
+ case 'landingpad': {
+ // not much to legalize
+ i++;
+ 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(',') + ']';
+ item.value.ident = '(';
+ for (var j = 1; j < elements.length; j++) {
+ item.value.ident += 'tempRet' + (j-1) + '=' + elements[j].ident + ',';
+ }
+ item.value.ident += elements[0].ident + ')';
i++;
continue;
}
@@ -341,6 +375,21 @@ function analyzer(data, sidePass) {
i += removeAndAdd(label.lines, i, toAdd);
continue;
}
+ case 'structvalue': {
+ bits = getBits(value.type);
+ var elements = getLegalVars(item.assignTo, bits);
+ var toAdd = [];
+ for (var j = 0; j < item.params.length; j++) {
+ toAdd[j] = {
+ intertype: 'value',
+ assignTo: elements[j].ident,
+ type: 'i32',
+ ident: item.params[j].ident
+ };
+ }
+ i += removeAndAdd(label.lines, i, toAdd);
+ continue;
+ }
case 'load': {
bits = getBits(value.valueType);
var elements = getLegalVars(item.assignTo, bits);
@@ -382,13 +431,9 @@ function analyzer(data, sidePass) {
var toAdd = [];
var elements = getLegalVars(item.assignTo, bits);
var j = 0;
- var literalValues = {}; // special handling of literals - we cannot unfold them normally
- value.params.map(function(param) {
- if (isNumber(param.value.ident)) {
- literalValues[param.value.ident] = getLegalLiterals(param.value.ident, bits);
- }
- });
+ var values = getLegalParams(value.params, bits);
elements.forEach(function(element) {
+ var k = 0;
toAdd.push({
intertype: 'phi',
assignTo: element.ident,
@@ -399,7 +444,7 @@ function analyzer(data, sidePass) {
label: param.label,
value: {
intertype: 'value',
- ident: (param.value.ident in literalValues) ? literalValues[param.value.ident][j].ident : (param.value.ident + '$' + j),
+ ident: values[k++][j].ident,
type: 'i' + element.bits,
}
};
@@ -414,6 +459,62 @@ function analyzer(data, sidePass) {
i++;
continue; // special case, handled in makeComparison
}
+ case 'extractvalue': { // XXX we assume 32-bit alignment in extractvalue/insertvalue,
+ // but in theory they can run on packed structs too (see use getStructuralTypePartBits)
+ // potentially legalize the actual extracted value too if it is >32 bits, not just the extraction in general
+ var index = item.indexes[0][0].text;
+ var parts = getStructureTypeParts(item.type);
+ var indexedType = parts[index];
+ var targetBits = getBits(indexedType);
+ var sourceBits = getBits(item.type);
+ var elements = getLegalVars(item.assignTo, targetBits, true); // possibly illegal
+ var sourceElements = getLegalVars(item.ident, sourceBits); // definitely illegal
+ var toAdd = [];
+ var sourceIndex = 0;
+ for (var partIndex = 0; partIndex < parts.length; partIndex++) {
+ if (partIndex == index) {
+ for (var j = 0; j < elements.length; j++) {
+ toAdd.push({
+ intertype: 'value',
+ assignTo: elements[j].ident,
+ type: 'i' + elements[j].bits,
+ ident: sourceElements[sourceIndex+j].ident
+ });
+ }
+ break;
+ }
+ sourceIndex += getStructuralTypePartBits(parts[partIndex])/32;
+ }
+ i += removeAndAdd(label.lines, i, toAdd);
+ continue;
+ }
+ case 'insertvalue': {
+ var index = item.indexes[0][0].text; // the modified index
+ var parts = getStructureTypeParts(item.type);
+ var indexedType = parts[index];
+ var indexBits = getBits(indexedType);
+ var bits = getBits(item.type); // source and target
+ bits = getBits(value.type);
+ var toAdd = [];
+ var elements = getLegalVars(item.assignTo, bits);
+ var sourceElements = getLegalVars(item.ident, bits);
+ var indexElements = getLegalVars(item.value.ident, indexBits, true); // possibly legal
+ var sourceIndex = 0;
+ for (var partIndex = 0; partIndex < parts.length; partIndex++) {
+ var currNum = getStructuralTypePartBits(parts[partIndex])/32;
+ for (var j = 0; j < currNum; j++) {
+ toAdd.push({
+ intertype: 'value',
+ assignTo: elements[sourceIndex+j].ident,
+ type: 'i' + elements[sourceIndex+j].bits,
+ ident: partIndex == index ? indexElements[j].ident : sourceElements[sourceIndex+j].ident
+ });
+ }
+ sourceIndex += currNum;
+ }
+ i += removeAndAdd(label.lines, i, toAdd);
+ continue;
+ }
case 'bitcast': {
var inType = item.type2;
var outType = item.type;
@@ -477,17 +578,16 @@ function analyzer(data, sidePass) {
}
case 'select': {
sourceBits = targetBits = getBits(value.params[1].type);
- var otherElementsA = getLegalVars(value.params[1].ident, sourceBits);
- var otherElementsB = getLegalVars(value.params[2].ident, sourceBits);
+ var params = getLegalParams(value.params.slice(1), sourceBits);
processor = function(result, j) {
return {
intertype: 'mathop',
op: 'select',
- type: 'i' + otherElementsA[j].bits,
+ type: 'i' + params[0][j].bits,
params: [
value.params[0],
- { intertype: 'value', ident: otherElementsA[j].ident, type: 'i' + otherElementsA[j].bits },
- { intertype: 'value', ident: otherElementsB[j].ident, type: 'i' + otherElementsB[j].bits }
+ { intertype: 'value', ident: params[0][j].ident, type: 'i' + params[0][j].bits },
+ { intertype: 'value', ident: params[1][j].ident, type: 'i' + params[1][j].bits }
]
};
};
@@ -554,9 +654,10 @@ function analyzer(data, sidePass) {
// 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 + ', ' +
+ value.ident = 'Runtime' + (ASM_JS ? '_' : '.') + 'bitshift64(' + sourceElements[0].ident + ', ' +
sourceElements[1].ident + ',"' + value.op + '",' + value.params[1].ident + '$0);' +
- 'var ' + value.assignTo + '$0 = ' + value.assignTo + '[0], ' + value.assignTo + '$1 = ' + value.assignTo + '[1];';
+ 'var ' + value.assignTo + '$0 = ' + makeGetTempDouble(0) + ', ' + value.assignTo + '$1 = ' + makeGetTempDouble(1) + ';';
+ value.assignTo = null;
i++;
continue;
}