aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/analyzer.js356
-rw-r--r--src/intertyper.js4
-rw-r--r--src/jsifier.js14
-rw-r--r--src/library.js105
-rw-r--r--src/modules.js61
-rw-r--r--src/parseTools.js201
-rw-r--r--src/preamble.js35
-rw-r--r--src/runtime.js30
-rw-r--r--src/settings.js8
9 files changed, 640 insertions, 174 deletions
diff --git a/src/analyzer.js b/src/analyzer.js
index 7412be6d..a4e7d52d 100644
--- a/src/analyzer.js
+++ b/src/analyzer.js
@@ -67,7 +67,7 @@ function analyzer(data, sidePass) {
if (subItem.intertype == 'function') {
item.functions.push(subItem);
subItem.endLineNum = null;
- subItem.lines = [];
+ subItem.lines = []; // We will fill in the function lines after the legalizer, since it can modify them
subItem.labels = [];
// 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
@@ -87,7 +87,6 @@ function analyzer(data, sidePass) {
} else if (item.functions.length > 0 && item.functions.slice(-1)[0].endLineNum === null) {
// Internal line
if (!currLabelFinished) {
- item.functions.slice(-1)[0].lines.push(subItem);
item.functions.slice(-1)[0].labels.slice(-1)[0].lines.push(subItem); // If this line fails, perhaps missing a label? LLVM_STYLE related?
if (subItem.intertype === 'branch') {
currLabelFinished = true;
@@ -100,7 +99,352 @@ function analyzer(data, sidePass) {
}
}
delete item.items;
- this.forwardItem(item, 'Typevestigator');
+ this.forwardItem(item, 'Legalizer');
+ }
+ });
+
+ // Legalize LLVM unrealistic types into realistic types.
+ //
+ // With full LLVM optimizations, it can generate types like i888 which do not exist in
+ // any actual hardware implementation, but are useful during optimization. LLVM then
+ // legalizes these types into real ones during code generation. Sadly, there is no LLVM
+ // IR pass to legalize them, which would have been useful and nice from a design perspective.
+ // The LLVM community is also not interested in receiving patches to implement that
+ // functionality, since it would duplicate existing code from the code generation
+ // component. Therefore, we implement legalization here in Emscripten.
+ //
+ // 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;
+ }
+ function getLegalVars(base, bits) {
+ if (isNumber(base)) {
+ return getLegalLiterals(base, bits);
+ }
+ var ret = new Array(Math.ceil(bits/32));
+ var i = 0;
+ while (bits > 0) {
+ ret[i] = { ident: base + '$' + i, 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].toString(), bits: Math.min(32, bits) };
+ bits -= 32;
+ i++;
+ }
+ 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;
+ lines.splice(i, 0, {
+ intertype: 'assign',
+ ident: tempIdent,
+ value: item[slot],
+ lineNum: lines[i].lineNum - 0.5
+ });
+ item[slot] = { intertype: 'value', ident: tempIdent, type: item[slot].type };
+ return i+1;
+ }
+ data.functions.forEach(function(func) {
+ 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);
+ i = unfold(label.lines, i, item, 'value');
+ label.lines.splice(i, 1);
+ bits = getBits(item.valueType);
+ var elements;
+ elements = getLegalVars(item.value.ident, bits);
+ var j = 0;
+ elements.forEach(function(element) {
+ var tempVar = '$st$' + i + '$' + j;
+ label.lines.splice(i+j*2, 0, {
+ intertype: 'assign',
+ ident: tempVar,
+ value: {
+ intertype: 'getelementptr',
+ 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' }
+ ],
+ },
+ lineNum: item.lineNum + (j/100)
+ });
+ var actualSizeType = 'i' + element.bits; // The last one may be smaller than 32 bits
+ label.lines.splice(i+j*2+1, 0, {
+ 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,
+ lineNum: item.lineNum + ((j+0.5)/100)
+ });
+ j++;
+ });
+ Types.needAnalysis['[0 x i32]'] = 0;
+ i += j*2;
+ continue;
+ }
+ } else if (item.intertype == 'assign') {
+ var value = item.value;
+ switch (value.intertype) {
+ case 'load': {
+ if (isIllegalType(value.valueType)) {
+ dprint('legalizer', 'Legalizing load at line ' + item.lineNum);
+ i = unfold(label.lines, i, value, 'pointer');
+ label.lines.splice(i, 1);
+ bits = getBits(value.valueType);
+// assert(value.pointer.intertype == 'value', 'TODO: unfolding');
+ var elements = getLegalVars(item.ident, bits);
+ var j = 0;
+ elements.forEach(function(element) {
+ var tempVar = '$st$' + i + '$' + j;
+ label.lines.splice(i+j*2, 0, {
+ intertype: 'assign',
+ ident: tempVar,
+ value: {
+ intertype: 'getelementptr',
+ 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/100)
+ });
+ var actualSizeType = 'i' + element.bits; // The last one may be smaller than 32 bits
+ label.lines.splice(i+j*2+1, 0, {
+ intertype: 'assign',
+ ident: element.ident,
+ value: {
+ intertype: 'load',
+ 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)/100)
+ });
+ j++;
+ });
+ Types.needAnalysis['[0 x i32]'] = 0;
+ i += j*2;
+ continue;
+ }
+ }
+ case 'mathop': {
+ if (isIllegalType(value.type)) {
+ dprint('legalizer', 'Legalizing mathop at line ' + item.lineNum);
+ label.lines.splice(i, 1);
+ 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.ident, 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);
+ }
+ toAdd.push({
+ intertype: 'assign',
+ ident: targetElements[j].ident,
+ value: result,
+ lineNum: item.lineNum + (j/100)
+ });
+ }
+ 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;
+ }
+ toAdd.push({
+ intertype: 'assign',
+ ident: item.ident,
+ value: legalValue,
+ lineNum: item.lineNum + ((j+1)/100)
+ });
+ }
+ Array.prototype.splice.apply(label.lines, [i, 0].concat(toAdd));
+ i += toAdd.length;
+ continue;
+ }
+ }
+ }
+ }
+ i++;
+ continue;
+ }
+ });
+ });
+ }
+
+ // Add function lines to func.lines, after our modifications to the label lines
+ data.functions.forEach(function(func) {
+ func.labels.forEach(function(label) {
+ func.lines = func.lines.concat(label.lines);
+ });
+ });
+ this.forwardItem(data, 'Typevestigator');
}
});
@@ -463,6 +807,12 @@ function analyzer(data, sidePass) {
item.functions.forEach(function(func) {
func.lines.forEach(function(line, i) {
if (line.intertype === 'assign' && line.value.intertype === 'load') {
+ // Floats have no concept of signedness. Mark them as 'signed', which is the default, for which we do nothing
+ if (line.value.type in Runtime.FLOAT_TYPES) {
+ line.value.unsigned = false;
+ return;
+ }
+ // Booleans are always unsigned
var data = func.variables[line.ident];
if (data.type === 'i1') {
line.value.unsigned = true;
diff --git a/src/intertyper.js b/src/intertyper.js
index ae9794b8..d03810d4 100644
--- a/src/intertyper.js
+++ b/src/intertyper.js
@@ -647,7 +647,7 @@ function intertyper(data, sidePass, baseLineNums) {
item.type = item.tokens[4].text; // The final type
Types.needAnalysis[item.type] = 0;
var to = getTokenIndexByText(item.tokens, 'to');
- item.params = [parseLLVMSegment(item.tokens.slice(2, to))];
+ item.params = [parseLLVMSegment(item.tokens.slice(1, to))];
item.ident = item.params[0].ident;
item.type2 = item.tokens[1].text; // The original type
Types.needAnalysis[item.type2] = 0;
@@ -864,7 +864,7 @@ function intertyper(data, sidePass, baseLineNums) {
var ret = {
intertype: 'store',
valueType: item.tokens[1].text,
- value: parseLLVMSegment(segments[0]), // TODO: Make everything use this method, with finalizeLLVMParameter too
+ value: parseLLVMSegment(segments[0]),
pointer: parseLLVMSegment(segments[1]),
lineNum: item.lineNum
};
diff --git a/src/jsifier.js b/src/jsifier.js
index 657a9673..e52d3a00 100644
--- a/src/jsifier.js
+++ b/src/jsifier.js
@@ -71,7 +71,7 @@ function JSify(data, functionsOnly, givenFunctions) {
}
}
} else {
- libFuncsToInclude = ['memset', 'malloc', 'free'];
+ libFuncsToInclude = ['memcpy', 'memset', 'malloc', 'free'];
}
libFuncsToInclude.forEach(function(ident) {
data.functionStubs.push({
@@ -719,6 +719,9 @@ function JSify(data, functionsOnly, givenFunctions) {
}
});
}
+ makeFuncLineActor('value', function(item) {
+ return item.ident;
+ });
makeFuncLineActor('noop', function(item) {
return ';';
});
@@ -824,7 +827,7 @@ function JSify(data, functionsOnly, givenFunctions) {
});
labelSets.forEach(function(labelSet) {
walkInterdata(labelSet.value, function mark(item) {
- if (item.intertype == 'value' && item.ident in deps) {
+ if (item.intertype == 'value' && item.ident in deps && labelSet.ident != item.ident) {
deps[labelSet.ident][item.ident] = true;
}
});
@@ -845,7 +848,7 @@ function JSify(data, functionsOnly, givenFunctions) {
}
}
// If we got here, we have circular dependencies, and must break at least one.
- pre = 'var ' + idents[0] + '$phi = ' + valueJSes[idents[i]] + ';' + pre;
+ pre = 'var ' + idents[0] + '$phi = ' + valueJSes[idents[0]] + ';' + pre;
post += 'var ' + idents[0] + ' = ' + idents[0] + '$phi;';
remove(idents[0]);
}
@@ -1029,7 +1032,10 @@ function JSify(data, functionsOnly, givenFunctions) {
makeFuncLineActor('mathop', processMathop);
makeFuncLineActor('bitcast', function(item) {
- return finalizeLLVMParameter(item.params[0]);
+ return processMathop({
+ op: 'bitcast', variant: null, type: item.type,
+ param1: item.params[0]
+ });
});
function makeFunctionCall(ident, params, funcData, type) {
diff --git a/src/library.js b/src/library.js
index 45c64bc7..6f1f2fe5 100644
--- a/src/library.js
+++ b/src/library.js
@@ -406,7 +406,7 @@ LibraryManager.library = {
// dirent.h
// ==========================================================================
- __dirent_struct_layout: Runtime.generateStructInfo(null, '%struct.dirent'),
+ __dirent_struct_layout: Runtime.generateStructInfo(['d_ino', 'd_name', 'd_off', 'd_reclen', 'd_type'], '%struct.dirent'),
opendir__deps: ['$FS', '__setErrNo', '$ERRNO_CODES', '__dirent_struct_layout'],
opendir: function(dirname) {
// DIR *opendir(const char *dirname);
@@ -561,7 +561,7 @@ LibraryManager.library = {
// utime.h
// ==========================================================================
- __utimbuf_struct_layout: Runtime.generateStructInfo(null, '%struct.utimbuf'),
+ __utimbuf_struct_layout: Runtime.generateStructInfo(['actime', 'modtime'], '%struct.utimbuf'),
utime__deps: ['$FS', '__setErrNo', '$ERRNO_CODES', '__utimbuf_struct_layout'],
utime: function(path, times) {
// int utime(const char *path, const struct utimbuf *times);
@@ -649,7 +649,24 @@ LibraryManager.library = {
// sys/stat.h
// ==========================================================================
- __stat_struct_layout: Runtime.generateStructInfo(null, '%struct.stat'),
+ __stat_struct_layout: Runtime.generateStructInfo([
+ 'st_dev',
+ 'st_ino',
+ 'st_mode',
+ 'st_nlink',
+ 'st_uid',
+ 'st_gid',
+ 'st_rdev',
+ 'st_size',
+ 'st_atime',
+ 'st_spare1',
+ 'st_mtime',
+ 'st_spare2',
+ 'st_ctime',
+ 'st_spare3',
+ 'st_blksize',
+ 'st_blocks',
+ 'st_spare4'], '%struct.stat'),
stat__deps: ['$FS', '__stat_struct_layout'],
stat: function(path, buf, dontResolveLastLink) {
// http://pubs.opengroup.org/onlinepubs/7908799/xsh/stat.html
@@ -818,7 +835,18 @@ LibraryManager.library = {
// sys/statvfs.h
// ==========================================================================
- __statvfs_struct_layout: Runtime.generateStructInfo(null, '%struct.statvfs'),
+ __statvfs_struct_layout: Runtime.generateStructInfo([
+ 'f_bsize',
+ 'f_frsize',
+ 'f_blocks',
+ 'f_bfree',
+ 'f_bavail',
+ 'f_files',
+ 'f_ffree',
+ 'f_favail',
+ 'f_fsid',
+ 'f_flag',
+ 'f_namemax'], '%struct.statvfs'),
statvfs__deps: ['$FS', '__statvfs_struct_layout'],
statvfs: function(path, buf) {
// http://pubs.opengroup.org/onlinepubs/7908799/xsh/stat.html
@@ -852,7 +880,13 @@ LibraryManager.library = {
// fcntl.h
// ==========================================================================
- __flock_struct_layout: Runtime.generateStructInfo(null, '%struct.flock'),
+ __flock_struct_layout: Runtime.generateStructInfo([
+ 'l_type',
+ 'l_whence',
+ 'l_start',
+ 'l_len',
+ 'l_pid',
+ 'l_xxx'], '%struct.flock'),
open__deps: ['$FS', '__setErrNo', '$ERRNO_CODES', '__dirent_struct_layout'],
open: function(path, oflag, varargs) {
// int open(const char *path, int oflag, ...);
@@ -1055,7 +1089,7 @@ LibraryManager.library = {
// poll.h
// ==========================================================================
- __pollfd_struct_layout: Runtime.generateStructInfo(null, '%struct.pollfd'),
+ __pollfd_struct_layout: Runtime.generateStructInfo(['fd', 'events', 'revents'], '%struct.pollfd'),
poll__deps: ['$FS', '__pollfd_struct_layout'],
poll: function(fds, nfds, timeout) {
// int poll(struct pollfd fds[], nfds_t nfds, int timeout);
@@ -2260,7 +2294,6 @@ LibraryManager.library = {
} else if (type == 'i64') {
ret = [{{{ makeGetValue('varargs', 'argIndex', 'i32', undefined, undefined, true) }}},
{{{ makeGetValue('varargs', 'argIndex+4', 'i32', undefined, undefined, true) }}}];
- ret = unSign(ret[0], 32) + unSign(ret[1], 32)*Math.pow(2, 32); // Unsigned in this notation. Signed later if needed. // XXX - loss of precision
#else
} else if (type == 'i64') {
ret = {{{ makeGetValue('varargs', 'argIndex', 'i64', undefined, undefined, true) }}};
@@ -2270,7 +2303,7 @@ LibraryManager.library = {
ret = {{{ makeGetValue('varargs', 'argIndex', 'i32', undefined, undefined, true) }}};
}
argIndex += Runtime.getNativeFieldSize(type);
- return Number(ret);
+ return ret;
}
var ret = [];
@@ -2392,6 +2425,12 @@ LibraryManager.library = {
var signed = next == 'd'.charCodeAt(0) || next == 'i'.charCodeAt(0);
argSize = argSize || 4;
var currArg = getNextArg('i' + (argSize * 8));
+#if I64_MODE == 1
+ // Flatten i64-1 [low, high] into a (slightly rounded) double
+ if (argSize == 8) {
+ currArg = Runtime.makeBigInt(currArg[0], currArg[1], next == 'u'.charCodeAt(0));
+ }
+#endif
// Truncate to requested size.
if (argSize <= 4) {
var limit = Math.pow(256, argSize) - 1;
@@ -3444,7 +3483,7 @@ LibraryManager.library = {
},
strtoll__deps: ['_parseInt'],
strtoll: function(str, endptr, base) {
- return __parseInt(str, endptr, base, -9223372036854775808, 9223372036854775807, 64); // LLONG_MIN, LLONG_MAX; imprecise.
+ return __parseInt(str, endptr, base, -9223372036854775200, 9223372036854775200, 64); // LLONG_MIN, LLONG_MAX; imprecise.
},
strtol__deps: ['_parseInt'],
strtol: function(str, endptr, base) {
@@ -4723,7 +4762,12 @@ LibraryManager.library = {
// sys/utsname.h
// ==========================================================================
- __utsname_struct_layout: Runtime.generateStructInfo(null, '%struct.utsname'),
+ __utsname_struct_layout: Runtime.generateStructInfo([
+ 'sysname',
+ 'nodename',
+ 'release',
+ 'version',
+ 'machine'], '%struct.utsname'),
uname__deps: ['__utsname_struct_layout'],
uname: function(name) {
// int uname(struct utsname *name);
@@ -4922,7 +4966,18 @@ LibraryManager.library = {
return time1 - time0;
},
- __tm_struct_layout: Runtime.generateStructInfo(null, '%struct.tm'),
+ __tm_struct_layout: Runtime.generateStructInfo([
+ 'tm_sec',
+ 'tm_min',
+ 'tm_hour',
+ 'tm_mday',
+ 'tm_mon',
+ 'tm_year',
+ 'tm_wday',
+ 'tm_yday',
+ 'tm_isdst',
+ 'tm_gmtoff',
+ 'tm_zone'], '%struct.tm'),
// Statically allocated time struct.
__tm_current: 0,
// Statically allocated timezone strings.
@@ -5121,7 +5176,7 @@ LibraryManager.library = {
// sys/time.h
// ==========================================================================
- __timespec_struct_layout: Runtime.generateStructInfo(null, '%struct.timespec'),
+ __timespec_struct_layout: Runtime.generateStructInfo(['tv_sec', 'tv_nsec'], '%struct.timespec'),
// TODO: Implement these for real.
clock_gettime__deps: ['__timespec_struct_layout'],
clock_gettime: function(clk_id, tp) {
@@ -5158,7 +5213,11 @@ LibraryManager.library = {
// sys/times.h
// ==========================================================================
- __tms_struct_layout: Runtime.generateStructInfo(null, '%struct.tms'),
+ __tms_struct_layout: Runtime.generateStructInfo([
+ 'tms_utime',
+ 'tms_stime',
+ 'tms_cutime',
+ 'tms_cstime'], '%struct.tms'),
times__deps: ['__tms_struct_layout', 'memset'],
times: function(buffer) {
// clock_t times(struct tms *buffer);
@@ -5655,7 +5714,7 @@ LibraryManager.library = {
// ==========================================================================
// TODO: Implement for real.
- __rlimit_struct_layout: Runtime.generateStructInfo(null, '%struct.rlimit'),
+ __rlimit_struct_layout: Runtime.generateStructInfo(['rlim_cur', 'rlim_max'], '%struct.rlimit'),
getrlimit__deps: ['__rlimit_struct_layout'],
getrlimit: function(resource, rlp) {
// int getrlimit(int resource, struct rlimit *rlp);
@@ -5670,7 +5729,23 @@ LibraryManager.library = {
__01getrlimit64_: 'getrlimit',
// TODO: Implement for real. We just do time used, and no useful data
- __rusage_struct_layout: Runtime.generateStructInfo(null, '%struct.rusage'),
+ __rusage_struct_layout: Runtime.generateStructInfo([
+ 'ru_utime',
+ 'ru_stime',
+ 'ru_maxrss',
+ 'ru_ixrss',
+ 'ru_idrss',
+ 'ru_isrss',
+ 'ru_minflt',
+ 'ru_majflt',
+ 'ru_nswap',
+ 'ru_inblock',
+ 'ru_oublock',
+ 'ru_msgsnd',
+ 'ru_msgrcv',
+ 'ru_nsignals',
+ 'ru_nvcsw',
+ 'ru_nivcsw'], '%struct.rusage'),
getrusage__deps: ['__rusage_struct_layout'],
getrusage: function(resource, rlp) {
// %struct.timeval = type { i32, i32 }
diff --git a/src/modules.js b/src/modules.js
index 7b8ac390..cfc29014 100644
--- a/src/modules.js
+++ b/src/modules.js
@@ -37,12 +37,6 @@ var Debugging = {
var metadataToParentMetadata = {};
var metadataToFilename = {};
- var structToMemberMeta = {};
- var memberMetaToStruct = {};
- var structMetaToStruct = {};
- var memberMetaToMembers = {};
- var metadataToMember = {};
-
var form1 = new RegExp(/^ .*, !dbg !(\d+) *$/);
var form2 = new RegExp(/^ .*, !dbg !(\d+) *; .*$/);
var form3 = new RegExp(/^!(\d+) = metadata !{i32 (\d+), (?:i32 \d+|null), metadata !(\d+), .*}$/);
@@ -55,9 +49,6 @@ var Debugging = {
var form4 = new RegExp(/^!llvm.dbg.[\w\.]+ = .*$/);
var form5 = new RegExp(/^!(\d+) = metadata !{.*$/);
var form6 = new RegExp(/^ (tail )?call void \@llvm.dbg.\w+\(metadata .*$/);
- var formStruct = /^!(\d+) = metadata !\{i32 \d+, (metadata !\d+|null), metadata !"([^"]+)", metadata !(\d+), (?:i32 \d+|null), i64 \d+, [^,]*, [^,]*, [^,]*, [^,]*, metadata !(\d+), .*}.*$/;
- var formStructMembers = /^!(\d+) = metadata !\{(.*)\}$/;
- var formMember = /^!(\d+) = metadata !\{i32 \d+, metadata !\d+, metadata !"([^"]+)", metadata !\d+, (?:i32 \d+|null), i64 \d+, i64 \d+, i64 \d+, .+?, metadata !(\d+)}.*$/;
for (var i = 0; i < lines.length; i++) {
var line = lines[i];
@@ -75,29 +66,6 @@ var Debugging = {
lines[i] = line.replace(/, !dbg !\d+/, '');
continue;
}
- calc = formStruct.exec(line);
- if (calc) {
- metadataToParentMetadata[calc[1]] = calc[4];
- if (!(calc[3] in structToMemberMeta)) {
- structMetaToStruct[calc[1]] = calc[3];
- structToMemberMeta[calc[3]] = calc[5];
- memberMetaToStruct[calc[5]] = calc[1];
- }
- skipLine = true;
- }
- calc = formStructMembers.exec(line);
- if (calc) {
- var children = calc[2].match(/!\d+/g) || [];
- memberMetaToMembers[calc[1]] = children.map(function(i) {
- return i.slice(1);
- });
- skipLine = true;
- }
- calc = formMember.exec(line);
- if (calc) {
- metadataToMember[calc[1]] = calc.slice(2);
- skipLine = true;
- }
calc = form3.exec(line);
if (calc) {
metadataToSourceLine[calc[1]] = calc[2];
@@ -146,35 +114,6 @@ var Debugging = {
this.llvmLineToSourceFile[l] = metadataToFilename[m];
}
- // Create struct definitions.
- // TODO: Account for bitfields.
- function generateStructDefinition(name) {
- if (!Types.structMetadata.hasOwnProperty(name)) {
- var struct = [];
- var membersMetaId = structToMemberMeta[name];
- var memberIds = memberMetaToMembers[membersMetaId];
- for (var i = 0; i < memberIds.length; i++) {
- var memberId = memberIds[i];
- if (memberId in metadataToMember) {
- var member = metadataToMember[memberId];
- if (member[1] in structMetaToStruct) {
- var def = generateStructDefinition(structMetaToStruct[member[1]]);
- var record = {};
- record[member[0]] = def;
- struct.push(record);
- } else {
- struct.push(member[0]);
- }
- }
- }
- Types.structMetadata[name] = struct;
- }
- return Types.structMetadata[name];
- }
- for (var name in structToMemberMeta) {
- generateStructDefinition(name);
- }
-
this.on = true;
},
diff --git a/src/parseTools.js b/src/parseTools.js
index 09168179..a53ff1c0 100644
--- a/src/parseTools.js
+++ b/src/parseTools.js
@@ -129,6 +129,11 @@ function isIntImplemented(type) {
return type[0] == 'i' || isPointerType(type);
}
+function getBits(type) {
+ if (!type || type[0] != 'i') return 0;
+ return parseInt(type.substr(1));
+}
+
function isVoidType(type) {
return type == 'void';
}
@@ -563,22 +568,13 @@ function makeInlineCalculation(expression, value, tempVar) {
return '(' + expression.replace(/VALUE/g, value) + ')';
}
-// Given two 32-bit unsigned parts of an emulated 64-bit number, combine them into a JS number (double).
-// 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
-function makeBigInt(low, high) {
- // here VALUE will be the big part
- return '(' + high + ' <= 2147483648 ? (' + makeSignOp(low, 'i32', 'un', 1, 1) + '+(' + makeSignOp(high, 'i32', 'un', 1, 1) + '*4294967296))' +
- ' : (' + makeSignOp(low, 'i32', 're', 1, 1) + '+(1+' + makeSignOp(high, 'i32', 're', 1, 1) + ')*4294967296))';
-}
-
// Makes a proper runtime value for a 64-bit value from low and high i32s. low and high are assumed to be unsigned.
function makeI64(low, high) {
high = high || '0';
if (I64_MODE == 1) {
return '[' + makeSignOp(low, 'i32', 'un', 1, 1) + ',' + makeSignOp(high, 'i32', 'un', 1, 1) + ']';
} else {
- if (high) return makeBigInt(low, high);
+ if (high) return RuntimeGenerator.makeBigInt(low, high);
return low;
}
}
@@ -594,7 +590,7 @@ function splitI64(value) {
}
function mergeI64(value) {
assert(I64_MODE == 1);
- return makeInlineCalculation(makeBigInt('VALUE[0]', 'VALUE[1]'), value, 'tempI64')