diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/analyzer.js | 356 | ||||
-rw-r--r-- | src/intertyper.js | 4 | ||||
-rw-r--r-- | src/jsifier.js | 14 | ||||
-rw-r--r-- | src/library.js | 105 | ||||
-rw-r--r-- | src/modules.js | 61 | ||||
-rw-r--r-- | src/parseTools.js | 201 | ||||
-rw-r--r-- | src/preamble.js | 35 | ||||
-rw-r--r-- | src/runtime.js | 30 | ||||
-rw-r--r-- | src/settings.js | 8 |
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') |