aboutsummaryrefslogtreecommitdiff
path: root/src/parseTools.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/parseTools.js')
-rw-r--r--src/parseTools.js146
1 files changed, 97 insertions, 49 deletions
diff --git a/src/parseTools.js b/src/parseTools.js
index 470c246f..e3b1df6d 100644
--- a/src/parseTools.js
+++ b/src/parseTools.js
@@ -5,11 +5,12 @@
// Does simple 'macro' substitution, using Django-like syntax,
// {{{ code }}} will be replaced with |eval(code)|.
+// NOTE: Be careful with that ret check. If ret is |0|, |ret ? ret.toString() : ''| would result in ''!
function processMacros(text) {
return text.replace(/{{{([^}]|}(?!}))+}}}/g, function(str) {
str = str.substr(3, str.length-6);
var ret = eval(str);
- return ret ? ret.toString() : '';
+ return ret !== null ? ret.toString() : '';
});
}
@@ -279,7 +280,7 @@ function isFunctionType(type, out) {
i--;
}
assert(argText);
- return isFunctionDef({ text: argText, item: tokenize(argText.substr(1, argText.length-2), true) }, out);
+ return isFunctionDef({ text: argText, item: tokenize(argText.substr(1, argText.length-2)) }, out);
}
function getReturnType(type) {
@@ -762,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,
@@ -913,13 +914,13 @@ function parseI64Constant(str, legalized) {
}
function parseNumerical(value, type) {
- if ((!type || type == 'double' || type == 'float') && (value.substr && value.substr(0,2) == '0x')) {
+ if ((!type || type === 'double' || type === 'float') && /^0x/.test(value)) {
// Hexadecimal double value, as the llvm docs say,
// "The one non-intuitive notation for constants is the hexadecimal form of floating point constants."
value = IEEEUnHex(value);
} else if (USE_TYPED_ARRAYS == 2 && isIllegalType(type)) {
return value; // do not parseFloat etc., that can lead to loss of precision
- } else if (value == 'null') {
+ } else if (value === 'null') {
// NULL *is* 0, in C/C++. No JS null! (null == 0 is false, etc.)
value = '0';
} else if (value === 'true') {
@@ -929,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 === 'double' || type === 'float') {
+ 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;
@@ -1135,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;
}
@@ -1143,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';
}
@@ -1518,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;
@@ -1550,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
@@ -1887,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
@@ -1978,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');
}
}
@@ -2046,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) {
@@ -2066,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');
}
}
@@ -2079,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;
}
@@ -2155,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 {
@@ -2306,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) {
@@ -2314,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) {
@@ -2322,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);
@@ -2351,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)
@@ -2370,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;
}
@@ -2393,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) {
@@ -2411,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
@@ -2449,13 +2474,6 @@ function walkInterdata(item, pre, post, obj) {
if (walkInterdata(item.params[i], pre, post, obj)) return true;
}
}
- if (item.possibleVars) { // other attributes that might contain interesting data; here, variables
- var box = { intertype: 'value', ident: '' };
- for (i = 0; i <= item.possibleVars.length; i++) {
- box.ident = item[item.possibleVars[i]];
- if (walkInterdata(box, pre, post, obj)) return true;
- }
- }
return post && post(item, originalObj, obj);
}
@@ -2475,7 +2493,6 @@ function walkAndModifyInterdata(item, pre) {
if (repl = walkAndModifyInterdata(item.params[i], pre)) item.params[i] = repl;
}
}
- // Ignore possibleVars because we can't replace them anyhow
}
function parseBlockAddress(segment) {
@@ -2552,3 +2569,34 @@ 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 deParenCarefully(text) {
+ if (text[0] === '(' && text.indexOf('(', 1) < 0 && text[text.length-1] === ')') 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
+ };
+ }
+}
+