aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/analyzer.js2766
-rw-r--r--src/compiler.js15
-rw-r--r--src/compiler_phase.html33
-rw-r--r--src/framework.js257
-rw-r--r--src/intertyper.js1850
-rw-r--r--src/jsifier.js1222
-rw-r--r--src/library.js158
-rw-r--r--src/library_fs.js72
-rw-r--r--src/library_gl.js168
-rw-r--r--src/library_idbfs.js216
-rw-r--r--src/library_memfs.js26
-rw-r--r--src/library_nodefs.js234
-rw-r--r--src/library_sdl.js280
-rw-r--r--src/library_sockfs.js12
-rw-r--r--src/modules.js6
-rw-r--r--src/parseTools.js211
-rw-r--r--src/postamble.js3
-rw-r--r--src/preamble.js25
-rw-r--r--src/relooper/Relooper.cpp2
-rw-r--r--src/relooper/emscripten/glue.js11
-rw-r--r--src/runtime.js41
-rw-r--r--src/settings.js3
-rw-r--r--src/utility.js11
23 files changed, 4181 insertions, 3441 deletions
diff --git a/src/analyzer.js b/src/analyzer.js
index b20dedff..3fb20253 100644
--- a/src/analyzer.js
+++ b/src/analyzer.js
@@ -27,82 +27,72 @@ var SHADOW_FLIP = { i64: 'double', double: 'i64' }; //, i32: 'float', float: 'i3
function analyzer(data, sidePass) {
var mainPass = !sidePass;
- // Substrate
- var substrate = new Substrate('Analyzer');
-
- // Sorter
- substrate.addActor('Sorter', {
- processItem: function(item) {
- item.items.sort(function (a, b) { return a.lineNum - b.lineNum });
- this.forwardItem(item, 'Gatherer');
+ var item = { items: data };
+ var data = item;
+
+ var newTypes = {};
+
+ // Gather
+ // Single-liners
+ ['globalVariable', 'functionStub', 'unparsedFunction', 'unparsedGlobals', 'unparsedTypes', 'alias'].forEach(function(intertype) {
+ var temp = splitter(item.items, function(item) { return item.intertype == intertype });
+ item.items = temp.leftIn;
+ item[intertype + 's'] = temp.splitOut;
+ });
+ var temp = splitter(item.items, function(item) { return item.intertype == 'type' });
+ item.items = temp.leftIn;
+ temp.splitOut.forEach(function(type) {
+ //dprint('types', 'adding defined type: ' + type.name_);
+ Types.types[type.name_] = type;
+ newTypes[type.name_] = 1;
+ if (QUANTUM_SIZE === 1) {
+ Types.fatTypes[type.name_] = copy(type);
}
});
- // Gatherer
- substrate.addActor('Gatherer', {
- processItem: function(item) {
- // Single-liners
- ['globalVariable', 'functionStub', 'unparsedFunction', 'unparsedGlobals', 'unparsedTypes', 'alias'].forEach(function(intertype) {
- var temp = splitter(item.items, function(item) { return item.intertype == intertype });
- item.items = temp.leftIn;
- item[intertype + 's'] = temp.splitOut;
- });
- var temp = splitter(item.items, function(item) { return item.intertype == 'type' });
- item.items = temp.leftIn;
- temp.splitOut.forEach(function(type) {
- //dprint('types', 'adding defined type: ' + type.name_);
- Types.types[type.name_] = type;
- if (QUANTUM_SIZE === 1) {
- Types.fatTypes[type.name_] = copy(type);
- }
- });
-
- // Functions & labels
- item.functions = [];
- var currLabelFinished; // Sometimes LLVM puts a branch in the middle of a label. We need to ignore all lines after that.
- item.items.sort(function(a, b) { return a.lineNum - b.lineNum });
- for (var i = 0; i < item.items.length; i++) {
- var subItem = item.items[i];
- assert(subItem.lineNum);
- if (subItem.intertype == 'function') {
- item.functions.push(subItem);
- subItem.endLineNum = null;
- subItem.lines = []; // We will fill in the function lines after the legalizer, since it can modify them
- subItem.labels = [];
- subItem.forceEmulated = false;
-
- // no explicit 'entry' label in clang on LLVM 2.8 - most of the time, but not all the time! - so we add one if necessary
- if (item.items[i+1].intertype !== 'label') {
- item.items.splice(i+1, 0, {
- intertype: 'label',
- ident: ENTRY_IDENT,
- lineNum: subItem.lineNum + '.5'
- });
- }
- } else if (subItem.intertype == 'functionEnd') {
- item.functions.slice(-1)[0].endLineNum = subItem.lineNum;
- } else if (subItem.intertype == 'label') {
- item.functions.slice(-1)[0].labels.push(subItem);
- subItem.lines = [];
- currLabelFinished = false;
- } else if (item.functions.length > 0 && item.functions.slice(-1)[0].endLineNum === null) {
- // Internal line
- if (!currLabelFinished) {
- item.functions.slice(-1)[0].labels.slice(-1)[0].lines.push(subItem); // If this line fails, perhaps missing a label?
- if (subItem.intertype in LABEL_ENDERS) {
- currLabelFinished = true;
- }
- } else {
- print('// WARNING: content after a branch in a label, line: ' + subItem.lineNum);
- }
- } else {
- throw 'ERROR: what is this? ' + dump(subItem);
+ // Functions & labels
+ item.functions = [];
+ var currLabelFinished = false; // Sometimes LLVM puts a branch in the middle of a label. We need to ignore all lines after that.
+ item.items.sort(function(a, b) { return a.lineNum - b.lineNum });
+ for (var i = 0; i < item.items.length; i++) {
+ var subItem = item.items[i];
+ assert(subItem.lineNum);
+ if (subItem.intertype == 'function') {
+ item.functions.push(subItem);
+ subItem.endLineNum = null;
+ subItem.lines = []; // We will fill in the function lines after the legalizer, since it can modify them
+ subItem.labels = [];
+ subItem.forceEmulated = false;
+
+ // no explicit 'entry' label in clang on LLVM 2.8 - most of the time, but not all the time! - so we add one if necessary
+ if (item.items[i+1].intertype !== 'label') {
+ item.items.splice(i+1, 0, {
+ intertype: 'label',
+ ident: ENTRY_IDENT,
+ lineNum: subItem.lineNum + '.5'
+ });
+ }
+ } else if (subItem.intertype == 'functionEnd') {
+ item.functions.slice(-1)[0].endLineNum = subItem.lineNum;
+ } else if (subItem.intertype == 'label') {
+ item.functions.slice(-1)[0].labels.push(subItem);
+ subItem.lines = [];
+ currLabelFinished = false;
+ } else if (item.functions.length > 0 && item.functions.slice(-1)[0].endLineNum === null) {
+ // Internal line
+ if (!currLabelFinished) {
+ item.functions.slice(-1)[0].labels.slice(-1)[0].lines.push(subItem); // If this line fails, perhaps missing a label?
+ if (subItem.intertype in LABEL_ENDERS) {
+ currLabelFinished = true;
}
+ } else {
+ print('// WARNING: content after a branch in a label, line: ' + subItem.lineNum);
}
- delete item.items;
- this.forwardItem(item, 'CastAway');
+ } else {
+ throw 'ERROR: what is this? ' + dump(subItem);
}
- });
+ }
+ delete item.items;
// CastAway - try to remove bitcasts of double<-->i64, which LLVM sometimes generates unnecessarily
// (load a double, convert to i64, use as i64).
@@ -113,75 +103,72 @@ function analyzer(data, sidePass) {
// Note that aside from being an optimization, this is needed for correctness in some cases: If code
// assumes it can bitcast a double to an i64 and back and forth without loss, that may be violated
// due to NaN canonicalization.
- substrate.addActor('CastAway', {
- processItem: function(item) {
- this.forwardItem(item, 'Legalizer');
- if (USE_TYPED_ARRAYS != 2) return;
+ function castAway() {
+ if (USE_TYPED_ARRAYS != 2) return;
- item.functions.forEach(function(func) {
- var has = false;
- func.labels.forEach(function(label) {
- var lines = label.lines;
- for (var i = 0; i < lines.length; i++) {
- var line = lines[i];
- if (line.intertype == 'bitcast' && line.type in SHADOW_FLIP) {
- has = true;
- }
+ item.functions.forEach(function(func) {
+ var has = false;
+ func.labels.forEach(function(label) {
+ var lines = label.lines;
+ for (var i = 0; i < lines.length; i++) {
+ var line = lines[i];
+ if (line.intertype == 'bitcast' && line.type in SHADOW_FLIP) {
+ has = true;
}
- });
- if (!has) return;
- // there are integer<->floating-point bitcasts, create shadows for everything
- var shadowed = {};
- func.labels.forEach(function(label) {
- var lines = label.lines;
- var i = 0;
- while (i < lines.length) {
- var lines = label.lines;
- var line = lines[i];
- if (line.intertype == 'load' && line.type in SHADOW_FLIP) {
- if (line.pointer.intertype != 'value') { i++; continue } // TODO
- shadowed[line.assignTo] = 1;
- var shadow = line.assignTo + '$$SHADOW';
- var flip = SHADOW_FLIP[line.type];
- lines.splice(i + 1, 0, { // if necessary this element will be legalized in the next phase
- tokens: null,
- indent: 2,
- lineNum: line.lineNum + 0.5,
- assignTo: shadow,
- intertype: 'load',
- pointerType: flip + '*',
- type: flip,
- valueType: flip,
- pointer: {
- intertype: 'value',
- ident: line.pointer.ident,
- type: flip + '*'
- },
- align: line.align,
- ident: line.ident
- });
- // note: no need to update func.lines, it is generated in a later pass
- i++;
- }
+ }
+ });
+ if (!has) return;
+ // there are integer<->floating-point bitcasts, create shadows for everything
+ var shadowed = {};
+ func.labels.forEach(function(label) {
+ var lines = label.lines;
+ var i = 0;
+ while (i < lines.length) {
+ var lines = label.lines;
+ var line = lines[i];
+ if (line.intertype == 'load' && line.type in SHADOW_FLIP) {
+ if (line.pointer.intertype != 'value') { i++; continue } // TODO
+ shadowed[line.assignTo] = 1;
+ var shadow = line.assignTo + '$$SHADOW';
+ var flip = SHADOW_FLIP[line.type];
+ lines.splice(i + 1, 0, { // if necessary this element will be legalized in the next phase
+ tokens: null,
+ indent: 2,
+ lineNum: line.lineNum + 0.5,
+ assignTo: shadow,
+ intertype: 'load',
+ pointerType: flip + '*',
+ type: flip,
+ valueType: flip,
+ pointer: {
+ intertype: 'value',
+ ident: line.pointer.ident,
+ type: flip + '*'
+ },
+ align: line.align,
+ ident: line.ident
+ });
+ // note: no need to update func.lines, it is generated in a later pass
i++;
}
- });
- // use shadows where possible
- func.labels.forEach(function(label) {
- var lines = label.lines;
- for (var i = 0; i < lines.length; i++) {
- var line = lines[i];
- if (line.intertype == 'bitcast' && line.type in SHADOW_FLIP && line.ident in shadowed) {
- var shadow = line.ident + '$$SHADOW';
- line.params[0].ident = shadow;
- line.params[0].type = line.type;
- line.type2 = line.type;
- }
+ i++;
+ }
+ });
+ // use shadows where possible
+ func.labels.forEach(function(label) {
+ var lines = label.lines;
+ for (var i = 0; i < lines.length; i++) {
+ var line = lines[i];
+ if (line.intertype == 'bitcast' && line.type in SHADOW_FLIP && line.ident in shadowed) {
+ var shadow = line.ident + '$$SHADOW';
+ line.params[0].ident = shadow;
+ line.params[0].type = line.type;
+ line.type2 = line.type;
}
- });
+ }
});
- }
- });
+ });
+ }
// Legalize LLVM unrealistic types into realistic types.
//
@@ -196,727 +183,724 @@ 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.
- substrate.addActor('Legalizer', {
- processItem: function(data) {
- // Legalization
- if (USE_TYPED_ARRAYS == 2) {
- function getLegalVars(base, bits, allowLegal) {
- bits = bits || 32; // things like pointers are all i32, but show up as 0 bits from getBits
- if (allowLegal && bits <= 32) return [{ ident: base + ('i' + bits in Runtime.INT_TYPES ? '' : '$0'), bits: bits }];
- if (isNumber(base)) return getLegalLiterals(base, bits);
- if (base[0] == '{') {
- warnOnce('seeing source of illegal data ' + base + ', likely an inline struct - assuming zeroinit');
- return getLegalLiterals('0', 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 ? base + '$' + i : '0', bits: Math.min(32, bits) };
- bits -= 32;
- i++;
- }
- return ret;
- }
- function getLegalLiterals(text, bits) {
- var parsed = parseArbitraryInt(text, bits);
- var ret = new Array(Math.ceil(bits/32));
- var i = 0;
- while (bits > 0) {
- ret[i] = { ident: (parsed[i]|0).toString(), bits: Math.min(32, bits) }; // resign all values
- bits -= 32;
- i++;
- }
- return ret;
+ function legalizer() {
+ // Legalization
+ if (USE_TYPED_ARRAYS == 2) {
+ function getLegalVars(base, bits, allowLegal) {
+ bits = bits || 32; // things like pointers are all i32, but show up as 0 bits from getBits
+ if (allowLegal && bits <= 32) return [{ ident: base + ('i' + bits in Runtime.INT_TYPES ? '' : '$0'), bits: bits }];
+ if (isNumber(base)) return getLegalLiterals(base, bits);
+ if (base[0] == '{') {
+ warnOnce('seeing source of illegal data ' + base + ', likely an inline struct - assuming zeroinit');
+ return getLegalLiterals('0', bits);
}
- function getLegalStructuralParts(value) {
- return value.params.slice(0);
+ 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 ? base + '$' + i : '0', bits: Math.min(32, bits) };
+ bits -= 32;
+ i++;
}
- 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);
- }
- });
+ return ret;
+ }
+ function getLegalLiterals(text, bits) {
+ var parsed = parseArbitraryInt(text, bits);
+ var ret = new Array(Math.ceil(bits/32));
+ var i = 0;
+ while (bits > 0) {
+ ret[i] = { ident: (parsed[i]|0).toString(), bits: Math.min(32, bits) }; // resign all values
+ bits -= 32;
+ i++;
}
- // 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);
- assert(k == 0 || toAdd[k].lineNum > toAdd[k-1].lineNum);
+ 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) {
+ 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);
+ assert(k == 0 || toAdd[k].lineNum > toAdd[k-1].lineNum);
}
- function removeAndAdd(lines, i, toAdd) {
- var item = lines[i];
- interpLines(lines, i, toAdd);
- Array.prototype.splice.apply(lines, [i, 1].concat(toAdd));
- if (i > 0) assert(lines[i].lineNum > lines[i-1].lineNum);
- if (i + toAdd.length < lines.length) assert(lines[i + toAdd.length - 1].lineNum < lines[i + toAdd.length].lineNum);
- return toAdd.length;
- }
- 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;
- } else if (param.intertype == 'structvalue') {
- // 'flatten' out the struct into scalars
- var toAdd = param.params;
- toAdd.forEach(function(param) {
- param.byval = 0;
- });
- Array.prototype.splice.apply(params, [i, 1].concat(toAdd));
- continue; // do not increment i; proceed to process the new params
- }
- i++;
+ }
+ function removeAndAdd(lines, i, toAdd) {
+ var item = lines[i];
+ interpLines(lines, i, toAdd);
+ Array.prototype.splice.apply(lines, [i, 1].concat(toAdd));
+ if (i > 0) assert(lines[i].lineNum > lines[i-1].lineNum);
+ if (i + toAdd.length < lines.length) assert(lines[i + toAdd.length - 1].lineNum < lines[i + toAdd.length].lineNum);
+ return toAdd.length;
+ }
+ 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;
+ } else if (param.intertype == 'structvalue') {
+ // 'flatten' out the struct into scalars
+ var toAdd = param.params;
+ toAdd.forEach(function(param) {
+ param.byval = 0;
+ });
+ Array.prototype.splice.apply(params, [i, 1].concat(toAdd));
+ continue; // do not increment i; proceed to process the new params
}
+ i++;
}
- function fixUnfolded(item) {
- // Unfolded items may need some correction to work properly in the global scope
- if (item.intertype in MATHOPS) {
- item.op = item.intertype;
- item.intertype = 'mathop';
- }
+ }
+ function fixUnfolded(item) {
+ // Unfolded items may need some correction to work properly in the global scope
+ if (item.intertype in MATHOPS) {
+ item.op = item.intertype;
+ item.intertype = 'mathop';
}
- data.functions.forEach(function(func) {
- // Legalize function params
- legalizeFunctionParameters(func.params);
- // 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];
- 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';
- }
- } else if (item.intertype == 'inttoptr') {
- var input = item.params[0];
- if (input.type == 'i64') input.type = 'i32'; // inttoptr can only care about 32 bits anyhow since pointers are 32-bit
- }
- if (isIllegalType(item.valueType) || isIllegalType(item.type)) {
- isIllegal = true;
- } else if ((item.intertype == 'load' || item.intertype == 'store') && isStructType(item.valueType)) {
- isIllegal = true; // storing an entire structure is illegal
- } else if (item.intertype == 'mathop' && item.op == 'trunc' && isIllegalType(item.params[1].ident)) { // trunc stores target value in second ident
- isIllegal = true;
+ }
+ data.functions.forEach(function(func) {
+ // Legalize function params
+ legalizeFunctionParameters(func.params);
+ // 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];
+ 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 (!isIllegal) {
- //if (dcheck('legalizer')) dprint('no need to legalize \n' + dump(item));
- i++;
- continue;
+ } else if (item.intertype == 'inttoptr') {
+ var input = item.params[0];
+ if (input.type == 'i64') input.type = 'i32'; // inttoptr can only care about 32 bits anyhow since pointers are 32-bit
}
- // 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)))) {
- if (item.intertype == 'phi') {
- assert(subItem.intertype == 'value' || subItem.intertype == 'structvalue' || subItem.intertype in PARSABLE_LLVM_FUNCTIONS, 'We can only unfold some expressions in phis');
- // we must handle this in the phi itself, if we unfold normally it will not be pushed back with the phi
- } else {
+ if (isIllegalType(item.valueType) || isIllegalType(item.type)) {
+ isIllegal = true;
+ } else if ((item.intertype == 'load' || item.intertype == 'store') && isStructType(item.valueType)) {
+ isIllegal = true; // storing an entire structure is illegal
+ } else if (item.intertype == 'mathop' && item.op == 'trunc' && isIllegalType(item.params[1].ident)) { // trunc stores target value in second ident
+ isIllegal = true;
+ }
+ });
+ if (!isIllegal) {
+ //if (dcheck('legalizer')) dprint('no need to legalize \n' + dump(item));
+ 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)))) {
+ if (item.intertype == 'phi') {
+ assert(subItem.intertype == 'value' || subItem.intertype == 'structvalue' || subItem.intertype in PARSABLE_LLVM_FUNCTIONS, 'We can only unfold some expressions 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 = '$$etemp$' + (tempId++);
+ subItem.assignTo = tempIdent;
+ unfolded.unshift(subItem);
+ fixUnfolded(subItem);
+ return { intertype: 'value', ident: tempIdent, type: subItem.type };
+ }
+ } else if (subItem.intertype == 'switch' && isIllegalType(subItem.type)) {
+ subItem.switchLabels.forEach(function(switchLabel) {
+ if (switchLabel.value[0] != '$') {
var tempIdent = '$$etemp$' + (tempId++);
- subItem.assignTo = tempIdent;
- unfolded.unshift(subItem);
- fixUnfolded(subItem);
- return { intertype: 'value', ident: tempIdent, type: subItem.type };
+ unfolded.unshift({
+ assignTo: tempIdent,
+ intertype: 'value',
+ ident: switchLabel.value,
+ type: subItem.type
+ });
+ switchLabel.value = tempIdent;
}
- } else if (subItem.intertype == 'switch' && isIllegalType(subItem.type)) {
- subItem.switchLabels.forEach(function(switchLabel) {
- if (switchLabel.value[0] != '$') {
- var tempIdent = '$$etemp$' + (tempId++);
- unfolded.unshift({
- assignTo: tempIdent,
- intertype: 'value',
- ident: switchLabel.value,
- type: subItem.type
- });
- switchLabel.value = tempIdent;
- }
+ });
+ }
+ });
+ 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);
+ var finalizer = null;
+ switch (item.intertype) {
+ case 'store': {
+ var toAdd = [];
+ bits = getBits(item.valueType);
+ var elements = getLegalParams([item.value], bits)[0];
+ var j = 0;
+ elements.forEach(function(element) {
+ var tempVar = '$st$' + (tempId++) + '$' + j;
+ toAdd.push({
+ intertype: 'getelementptr',
+ assignTo: tempVar,
+ ident: item.pointer.ident,
+ type: '[0 x i32]*',
+ params: [
+ { intertype: 'value', ident: item.pointer.ident, type: '[0 x i32]*' }, // technically a bitcase is needed in llvm, but not for us
+ { intertype: 'value', ident: '0', type: 'i32' },
+ { intertype: 'value', ident: j.toString(), type: 'i32' }
+ ],
});
- }
- });
- 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
+ var actualSizeType = 'i' + element.bits; // The last one may be smaller than 32 bits
+ toAdd.push({
+ intertype: 'store',
+ valueType: actualSizeType,
+ value: { intertype: 'value', ident: element.ident, type: actualSizeType },
+ pointer: { intertype: 'value', ident: tempVar, type: actualSizeType + '*' },
+ ident: tempVar,
+ pointerType: actualSizeType + '*',
+ align: item.align,
+ });
+ j++;
+ });
+ Types.needAnalysis['[0 x i32]'] = 0;
+ i += removeAndAdd(label.lines, i, toAdd);
+ continue;
}
- // This is an illegal-containing line, and it is unfolded. Legalize it now
- dprint('legalizer', 'Legalizing ' + item.intertype + ' at line ' + item.lineNum);
- var finalizer = null;
- switch (item.intertype) {
- case 'store': {
- var toAdd = [];
- bits = getBits(item.valueType);
- var elements = getLegalParams([item.value], bits)[0];
- var j = 0;
- elements.forEach(function(element) {
- var tempVar = '$st$' + (tempId++) + '$' + j;
- toAdd.push({
- intertype: 'getelementptr',
- assignTo: tempVar,
- ident: item.pointer.ident,
- type: '[0 x i32]*',
- params: [
- { intertype: 'value', ident: item.pointer.ident, type: '[0 x i32]*' }, // technically a bitcase 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
+ // call, return: Return the first 32 bits, the rest are in temp
+ case 'call': {
+ var toAdd = [value];
+ // legalize parameters
+ legalizeFunctionParameters(value.params);
+ // legalize return value, if any
+ var returnType = getReturnType(item.type);
+ if (value.assignTo && isIllegalType(returnType)) {
+ bits = getBits(returnType);
+ var elements = getLegalVars(item.assignTo, bits);
+ // legalize return value
+ value.assignTo = elements[0].ident;
+ for (var j = 1; j < elements.length; j++) {
+ var element = elements[j];
toAdd.push({
- intertype: 'store',
- valueType: actualSizeType,
- value: { intertype: 'value', ident: element.ident, type: actualSizeType },
- pointer: { intertype: 'value', ident: tempVar, type: actualSizeType + '*' },
- ident: tempVar,
- pointerType: actualSizeType + '*',
- align: item.align,
+ intertype: 'value',
+ assignTo: element.ident,
+ type: element.bits,
+ ident: 'tempRet' + (j - 1)
});
- j++;
- });
- Types.needAnalysis['[0 x i32]'] = 0;