aboutsummaryrefslogtreecommitdiff
path: root/src/parseTools.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/parseTools.js')
-rw-r--r--src/parseTools.js211
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));
+}
+