6
6
// Does simple 'macro' substitution, using Django-like syntax,
7
7
// {{{ code }}} will be replaced with |eval(code)|.
8
// NOTE: Be careful with that ret check. If ret is |0|, |ret ? ret.toString() : ''| would result in ''!
8
9
function processMacros(text) {
9
10
return text.replace(/{{{([^}]|}(?!}))+}}}/g, function(str) {
10
11
str = str.substr(3, str.length-6);
11
12
var ret = eval(str);
12
return ret ? ret.toString() : '';
13
return ret !== null ? ret.toString() : '';
16
17
// Simple #if/else/endif preprocessing for a file. Checks if the
17
18
// ident checked is true in our global.
19
// Also handles #include x.js (similar to C #include <file>)
18
20
function preprocess(text) {
19
21
var lines = text.split('\n');
29
31
ret += line + '\n';
32
if (line[1] && line[1] == 'i') { // if
33
var parts = line.split(' ');
39
showStack.push(ident in this && this[ident] == value);
40
} else if (op === '!=') {
41
showStack.push(!(ident in this && this[ident] == value));
35
if (line[2] == 'f') { // if
36
var parts = line.split(' ');
42
showStack.push(ident in this && this[ident] == value);
43
} else if (op === '!=') {
44
showStack.push(!(ident in this && this[ident] == value));
46
error('unsupported preprecessor op ' + op);
43
error('unsupported preprecessor op ' + op);
49
showStack.push(ident in this && this[ident] > 0);
46
showStack.push(ident in this && this[ident] > 0);
51
} else if (line[2] == 'n') { // include
52
var included = read(line.substr(line.indexOf(' ')+1));
53
ret += '\n' + preprocess(included) + '\n'
48
} else if (line[2] && line[2] == 'l') { // else
55
} else if (line[2] == 'l') { // else
49
56
showStack.push(!showStack.pop());
50
} else if (line[2] && line[2] == 'n') { // endif
57
} else if (line[2] == 'n') { // endif
53
60
throw "Unclear preprocessor command: " + line;
431
493
Types.needAnalysis[ret[ret.length-1].type] = 0;
432
494
anonymousIndex ++;
434
} else if (segment[1].text in PARSABLE_LLVM_FUNCTIONS) {
435
ret.push(parseLLVMFunctionCall(segment));
436
} else if (segment[1].text === 'blockaddress') {
437
ret.push(parseBlockAddress(segment));
438
} else if (segment[1].type && segment[1].type == '{') {
439
ret.push(parseLLVMSegment(segment));
441
497
if (segment[2] && segment[2].text == 'to') { // part of bitcast params
442
498
segment = segment.slice(0, 2);
444
while (segment.length > 2) {
445
segment[0].text += segment[1].text;
446
segment.splice(1, 1); // TODO: merge tokens nicely
450
type: segment[0].text,
451
ident: toNiceIdent(parseNumerical(segment[1].text, segment[0].text))
453
Types.needAnalysis[removeAllPointing(ret[ret.length-1].type)] = 0;
500
var parsed = parseLLVMSegment(segment);
501
if (parsed.intertype === 'value' && !isIllegalType(parsed.type)) parsed.ident = parseNumerical(parsed.ident, parsed.type);
455
504
ret[ret.length-1].byVal = byVal;
596
637
var MATHOPS = set(['add', 'sub', 'sdiv', 'udiv', 'mul', 'icmp', 'zext', 'urem', 'srem', 'fadd', 'fsub', 'fmul', 'fdiv', 'fcmp', 'frem', 'uitofp', 'sitofp', 'fpext', 'fptrunc', 'fptoui', 'fptosi', 'trunc', 'sext', 'select', 'shl', 'shr', 'ashl', 'ashr', 'lshr', 'lshl', 'xor', 'or', 'and', 'ptrtoint', 'inttoptr']);
639
var JS_MATH_BUILTINS = set(['Math_sin', 'Math_cos', 'Math_tan', 'Math_asin', 'Math_acos', 'Math_atan', 'Math_ceil', 'Math_floor', 'Math_exp', 'Math_log', 'Math_sqrt']);
598
641
var PARSABLE_LLVM_FUNCTIONS = set('getelementptr', 'bitcast');
599
642
mergeInto(PARSABLE_LLVM_FUNCTIONS, MATHOPS);
752
795
if (floatConversion && ASM_JS) lowInput = asmFloatToInt(lowInput);
753
796
var low = lowInput + '>>>0';
754
797
var high = makeInlineCalculation(
755
asmCoercion('Math.abs(VALUE)', 'double') + ' >= ' + asmEnsureFloat('1', 'double') + ' ? ' +
798
asmCoercion('Math_abs(VALUE)', 'double') + ' >= ' + asmEnsureFloat('1', 'double') + ' ? ' +
756
799
'(VALUE > ' + asmEnsureFloat('0', 'double') + ' ? ' +
757
asmCoercion('Math.min(' + asmCoercion('Math.floor((VALUE)/' + asmEnsureFloat(4294967296, 'float') + ')', 'double') + ', ' + asmEnsureFloat(4294967295, 'float') + ')', 'i32') + '>>>0' +
758
' : ' + asmFloatToInt(asmCoercion('Math.ceil((VALUE - +((' + asmFloatToInt('VALUE') + ')>>>0))/' + asmEnsureFloat(4294967296, 'float') + ')', 'double')) + '>>>0' +
800
asmCoercion('Math_min(' + asmCoercion('Math_floor((VALUE)/' + asmEnsureFloat(4294967296, 'double') + ')', 'double') + ', ' + asmEnsureFloat(4294967295, 'double') + ')', 'i32') + '>>>0' +
801
' : ' + asmFloatToInt(asmCoercion('Math_ceil((VALUE - +((' + asmFloatToInt('VALUE') + ')>>>0))/' + asmEnsureFloat(4294967296, 'double') + ')', 'double')) + '>>>0' +
905
948
function parseNumerical(value, type) {
906
if ((!type || type == 'double' || type == 'float') && (value.substr && value.substr(0,2) == '0x')) {
949
if ((!type || type === 'double' || type === 'float') && /^0x/.test(value)) {
907
950
// Hexadecimal double value, as the llvm docs say,
908
951
// "The one non-intuitive notation for constants is the hexadecimal form of floating point constants."
909
952
value = IEEEUnHex(value);
910
953
} else if (USE_TYPED_ARRAYS == 2 && isIllegalType(type)) {
911
954
return value; // do not parseFloat etc., that can lead to loss of precision
912
} else if (value == 'null') {
955
} else if (value === 'null') {
913
956
// NULL *is* 0, in C/C++. No JS null! (null == 0 is false, etc.)
915
958
} else if (value === 'true') {
1184
function ensureDot(value) {
1185
value = value.toString();
1186
// if already dotted, or Infinity or NaN, nothing to do here
1187
// if smaller than 1 and running js opts, we always need to force a coercion (0.001 will turn into 1e-3, which has no .)
1188
if ((value.indexOf('.') >= 0 || /[IN]/.test(value)) && (!RUNNING_JS_OPTS || Math.abs(value) >= 1)) return value;
1189
if (RUNNING_JS_OPTS) return '(+' + value + ')'; // JS optimizer will run, we must do +x, and it will be corrected later
1190
var e = value.indexOf('e');
1191
if (e < 0) return value + '.0';
1192
return value.substr(0, e) + '.0' + value.substr(e);
1124
1195
function asmEnsureFloat(value, type) { // ensures that a float type has either 5.5 (clearly a float) or +5 (float due to asm coercion)
1125
1196
if (!ASM_JS) return value;
1126
// coerce if missing a '.', or if smaller than 1, so could be 1e-5 which has no .
1127
if (type in Runtime.FLOAT_TYPES && isNumber(value) && (value.toString().indexOf('.') < 0 || Math.abs(value) < 1)) {
1128
return '(+(' + value + '))';
1197
if (!isNumber(value)) return value;
1198
if (PRECISE_F32 && type === 'float') {
1199
// normally ok to just emit Math_fround(0), but if the constant is large we may need a .0 (if it can't fit in an int)
1200
if (value == 0) return 'Math_fround(0)';
1201
value = ensureDot(value);
1202
return 'Math_fround(' + value + ')';
1204
if (type in Runtime.FLOAT_TYPES) {
1205
return ensureDot(value);
1134
function asmInitializer(type, impl) {
1211
function asmInitializer(type) {
1135
1212
if (type in Runtime.FLOAT_TYPES) {
1213
if (PRECISE_F32 && type === 'float') return 'Math_fround(0)';
1214
return RUNNING_JS_OPTS ? '+0' : '.0';
1204
1286
// In double mode 1, in x86 we always assume unaligned because we can't trust that; otherwise in le32
1205
1287
// we need this code path if we are not fully aligned.
1206
1288
if (DOUBLE_MODE == 1 && USE_TYPED_ARRAYS == 2 && type == 'double' && (TARGET_X86 || align < 8)) {
1207
return '(' + makeSetTempDouble(0, 'i32', makeGetValue(ptr, pos, 'i32', noNeedFirst, unsigned, ignore, align)) + ',' +
1208
makeSetTempDouble(1, 'i32', makeGetValue(ptr, getFastValue(pos, '+', Runtime.getNativeTypeSize('i32')), 'i32', noNeedFirst, unsigned, ignore, align)) + ',' +
1289
return '(' + makeSetTempDouble(0, 'i32', makeGetValue(ptr, pos, 'i32', noNeedFirst, unsigned, ignore, align, noSafe)) + ',' +
1290
makeSetTempDouble(1, 'i32', makeGetValue(ptr, getFastValue(pos, '+', Runtime.getNativeTypeSize('i32')), 'i32', noNeedFirst, unsigned, ignore, align, noSafe)) + ',' +
1209
1291
makeGetTempDouble(0, 'double') + ')';
1218
1300
if (isIntImplemented(type)) {
1219
1301
if (bytes == 4 && align == 2) {
1220
1302
// Special case that we can optimize
1221
ret += makeGetValue(ptr, pos, 'i16', noNeedFirst, 2, ignore) + '|' +
1222
'(' + makeGetValue(ptr, getFastValue(pos, '+', 2), 'i16', noNeedFirst, 2, ignore) + '<<16)';
1303
ret += makeGetValue(ptr, pos, 'i16', noNeedFirst, 2, ignore, 2, noSafe) + '|' +
1304
'(' + makeGetValue(ptr, getFastValue(pos, '+', 2), 'i16', noNeedFirst, 2, ignore, 2, noSafe) + '<<16)';
1223
1305
} else { // XXX we cannot truly handle > 4... (in x86)
1225
1307
for (var i = 0; i < bytes; i++) {
1226
ret += '(' + makeGetValue(ptr, getFastValue(pos, '+', i), 'i8', noNeedFirst, 1, ignore) + (i > 0 ? '<<' + (8*i) : '') + ')';
1308
ret += '(' + makeGetValue(ptr, getFastValue(pos, '+', i), 'i8', noNeedFirst, 1, ignore, 1, noSafe) + (i > 0 ? '<<' + (8*i) : '') + ')';
1227
1309
if (i < bytes-1) ret += '|';
1229
1311
ret = '(' + makeSignOp(ret, type, unsigned ? 'un' : 're', true);
1329
1411
if (bytes == 4 && align == 2) {
1330
1412
// Special case that we can optimize
1331
1413
ret += 'tempBigInt=' + value + sep;
1332
ret += makeSetValue(ptr, pos, 'tempBigInt&0xffff', 'i16', noNeedFirst, ignore, 2) + sep;
1333
ret += makeSetValue(ptr, getFastValue(pos, '+', 2), 'tempBigInt>>16', 'i16', noNeedFirst, ignore, 2);
1414
ret += makeSetValue(ptr, pos, 'tempBigInt&0xffff', 'i16', noNeedFirst, ignore, 2, noSafe) + sep;
1415
ret += makeSetValue(ptr, getFastValue(pos, '+', 2), 'tempBigInt>>16', 'i16', noNeedFirst, ignore, 2, noSafe);
1335
1417
ret += 'tempBigInt=' + value + sep;
1336
1418
for (var i = 0; i < bytes; i++) {
1337
ret += makeSetValue(ptr, getFastValue(pos, '+', i), 'tempBigInt&0xff', 'i8', noNeedFirst, ignore, 1);
1419
ret += makeSetValue(ptr, getFastValue(pos, '+', i), 'tempBigInt&0xff', 'i8', noNeedFirst, ignore, 1, noSafe);
1338
1420
if (i < bytes-1) ret += sep + 'tempBigInt = tempBigInt>>8' + sep;
1342
ret += makeSetValue('tempDoublePtr', 0, value, type, noNeedFirst, ignore, 8, null, null, true) + sep;
1424
ret += makeSetValue('tempDoublePtr', 0, value, type, noNeedFirst, ignore, 8, noSafe, null, true) + sep;
1343
1425
ret += makeCopyValues(getFastValue(ptr, '+', pos), 'tempDoublePtr', Runtime.getNativeTypeSize(type), type, null, align, sep);
1464
1547
return 'HEAP' + which + '.subarray((' + start + ')' + mod + ',(' + end + ')' + mod + ')';
1467
var PLUS_MUL = set('+', '*');
1468
var MUL_DIV = set('*', '/');
1469
var PLUS_MINUS = set('+', '-');
1470
1550
var TWO_TWENTY = Math.pow(2, 20);
1472
1552
// Given two values and an operation, returns the result of that operation.
1473
1553
// Tries to do as much as possible at compile time.
1474
1554
// Leaves overflows etc. unhandled, *except* for integer multiply, in order to be efficient with Math.imul
1475
1555
function getFastValue(a, op, b, type) {
1478
a = a == 'true' ? '1' : (a == 'false' ? '0' : a);
1479
b = b == 'true' ? '1' : (b == 'false' ? '0' : b);
1480
if (isNumber(a) && isNumber(b)) {
1482
return Math.pow(a, b).toString();
1484
var value = eval(a + op + '(' + b + ')'); // parens protect us from "5 - -12" being seen as "5--12" which is "(5--)12"
1485
if (op == '/' && type in Runtime.INT_TYPES) value = value|0; // avoid emitting floats
1486
return value.toString();
1556
a = a === 'true' ? '1' : (a === 'false' ? '0' : a);
1557
b = b === 'true' ? '1' : (b === 'false' ? '0' : b);
1559
var aNumber = null, bNumber = null;
1560
if (typeof a === 'number') {
1563
} else if (isNumber(a)) aNumber = parseFloat(a);
1564
if (typeof b === 'number') {
1567
} else if (isNumber(b)) bNumber = parseFloat(b);
1569
if (aNumber !== null && bNumber !== null) {
1571
case '+': return (aNumber + bNumber).toString();
1572
case '-': return (aNumber - bNumber).toString();
1573
case '*': return (aNumber * bNumber).toString();
1575
if (type[0] === 'i') {
1576
return ((aNumber / bNumber)|0).toString();
1578
return (aNumber / bNumber).toString();
1581
case '%': return (aNumber % bNumber).toString();
1582
case '|': return (aNumber | bNumber).toString();
1583
case '>>>': return (aNumber >>> bNumber).toString();
1584
case '&': return (aNumber & bNumber).toString();
1585
case 'pow': return Math.pow(aNumber, bNumber).toString();
1586
default: throw 'need to implement getFastValue pn ' + op;
1490
if (a == '2' && isIntImplemented(type)) {
1590
if (a === '2' && isIntImplemented(type)) {
1491
1591
return '(1 << (' + b + '))';
1493
return 'Math.pow(' + a + ', ' + b + ')';
1593
return 'Math_pow(' + a + ', ' + b + ')';
1495
if (op in PLUS_MUL && isNumber(a)) { // if one of them is a number, keep it last
1595
if ((op === '+' || op === '*') && aNumber !== null) { // if one of them is a number, keep it last
1599
var cNumber = bNumber;
1500
if (op in MUL_DIV) {
1502
if (a == 0 || b == 0) {
1504
} else if (a == 1) {
1506
} else if (b == 1) {
1508
} else if (isNumber(b) && type && isIntImplemented(type) && Runtime.getNativeTypeSize(type) <= 32) {
1509
var shifts = Math.log(parseFloat(b))/Math.LN2;
1510
if (shifts % 1 == 0) {
1511
return '(' + a + '<<' + shifts + ')';
1514
if (!(type in Runtime.FLOAT_TYPES)) {
1515
// if guaranteed small enough to not overflow into a double, do a normal multiply
1516
var bits = getBits(type) || 32; // default is 32-bit multiply for things like getelementptr indexes
1517
// 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
1518
if ((isNumber(a) && Math.abs(a) < TWO_TWENTY) || (isNumber(b) && Math.abs(b) < TWO_TWENTY) || (bits < 32 && !ASM_JS)) {
1519
return '(((' + a + ')*(' + b + '))&' + ((Math.pow(2, bits)-1)|0) + ')'; // keep a non-eliminatable coercion directly on this
1521
return '(Math.imul(' + a + ',' + b + ')|0)';
1526
} else if (b == 1) {
1528
} // Doing shifts for division is problematic, as getting the rounding right on negatives is tricky
1530
} else if (op in PLUS_MINUS) {
1532
op = op == '+' ? '-' : '+';
1604
// We can't eliminate where a or b are 0 as that would break things for creating
1606
if ((aNumber === 0 || bNumber === 0) && !(type in Runtime.FLOAT_TYPES)) {
1608
} else if (aNumber === 1) {
1610
} else if (bNumber === 1) {
1612
} else if (bNumber !== null && type && isIntImplemented(type) && Runtime.getNativeTypeSize(type) <= 32) {
1613
var shifts = Math.log(bNumber)/Math.LN2;
1614
if (shifts % 1 === 0) {
1615
return '(' + a + '<<' + shifts + ')';
1618
if (!(type in Runtime.FLOAT_TYPES)) {
1619
// if guaranteed small enough to not overflow into a double, do a normal multiply
1620
var bits = getBits(type) || 32; // default is 32-bit multiply for things like getelementptr indexes
1621
// 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
1622
if ((aNumber !== null && Math.abs(a) < TWO_TWENTY) || (bNumber !== null && Math.abs(b) < TWO_TWENTY) || (bits < 32 && !ASM_JS)) {
1623
return '(((' + a + ')*(' + b + '))&' + ((Math.pow(2, bits)-1)|0) + ')'; // keep a non-eliminatable coercion directly on this
1625
return '(Math_imul(' + a + ',' + b + ')|0)';
1627
} else if (op === '/') {
1628
if (a === '0' && !(type in Runtime.FLOAT_TYPES)) { // careful on floats, since 0*NaN is not 0
1630
} else if (b === 1) {
1632
} // Doing shifts for division is problematic, as getting the rounding right on negatives is tricky
1633
} else if (op === '+' || op === '-') {
1635
op = op === '+' ? '-' : '+';
1533
1636
b = b.substr(1);
1536
return op == '+' ? b : '(-' + b + ')';
1537
} else if (b == 0) {
1638
if (aNumber === 0) {
1639
return op === '+' ? b : '(-' + b + ')';
1640
} else if (bNumber === 0) {
1960
2071
if (USE_TYPED_ARRAYS == 2 && type == 'i64') {
1961
2072
return value; // these are always assumed to be two 32-bit unsigneds.
1964
2074
if (isPointerType(type)) type = 'i32'; // Pointers are treated as 32-bit ints
1965
2075
if (!value) return value;
1966
2076
var bits, full;
1967
if (type in Runtime.INT_TYPES) {
2077
if (type[0] === 'i') {
1968
2078
bits = parseInt(type.substr(1));
1969
full = op + 'Sign(' + value + ', ' + bits + ', ' + Math.floor(ignore || (correctSpecificSign())) + ')';
2079
full = op + 'Sign(' + value + ', ' + bits + ', ' + Math.floor(ignore || correctSpecificSign()) + ')';
1970
2080
// Always sign/unsign constants at compile time, regardless of CHECK/CORRECT
1971
2081
if (isNumber(value)) {
1972
2082
return eval(full).toString();
1975
2085
if ((ignore || !correctSigns()) && !CHECK_SIGNS && !force) return value;
1976
if (type in Runtime.INT_TYPES) {
2086
if (type[0] === 'i') {
2087
// this is an integer, but not a number (or we would have already handled it)
1978
2089
if (!CHECK_SIGNS || ignore) {
2090
if (value === 'true') {
2092
} else if (value === 'false') {
2094
} else if (needsQuoting(value)) value = '(' + value + ')';
1979
2095
if (bits === 32) {
1980
2096
if (op === 're') {
1981
return '(' + getFastValue(value, '|', '0') + ')';
2097
return '(' + value + '|0)';
1984
return '(' + getFastValue(value, '>>>', '0') + ')';
1985
// Alternatively, we can consider the lengthier
1986
// return makeInlineCalculation('VALUE >= 0 ? VALUE : ' + Math.pow(2, bits) + ' + VALUE', value, 'tempBigInt');
1987
// which does not always turn us into a 32-bit *un*signed value
2099
return '(' + value + '>>>0)';
1989
2101
} else if (bits < 32) {
1990
2102
if (op === 're') {
1991
return makeInlineCalculation('(VALUE << ' + (32-bits) + ') >> ' + (32-bits), value, 'tempInt');
2103
return '((' + value + '<<' + (32-bits) + ')>>' + (32-bits) + ')';
1993
return '(' + getFastValue(value, '&', Math.pow(2, bits)-1) + ')';
2105
return '(' + value + '&' + (Math.pow(2, bits)-1) + ')';
1995
2107
} else { // bits > 32
1996
2108
if (op === 're') {
2018
2130
// as |0, but &-1 hints to the js optimizer that this is a rounding correction
2019
2131
// Do Math.floor, which is reasonably fast, if we either don't care, or if we can be sure
2020
2132
// the value is non-negative
2021
if (!correctRoundings() || (!signed && !floatConversion)) return 'Math.floor(' + value + ')';
2133
if (!correctRoundings() || (!signed && !floatConversion)) return 'Math_floor(' + value + ')';
2022
2134
// We are left with >32 bits signed, or a float conversion. Check and correct inline
2023
2135
// Note that if converting a float, we may have the wrong sign at this point! But, we have
2024
2136
// been rounded properly regardless, and we will be sign-corrected later when actually used, if
2026
return makeInlineCalculation(makeComparison('VALUE', '>=', '0', 'float') + ' ? Math.floor(VALUE) : Math.ceil(VALUE)', value, 'tempBigIntR');
2138
return makeInlineCalculation(makeComparison('VALUE', '>=', '0', 'float') + ' ? Math_floor(VALUE) : Math_ceil(VALUE)', value, 'tempBigIntR');
2028
2140
// asm.js mode, cleaner refactoring of this function as well. TODO: use in non-asm case, most of this
2029
2141
if (floatConversion && bits <= 32) {
2040
2152
// Math.floor is reasonably fast if we don't care about corrections (and even correct if unsigned)
2041
if (!correctRoundings() || !signed) return 'Math.floor(' + value + ')';
2153
if (!correctRoundings() || !signed) return '(+Math_floor(' + value + '))';
2042
2154
// We are left with >32 bits
2043
return makeInlineCalculation(makeComparison('VALUE', '>=', '0', 'float') + ' ? Math.floor(VALUE) : Math.ceil(VALUE)', value, 'tempBigIntR');
2155
return makeInlineCalculation(makeComparison('VALUE', '>=', '0', 'float') + ' ? +Math_floor(VALUE) : +Math_ceil(VALUE)', value, 'tempBigIntR');
2047
function makeIsNaN(value) {
2048
if (ASM_JS) return makeInlineCalculation('((VALUE) != (VALUE))', value, 'tempDouble');
2159
function makeIsNaN(value, type) {
2160
if (ASM_JS) return makeInlineCalculation('((VALUE) != (VALUE))', value, type === 'float' ? 'tempFloat' : 'tempDouble');
2049
2161
return 'isNaN(' + value + ')';
2052
2164
function makeFloat(value, type) {
2053
if (TO_FLOAT32 && type == 'float') {
2054
return 'Math.toFloat32(' + value + ')';
2165
if (PRECISE_F32 && type == 'float') {
2166
return 'Math_fround(' + value + ')';
2386
if (type[0] === '<' && type[type.length-1] !== '*') {
2387
// vector/SIMD operation
2388
Types.usesSIMD = true;
2390
case 'fadd': return 'SIMD.float32x4.add(' + idents[0] + ',' + idents[1] + ')';
2391
case 'fsub': return 'SIMD.float32x4.sub(' + idents[0] + ',' + idents[1] + ')';
2392
case 'fmul': return 'SIMD.float32x4.mul(' + idents[0] + ',' + idents[1] + ')';
2393
case 'fdiv': return 'SIMD.float32x4.div(' + idents[0] + ',' + idents[1] + ')';
2394
case 'add' : return 'SIMD.int32x4.add(' + idents[0] + ',' + idents[1] + ')';
2395
case 'sub' : return 'SIMD.int32x4.sub(' + idents[0] + ',' + idents[1] + ')';
2396
case 'mul' : return 'SIMD.int32x4.mul(' + idents[0] + ',' + idents[1] + ')';
2398
var inType = item.params[0].type;
2399
var outType = item.type;
2400
if (inType === '<4 x float>') {
2401
assert(outType === '<4 x i32>');
2402
return 'SIMD.float32x4.bitsToInt32x4(' + idents[0] + ')';
2404
assert(inType === '<4 x i32>');
2405
assert(outType === '<4 x float>');
2406
return 'SIMD.int32x4.bitsToFloat32x4(' + idents[0] + ')';
2409
case 'and': return 'SIMD.int32x4.and(' + idents[0] + ',' + idents[1] + ')';
2410
case 'or': return 'SIMD.int32x4.or(' + idents[0] + ',' + idents[1] + ')';
2411
case 'xor': return 'SIMD.int32x4.xor(' + idents[0] + ',' + idents[1] + ')';
2412
default: throw 'vector op todo: ' + dump(item);
2269
2417
// basic integer ops
2270
2418
case 'add': return handleOverflow(getFastValue(idents[0], '+', idents[1], item.type), bits);
2294
2442
dprint('Warning: 64 bit XOR - precision limit may be hit on llvm line ' + item.lineNum);
2295
2443
return 'Runtime.xor64(' + idents[0] + ', ' + idents[1] + ')';
2297
return idents[0] + ' ^ ' + idents[1];
2445
return idents[0] + '^' + idents[1];
2300
2448
if (bits > 32) return idents[0] + '*' + getFastValue(2, 'pow', idents[1]);
2301
return idents[0] + ' << ' + idents[1];
2449
return idents[0] + '<<' + idents[1];
2304
2452
if (bits > 32) return integerizeBignum(idents[0] + '/' + getFastValue(2, 'pow', idents[1]));
2305
if (bits === 32) return originalIdents[0] + ' >> ' + idents[1]; // No need to reSign in this case
2306
return idents[0] + ' >> ' + idents[1];
2453
if (bits === 32) return originalIdents[0] + '>>' + idents[1]; // No need to reSign in this case
2454
return idents[0] + '>>' + idents[1];
2309
2457
if (bits > 32) return integerizeBignum(idents[0] + '/' + getFastValue(2, 'pow', idents[1]));
2310
if (bits === 32) return originalIdents[0] + ' >>> ' + idents[1]; // No need to unSign in this case
2311
return idents[0] + ' >>> ' + idents[1];
2458
if (bits === 32) return originalIdents[0] + '>>>' + idents[1]; // No need to unSign in this case
2459
return idents[0] + '>>>' + idents[1];
2313
2461
// basic float ops
2314
2462
case 'fadd': return makeFloat(getFastValue(idents[0], '+', idents[1], item.type), item.type);
2316
2464
case 'fdiv': return makeFloat(getFastValue(idents[0], '/', idents[1], item.type), item.type);
2317
2465
case 'fmul': return makeFloat(getFastValue(idents[0], '*', idents[1], item.type), item.type);
2318
2466
case 'frem': return makeFloat(getFastValue(idents[0], '%', idents[1], item.type), item.type);
2319
case 'uitofp': case 'sitofp': return asmCoercion(idents[0], 'double', op[0]);
2467
case 'uitofp': case 'sitofp': return asmCoercion(idents[0], item.type, op[0]);
2320
2468
case 'fptoui': case 'fptosi': return makeRounding(idents[0], bitsLeft, op === 'fptosi', true);
2322
2470
// TODO: We sometimes generate false instead of 0, etc., in the *cmps. It seemed slightly faster before, but worth rechecking
2323
2471
// Note that with typed arrays, these become 0 when written. So that is a potential difference with non-typed array runs.
2473
// unsigned coercions can be (X&Y), which is not a valid asm coercion for comparisons
2474
if (ASM_JS && variant[0] === 'u') {
2475
if (idents[0].indexOf('>>>') < 0) idents[0] = '((' + idents[0] + ')>>>0)';
2476
if (idents[1].indexOf('>>>') < 0) idents[1] = '((' + idents[1] + ')>>>0)';
2325
2478
switch (variant) {
2326
case 'uge': case 'sge': return idents[0] + ' >= ' + idents[1];
2327
case 'ule': case 'sle': return idents[0] + ' <= ' + idents[1];
2328
case 'ugt': case 'sgt': return idents[0] + ' > ' + idents[1];
2329
case 'ult': case 'slt': return idents[0] + ' < ' + idents[1];
2479
case 'uge': case 'sge': return idents[0] + '>=' + idents[1];
2480
case 'ule': case 'sle': return idents[0] + '<=' + idents[1];
2481
case 'ugt': case 'sgt': return idents[0] + '>' + idents[1];
2482
case 'ult': case 'slt': return idents[0] + '<' + idents[1];
2330
2483
// We use loose comparisons, which allows false == 0 to be true, etc. Ditto in fcmp
2331
2484
case 'ne': case 'eq': {
2332
2485
// We must sign them, so we do not compare -1 to 255 (could have unsigned them both too)
2342
2495
switch (variant) {
2343
2496
// TODO 'o' ones should be 'ordered (no NaN) and',
2344
2497
// 'u' ones should be 'unordered or'.
2345
case 'uge': case 'oge': return idents[0] + ' >= ' + idents[1];
2346
case 'ule': case 'ole': return idents[0] + ' <= ' + idents[1];
2347
case 'ugt': case 'ogt': return idents[0] + ' > ' + idents[1];
2348
case 'ult': case 'olt': return idents[0] + ' < ' + idents[1];
2349
case 'une': case 'one': return idents[0] + ' != ' + idents[1];
2350
case 'ueq': case 'oeq': return idents[0] + ' == ' + idents[1];
2351
case 'ord': return '!' + makeIsNaN(idents[0]) + ' & !' + makeIsNaN(idents[1]);
2352
case 'uno': return makeIsNaN(idents[0]) + ' | ' + makeIsNaN(idents[1]);
2498
case 'uge': case 'oge': return idents[0] + '>=' + idents[1];
2499
case 'ule': case 'ole': return idents[0] + '<=' + idents[1];
2500
case 'ugt': case 'ogt': return idents[0] + '>' + idents[1];
2501
case 'ult': case 'olt': return idents[0] + '<' + idents[1];
2502
case 'une': case 'one': return idents[0] + '!=' + idents[1];
2503
case 'ueq': case 'oeq': return idents[0] + '==' + idents[1];
2504
case 'ord': return '!' + makeIsNaN(idents[0], paramTypes[0]) + '&!' + makeIsNaN(idents[1], paramTypes[0]);
2505
case 'uno': return makeIsNaN(idents[0], paramTypes[0]) + '|' + makeIsNaN(idents[1], paramTypes[0]);
2353
2506
case 'true': return '1';
2354
2507
default: throw 'Unknown fcmp variant: ' + variant;
2674
function parseAlign(text) { // parse ", align \d+"
2675
if (!text) return QUANTUM_SIZE;
2676
return parseInt(text.substr(8));
2679
function deParen(text) {
2680
if (text[0] === '(') return text.substr(1, text.length-2);
2684
function deParenCarefully(text) {
2685
if (text[0] === '(' && text.indexOf('(', 1) < 0 && text[text.length-1] === ')') return text.substr(1, text.length-2);
2689
function addVariable(ident, type, funcData) {
2690
funcData = funcData || Framework.currItem.funcData;
2692
var old = funcData.variables[ident];
2694
assert(old.type === type);
2696
funcData.variables[ident] = {
2702
hasValueTaken: false,
2710
var SIMDLane = ['X', 'Y', 'Z', 'W'];
2711
var simdLane = ['x', 'y', 'z', 'w'];
2713
function ensureVector(ident, base) {
2714
Types.usesSIMD = true;
2715
return ident == 0 ? base + '32x4.splat(0)' : ident;
2718
function ensureValidFFIType(type) {
2719
return type === 'float' ? 'double' : type; // ffi does not tolerate float XXX
2722
// FFI return values must arrive as doubles, and we can force them to floats afterwards
2723
function asmFFICoercion(value, type) {
2724
value = asmCoercion(value, ensureValidFFIType(type));
2725
if (PRECISE_F32 && type === 'float') value = asmCoercion(value, 'float');