aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AUTHORS4
-rwxr-xr-xemcc3
-rwxr-xr-xemscripten.py4
-rw-r--r--src/analyzer.js2743
-rw-r--r--src/compiler.js5
-rw-r--r--src/framework.js257
-rw-r--r--src/intertyper.js1733
-rw-r--r--src/jsifier.js1216
-rw-r--r--src/library.js46
-rw-r--r--src/library_gl.js112
-rw-r--r--src/library_sdl.js280
-rw-r--r--src/modules.js4
-rw-r--r--src/parseTools.js32
-rw-r--r--src/preamble.js22
-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.js1
-rw-r--r--system/include/libc/assert.h2
-rw-r--r--system/lib/libc/musl/readme.txt1
-rw-r--r--tests/cases/atomicrmw_unaligned.emcc1
-rw-r--r--tests/cases/atomicrmw_unaligned.ll21
-rw-r--r--tests/cases/atomicrmw_unaligned.txt1
-rw-r--r--tests/printf/output.txt11
-rw-r--r--tests/printf/output_i64_1.txt11
-rw-r--r--tests/printf/test.c11
-rw-r--r--tests/sdl_audio_beep.cpp246
-rw-r--r--tests/sdl_canvas_alpha.c46
-rw-r--r--tests/sdl_canvas_alpha.pngbin0 -> 169826 bytes
-rw-r--r--tests/test_browser.py11
-rw-r--r--tests/test_core.py51
-rw-r--r--tests/test_other.py6
-rw-r--r--tools/js_optimizer.py4
-rw-r--r--tools/shared.py7
34 files changed, 3628 insertions, 3318 deletions
diff --git a/AUTHORS b/AUTHORS
index 604bd6bd..d8f9da02 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -1,4 +1,4 @@
-The following authors have all licensed their contributions to Emscripten
+The following authors have all licensed their contributions to Emscripten
under the licensing terms detailed in LICENSE.
(Authors keep copyright of their contributions, of course; they just grant
@@ -97,4 +97,6 @@ a license to everyone to use it as detailed in LICENSE.)
* Charlie Birks <admin@daftgames.net>
* Ranger Harke <ranger.harke@autodesk.com> (copyright owned by Autodesk, Inc.)
* Tobias Vrinssen <tobias@vrinssen.de>
+* Patrick R. Martin <patrick.martin.r@gmail.com>
+* Richard Quirk <richard.quirk@gmail.com>
diff --git a/emcc b/emcc
index 1c116bf5..d4889b58 100755
--- a/emcc
+++ b/emcc
@@ -238,6 +238,9 @@ Options that are modified or new in %s include:
(see --llvm-opts), setting this has no
effect.
+ Note that LLVM LTO is not perfectly stable yet,
+ and can can cause code to behave incorrectly.
+
--closure <on> 0: No closure compiler (default in -O2 and below)
1: Run closure compiler. This greatly reduces
code size and may in some cases increase
diff --git a/emscripten.py b/emscripten.py
index 4d744fdd..19e2160d 100755
--- a/emscripten.py
+++ b/emscripten.py
@@ -39,7 +39,7 @@ def scan(ll, settings):
if len(blockaddrs) > 0:
settings['NECESSARY_BLOCKADDRS'] = blockaddrs
-NUM_CHUNKS_PER_CORE = 1.25
+NUM_CHUNKS_PER_CORE = 1.0
MIN_CHUNK_SIZE = 1024*1024
MAX_CHUNK_SIZE = float(os.environ.get('EMSCRIPT_MAX_CHUNK_SIZE') or 'inf') # configuring this is just for debugging purposes
@@ -209,7 +209,7 @@ def emscript(infile, settings, outfile, libraries=[], compiler_engine=None,
if cores > 1:
intended_num_chunks = int(round(cores * NUM_CHUNKS_PER_CORE))
chunk_size = max(MIN_CHUNK_SIZE, total_ll_size / intended_num_chunks)
- chunk_size += 3*len(meta) + len(forwarded_data)/3 # keep ratio of lots of function code to meta (expensive to process, and done in each parallel task) and forwarded data (less expensive but potentially significant)
+ chunk_size += 3*len(meta) # keep ratio of lots of function code to meta (expensive to process, and done in each parallel task)
chunk_size = min(MAX_CHUNK_SIZE, chunk_size)
else:
chunk_size = MAX_CHUNK_SIZE # if 1 core, just use the max chunk size
diff --git a/src/analyzer.js b/src/analyzer.js
index b20dedff..750f2a4c 100644
--- a/src/analyzer.js
+++ b/src/analyzer.js
@@ -27,82 +27,69 @@ 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;
+
+ // 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;
+ 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 +100,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,725 +180,722 @@ 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 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 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 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
+ }
+ 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;
}
- // 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 (!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.