diff options
Diffstat (limited to 'src/parseTools.js')
-rw-r--r-- | src/parseTools.js | 211 |
1 files changed, 122 insertions, 89 deletions
diff --git a/src/parseTools.js b/src/parseTools.js index 2ccf0179..7ebc0de2 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -111,12 +111,22 @@ function isNiceIdent(ident, loose) { } function isJSVar(ident) { - return /^\(?[$_]?[\w$_\d ]*\)+$/.test(ident); - + if (ident[0] === '(') { + if (ident[ident.length-1] !== ')') return false; + ident = ident.substr(1, ident.length-2); + } + return /^[$_]?[\w$_\d]* *$/.test(ident); } function isLocalVar(ident) { - return ident[0] == '$'; + return ident[0] === '$'; +} + +// Simple variables or numbers, or things already quoted, do not need to be quoted +function needsQuoting(ident) { + if (/^[-+]?[$_]?[\w$_\d]*$/.test(ident)) return false; // number or variable + if (ident[0] === '(' && ident[ident.length-1] === ')' && ident.indexOf('(', 1) < 0) return false; // already fully quoted + return true; } function isStructPointerType(type) { @@ -933,12 +943,12 @@ function parseLLVMString(str) { var ret = []; var i = 0; while (i < str.length) { - var chr = str[i]; - if (chr != '\\') { - ret.push(chr.charCodeAt(0)); + var chr = str.charCodeAt(i); + if (chr !== 92) { // 92 === '//'.charCodeAt(0) + ret.push(chr); i++; } else { - ret.push(eval('0x' + str[i+1]+str[i+2])); + ret.push(parseInt(str[i+1]+str[i+2], '16')); i += 3; } } @@ -1197,7 +1207,7 @@ function makeGetValue(ptr, pos, type, noNeedFirst, unsigned, ignore, align, noSa var typeData = Types.types[type]; var ret = []; for (var i = 0; i < typeData.fields.length; i++) { - ret.push('f' + i + ': ' + makeGetValue(ptr, pos + typeData.flatIndexes[i], typeData.fields[i], noNeedFirst, unsigned)); + ret.push('f' + i + ': ' + makeGetValue(ptr, pos + typeData.flatIndexes[i], typeData.fields[i], noNeedFirst, unsigned, 0, 0, noSafe)); } return '{ ' + ret.join(', ') + ' }'; } @@ -1205,8 +1215,8 @@ function makeGetValue(ptr, pos, type, noNeedFirst, unsigned, ignore, align, noSa // In double mode 1, in x86 we always assume unaligned because we can't trust that; otherwise in le32 // we need this code path if we are not fully aligned. if (DOUBLE_MODE == 1 && USE_TYPED_ARRAYS == 2 && type == 'double' && (TARGET_X86 || align < 8)) { - return '(' + makeSetTempDouble(0, 'i32', makeGetValue(ptr, pos, 'i32', noNeedFirst, unsigned, ignore, align)) + ',' + - makeSetTempDouble(1, 'i32', makeGetValue(ptr, getFastValue(pos, '+', Runtime.getNativeTypeSize('i32')), 'i32', noNeedFirst, unsigned, ignore, align)) + ',' + + return '(' + makeSetTempDouble(0, 'i32', makeGetValue(ptr, pos, 'i32', noNeedFirst, unsigned, ignore, align, noSafe)) + ',' + + makeSetTempDouble(1, 'i32', makeGetValue(ptr, getFastValue(pos, '+', Runtime.getNativeTypeSize('i32')), 'i32', noNeedFirst, unsigned, ignore, align, noSafe)) + ',' + makeGetTempDouble(0, 'double') + ')'; } @@ -1219,12 +1229,12 @@ function makeGetValue(ptr, pos, type, noNeedFirst, unsigned, ignore, align, noSa if (isIntImplemented(type)) { if (bytes == 4 && align == 2) { // Special case that we can optimize - ret += makeGetValue(ptr, pos, 'i16', noNeedFirst, 2, ignore) + '|' + - '(' + makeGetValue(ptr, getFastValue(pos, '+', 2), 'i16', noNeedFirst, 2, ignore) + '<<16)'; + ret += makeGetValue(ptr, pos, 'i16', noNeedFirst, 2, ignore, 2, noSafe) + '|' + + '(' + makeGetValue(ptr, getFastValue(pos, '+', 2), 'i16', noNeedFirst, 2, ignore, 2, noSafe) + '<<16)'; } else { // XXX we cannot truly handle > 4... (in x86) ret = ''; for (var i = 0; i < bytes; i++) { - ret += '(' + makeGetValue(ptr, getFastValue(pos, '+', i), 'i8', noNeedFirst, 1, ignore) + (i > 0 ? '<<' + (8*i) : '') + ')'; + ret += '(' + makeGetValue(ptr, getFastValue(pos, '+', i), 'i8', noNeedFirst, 1, ignore, 1, noSafe) + (i > 0 ? '<<' + (8*i) : '') + ')'; if (i < bytes-1) ret += '|'; } ret = '(' + makeSignOp(ret, type, unsigned ? 'un' : 're', true); @@ -1303,7 +1313,7 @@ function makeSetValue(ptr, pos, value, type, noNeedFirst, ignore, align, noSafe, value = range(typeData.fields.length).map(function(i) { return value + '.f' + i }); } for (var i = 0; i < typeData.fields.length; i++) { - ret.push(makeSetValue(ptr, getFastValue(pos, '+', typeData.flatIndexes[i]), value[i], typeData.fields[i], noNeedFirst)); + ret.push(makeSetValue(ptr, getFastValue(pos, '+', typeData.flatIndexes[i]), value[i], typeData.fields[i], noNeedFirst, 0, 0, noSafe)); } return ret.join('; '); } @@ -1330,17 +1340,17 @@ function makeSetValue(ptr, pos, value, type, noNeedFirst, ignore, align, noSafe, if (bytes == 4 && align == 2) { // Special case that we can optimize ret += 'tempBigInt=' + value + sep; - ret += makeSetValue(ptr, pos, 'tempBigInt&0xffff', 'i16', noNeedFirst, ignore, 2) + sep; - ret += makeSetValue(ptr, getFastValue(pos, '+', 2), 'tempBigInt>>16', 'i16', noNeedFirst, ignore, 2); + ret += makeSetValue(ptr, pos, 'tempBigInt&0xffff', 'i16', noNeedFirst, ignore, 2, noSafe) + sep; + ret += makeSetValue(ptr, getFastValue(pos, '+', 2), 'tempBigInt>>16', 'i16', noNeedFirst, ignore, 2, noSafe); } else { ret += 'tempBigInt=' + value + sep; for (var i = 0; i < bytes; i++) { - ret += makeSetValue(ptr, getFastValue(pos, '+', i), 'tempBigInt&0xff', 'i8', noNeedFirst, ignore, 1); + ret += makeSetValue(ptr, getFastValue(pos, '+', i), 'tempBigInt&0xff', 'i8', noNeedFirst, ignore, 1, noSafe); if (i < bytes-1) ret += sep + 'tempBigInt = tempBigInt>>8' + sep; } } } else { - ret += makeSetValue('tempDoublePtr', 0, value, type, noNeedFirst, ignore, 8, null, null, true) + sep; + ret += makeSetValue('tempDoublePtr', 0, value, type, noNeedFirst, ignore, 8, noSafe, null, true) + sep; ret += makeCopyValues(getFastValue(ptr, '+', pos), 'tempDoublePtr', Runtime.getNativeTypeSize(type), type, null, align, sep); } return ret; @@ -1349,6 +1359,7 @@ function makeSetValue(ptr, pos, value, type, noNeedFirst, ignore, align, noSafe, value = indexizeFunctions(value, type); var offset = calcFastOffset(ptr, pos, noNeedFirst); + if (phase === 'pre' && isNumber(offset)) offset += ' '; // avoid pure numeric strings, seem to be perf issues with overly-aggressive interning or slt in pre processing of heap inits if (SAFE_HEAP && !noSafe) { var printType = type; if (printType !== 'null' && printType[0] !== '#') printType = '"' + safeQuote(printType) + '"'; @@ -1465,77 +1476,97 @@ function makeHEAPView(which, start, end) { return 'HEAP' + which + '.subarray((' + start + ')' + mod + ',(' + end + ')' + mod + ')'; } -var PLUS_MUL = set('+', '*'); -var MUL_DIV = set('*', '/'); -var PLUS_MINUS = set('+', '-'); var TWO_TWENTY = Math.pow(2, 20); // Given two values and an operation, returns the result of that operation. // Tries to do as much as possible at compile time. // Leaves overflows etc. unhandled, *except* for integer multiply, in order to be efficient with Math.imul function getFastValue(a, op, b, type) { - a = a.toString(); - b = b.toString(); - a = a == 'true' ? '1' : (a == 'false' ? '0' : a); - b = b == 'true' ? '1' : (b == 'false' ? '0' : b); - if (isNumber(a) && isNumber(b)) { - if (op == 'pow') { - return Math.pow(a, b).toString(); - } else { - var value = eval(a + op + '(' + b + ')'); // parens protect us from "5 - -12" being seen as "5--12" which is "(5--)12" - if (op == '/' && type in Runtime.INT_TYPES) value = value|0; // avoid emitting floats - return value.toString(); + a = a === 'true' ? '1' : (a === 'false' ? '0' : a); + b = b === 'true' ? '1' : (b === 'false' ? '0' : b); + + var aNumber = null, bNumber = null; + if (typeof a === 'number') { + aNumber = a; + a = a.toString(); + } else if (isNumber(a)) aNumber = parseFloat(a); + if (typeof b === 'number') { + bNumber = b; + b = b.toString(); + } else if (isNumber(b)) bNumber = parseFloat(b); + + if (aNumber !== null && bNumber !== null) { + switch (op) { + case '+': return (aNumber + bNumber).toString(); + case '-': return (aNumber - bNumber).toString(); + case '*': return (aNumber * bNumber).toString(); + case '/': { + if (type[0] === 'i') { + return ((aNumber / bNumber)|0).toString(); + } else { + return (aNumber / bNumber).toString(); + } + } + case '%': return (aNumber % bNumber).toString(); + case '|': return (aNumber | bNumber).toString(); + case '>>>': return (aNumber >>> bNumber).toString(); + case '&': return (aNumber & bNumber).toString(); + case 'pow': return Math.pow(aNumber, bNumber).toString(); + default: throw 'need to implement getFastValue pn ' + op; } } - if (op == 'pow') { - if (a == '2' && isIntImplemented(type)) { + if (op === 'pow') { + if (a === '2' && isIntImplemented(type)) { return '(1 << (' + b + '))'; } return 'Math.pow(' + a + ', ' + b + ')'; } - if (op in PLUS_MUL && isNumber(a)) { // if one of them is a number, keep it last + if ((op === '+' || op === '*') && aNumber !== null) { // if one of them is a number, keep it last var c = b; b = a; a = c; - } - if (op in MUL_DIV) { - if (op == '*') { - if (a == 0 || b == 0) { - return '0'; - } else if (a == 1) { - return b; - } else if (b == 1) { - return a; - } else if (isNumber(b) && type && isIntImplemented(type) && Runtime.getNativeTypeSize(type) <= 32) { - var shifts = Math.log(parseFloat(b))/Math.LN2; - if (shifts % 1 == 0) { - return '(' + a + '<<' + shifts + ')'; - } + var cNumber = bNumber; + bNumber = aNumber; + aNumber = cNumber; + } + if (op === '*') { + // We can't eliminate where a or b are 0 as that would break things for creating + // a negative 0. + if ((aNumber === 0 || bNumber === 0) && !(type in Runtime.FLOAT_TYPES)) { + return '0'; + } else if (aNumber === 1) { + return b; + } else if (bNumber === 1) { + return a; + } else if (bNumber !== null && type && isIntImplemented(type) && Runtime.getNativeTypeSize(type) <= 32) { + var shifts = Math.log(bNumber)/Math.LN2; + if (shifts % 1 === 0) { + return '(' + a + '<<' + shifts + ')'; } - if (!(type in Runtime.FLOAT_TYPES)) { - // if guaranteed small enough to not overflow into a double, do a normal multiply - var bits = getBits(type) || 32; // default is 32-bit multiply for things like getelementptr indexes - // Note that we can emit simple multiple in non-asm.js mode, but asm.js will not parse "16-bit" multiple, so must do imul there - if ((isNumber(a) && Math.abs(a) < TWO_TWENTY) || (isNumber(b) && Math.abs(b) < TWO_TWENTY) || (bits < 32 && !ASM_JS)) { - return '(((' + a + ')*(' + b + '))&' + ((Math.pow(2, bits)-1)|0) + ')'; // keep a non-eliminatable coercion directly on this - } - return '(Math.imul(' + a + ',' + b + ')|0)'; + } + if (!(type in Runtime.FLOAT_TYPES)) { + // if guaranteed small enough to not overflow into a double, do a normal multiply + var bits = getBits(type) || 32; // default is 32-bit multiply for things like getelementptr indexes + // Note that we can emit simple multiple in non-asm.js mode, but asm.js will not parse "16-bit" multiple, so must do imul there + if ((aNumber !== null && Math.abs(a) < TWO_TWENTY) || (bNumber !== null && Math.abs(b) < TWO_TWENTY) || (bits < 32 && !ASM_JS)) { + return '(((' + a + ')*(' + b + '))&' + ((Math.pow(2, bits)-1)|0) + ')'; // keep a non-eliminatable coercion directly on this } - } else { - if (a == '0') { - return '0'; - } else if (b == 1) { - return a; - } // Doing shifts for division is problematic, as getting the rounding right on negatives is tricky - } - } else if (op in PLUS_MINUS) { - if (b[0] == '-') { - op = op == '+' ? '-' : '+'; + return '(Math.imul(' + a + ',' + b + ')|0)'; + } + } else if (op === '/') { + if (a === '0' && !(type in Runtime.FLOAT_TYPES)) { // careful on floats, since 0*NaN is not 0 + return '0'; + } else if (b === 1) { + return a; + } // Doing shifts for division is problematic, as getting the rounding right on negatives is tricky + } else if (op === '+' || op === '-') { + if (b[0] === '-') { + op = op === '+' ? '-' : '+'; b = b.substr(1); } - if (a == 0) { - return op == '+' ? b : '(-' + b + ')'; - } else if (b == 0) { + if (aNumber === 0) { + return op === '+' ? b : '(-' + b + ')'; + } else if (bNumber === 0) { return a; } } @@ -1564,12 +1595,8 @@ function getFastValues(list, op, type) { } function calcFastOffset(ptr, pos, noNeedFirst) { - var offset = noNeedFirst ? '0' : makeGetPos(ptr); - return getFastValue(offset, '+', pos, 'i32'); -} - -function makeGetPos(ptr) { - return ptr; + assert(!noNeedFirst); + return getFastValue(ptr, '+', pos, 'i32'); } var IHEAP_FHEAP = set('IHEAP', 'IHEAPU', 'FHEAP'); @@ -1759,7 +1786,7 @@ function checkBitcast(item) { } else { warnOnce('Casting a function pointer type to a potentially incompatible one (use -s VERBOSE=1 to see more)'); } - warnOnce('See https://github.com/kripken/emscripten/wiki/CodeGuidlinesAndLimitations#function-pointer-issues for more information on dangerous function pointer casts'); + warnOnce('See https://github.com/kripken/emscripten/wiki/CodeGuidelinesAndLimitations#function-pointer-issues for more information on dangerous function pointer casts'); if (ASM_JS) warnOnce('Incompatible function pointer casts are very dangerous with ASM_JS=1, you should investigate and correct these'); } if (oldCount != newCount && oldCount && newCount) showWarning(); @@ -1806,7 +1833,7 @@ function getGetElementPtrIndexes(item) { // struct, and possibly further substructures, all embedded // can also be to 'blocks': [8 x i32]*, not just structs type = removePointing(type); - var indexes = [makeGetPos(ident)]; + var indexes = [ident]; var offset = item.params[1]; if (offset != 0) { if (isStructType(type)) { @@ -1961,13 +1988,12 @@ function makeSignOp(value, type, op, force, ignore) { if (USE_TYPED_ARRAYS == 2 && type == 'i64') { return value; // these are always assumed to be two 32-bit unsigneds. } - if (isPointerType(type)) type = 'i32'; // Pointers are treated as 32-bit ints if (!value) return value; var bits, full; if (type in Runtime.INT_TYPES) { bits = parseInt(type.substr(1)); - full = op + 'Sign(' + value + ', ' + bits + ', ' + Math.floor(ignore || (correctSpecificSign())) + ')'; + full = op + 'Sign(' + value + ', ' + bits + ', ' + Math.floor(ignore || correctSpecificSign()) + ')'; // Always sign/unsign constants at compile time, regardless of CHECK/CORRECT if (isNumber(value)) { return eval(full).toString(); @@ -1975,23 +2001,25 @@ function makeSignOp(value, type, op, force, ignore) { } if ((ignore || !correctSigns()) && !CHECK_SIGNS && !force) return value; if (type in Runtime.INT_TYPES) { + // this is an integer, but not a number (or we would have already handled it) // shortcuts if (!CHECK_SIGNS || ignore) { + if (value === 'true') { + value = '1'; + } else if (value === 'false') { + value = '0'; + } else if (needsQuoting(value)) value = '(' + value + ')'; if (bits === 32) { if (op === 're') { - return '(' + getFastValue(value, '|', '0') + ')'; + return '(' + value + '|0)'; } else { - - return '(' + getFastValue(value, '>>>', '0') + ')'; - // Alternatively, we can consider the lengthier - // return makeInlineCalculation('VALUE >= 0 ? VALUE : ' + Math.pow(2, bits) + ' + VALUE', value, 'tempBigInt'); - // which does not always turn us into a 32-bit *un*signed value + return '(' + value + '>>>0)'; } } else if (bits < 32) { if (op === 're') { - return makeInlineCalculation('(VALUE << ' + (32-bits) + ') >> ' + (32-bits), value, 'tempInt'); + return '((' + value + '<<' + (32-bits) + ')>>' + (32-bits) + ')'; } else { - return '(' + getFastValue(value, '&', Math.pow(2, bits)-1) + ')'; + return '(' + value + '&' + (Math.pow(2, bits)-1) + ')'; } } else { // bits > 32 if (op === 're') { @@ -2081,7 +2109,7 @@ function processMathop(item) { if (item.params[i]) { paramTypes[i] = item.params[i].type || type; idents[i] = finalizeLLVMParameter(item.params[i]); - if (!isNumber(idents[i]) && !isNiceIdent(idents[i])) { + if (needsQuoting(idents[i])) { idents[i] = '(' + idents[i] + ')'; // we may have nested expressions. So enforce the order of operations we want } } else { @@ -2520,3 +2548,8 @@ function makePrintChars(s, sep) { return ret; } +function parseAlign(text) { // parse ", align \d+" + if (!text) return QUANTUM_SIZE; + return parseInt(text.substr(8)); +} + |