diff options
Diffstat (limited to 'src/parseTools.js')
-rw-r--r-- | src/parseTools.js | 124 |
1 files changed, 87 insertions, 37 deletions
diff --git a/src/parseTools.js b/src/parseTools.js index 7ebc0de2..addf0f21 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -763,10 +763,10 @@ function splitI64(value, floatConversion) { if (floatConversion && ASM_JS) lowInput = asmFloatToInt(lowInput); var low = lowInput + '>>>0'; var high = makeInlineCalculation( - asmCoercion('Math.abs(VALUE)', 'double') + ' >= ' + asmEnsureFloat('1', 'double') + ' ? ' + + asmCoercion('Math_abs(VALUE)', 'double') + ' >= ' + asmEnsureFloat('1', 'double') + ' ? ' + '(VALUE > ' + asmEnsureFloat('0', 'double') + ' ? ' + - asmCoercion('Math.min(' + asmCoercion('Math.floor((VALUE)/' + asmEnsureFloat(4294967296, 'float') + ')', 'double') + ', ' + asmEnsureFloat(4294967295, 'float') + ')', 'i32') + '>>>0' + - ' : ' + asmFloatToInt(asmCoercion('Math.ceil((VALUE - +((' + asmFloatToInt('VALUE') + ')>>>0))/' + asmEnsureFloat(4294967296, 'float') + ')', 'double')) + '>>>0' + + asmCoercion('Math_min(' + asmCoercion('Math_floor((VALUE)/' + asmEnsureFloat(4294967296, 'float') + ')', 'double') + ', ' + asmEnsureFloat(4294967295, 'float') + ')', 'i32') + '>>>0' + + ' : ' + asmFloatToInt(asmCoercion('Math_ceil((VALUE - +((' + asmFloatToInt('VALUE') + ')>>>0))/' + asmEnsureFloat(4294967296, 'float') + ')', 'double')) + '>>>0' + ')' + ' : 0', value, @@ -930,7 +930,10 @@ function parseNumerical(value, type) { } if (isNumber(value)) { var ret = parseFloat(value); // will change e.g. 5.000000e+01 to 50 - if (type in Runtime.FLOAT_TYPES && value[0] == '-' && ret === 0) return '-0'; // fix negative 0, toString makes it 0 + if (type in Runtime.FLOAT_TYPES) { + if (value[0] === '-' && ret === 0) return '-.0'; // fix negative 0, toString makes it 0 + if (!RUNNING_JS_OPTS) ret = asmEnsureFloat(ret, type); + } return ret.toString(); } else { return value; @@ -1136,7 +1139,16 @@ function asmEnsureFloat(value, type) { // ensures that a float type has either 5 if (!ASM_JS) return value; // coerce if missing a '.', or if smaller than 1, so could be 1e-5 which has no . if (type in Runtime.FLOAT_TYPES && isNumber(value) && (value.toString().indexOf('.') < 0 || Math.abs(value) < 1)) { - return '(+(' + value + '))'; + if (RUNNING_JS_OPTS) { + return '(+' + value + ')'; // JS optimizer will run, we must do +x, and it will be corrected later + } else { + // ensure a . + value = value.toString(); + if (value.indexOf('.') >= 0 || /[IN]/.test(value)) return value; // if already dotted, or Infinity or NaN, nothing to do here + var e = value.indexOf('e'); + if (e < 0) return value + '.0'; + return value.substr(0, e) + '.0' + value.substr(e); + } } else { return value; } @@ -1144,7 +1156,11 @@ function asmEnsureFloat(value, type) { // ensures that a float type has either 5 function asmInitializer(type, impl) { if (type in Runtime.FLOAT_TYPES) { - return '+0'; + if (RUNNING_JS_OPTS) { + return '+0'; + } else { + return '.0'; + } } else { return '0'; } @@ -1519,7 +1535,7 @@ function getFastValue(a, op, b, type) { if (a === '2' && isIntImplemented(type)) { return '(1 << (' + b + '))'; } - return 'Math.pow(' + a + ', ' + b + ')'; + return 'Math_pow(' + a + ', ' + b + ')'; } if ((op === '+' || op === '*') && aNumber !== null) { // if one of them is a number, keep it last var c = b; @@ -1551,7 +1567,7 @@ function getFastValue(a, op, b, type) { 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 } - return '(Math.imul(' + a + ',' + b + ')|0)'; + 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 @@ -1888,8 +1904,10 @@ function handleOverflow(text, bits) { if (CHECK_OVERFLOWS) return 'CHECK_OVERFLOW(' + text + ', ' + bits + ', ' + Math.floor(correctSpecificOverflow()) + ')'; if (!correct) return text; if (bits == 32) { + if (isNumber(text)) return text | 0; return '((' + text + ')|0)'; } else if (bits < 32) { + if (isNumber(text)) return text & (Math.pow(2, bits) - 1); return '((' + text + ')&' + (Math.pow(2, bits) - 1) + ')'; } else { return text; // We warned about this earlier @@ -1979,7 +1997,7 @@ function makeComparison(a, op, b, type) { return asmCoercion(a, type) + op + asmCoercion(b, type); } else { assert(type == 'i64'); - return asmCoercion(a + '$0', 'i32') + op + asmCoercion(b + '$0', 'i32') + ' & ' + + return asmCoercion(a + '$0', 'i32') + op + asmCoercion(b + '$0', 'i32') + '&' + asmCoercion(a + '$1', 'i32') + op + asmCoercion(b + '$1', 'i32'); } } @@ -2047,12 +2065,12 @@ function makeRounding(value, bits, signed, floatConversion) { // as |0, but &-1 hints to the js optimizer that this is a rounding correction // Do Math.floor, which is reasonably fast, if we either don't care, or if we can be sure // the value is non-negative - if (!correctRoundings() || (!signed && !floatConversion)) return 'Math.floor(' + value + ')'; + if (!correctRoundings() || (!signed && !floatConversion)) return 'Math_floor(' + value + ')'; // We are left with >32 bits signed, or a float conversion. Check and correct inline // Note that if converting a float, we may have the wrong sign at this point! But, we have // been rounded properly regardless, and we will be sign-corrected later when actually used, if // necessary. - return makeInlineCalculation(makeComparison('VALUE', '>=', '0', 'float') + ' ? Math.floor(VALUE) : Math.ceil(VALUE)', value, 'tempBigIntR'); + return makeInlineCalculation(makeComparison('VALUE', '>=', '0', 'float') + ' ? Math_floor(VALUE) : Math_ceil(VALUE)', value, 'tempBigIntR'); } else { // asm.js mode, cleaner refactoring of this function as well. TODO: use in non-asm case, most of this if (floatConversion && bits <= 32) { @@ -2067,9 +2085,9 @@ function makeRounding(value, bits, signed, floatConversion) { } } // Math.floor is reasonably fast if we don't care about corrections (and even correct if unsigned) - if (!correctRoundings() || !signed) return 'Math.floor(' + value + ')'; + if (!correctRoundings() || !signed) return 'Math_floor(' + value + ')'; // We are left with >32 bits - return makeInlineCalculation(makeComparison('VALUE', '>=', '0', 'float') + ' ? Math.floor(VALUE) : Math.ceil(VALUE)', value, 'tempBigIntR'); + return makeInlineCalculation(makeComparison('VALUE', '>=', '0', 'float') + ' ? Math_floor(VALUE) : Math_ceil(VALUE)', value, 'tempBigIntR'); } } @@ -2080,7 +2098,7 @@ function makeIsNaN(value) { function makeFloat(value, type) { if (TO_FLOAT32 && type == 'float') { - return 'Math.toFloat32(' + value + ')'; + return 'Math_toFloat32(' + value + ')'; } return value; } @@ -2156,7 +2174,13 @@ function processMathop(item) { // If this is in legalization mode, steal the assign and assign into two vars if (legalizedI64s) { assert(item.assignTo); - var ret = 'var ' + item.assignTo + '$0 = ' + result[0] + '; var ' + item.assignTo + '$1 = ' + result[1] + ';'; + if (ASM_JS) { + var ret = item.assignTo + '$0=' + result[0] + ';' + item.assignTo + '$1=' + result[1] + ';'; + addVariable(item.assignTo + '$0', 'i32'); + addVariable(item.assignTo + '$1', 'i32'); + } else { + var ret = 'var ' + item.assignTo + '$0=' + result[0] + ';var ' + item.assignTo + '$1=' + result[1] + ';'; + } item.assignTo = null; return ret; } else { @@ -2307,7 +2331,7 @@ function processMathop(item) { dprint('Warning: 64 bit OR - precision limit may be hit on llvm line ' + item.lineNum); return 'Runtime.or64(' + idents[0] + ', ' + idents[1] + ')'; } - return idents[0] + ' | ' + idents[1]; + return idents[0] + '|' + idents[1]; } case 'and': { if (bits > 32) { @@ -2315,7 +2339,7 @@ function processMathop(item) { dprint('Warning: 64 bit AND - precision limit may be hit on llvm line ' + item.lineNum); return 'Runtime.and64(' + idents[0] + ', ' + idents[1] + ')'; } - return idents[0] + ' & ' + idents[1]; + return idents[0] + '&' + idents[1]; } case 'xor': { if (bits > 32) { @@ -2323,21 +2347,21 @@ function processMathop(item) { dprint('Warning: 64 bit XOR - precision limit may be hit on llvm line ' + item.lineNum); return 'Runtime.xor64(' + idents[0] + ', ' + idents[1] + ')'; } - return idents[0] + ' ^ ' + idents[1]; + return idents[0] + '^' + idents[1]; } case 'shl': { if (bits > 32) return idents[0] + '*' + getFastValue(2, 'pow', idents[1]); - return idents[0] + ' << ' + idents[1]; + return idents[0] + '<<' + idents[1]; } case 'ashr': { if (bits > 32) return integerizeBignum(idents[0] + '/' + getFastValue(2, 'pow', idents[1])); - if (bits === 32) return originalIdents[0] + ' >> ' + idents[1]; // No need to reSign in this case - return idents[0] + ' >> ' + idents[1]; + if (bits === 32) return originalIdents[0] + '>>' + idents[1]; // No need to reSign in this case + return idents[0] + '>>' + idents[1]; } case 'lshr': { if (bits > 32) return integerizeBignum(idents[0] + '/' + getFastValue(2, 'pow', idents[1])); - if (bits === 32) return originalIdents[0] + ' >>> ' + idents[1]; // No need to unSign in this case - return idents[0] + ' >>> ' + idents[1]; + if (bits === 32) return originalIdents[0] + '>>>' + idents[1]; // No need to unSign in this case + return idents[0] + '>>>' + idents[1]; } // basic float ops case 'fadd': return makeFloat(getFastValue(idents[0], '+', idents[1], item.type), item.type); @@ -2352,10 +2376,10 @@ function processMathop(item) { // Note that with typed arrays, these become 0 when written. So that is a potential difference with non-typed array runs. case 'icmp': { switch (variant) { - case 'uge': case 'sge': return idents[0] + ' >= ' + idents[1]; - case 'ule': case 'sle': return idents[0] + ' <= ' + idents[1]; - case 'ugt': case 'sgt': return idents[0] + ' > ' + idents[1]; - case 'ult': case 'slt': return idents[0] + ' < ' + idents[1]; + case 'uge': case 'sge': return idents[0] + '>=' + idents[1]; + case 'ule': case 'sle': return idents[0] + '<=' + idents[1]; + case 'ugt': case 'sgt': return idents[0] + '>' + idents[1]; + case 'ult': case 'slt': return idents[0] + '<' + idents[1]; // We use loose comparisons, which allows false == 0 to be true, etc. Ditto in fcmp case 'ne': case 'eq': { // We must sign them, so we do not compare -1 to 255 (could have unsigned them both too) @@ -2371,14 +2395,14 @@ function processMathop(item) { switch (variant) { // TODO 'o' ones should be 'ordered (no NaN) and', // 'u' ones should be 'unordered or'. - case 'uge': case 'oge': return idents[0] + ' >= ' + idents[1]; - case 'ule': case 'ole': return idents[0] + ' <= ' + idents[1]; - case 'ugt': case 'ogt': return idents[0] + ' > ' + idents[1]; - case 'ult': case 'olt': return idents[0] + ' < ' + idents[1]; - case 'une': case 'one': return idents[0] + ' != ' + idents[1]; - case 'ueq': case 'oeq': return idents[0] + ' == ' + idents[1]; - case 'ord': return '!' + makeIsNaN(idents[0]) + ' & !' + makeIsNaN(idents[1]); - case 'uno': return makeIsNaN(idents[0]) + ' | ' + makeIsNaN(idents[1]); + case 'uge': case 'oge': return idents[0] + '>=' + idents[1]; + case 'ule': case 'ole': return idents[0] + '<=' + idents[1]; + case 'ugt': case 'ogt': return idents[0] + '>' + idents[1]; + case 'ult': case 'olt': return idents[0] + '<' + idents[1]; + case 'une': case 'one': return idents[0] + '!=' + idents[1]; + case 'ueq': case 'oeq': return idents[0] + '==' + idents[1]; + case 'ord': return '!' + makeIsNaN(idents[0]) + '&!' + makeIsNaN(idents[1]); + case 'uno': return makeIsNaN(idents[0]) + '|' + makeIsNaN(idents[1]); case 'true': return '1'; default: throw 'Unknown fcmp variant: ' + variant; } @@ -2394,7 +2418,7 @@ function processMathop(item) { } case 'fpext': case 'sext': return idents[0]; case 'fptrunc': return idents[0]; - case 'select': return idents[0] + ' ? ' + asmEnsureFloat(idents[1], item.type) + ' : ' + asmEnsureFloat(idents[2], item.type); + case 'select': return idents[0] + '?' + asmEnsureFloat(idents[1], item.type) + ':' + asmEnsureFloat(idents[2], item.type); case 'ptrtoint': case 'inttoptr': { var ret = ''; if (QUANTUM_SIZE == 1) { @@ -2412,7 +2436,7 @@ function processMathop(item) { // truncating can change the number, e.g. by truncating to an i1 // in order to get the first bit assert(bitsLeft <= 32, 'Cannot truncate to more than 32 bits, since we use a native & op'); - return '((' + idents[0] + ') & ' + (Math.pow(2, bitsLeft)-1) + ')'; + return '((' + idents[0] + ')&' + (Math.pow(2, bitsLeft)-1) + ')'; } case 'bitcast': { // Most bitcasts are no-ops for us. However, the exception is int to float and float to int @@ -2553,3 +2577,29 @@ function parseAlign(text) { // parse ", align \d+" return parseInt(text.substr(8)); } +function deParen(text) { + if (text[0] === '(') return text.substr(1, text.length-2); + return text; +} + +function addVariable(ident, type, funcData) { + funcData = funcData || Framework.currItem.funcData; + assert(type); + var old = funcData.variables[ident]; + if (old) { + assert(old.type === type); + } else { + funcData.variables[ident] = { + ident: ident, + type: type, + origin: 'added', + lineNum: 0, + rawLinesIndex: 0, + hasValueTaken: false, + pointingLevels: 0, + uses: 0, + impl: VAR_EMULATED + }; + } +} + |