3
// Various tools for parsing LLVM. Utilities of various sorts, that are
4
// specific to Emscripten (and hence not in utility.js).
6
// Does simple 'macro' substitution, using Django-like syntax,
7
// {{{ code }}} will be replaced with |eval(code)|.
8
function processMacros(text) {
9
return text.replace(/{{{([^}]|}(?!}))+}}}/g, function(str) {
10
str = str.substr(3, str.length-6);
12
return ret ? ret.toString() : '';
16
// Simple #if/else/endif preprocessing for a file. Checks if the
17
// ident checked is true in our global.
18
function preprocess(text) {
19
var lines = text.split('\n');
22
for (var i = 0; i < lines.length; i++) {
24
if (line[line.length-1] == '\r') {
25
line = line.substr(0, line.length-1); // Windows will have '\r' left over from splitting over '\r\n'
27
if (!line[0] || line[0] != '#') {
28
if (showStack.indexOf(false) == -1) {
32
if (line[1] && line[1] == 'i') { // if
33
var parts = line.split(' ');
39
showStack.push(ident in this && this[ident] == value);
41
showStack.push(ident in this && this[ident] > 0);
43
} else if (line[2] && line[2] == 'l') { // else
44
showStack.push(!showStack.pop());
45
} else if (line[2] && line[2] == 'n') { // endif
48
throw "Unclear preprocessor command: " + line;
52
assert(showStack.length == 0);
56
function addPointing(type) { return type + '*' }
57
function removePointing(type, num) {
58
if (num === 0) return type;
59
assert(type.substr(type.length-(num ? num : 1)).replace(/\*/g, '') === ''); //, 'Error in removePointing with ' + [type, num, type.substr(type.length-(num ? num : 1))]);
60
return type.substr(0, type.length-(num ? num : 1));
63
function pointingLevels(type) {
66
var len1 = type.length - 1;
67
while (type[len1-ret] && type[len1-ret] === '*') {
73
function removeAllPointing(type) {
74
return removePointing(type, pointingLevels(type));
77
function toNiceIdent(ident) {
79
if (parseFloat(ident) == ident) return ident;
80
if (ident == 'null') return '0'; // see parseNumerical
81
if (ident == 'undef') return '0';
82
return ident.replace('%', '$').replace(/["&\\ \.@:<>,\*\[\]\(\)-]/g, '_');
85
// Kind of a hack. In some cases we have strings that we do not want
86
// to |toNiceIdent|, as they are the output of previous processing. We
87
// should refactor everything into an object, with an explicit flag
88
// saying what has been |toNiceIdent|ed. Until then, this will detect
89
// simple idents that are in need of |toNiceIdent|ation. Or, we should
90
// ensure that processed strings never start with %,@, e.g. by always
91
// enclosing them in ().
92
function toNiceIdentCarefully(ident) {
93
if (ident[0] == '%' || ident[0] == '@') ident = toNiceIdent(ident);
97
// Returns true if ident is a niceIdent (see toNiceIdent). If loose
98
// is true, then also allow () and spaces.
99
function isNiceIdent(ident, loose) {
101
return /^\(?[$_]+[\w$_\d ]*\)?$/.test(ident);
103
return /^[$_]+[\w$_\d]*$/.test(ident);
107
function isJSVar(ident) {
108
return /^\(?[$_]?[\w$_\d ]*\)+$/.test(ident);
112
function isLocalVar(ident) {
113
return ident[0] == '$';
116
function isStructPointerType(type) {
117
// This test is necessary for clang - in llvm-gcc, we
118
// could check for %struct. The downside is that %1 can
119
// be either a variable or a structure, and we guess it is
120
// a struct, which can lead to |call i32 %5()| having
121
// |%5()| as a function call (like |i32 (i8*)| etc.). So
122
// we must check later on, in call(), where we have more
123
// context, to differentiate such cases.
124
// A similar thing happens in isStructType()
125
return !Runtime.isNumberType(type) && type[0] == '%';
128
function isPointerType(type) {
129
return type[type.length-1] == '*';
132
function isStructType(type) {
133
if (isPointerType(type)) return false;
134
if (/^\[\d+\ x\ (.*)\]/.test(type)) return true; // [15 x ?] blocks. Like structs
135
if (/<?{ ?[^}]* ?}>?/.test(type)) return true; // { i32, i8 } etc. - anonymous struct types
136
// See comment in isStructPointerType()
137
return type[0] == '%';
140
function isStructuralType(type) {
141
return /^{ ?[^}]* ?}$/.test(type); // { i32, i8 } etc. - anonymous struct types
144
function getStructuralTypeParts(type) { // split { i32, i8 } etc. into parts
145
return type.replace(/[ {}]/g, '').split(',');
148
function getStructureTypeParts(type) {
149
if (isStructuralType(type)) {
150
return type.replace(/[ {}]/g, '').split(',');
152
var typeData = Types.types[type];
153
assert(typeData, type);
154
return typeData.fields;
158
function getStructuralTypePartBits(part) {
159
return Math.ceil((getBits(part) || 32)/32)*32; // simple 32-bit alignment. || 32 is for pointers
162
function isIntImplemented(type) {
163
return type[0] == 'i' || isPointerType(type);
166
// Note: works for iX types and structure types, not pointers (even though they are implemented as ints)
167
function getBits(type, allowPointers) {
168
if (allowPointers && isPointerType(type)) return 32;
170
if (type[0] == 'i') {
171
var left = type.substr(1);
172
if (!isNumber(left)) return 0;
173
return parseInt(left);
175
if (isStructuralType(type)) {
176
return sum(getStructuralTypeParts(type).map(getStructuralTypePartBits));
178
if (isStructType(type)) {
179
var typeData = Types.types[type];
180
if (typeData === undefined) return 0;
181
return typeData.flatSize*8;
186
function getNumIntChunks(type) {
187
return Math.ceil(getBits(type, true)/32);
190
function isIdenticallyImplemented(type1, type2) {
191
var floats = +(type1 in Runtime.FLOAT_TYPES) + +(type2 in Runtime.FLOAT_TYPES);
192
if (floats == 2) return true;
193
if (floats == 1) return false;
194
return getNumIntChunks(type1) == getNumIntChunks(type2);
197
function isIllegalType(type) {
198
var bits = getBits(type);
199
return bits > 0 && (bits >= 64 || !isPowerOfTwo(bits));
202
function isVoidType(type) {
203
return type == 'void';
206
// Detects a function definition, ([...|type,[type,...]])
207
function isFunctionDef(token, out) {
208
var text = token.text;
209
var nonPointing = removeAllPointing(text);
210
if (nonPointing[0] != '(' || nonPointing.substr(-1) != ')')
212
if (nonPointing === '()') return true;
213
if (!token.item) return false;
215
var segments = splitTokenList(token.item.tokens);
216
segments.forEach(function(segment) {
217
var subtext = segment[0].text;
218
fail = fail || segment.length > 1 || !(isType(subtext) || subtext == '...');
221
out.segments = segments;
222
out.numArgs = segments.length;
227
function isPossiblyFunctionType(type) {
228
// A quick but unreliable way to see if something is a function type. Yes is just 'maybe', no is definite.
229
var len = type.length;
230
return type[len-2] == ')' && type[len-1] == '*';
233
function isFunctionType(type, out) {
234
if (!isPossiblyFunctionType(type)) return false;
235
type = type.substr(0, type.length-1); // remove final '*'
236
var firstOpen = type.indexOf('(');
237
if (firstOpen <= 0) return false;
238
type = type.replace(/"[^"]+"/g, '".."');
239
var lastOpen = type.lastIndexOf('(');
241
if (firstOpen == lastOpen) {
242
returnType = getReturnType(type);
243
if (!isType(returnType)) return false;
245
returnType = 'i8*'; // some pointer type, no point in analyzing further
247
if (out) out.returnType = returnType;
248
// find ( that starts the arguments
249
var depth = 0, i = type.length-1, argText = null;
252
if (curr == ')') depth++;
253
else if (curr == '(') {
256
argText = type.substr(i);
263
return isFunctionDef({ text: argText, item: tokenize(argText.substr(1, argText.length-2), true) }, out);
266
function getReturnType(type) {
267
if (pointingLevels(type) > 1) return '*'; // the type of a call can be either the return value, or the entire function. ** or more means it is a return value
268
var lastOpen = type.lastIndexOf('(');
270
return type.substr(0, lastOpen-1);
275
var isTypeCache = {}; // quite hot, optimize as much as possible
276
function isType(type) {
277
if (type in isTypeCache) return isTypeCache[type];
278
var ret = isPointerType(type) || isVoidType(type) || Runtime.isNumberType(type) || isStructType(type) || isFunctionType(type);
279
isTypeCache[type] = ret;
283
function isVarArgsFunctionType(type) {
284
// assumes this is known to be a function type already
285
var varArgsSuffix = '...)*';
286
return type.substr(-varArgsSuffix.length) == varArgsSuffix;
289
function countNormalArgs(type, out) {
291
if (!isFunctionType(type, out)) return -1;
292
if (isVarArgsFunctionType(type)) out.numArgs--;
296
function addIdent(token) {
297
token.ident = token.text;
301
function combineTokens(tokens) {
303
lineNum: tokens[0].lineNum,
307
tokens.forEach(function(token) {
308
ret.text += token.text;
309
ret.tokens.push(token);
314
function compareTokens(a, b) {
319
var ret = JSON.stringify(a) == JSON.stringify(b);
325
function getTokenIndexByText(tokens, text) {
327
while (tokens[i] && tokens[i].text != text) i++;
331
function findTokenText(item, text) {
332
return findTokenTextAfter(item, text, 0);
335
function findTokenTextAfter(item, text, startAt) {
336
for (var i = startAt; i < item.tokens.length; i++) {
337
if (item.tokens[i].text == text) return i;
342
var SPLIT_TOKEN_LIST_SPLITTERS = set(',', 'to'); // 'to' can separate parameters as well...
344
// Splits a list of tokens separated by commas. For example, a list of arguments in a function call
345
function splitTokenList(tokens) {
346
if (tokens.length == 0) return [];
347
if (!tokens.slice) tokens = tokens.tokens;
348
if (tokens.slice(-1)[0].text != ',') tokens.push({text:','});
351
for (var i = 0; i < tokens.length; i++) {
352
var token = tokens[i];
353
if (token.text in SPLIT_TOKEN_LIST_SPLITTERS) {
356
} else if (token.text == ';') {
366
function parseParamTokens(params) {
367
if (params.length === 0) return [];
369
if (params[params.length-1].text != ',') {
370
params.push({ text: ',' });
372
var anonymousIndex = 0;
373
while (params.length > 0) {
375
while (params[i].text != ',') i++;
376
var segment = params.slice(0, i);
377
params = params.slice(i+1);
378
segment = cleanSegment(segment);
380
if (segment[1] && segment[1].text === 'byval') {
381
// handle 'byval' and 'byval align X'. We store the alignment in 'byVal'
382
byVal = QUANTUM_SIZE;
383
segment.splice(1, 1);
384
if (segment[1] && segment[1].text === 'align') {
385
assert(isNumber(segment[2].text));
386
byVal = parseInt(segment[2].text);
387
segment.splice(1, 2);
390
if (segment.length == 1) {
391
if (segment[0].text == '...') {
393
intertype: 'varargs',
395
ident: 'varrp' // the conventional name we have for this
398
// Clang sometimes has a parameter with just a type,
399
// no name... the name is implied to be %{the index}
402
type: segment[0].text,
403
ident: toNiceIdent('%') + anonymousIndex
405
Types.needAnalysis[ret[ret.length-1].type] = 0;
408
} else if (segment[1].text in PARSABLE_LLVM_FUNCTIONS) {
409
ret.push(parseLLVMFunctionCall(segment));
410
} else if (segment[1].text === 'blockaddress') {
411
ret.push(parseBlockAddress(segment));
413
if (segment[2] && segment[2].text == 'to') { // part of bitcast params
414
segment = segment.slice(0, 2);
416
while (segment.length > 2) {
417
segment[0].text += segment[1].text;
418
segment.splice(1, 1); // TODO: merge tokens nicely
422
type: segment[0].text,
423
ident: toNiceIdent(parseNumerical(segment[1].text, segment[0].text))
425
Types.needAnalysis[removeAllPointing(ret[ret.length-1].type)] = 0;
427
ret[ret.length-1].byVal = byVal;
432
function hasVarArgs(params) {
433
for (var i = 0; i < params.length; i++) {
434
if (params[i].intertype == 'varargs') {
441
var UNINDEXABLE_GLOBALS = set(
442
'_llvm_global_ctors' // special-cased
445
function isIndexableGlobal(ident) {
446
if (!(ident in Variables.globals)) return false;
447
if (ident in UNINDEXABLE_GLOBALS) {
448
Variables.globals[ident].unIndexable = true;
451
var data = Variables.globals[ident];
452
return !data.alias && !data.external;
455
function makeGlobalDef(ident) {
456
if (!NAMED_GLOBALS && isIndexableGlobal(ident)) return '';
457
return 'var ' + ident + ';';
460
function makeGlobalUse(ident) {
461
if (!NAMED_GLOBALS && isIndexableGlobal(ident)) {
462
var index = Variables.indexedGlobals[ident];
463
if (index === undefined) {
464
// we are accessing this before we index globals, likely from the library. mark as unindexable
465
UNINDEXABLE_GLOBALS[ident] = 1;
468
// We know and assert on TOTAL_STACK being equal to GLOBAL_BASE
469
return (TOTAL_STACK + index).toString();
474
function sortGlobals(globals) {
475
var ks = keys(globals);
477
var inv = invertArray(ks);
478
return values(globals).sort(function(a, b) {
479
return inv[b.ident] - inv[a.ident];
483
function finalizeParam(param) {
484
if (param.intertype in PARSABLE_LLVM_FUNCTIONS) {
485
return finalizeLLVMFunctionCall(param);
486
} else if (param.intertype === 'blockaddress') {
487
return finalizeBlockAddress(param);
488
} else if (param.intertype === 'jsvalue') {
491
if (param.type == 'i64' && USE_TYPED_ARRAYS == 2) {
492
return parseI64Constant(param.ident);
494
var ret = toNiceIdent(param.ident);
495
if (ret in Variables.globals) {
496
ret = makeGlobalUse(ret);
502
// Segment ==> Parameter
503
function parseLLVMSegment(segment) {
505
if (segment.length == 1) {
506
if (isType(segment[0].text)) {
507
Types.needAnalysis[segment[0].text] = 0;
510
ident: toNiceIdent(segment[0].text),
511
type: segment[0].text
516
ident: toNiceIdent(segment[0].text),
520
} else if (segment[1].type && segment[1].type == '{') {
521
type = segment[0].text;
522
Types.needAnalysis[type] = 0;
524
intertype: 'structvalue',
525
params: splitTokenList(segment[1].tokens).map(parseLLVMSegment),
528
} else if (segment[0].text in PARSABLE_LLVM_FUNCTIONS) {
529
return parseLLVMFunctionCall([{text: '?'}].concat(segment));
530
} else if (segment[1].text in PARSABLE_LLVM_FUNCTIONS) {
531
return parseLLVMFunctionCall(segment);
532
} else if (segment[1].text === 'blockaddress') {
533
return parseBlockAddress(segment);
535
type = segment[0].text;
536
Types.needAnalysis[type] = 0;
539
ident: toNiceIdent(segment[1].text),
545
function cleanSegment(segment) {
546
while (segment.length >= 2 && ['noalias', 'sret', 'nocapture', 'nest', 'zeroext', 'signext'].indexOf(segment[1].text) != -1) {
547
segment.splice(1, 1);
552
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']);
554
var PARSABLE_LLVM_FUNCTIONS = set('getelementptr', 'bitcast');
555
mergeInto(PARSABLE_LLVM_FUNCTIONS, MATHOPS);
557
// Parses a function call of form
558
// TYPE functionname MODIFIERS (...)
560
// i32* getelementptr inbounds (...)
561
function parseLLVMFunctionCall(segment) {
562
segment = segment.slice(0);
563
segment = cleanSegment(segment);
564
// Remove additional modifiers
566
if (!segment[2] || !segment[2].item) {
567
variant = segment.splice(2, 1)[0];
568
if (variant && variant.text) variant = variant.text; // needed for mathops
570
assertTrue(['inreg', 'byval'].indexOf(segment[1].text) == -1);
571
assert(segment[1].text in PARSABLE_LLVM_FUNCTIONS);
572
while (!segment[2].item) {
573
segment.splice(2, 1); // Remove modifiers
574
if (!segment[2]) throw 'Invalid segment!';
576
var intertype = segment[1].text;
577
var type = segment[0].text;
579
if (intertype === 'getelementptr') {
580
type = '*'; // a pointer, we can easily say, this is
581
} else if (segment[2].item.tokens.slice(-2)[0].text === 'to') {
582
type = segment[2].item.tokens.slice(-1)[0].text;
586
intertype: intertype,
589
params: parseParamTokens(segment[2].item.tokens)
591
Types.needAnalysis[ret.type] = 0;
592
ret.ident = toNiceIdent(ret.params[0].ident || 'NOIDENT');
596
// Gets an array of tokens, we parse out the first
597
// 'ident' - either a simple ident of one token, or
598
// an LLVM internal function that generates an ident.
599
// We shift out of the array list the tokens that
601
function eatLLVMIdent(tokens) {
603
if (tokens[0].text in PARSABLE_LLVM_FUNCTIONS) {
604
var item = parseLLVMFunctionCall([{text: '?'}].concat(tokens.slice(0,2))); // TODO: Handle more cases, return a full object, process it later
605
if (item.intertype == 'bitcast') checkBitcast(item);
610
ret = tokens[0].text;
616
function cleanOutTokens(filterOut, tokens, indexes) {
617
if (typeof indexes !== 'object') indexes = [indexes];
618
for (var i = indexes.length-1; i >=0; i--) {
619
var index = indexes[i];
620
while (index < tokens.length && tokens[index].text in filterOut) {
621
tokens.splice(index, 1);
626
function _IntToHex(x) {
627
assert(x >= 0 && x <= 15);
629
return String.fromCharCode('0'.charCodeAt(0) + x);
631
return String.fromCharCode('A'.charCodeAt(0) + x - 10);
635
function IEEEUnHex(stringy) {
636
stringy = stringy.substr(2); // leading '0x';
637
if (stringy.replace(/0/g, '') === '') return 0;
638
while (stringy.length < 16) stringy = '0' + stringy;
639
if (FAKE_X86_FP80 && stringy.length > 16) {
640
stringy = stringy.substr(stringy.length-16, 16);
641
warnOnce('.ll contains floating-point values with more than 64 bits. Faking values for them. If they are used, this will almost certainly break horribly!');
643
assert(stringy.length === 16, 'Can only unhex 16-digit double numbers, nothing platform-specific'); // |long double| can cause x86_fp80 which causes this
644
var top = eval('0x' + stringy[0]);
645
var neg = !!(top & 8); // sign
647
stringy = _IntToHex(top & ~8) + stringy.substr(1);
649
var a = eval('0x' + stringy.substr(0, 8)); // top half
650
var b = eval('0x' + stringy.substr(8)); // bottom half
651
var e = a >> ((52 - 32) & 0x7ff); // exponent
654
if (a == 0 && b == 0) {
655
return neg ? '-Infinity' : 'Infinity';
661
var absolute = ((((a | 0x100000) * 1.0) / Math.pow(2,52-32)) * Math.pow(2, e)) + (((b * 1.0) / Math.pow(2, 52)) * Math.pow(2, e));
662
return (absolute * (neg ? -1 : 1)).toString();
665
// Given an expression like (VALUE=VALUE*2,VALUE<10?VALUE:t+1) , this will
666
// replace VALUE with value. If value is not a simple identifier of a variable,
667
// value will be replaced with tempVar.
668
function makeInlineCalculation(expression, value, tempVar) {
669
if (!isNiceIdent(value, true)) {
670
expression = tempVar + '=' + value + ',' + expression;
673
return '(' + expression.replace(/VALUE/g, value) + ')';
676
// Makes a proper runtime value for a 64-bit value from low and high i32s. low and high are assumed to be unsigned.
677
function makeI64(low, high) {
679
if (USE_TYPED_ARRAYS == 2) {
680
return '[' + makeSignOp(low, 'i32', 'un', 1, 1) + ',' + makeSignOp(high, 'i32', 'un', 1, 1) + ']';
682
if (high) return RuntimeGenerator.makeBigInt(low, high);
687
// XXX Make all i64 parts signed
689
// Splits a number (an integer in a double, possibly > 32 bits) into an USE_TYPED_ARRAYS == 2 i64 value.
690
// Will suffer from rounding. mergeI64 does the opposite.
691
function splitI64(value, floatConversion) {
692
// We need to min here, since our input might be a double, and large values are rounded, so they can
693
// be slightly higher than expected. And if we get 4294967296, that will turn into a 0 if put into a
694
// HEAP32 or |0'd, etc.
695
var lowInput = legalizedI64s ? value : 'VALUE';
696
if (floatConversion && ASM_JS) lowInput = asmFloatToInt(lowInput);
698
return [lowInput + '>>>0', 'Math.min(Math.floor((' + value + ')/' + asmEnsureFloat(4294967296, 'float') + '), ' + asmEnsureFloat(4294967295, 'float') + ')>>>0'];
700
return makeInlineCalculation(makeI64(lowInput + '>>>0', 'Math.min(Math.floor(VALUE/' + asmEnsureFloat(4294967296, 'float') + '), ' + asmEnsureFloat(4294967295, 'float') + ')>>>0'), value, 'tempBigIntP');
703
function mergeI64(value, unsigned) {
704
assert(USE_TYPED_ARRAYS == 2);
706
return RuntimeGenerator.makeBigInt(value + '$0', value + '$1', unsigned);
708
return makeInlineCalculation(RuntimeGenerator.makeBigInt('VALUE[0]', 'VALUE[1]', unsigned), value, 'tempI64');
712
// Takes an i64 value and changes it into the [low, high] form used in i64 mode 1. In that
713
// mode, this is a no-op
714
function ensureI64_1(value) {
715
if (USE_TYPED_ARRAYS == 2) return value;
716
return splitI64(value, 1);
719
function makeCopyI64(value) {
720
assert(USE_TYPED_ARRAYS == 2);
721
return value + '.slice(0)';
724
// Given a string representation of an integer of arbitrary size, return it
725
// split up into 32-bit chunks
726
function parseArbitraryInt(str, bits) {
727
// We parse the string into a vector of digits, base 10. This is convenient to work on.
729
assert(bits > 0); // NB: we don't check that the value in str can fit in this amount of bits
731
function str2vec(s) { // index 0 is the highest value
733
for (var i = 0; i < s.length; i++) {
734
ret.push(s.charCodeAt(i) - '0'.charCodeAt(0));
739
function divide2(v) { // v /= 2
740
for (var i = v.length-1; i >= 0; i--) {
746
assert(i+1 < v.length);
758
function mul2(v) { // v *= 2
759
for (var i = v.length-1; i >= 0; i--) {
769
v[j] += 0.5; // will be multiplied
774
function subtract(v, w) { // v -= w. we assume v >= w
775
while (v.length > w.length) w.splice(0, 0, 0);
776
for (var i = 0; i < v.length; i++) {
780
// find something to take from
793
for (var i = 0; i < v.length; i++) {
794
if (v[i] > 0) return false;
802
// twos-complement is needed
805
for (var i = 0; i < bits; i++) {
808
subtract(v, str2vec(str));
815
bitsv.push((v[v.length-1] % 2 != 0)+0);
816
v[v.length-1] = v[v.length-1] & 0xfe;
820
var ret = zeros(Math.ceil(bits/32));
821
for (var i = 0; i < bitsv.length; i++) {
822
ret[Math.floor(i/32)] += bitsv[i]*Math.pow(2, i % 32);
827
function parseI64Constant(str, legalized) {
828
if (!isNumber(str)) {
829
// This is a variable. Copy it, so we do not modify the original
830
return legalizedI64s ? str : makeCopyI64(str);
833
var parsed = parseArbitraryInt(str, 64);
834
if (legalizedI64s || legalized) return parsed;
835
return '[' + parsed[0] + ',' + parsed[1] + ']';
838
function parseNumerical(value, type) {
839
if ((!type || type == 'double' || type == 'float') && (value.substr && value.substr(0,2) == '0x')) {
840
// Hexadecimal double value, as the llvm docs say,
841
// "The one non-intuitive notation for constants is the hexadecimal form of floating point constants."
842
value = IEEEUnHex(value);
843
} else if (USE_TYPED_ARRAYS == 2 && isIllegalType(type)) {
844
return value; // do not parseFloat etc., that can lead to loss of precision
845
} else if (value == 'null') {
846
// NULL *is* 0, in C/C++. No JS null! (null == 0 is false, etc.)
848
} else if (value === 'true') {
850
} else if (value === 'false') {
853
if (isNumber(value)) {
854
var ret = parseFloat(value); // will change e.g. 5.000000e+01 to 50
855
if (type in Runtime.FLOAT_TYPES && value[0] == '-' && ret === 0) return '-0'; // fix negative 0, toString makes it 0
856
return ret.toString();
862
// \0Dsometext is really '\r', then sometext
863
// This function returns an array of int values
864
function parseLLVMString(str) {
867
while (i < str.length) {
870
ret.push(chr.charCodeAt(0));
873
ret.push(eval('0x' + str[i+1]+str[i+2]));
880
function getLabelIds(labels) {
881
return labels.map(function(label) { return label.ident });
884
function cleanLabel(label) {
885
if (label[0] == 'B') {
886
return label.substr(5);
892
function getOldLabel(label) {
893
var parts = label.split('|');
894
return parts[parts.length-1];
897
function calcAllocatedSize(type) {
898
if (pointingLevels(type) == 0 && isStructType(type)) {
899
return Types.types[type].flatSize; // makeEmptyStruct(item.allocatedType).length;
901
return Runtime.getNativeTypeSize(type); // We can really get away with '1', though, at least on the stack...
905
// Generates the type signature for a structure, for each byte, the type that is there.
906
// i32, 0, 0, 0 - for example, an int32 is here, then nothing to do for the 3 next bytes, naturally
907
function generateStructTypes(type) {
908
if (isArray(type)) return type; // already in the form of [type, type,...]
909
if (Runtime.isNumberType(type) || isPointerType(type)) {
910
if (USE_TYPED_ARRAYS == 2 && type == 'i64') {
911
return ['i64', 0, 0, 0, 'i32', 0, 0, 0];
913
return [type].concat(zeros(Runtime.getNativeFieldSize(type)-1));
916
// Avoid multiple concats by finding the size first. This is much faster
917
var typeData = Types.types[type];
918
var size = typeData.flatSize;
919
var ret = new Array(size);
921
function add(typeData) {
923
for (var i = 0; i < typeData.fields.length; i++) {
924
var type = typeData.fields[i];
925
if (!SAFE_HEAP && isPointerType(type)) type = '*'; // do not include unneeded type names without safe heap
926
if (Runtime.isNumberType(type) || isPointerType(type)) {
927
if (USE_TYPED_ARRAYS == 2 && type == 'i64') {
928
ret[index++] = 'i64';
932
ret[index++] = 'i32';
940
add(Types.types[type]);
942
var more = (i+1 < typeData.fields.length ? typeData.flatIndexes[i+1] : typeData.flatSize) - (index - start);
943
for (var j = 0; j < more; j++) {
949
assert(index == size);
955
function recurseBlock(block, func) {
957
if (block.type == 'reloop') {
958
ret.push(func(block.inner));
959
} else if (block.type == 'multiple') {
960
block.entryLabels.forEach(function(entryLabel) { ret.push(func(entryLabel.block)) });
962
ret.push(func(block.next));
966
function getActualLabelId(labelId) {
967
return labelId.split('|').slice(-1)[0];
972
function indentify(text, indent) {
973
if (text.length > 1024*1024) return text; // Don't try to indentify huge strings - we may run out of memory
974
if (typeof indent === 'number') {
977
for (var i = 0; i < len; i++) indent += ' ';
979
return text.replace(/\n/g, '\n' + indent);
984
function correctSpecificSign() {
985
if (!Framework.currItem) return false;
986
if (Framework.currItem.funcData.ident.indexOf('emscripten_autodebug') >= 0) return 1; // always correct in the autodebugger code!
987
return (CORRECT_SIGNS === 2 && Debugging.getIdentifier() in CORRECT_SIGNS_LINES) ||
988
(CORRECT_SIGNS === 3 && !(Debugging.getIdentifier() in CORRECT_SIGNS_LINES));
990
function correctSigns() {
991
return CORRECT_SIGNS === 1 || correctSpecificSign();
994
function correctSpecificOverflow() {
995
if (!Framework.currItem) return false;
996
return (CORRECT_OVERFLOWS === 2 && Debugging.getIdentifier() in CORRECT_OVERFLOWS_LINES) ||
997
(CORRECT_OVERFLOWS === 3 && !(Debugging.getIdentifier() in CORRECT_OVERFLOWS_LINES));
999
function correctOverflows() {
1000
return CORRECT_OVERFLOWS === 1 || correctSpecificOverflow();
1003
function correctSpecificRounding() {
1004
if (!Framework.currItem) return false;
1005
return (CORRECT_ROUNDINGS === 2 && Debugging.getIdentifier() in CORRECT_ROUNDINGS_LINES) ||
1006
(CORRECT_ROUNDINGS === 3 && !(Debugging.getIdentifier() in CORRECT_ROUNDINGS_LINES));
1008
function correctRoundings() {
1009
return CORRECT_ROUNDINGS === 1 || correctSpecificRounding();
1012
function checkSpecificSafeHeap() {
1013
if (!Framework.currItem) return false;
1014
return (SAFE_HEAP === 2 && Debugging.getIdentifier() in SAFE_HEAP_LINES) ||
1015
(SAFE_HEAP === 3 && !(Debugging.getIdentifier() in SAFE_HEAP_LINES));
1017
function checkSafeHeap() {
1018
return SAFE_HEAP === 1 || checkSpecificSafeHeap();
1021
function getHeapOffset(offset, type, forceAsm) {
1022
if (USE_TYPED_ARRAYS !== 2) {
1026
if (Runtime.getNativeFieldSize(type) > 4) {
1027
if (type == 'i64' || TARGET_X86) {
1028
type = 'i32'; // XXX we emulate 64-bit values as 32 in x86, and also in le32 but only i64, not double
1032
var sz = Runtime.getNativeTypeSize(type);
1033
var shifts = Math.log(sz)/Math.LN2;
1034
offset = '(' + offset + ')';
1036
if (CHECK_HEAP_ALIGN) {
1037
return '(CHECK_ALIGN_' + sz + '(' + offset + '|0)>>' + shifts + ')';
1039
return '(' + offset + '>>' + shifts + ')';
1042
// we need to guard against overflows here, HEAP[U]8 expects a guaranteed int
1043
return isJSVar(offset) ? offset : '(' + offset + '|0)';
1047
function makeVarDef(js) {
1048
if (!ASM_JS) js = 'var ' + js;
1052
function asmEnsureFloat(value, type) { // ensures that a float type has either 5.5 (clearly a float) or +5 (float due to asm coercion)
1053
if (!ASM_JS) return value;
1054
// coerce if missing a '.', or if smaller than 1, so could be 1e-5 which has no .
1055
if (type in Runtime.FLOAT_TYPES && isNumber(value) && (value.toString().indexOf('.') < 0 || Math.abs(value) < 1)) {
1056
return '(+(' + value + '))';
1062
function asmInitializer(type, impl) {
1063
if (type in Runtime.FLOAT_TYPES) {
1070
function asmCoercion(value, type, signedness) {
1071
if (!ASM_JS) return value;
1072
if (type == 'void') {
1074
} else if (type in Runtime.FLOAT_TYPES) {
1075
if (isNumber(value)) {
1076
return asmEnsureFloat(value, type);
1079
if (signedness == 'u') {
1080
value = '(' + value + ')>>>0';
1082
value = '(' + value + ')|0';
1085
return '(+(' + value + '))';
1088
return '((' + value + ')|0)';
1092
function asmFloatToInt(x) {
1093
return '(~~(' + x + '))';
1096
function makeGetTempDouble(i, type, forSet) { // get an aliased part of the tempDouble temporary storage
1097
// Cannot use makeGetValue because it uses us
1098
// this is a unique case where we *can* use HEAPF64
1099
var slab = type == 'double' ? 'HEAPF64' : makeGetSlabs(null, type)[0];
1100
var ptr = getFastValue('tempDoublePtr', '+', Runtime.getNativeTypeSize(type)*i);
1102
if (type == 'double') {
1103
offset = '(' + ptr + ')>>3';
1105
offset = getHeapOffset(ptr, type);
1107
var ret = slab + '[' + offset + ']';
1108
if (!forSet) ret = asmCoercion(ret, type);
1112
function makeSetTempDouble(i, type, value) {
1113
return makeGetTempDouble(i, type, true) + '=' + asmEnsureFloat(value, type);
1116
var asmPrintCounter = 0;
1119
function makeGetValue(ptr, pos, type, noNeedFirst, unsigned, ignore, align, noSafe, forceAsm) {
1120
if (UNALIGNED_MEMORY) align = 1;
1121
if (isStructType(type)) {
1122
var typeData = Types.types[type];
1124
for (var i = 0; i < typeData.fields.length; i++) {
1125
ret.push('f' + i + ': ' + makeGetValue(ptr, pos + typeData.flatIndexes[i], typeData.fields[i], noNeedFirst, unsigned));
1127
return '{ ' + ret.join(', ') + ' }';
1130
// In double mode 1, in x86 we always assume unaligned because we can't trust that; otherwise in le32
1131
// we need this code path if we are not fully aligned.
1132
if (DOUBLE_MODE == 1 && USE_TYPED_ARRAYS == 2 && type == 'double' && (TARGET_X86 || align < 8)) {
1133
return '(' + makeSetTempDouble(0, 'i32', makeGetValue(ptr, pos, 'i32', noNeedFirst, unsigned, ignore, align)) + ',' +
1134
makeSetTempDouble(1, 'i32', makeGetValue(ptr, getFastValue(pos, '+', Runtime.getNativeTypeSize('i32')), 'i32', noNeedFirst, unsigned, ignore, align)) + ',' +
1135
makeGetTempDouble(0, 'double') + ')';
1138
if (USE_TYPED_ARRAYS == 2 && align) {
1139
// Alignment is important here. May need to split this up
1140
var bytes = Runtime.getNativeTypeSize(type);
1141
if (DOUBLE_MODE == 0 && type == 'double') bytes = 4; // we will really only read 4 bytes here
1142
if (bytes > align) {
1144
if (isIntImplemented(type)) {
1145
if (bytes == 4 && align == 2) {
1146
// Special case that we can optimize
1147
ret += makeGetValue(ptr, pos, 'i16', noNeedFirst, 2, ignore) + '|' +
1148
'(' + makeGetValue(ptr, getFastValue(pos, '+', 2), 'i16', noNeedFirst, 2, ignore) + '<<16)';
1149
} else { // XXX we cannot truly handle > 4... (in x86)
1151
for (var i = 0; i < bytes; i++) {
1152
ret += '(' + makeGetValue(ptr, getFastValue(pos, '+', i), 'i8', noNeedFirst, 1, ignore) + (i > 0 ? '<<' + (8*i) : '') + ')';
1153
if (i < bytes-1) ret += '|';
1155
ret = '(' + makeSignOp(ret, type, unsigned ? 'un' : 're', true);
1158
if (type == 'float') {
1159
ret += 'copyTempFloat(' + asmCoercion(getFastValue(ptr, '+', pos), 'i32') + '),' + makeGetTempDouble(0, 'float');
1161
ret += 'copyTempDouble(' + asmCoercion(getFastValue(ptr, '+', pos), 'i32') + '),' + makeGetTempDouble(0, 'double');
1169
var offset = calcFastOffset(ptr, pos, noNeedFirst);
1170
if (SAFE_HEAP && !noSafe) {
1171
var printType = type;
1172
if (printType !== 'null' && printType[0] !== '#') printType = '"' + safeQuote(printType) + '"';
1173
if (printType[0] === '#') printType = printType.substr(1);
1174
return asmCoercion('SAFE_HEAP_LOAD(' + asmCoercion(offset, 'i32') + ', ' + (ASM_JS ? 0 : printType) + ', ' + (!!unsigned+0) + ', ' + ((!checkSafeHeap() || ignore)|0) + ')', type);
1176
var ret = makeGetSlabs(ptr, type, false, unsigned)[0] + '[' + getHeapOffset(offset, type, forceAsm) + ']';
1177
if (ASM_JS && (phase == 'funcs' || forceAsm)) {
1178
ret = asmCoercion(ret, type);
1181
ret = makeInlineCalculation('(asmPrint' + (type in Runtime.FLOAT_TYPES ? 'Float' : 'Int') + '(' + (asmPrintCounter++) + ',' + asmCoercion('VALUE', type) + '), VALUE)', ret,
1182
'temp' + (type in Runtime.FLOAT_TYPES ? 'Double' : 'Int'));
1188
function makeGetValueAsm(ptr, pos, type, unsigned) {
1189
return makeGetValue(ptr, pos, type, null, unsigned, null, null, null, true);
1192
function indexizeFunctions(value, type) {
1193
assert((type && type !== '?') || (typeof value === 'string' && value.substr(0, 6) === 'CHECK_'), 'No type given for function indexizing');
1194
assert(value !== type, 'Type set to value');
1196
if (type && isFunctionType(type, out) && value[0] === '_') { // checking for _ differentiates from $ (local vars)
1197
// add signature to library functions that we now know need indexing
1198
if (!(value in Functions.implementedFunctions) && !(value in Functions.unimplementedFunctions)) {
1199
Functions.unimplementedFunctions[value] = Functions.getSignature(out.returnType, out.segments ? out.segments.map(function(segment) { return segment[0].text }) : []);
1202
if (BUILD_AS_SHARED_LIB) {
1203
return '(FUNCTION_TABLE_OFFSET + ' + Functions.getIndex(value) + ')';
1205
return Functions.getIndex(value);
1211
//! @param ptr The pointer. Used to find both the slab and the offset in that slab. If the pointer
1212
//! is just an integer, then this is almost redundant, but in general the pointer type
1213
//! may in the future include information about which slab as well. So, for now it is
1214
//! possible to put |0| here, but if a pointer is available, that is more future-proof.
1215
//! @param pos The position in that slab - the offset. Added to any offset in the pointer itself.
1216
//! @param value The value to set.
1217
//! @param type A string defining the type. Used to find the slab (IHEAP, FHEAP, etc.).
1218
//! 'null' means, in the context of SAFE_HEAP, that we should accept all types;
1219
//! which means we should write to all slabs, ignore type differences if any on reads, etc.
1220
//! @param noNeedFirst Whether to ignore the offset in the pointer itself.
1221
function makeSetValue(ptr, pos, value, type, noNeedFirst, ignore, align, noSafe, sep, forcedAlign, forceAsm) {
1222
if (UNALIGNED_MEMORY && !forcedAlign) align = 1;
1224
if (isStructType(type)) {
1225
var typeData = Types.types[type];
1227
// We can receive either an object - an object literal that was in the .ll - or a string,
1228
// which is the ident of an aggregate struct
1229
if (typeof value === 'string') {
1230
value = range(typeData.fields.length).map(function(i) { return value + '.f' + i });
1232
for (var i = 0; i < typeData.fields.length; i++) {
1233
ret.push(makeSetValue(ptr, getFastValue(pos, '+', typeData.flatIndexes[i]), value[i], typeData.fields[i], noNeedFirst));
1235
return ret.join('; ');
1238
if (DOUBLE_MODE == 1 && USE_TYPED_ARRAYS == 2 && type == 'double' && (TARGET_X86 || align < 8)) {
1239
return '(' + makeSetTempDouble(0, 'double', value) + ',' +
1240
makeSetValue(ptr, pos, makeGetTempDouble(0, 'i32'), 'i32', noNeedFirst, ignore, align, noSafe, ',') + ',' +
1241
makeSetValue(ptr, getFastValue(pos, '+', Runtime.getNativeTypeSize('i32')), makeGetTempDouble(1, 'i32'), 'i32', noNeedFirst, ignore, align, noSafe, ',') + ')';
1242
} else if (USE_TYPED_ARRAYS == 2 && type == 'i64') {
1243
return '(tempI64 = [' + splitI64(value) + '],' +
1244
makeSetValue(ptr, pos, 'tempI64[0]', 'i32', noNeedFirst, ignore, align, noSafe, ',') + ',' +
1245
makeSetValue(ptr, getFastValue(pos, '+', Runtime.getNativeTypeSize('i32')), 'tempI64[1]', 'i32', noNeedFirst, ignore, align, noSafe, ',') + ')';
1248
var bits = getBits(type);
1249
var needSplitting = bits > 0 && !isPowerOfTwo(bits); // an unnatural type like i24
1250
if (USE_TYPED_ARRAYS == 2 && (align || needSplitting)) {
1251
// Alignment is important here, or we need to split this up for other reasons.
1252
var bytes = Runtime.getNativeTypeSize(type);
1253
if (DOUBLE_MODE == 0 && type == 'double') bytes = 4; // we will really only read 4 bytes here
1254
if (bytes > align || needSplitting) {
1256
if (isIntImplemented(type)) {
1257
if (bytes == 4 && align == 2) {
1258
// Special case that we can optimize
1259
ret += 'tempBigInt=' + value + sep;
1260
ret += makeSetValue(ptr, pos, 'tempBigInt&0xffff', 'i16', noNeedFirst, ignore, 2) + sep;
1261
ret += makeSetValue(ptr, getFastValue(pos, '+', 2), 'tempBigInt>>16', 'i16', noNeedFirst, ignore, 2);
1263
ret += 'tempBigInt=' + value + sep;
1264
for (var i = 0; i < bytes; i++) {
1265
ret += makeSetValue(ptr, getFastValue(pos, '+', i), 'tempBigInt&0xff', 'i8', noNeedFirst, ignore, 1);
1266
if (i < bytes-1) ret += sep + 'tempBigInt = tempBigInt>>8' + sep;
1270
ret += makeSetValue('tempDoublePtr', 0, value, type, noNeedFirst, ignore, 8, null, null, true) + sep;
1271
ret += makeCopyValues(getFastValue(ptr, '+', pos), 'tempDoublePtr', Runtime.getNativeTypeSize(type), type, null, align, sep);
1277
value = indexizeFunctions(value, type);
1278
var offset = calcFastOffset(ptr, pos, noNeedFirst);
1279
if (SAFE_HEAP && !noSafe) {
1280
var printType = type;
1281
if (printType !== 'null' && printType[0] !== '#') printType = '"' + safeQuote(printType) + '"';
1282
if (printType[0] === '#') printType = printType.substr(1);
1283
return 'SAFE_HEAP_STORE(' + asmCoercion(offset, 'i32') + ', ' + asmCoercion(value, type) + ', ' + (ASM_JS ? 0 : printType) + ', ' + ((!checkSafeHeap() || ignore)|0) + ')';
1285
return makeGetSlabs(ptr, type, true).map(function(slab) { return slab + '[' + getHeapOffset(offset, type, forceAsm) + ']=' + value }).join(sep);
1289
function makeSetValueAsm(ptr, pos, value, type, noNeedFirst, ignore, align, noSafe, sep, forcedAlign) {
1290
return makeSetValue(ptr, pos, value, type, noNeedFirst, ignore, align, noSafe, sep, forcedAlign, true);
1293
var UNROLL_LOOP_MAX = 8;
1295
function makeSetValues(ptr, pos, value, type, num, align) {
1296
function unroll(type, num, jump, value$) {
1298
value$ = value$ || value;
1299
return range(num).map(function(i) {
1300
return makeSetValue(ptr, getFastValue(pos, '+', i*jump), value$, type);
1303
if (USE_TYPED_ARRAYS <= 1) {
1304
if (isNumber(num) && parseInt(num) <= UNROLL_LOOP_MAX) {
1305
return unroll(type, num);
1307
return 'for (var $$dest = ' + getFastValue(ptr, '+', pos) + ', $$stop = $$dest + ' + num + '; $$dest < $$stop; $$dest++) {\n' +
1308
makeSetValue('$$dest', '0', value, type) + '\n}';
1309
} else { // USE_TYPED_ARRAYS == 2
1310
// If we don't know how to handle this at compile-time, or handling it is best done in a large amount of code, call memset
1311
// TODO: optimize the case of numeric num but non-numeric value
1312
if (!isNumber(num) || !isNumber(value) || (parseInt(num)/align >= UNROLL_LOOP_MAX)) {
1313
return '_memset(' + asmCoercion(getFastValue(ptr, '+', pos), 'i32') + ', ' + asmCoercion(value, 'i32') + ', ' + asmCoercion(num, 'i32') + ')';
1315
num = parseInt(num);
1316
value = parseInt(value);
1317
if (value < 0) value += 256; // make it unsigned
1320
2: value | (value << 8),
1321
4: value | (value << 8) | (value << 16) | (value << 24)
1324
[4, 2, 1].forEach(function(possibleAlign) {
1325
if (num == 0) return;
1326
if (align >= possibleAlign) {
1327
ret.push(unroll('i' + (possibleAlign*8), Math.floor(num/possibleAlign), possibleAlign, values[possibleAlign]));
1328
pos = getFastValue(pos, '+', Math.floor(num/possibleAlign)*possibleAlign);
1329
num %= possibleAlign;
1332
return ret.join('; ');
1336
var TYPED_ARRAY_SET_MIN = Infinity; // .set() as memcpy seems to just slow us down
1338
function makeCopyValues(dest, src, num, type, modifier, align, sep) {
1340
function unroll(type, num, jump) {
1342
return range(num).map(function(i) {
1343
if (USE_TYPED_ARRAYS <= 1 && type === 'null') {
1344
// Null is special-cased: We copy over all heaps
1345
return makeGetSlabs(dest, 'null', true).map(function(slab) {
1346
return slab + '[' + getFastValue(dest, '+', i) + ']=' + slab + '[' + getFastValue(src, '+', i) + ']';
1347
}).join(sep) + (SAFE_HEAP ? sep + 'SAFE_HEAP_COPY_HISTORY(' + getFastValue(dest, '+', i) + ', ' + getFastValue(src, '+', i) + ')' : '');
1349
return makeSetValue(dest, i*jump, makeGetValue(src, i*jump, type), type);
1353
if (USE_TYPED_ARRAYS <= 1) {
1354
if (isNumber(num) && parseInt(num) <= UNROLL_LOOP_MAX) {
1355
return unroll(type, num);
1357
var oldDest = dest, oldSrc = src;
1360
return 'for (var $$src = ' + oldSrc + ', $$dest = ' + oldDest + ', $$stop = $$src + ' + num + '; $$src < $$stop; $$src++, $$dest++) {\n' +
1361
unroll(type, 1) + ' }';
1362
} else { // USE_TYPED_ARRAYS == 2
1363
// If we don't know how to handle this at compile-time, or handling it is best done in a large amount of code, call memset
1364
if (!isNumber(num)) num = stripCorrections(num);
1365
if (!isNumber(align)) align = stripCorrections(align);
1366
if (!isNumber(num) || (parseInt(num)/align >= UNROLL_LOOP_MAX)) {
1367
return '_memcpy(' + dest + ', ' + src + ', ' + num + ')';
1369
num = parseInt(num);
1371
dest = stripCorrections(dest); // remove corrections, since we will be correcting after we add anyhow,
1372
src = stripCorrections(src); // and in the heap assignment expression
1375
[4, 2, 1].forEach(function(possibleAlign) {
1376
if (num == 0) return;
1377
if (align >= possibleAlign) {
1378
ret.push(unroll('i' + (possibleAlign*8), Math.floor(num/possibleAlign), possibleAlign));
1379
src = getFastValue(src, '+', Math.floor(num/possibleAlign)*possibleAlign);
1380
dest = getFastValue(dest, '+', Math.floor(num/possibleAlign)*possibleAlign);
1381
num %= possibleAlign;
1384
return ret.join(sep);
1388
function makeHEAPView(which, start, end) {
1389
// Assumes USE_TYPED_ARRAYS == 2
1390
var size = parseInt(which.replace('U', '').replace('F', ''))/8;
1391
var mod = size == 1 ? '' : ('>>' + log2(size));
1392
return 'HEAP' + which + '.subarray((' + start + ')' + mod + ',(' + end + ')' + mod + ')';
1395
var PLUS_MUL = set('+', '*');
1396
var MUL_DIV = set('*', '/');
1397
var PLUS_MINUS = set('+', '-');
1398
var TWO_TWENTY = Math.pow(2, 20);
1400
// Given two values and an operation, returns the result of that operation.
1401
// Tries to do as much as possible at compile time.
1402
// Leaves overflows etc. unhandled, *except* for integer multiply, in order to be efficient with Math.imul
1403
function getFastValue(a, op, b, type) {
1406
a = a == 'true' ? '1' : (a == 'false' ? '0' : a);
1407
b = b == 'true' ? '1' : (b == 'false' ? '0' : b);
1408
if (isNumber(a) && isNumber(b)) {
1410
return Math.pow(a, b).toString();
1412
var value = eval(a + op + '(' + b + ')'); // parens protect us from "5 - -12" being seen as "5--12" which is "(5--)12"
1413
if (op == '/' && type in Runtime.INT_TYPES) value = value|0; // avoid emitting floats
1414
return value.toString();
1418
if (a == '2' && isIntImplemented(type)) {
1419
return '(1 << (' + b + '))';
1421
return 'Math.pow(' + a + ', ' + b + ')';
1423
if (op in PLUS_MUL && isNumber(a)) { // if one of them is a number, keep it last
1428
if (op in MUL_DIV) {
1430
if (a == 0 || b == 0) {
1432
} else if (a == 1) {
1434
} else if (b == 1) {
1436
} else if (isNumber(b) && type && isIntImplemented(type) && Runtime.getNativeTypeSize(type) <= 32) {
1437
var shifts = Math.log(parseFloat(b))/Math.LN2;
1438
if (shifts % 1 == 0) {
1439
return '(' + a + '<<' + shifts + ')';
1442
if (!(type in Runtime.FLOAT_TYPES)) {
1443
// if guaranteed small enough to not overflow into a double, do a normal multiply
1444
var bits = getBits(type) || 32; // default is 32-bit multiply for things like getelementptr indexes
1445
// 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
1446
if ((isNumber(a) && Math.abs(a) < TWO_TWENTY) || (isNumber(b) && Math.abs(b) < TWO_TWENTY) || (bits < 32 && !ASM_JS)) {
1447
return '(((' + a + ')*(' + b + '))&' + ((Math.pow(2, bits)-1)|0) + ')'; // keep a non-eliminatable coercion directly on this
1449
return 'Math.imul(' + a + ',' + b + ')';
1454
} else if (b == 1) {
1456
} // Doing shifts for division is problematic, as getting the rounding right on negatives is tricky
1458
} else if (op in PLUS_MINUS) {
1460
op = op == '+' ? '-' : '+';
1464
return op == '+' ? b : '(-' + b + ')';
1465
} else if (b == 0) {
1469
return '(' + a + ')' + op + '(' + b + ')';
1472
function getFastValues(list, op, type) {
1477
for (var i = 0; i < list.length-1; i++) {
1478
var fast = getFastValue(list[i], op, list[i+1], type);
1479
var raw = list[i] + op + list[i+1];
1480
if (fast.length < raw.length || fast.indexOf(op) < 0) {
1482
list.splice(i+1, 1);
1489
if (list.length == 1) return list[0];
1490
return list.reduce(function(a, b) { return a + op + b });
1493
function calcFastOffset(ptr, pos, noNeedFirst) {
1494
var offset = noNeedFirst ? '0' : makeGetPos(ptr);
1495
return getFastValue(offset, '+', pos, 'i32');
1498
function makeGetPos(ptr) {
1502
var IHEAP_FHEAP = set('IHEAP', 'IHEAPU', 'FHEAP');
1504
var temp64f = new Float64Array(1);
1505
var temp32f = new Float32Array(temp64f.buffer);
1506
var temp32 = new Uint32Array(temp64f.buffer);
1507
var temp16 = new Uint16Array(temp64f.buffer);
1508
var temp8 = new Uint8Array(temp64f.buffer);
1509
var memoryInitialization = [];
1511
function writeInt8s(slab, i, value, type) {
1515
case 'i8': temp8[0] = value; currSize = 1; break;
1516
case 'i16': temp16[0] = value; currSize = 2; break;
1517
case 'float': temp32f[0] = value; currSize = 4; break;
1518
case 'double': temp64f[0] = value; currSize = 8; break;
1519
case 'i64': // fall through, i64 is two i32 chunks
1520
case 'i32': // fall through, i32 can be a pointer
1522
if (type == 'i32' || type == 'i64' || type[type.length-1] == '*') {
1523
if (!isNumber(value)) { // function table stuff, etc.
1525
slab[i+1] = slab[i+2] = slab[i+3] = 0;
1531
throw 'what? ' + types[i];
1535
for (var j = 0; j < currSize; j++) {
1536
slab[i+j] = temp8[j];
1541
function makePointer(slab, pos, allocator, type, ptr, finalMemoryInitialization) {
1542
assert(type, 'makePointer requires type info');
1543
if (typeof slab == 'string' && (slab.substr(0, 4) === 'HEAP' || (USE_TYPED_ARRAYS == 1 && slab in IHEAP_FHEAP))) return pos;
1544
var types = generateStructTypes(type);
1545
if (typeof slab == 'object') {
1546
for (var i = 0; i < slab.length; i++) {
1548
if (isNumber(curr)) {
1549
slab[i] = parseFloat(curr); // fix "5" to 5 etc.
1550
} else if (curr == 'undef') {
1555
// compress type info and data if possible
1556
if (USE_TYPED_ARRAYS != 2) {
1559
// compress all-zeros into a number (which will become zeros(..)).
1560
// note that we cannot always eval the slab, e.g., if it contains ident,0,0 etc. In that case, no compression TODO: ensure we get arrays here, not str
1561
var evaled = typeof slab === 'string' ? eval(slab) : slab;
1563
if (de.length === 1 && de[0] == 0) {
1564
slab = types.length;
1566
// TODO: if not all zeros, at least filter out items with type === 0. requires cleverness to know how to skip at runtime though. also
1567
// be careful of structure padding
1570
if (de.length === 1) {
1572
} else if (de.length === 2 && typeof slab === 'number') {
1573
// If slab is all zeros, we can compress types even if we have i32,0,0,0,i32,0,0,0 etc. - we do not need the zeros
1574
de = de.filter(function(x) { return x !== 0 });
1575
if (de.length === 1) {
1579
} else { // USE_TYPED_ARRAYS == 2
1580
if (!finalMemoryInitialization) {
1581
// XXX This heavily assumes the target endianness is the same as our current endianness! XXX
1583
while (i < slab.length) {
1584
var currType = types[i];
1585
if (!currType) { i++; continue }
1586
i += writeInt8s(slab, i, slab[i], currType);
1591
if (allocator == 'ALLOC_NONE' && USE_TYPED_ARRAYS == 2) {
1592
if (!finalMemoryInitialization) {
1593
// writing out into memory, without a normal allocation. We put all of these into a single big chunk.
1594
assert(typeof slab == 'object');
1595
assert(slab.length % QUANTUM_SIZE == 0, slab.length); // must be aligned already
1596
var offset = ptr - TOTAL_STACK; // we assert on GLOBAL_BASE being equal to TOTAL_STACK
1597
for (var i = 0; i < slab.length; i++) {
1598
memoryInitialization[offset + i] = slab[i];
1602
// This is the final memory initialization
1606
// JS engines sometimes say array initializers are too large. Work around that by chunking and calling concat to combine at runtime
1607
var chunkSize = JS_CHUNK_SIZE;
1608
function chunkify(array) {
1609
// break very large slabs into parts
1612
while (index < array.length) {
1613
ret = (ret ? ret + '.concat(' : '') + '[' + array.slice(index, index + chunkSize).map(JSON.stringify) + ']' + (ret ? ')\n' : '');
1618
if (typeof slab == 'object' && slab.length > chunkSize) {
1619
slab = chunkify(slab);
1621
if (typeof types == 'object') {
1622
while (types.length < slab.length) types.push(0);
1624
if (typeof types != 'string' && types.length > chunkSize) {
1625
types = chunkify(types);
1627
types = JSON.stringify(types);
1629
if (typeof slab == 'object') slab = '[' + slab.join(',') + ']';
1630
return 'allocate(' + slab + ', ' + types + (allocator ? ', ' + allocator : '') + (allocator == 'ALLOC_NONE' ? ', ' + ptr : '') + ')';
1633
function makeGetSlabs(ptr, type, allowMultiple, unsigned) {
1635
if (!USE_TYPED_ARRAYS) {
1637
} else if (USE_TYPED_ARRAYS == 1) {
1638
if (type in Runtime.FLOAT_TYPES || type === 'int64') { // XXX should be i64, no?
1639
return ['FHEAP']; // If USE_FHEAP is false, will fail at runtime. At compiletime we do need it for library stuff.
1640
} else if (type in Runtime.INT_TYPES || isPointerType(type)) {
1641
return [unsigned ? 'IHEAPU' : 'IHEAP'];
1643
assert(allowMultiple, 'Unknown slab type and !allowMultiple: ' + type);
1645
return ['IHEAP', 'FHEAP']; // unknown, so assign to both typed arrays
1650
} else { // USE_TYPED_ARRAYS == 2)
1651
if (isPointerType(type)) type = 'i32'; // Hardcoded 32-bit
1653
case 'i1': case 'i8': return [unsigned ? 'HEAPU8' : 'HEAP8']; break;
1654
case 'i16': return [unsigned ? 'HEAPU16' : 'HEAP16']; break;
1655
case 'i32': case 'i64': return [unsigned ? 'HEAPU32' : 'HEAP32']; break;
1657
if (TARGET_LE32) return ['HEAPF64']; // in le32, we do have the ability to assume 64-bit alignment
1658
// otherwise, fall through to float
1660
case 'float': return ['HEAPF32'];
1662
throw 'what, exactly, can we do for unknown types in TA2?! ' + new Error().stack;
1669
function checkBitcast(item) {
1670
// Warn about some types of casts, then fall through to the handling code below
1671
var oldType = item.params[0].type;
1672
var newType = item.type;
1673
if (isPossiblyFunctionType(oldType) && isPossiblyFunctionType(newType)) {
1674
var oldInfo = {}, newInfo = {};
1675
var oldCount = countNormalArgs(oldType, oldInfo);
1676
var newCount = countNormalArgs(newType, newInfo);
1678
function showWarning() {
1681
if (VERBOSE || ASM_JS) {
1682
warnOnce('Casting potentially incompatible function pointer ' + oldType + ' to ' + newType + ', for ' + item.params[0].ident.slice(1));
1684
warnOnce('Casting a function pointer type to a potentially incompatible one (use VERBOSE=1 to see more)');
1686
warnOnce('See https://github.com/kripken/emscripten/wiki/CodeGuidlinesAndLimitations#function-pointer-issues for more information on dangerous function pointer casts');
1687
if (ASM_JS) warnOnce('Incompatible function pointer casts are very dangerous with ASM_JS=1, you should investigate and correct these');
1689
if (oldCount != newCount && oldCount && newCount) showWarning();
1691
if (oldCount != newCount) showWarning();
1692
else if (!isIdenticallyImplemented(oldInfo.returnType, newInfo.returnType)) {
1695
for (var i = 0; i < oldCount; i++) {
1696
if (!isIdenticallyImplemented(oldInfo.segments[i][0].text, newInfo.segments[i][0].text)) {
1706
function finalizeLLVMFunctionCall(item, noIndexizeFunctions) {
1707
if (item.intertype == 'getelementptr') { // TODO finalizeLLVMParameter on the ident and the indexes?
1708
return makePointer(makeGetSlabs(item.ident, item.type)[0], getGetElementPtrIndexes(item), null, item.type);
1710
if (item.intertype == 'bitcast') checkBitcast(item);
1713
variant: item.variant,
1715
params: item.params.slice(0) // XXX slice?
1717
return processMathop(temp);
1720
function getGetElementPtrIndexes(item) {
1721
var type = item.params[0].type;
1722
if (USE_TYPED_ARRAYS == 2) {
1723
// GEP indexes are marked as i64s, but they are just numbers to us
1724
item.params.forEach(function(param) { param.type = 'i32' });
1726
item.params = item.params.map(finalizeLLVMParameter);
1727
var ident = item.params[0];
1729
// struct pointer, struct*, and getting a ptr to an element in that struct. Param 1 is which struct, then we have items in that
1730
// struct, and possibly further substructures, all embedded
1731
// can also be to 'blocks': [8 x i32]*, not just structs
1732
type = removePointing(type);
1733
var indexes = [makeGetPos(ident)];
1734
var offset = item.params[1];
1736
if (isStructType(type)) {
1737
indexes.push(getFastValue(Types.types[type].flatSize, '*', offset, 'i32'));
1739
indexes.push(getFastValue(Runtime.getNativeTypeSize(type), '*', offset, 'i32'));
1742
item.params.slice(2, item.params.length).forEach(function(arg) {
1744
// TODO: If index is constant, optimize
1745
var typeData = Types.types[type];
1746
if (isStructType(type) && typeData.needsFlattening) {
1747
if (typeData.flatFactor) {
1748
indexes.push(getFastValue(curr, '*', typeData.flatFactor, 'i32'));
1750
if (isNumber(curr)) {
1751
indexes.push(typeData.flatIndexes[curr]);
1753
indexes.push(toNiceIdent(type) + '___FLATTENER[' + curr + ']'); // TODO: If curr is constant, optimize out the flattener struct
1761
if (!isNumber(curr) || parseInt(curr) < 0) {
1762
// We have a *variable* to index with, or a negative number. In both
1763
// cases, in theory we might need to do something dynamic here. FIXME?
1764
// But, most likely all the possible types are the same, so do that case here now...
1765
for (var i = 1; i < typeData.fields.length; i++) {
1766
assert(typeData.fields[0] === typeData.fields[i]);
1770
type = typeData && typeData.fields[curr] ? typeData.fields[curr] : '';
1773
var ret = getFastValues(indexes, '+', 'i32');
1775
ret = handleOverflow(ret, 32); // XXX - we assume a 32-bit arch here. If you fail on this, change to 64
1780
function handleOverflow(text, bits) {
1781
// TODO: handle overflows of i64s
1782
if (!bits) return text;
1783
var correct = correctOverflows();
1784
warnOnce(!correct || bits <= 32, 'Cannot correct overflows of this many bits: ' + bits);
1785
if (CHECK_OVERFLOWS) return 'CHECK_OVERFLOW(' + text + ', ' + bits + ', ' + Math.floor(correctSpecificOverflow()) + ')';
1786
if (!correct) return text;
1788
return '((' + text + ')|0)';
1789
} else if (bits < 32) {
1790
return '((' + text + ')&' + (Math.pow(2, bits) - 1) + ')';
1792
return text; // We warned about this earlier
1796
function makeLLVMStruct(values) {
1797
if (USE_TYPED_ARRAYS == 2) {
1798
return 'DEPRECATED' + (new Error().stack) + 'XXX';
1800
return '{ ' + values.map(function(value, i) { return 'f' + i + ': ' + value }).join(', ') + ' }'
1804
function makeStructuralReturn(values, inAsm) {
1805
if (USE_TYPED_ARRAYS == 2) {
1807
return 'return ' + asmCoercion(values.slice(1).map(function(value) {
1809
return ASM_JS ? (inAsm ? 'tempRet' + i + ' = ' + value : 'asm.setTempRet' + i + '(' + value + ')')
1810
: 'tempRet' + i + ' = ' + value;
1811
}).concat([values[0]]).join(','), 'i32');
1814
return 'return { ' + values.map(function(value) {
1815
return 'f' + (i++) + ': ' + value;
1816
}).join(', ') + ' }';
1820
function makeStructuralAccess(ident, i) {
1821
if (USE_TYPED_ARRAYS == 2) {
1822
return ident + '$' + i;
1824
return ident + '.f' + i;
1828
function makeThrow(what) {
1829
return 'throw ' + what + (DISABLE_EXCEPTION_CATCHING == 1 ? ' + " - Exception catching is disabled, this exception cannot be caught. Compile with -s DISABLE_EXCEPTION_CATCHING=0 or DISABLE_EXCEPTION_CATCHING=2 to catch."' : '') + ';';
1832
// From parseLLVMSegment
1833
function finalizeLLVMParameter(param, noIndexizeFunctions) {
1835
if (isNumber(param)) {
1837
} else if (typeof param === 'string') {
1838
return toNiceIdentCarefully(param);
1839
} else if (param.intertype in PARSABLE_LLVM_FUNCTIONS) {
1840
ret = finalizeLLVMFunctionCall(param, noIndexizeFunctions);
1841
} else if (param.ident == 'zeroinitializer') {
1842
if (isStructType(param.type)) {
1843
return makeLLVMStruct(zeros(Types.types[param.type].fields.length));
1847
} else if (param.intertype == 'value') {
1849
if (ret in Variables.globals) {
1850
ret = makeGlobalUse(ret);
1852
if (param.type == 'i64' && USE_TYPED_ARRAYS == 2) {
1853
ret = parseI64Constant(ret);
1855
ret = parseNumerical(ret, param.type);
1856
ret = asmEnsureFloat(ret, param.type);
1857
} else if (param.intertype == 'structvalue') {
1858
ret = makeLLVMStruct(param.params.map(function(value) { return finalizeLLVMParameter(value, noIndexizeFunctions) }));
1859
} else if (param.intertype === 'blockaddress') {
1860
return finalizeBlockAddress(param);
1861
} else if (param.intertype === 'type') {
1862
return param.ident; // we don't really want the type here
1863
} else if (param.intertype == 'mathop') {
1864
return processMathop(param);
1866
throw 'invalid llvm parameter: ' + param.intertype;
1868
assert(param.type || (typeof param === 'string' && param.substr(0, 6) === 'CHECK_'), 'Missing type for param!');
1869
if (!noIndexizeFunctions) ret = indexizeFunctions(ret, param.type);
1873
function makeComparison(a, op, b, type) {
1875
if (!isIllegalType(type)) {
1876
return asmCoercion(a, type) + op + asmCoercion(b, type);
1878
assert(type == 'i64');
1879
return asmCoercion(a + '$0', 'i32') + op + asmCoercion(b + '$0', 'i32') + ' & ' +
1880
asmCoercion(a + '$1', 'i32') + op + asmCoercion(b + '$1', 'i32');
1884
function makeSignOp(value, type, op, force, ignore) {
1885
if (USE_TYPED_ARRAYS == 2 && type == 'i64') {
1886
return value; // these are always assumed to be two 32-bit unsigneds.
1889
if (isPointerType(type)) type = 'i32'; // Pointers are treated as 32-bit ints
1890
if (!value) return value;
1892
if (type in Runtime.INT_TYPES) {
1893
bits = parseInt(type.substr(1));
1894
full = op + 'Sign(' + value + ', ' + bits + ', ' + Math.floor(ignore || (correctSpecificSign())) + ')';
1895
// Always sign/unsign constants at compile time, regardless of CHECK/CORRECT
1896
if (isNumber(value)) {
1897
return eval(full).toString();
1900
if ((ignore || !correctSigns()) && !CHECK_SIGNS && !force) return value;
1901
if (type in Runtime.INT_TYPES) {
1903
if (!CHECK_SIGNS || ignore) {
1906
return '(' + getFastValue(value, '|', '0') + ')';
1909
return '(' + getFastValue(value, '>>>', '0') + ')';
1910
// Alternatively, we can consider the lengthier
1911
// return makeInlineCalculation('VALUE >= 0 ? VALUE : ' + Math.pow(2, bits) + ' + VALUE', value, 'tempBigInt');
1912
// which does not always turn us into a 32-bit *un*signed value
1914
} else if (bits < 32) {
1916
return makeInlineCalculation('(VALUE << ' + (32-bits) + ') >> ' + (32-bits), value, 'tempInt');
1918
return '(' + getFastValue(value, '&', Math.pow(2, bits)-1) + ')';
1920
} else { // bits > 32
1922
return makeInlineCalculation('VALUE >= ' + Math.pow(2, bits-1) + ' ? VALUE-' + Math.pow(2, bits) + ' : VALUE', value, 'tempBigIntS');
1924
return makeInlineCalculation('VALUE >= 0 ? VALUE : ' + Math.pow(2, bits) + '+VALUE', value, 'tempBigIntS');
1933
// @param floatConversion Means that we are receiving a float and rounding it to
1934
// an integer. We must be careful here, the input has *not*
1935
// already been converted to a signed/unsigned value (that
1936
// would already do rounding, before us!)
1937
function makeRounding(value, bits, signed, floatConversion) {
1938
// TODO: handle roundings of i64s
1941
// C rounds to 0 (-5.5 to -5, +5.5 to 5), while JS has no direct way to do that.
1942
if (bits <= 32 && signed) return '((' + value + ')&-1)'; // This is fast and even correct, for all cases. Note that it is the same
1943
// as |0, but &-1 hints to the js optimizer that this is a rounding correction
1944
// Do Math.floor, which is reasonably fast, if we either don't care, or if we can be sure
1945
// the value is non-negative
1946
if (!correctRoundings() || (!signed && !floatConversion)) return 'Math.floor(' + value + ')';
1947
// We are left with >32 bits signed, or a float conversion. Check and correct inline
1948
// Note that if converting a float, we may have the wrong sign at this point! But, we have
1949
// been rounded properly regardless, and we will be sign-corrected later when actually used, if
1951
return makeInlineCalculation(makeComparison('VALUE', '>=', '0', 'float') + ' ? Math.floor(VALUE) : Math.ceil(VALUE)', value, 'tempBigIntR');
1953
// asm.js mode, cleaner refactoring of this function as well. TODO: use in non-asm case, most of this
1954
if (floatConversion && bits <= 32) {
1955
return '(~~(' + value + '))'; // explicit float-to-int conversion
1960
return '((' + value + ')&-1)'; // &-1 (instead of |0) hints to the js optimizer that this is a rounding correction
1962
return '((' + value + ')>>>0)';
1965
// Math.floor is reasonably fast if we don't care about corrections (and even correct if unsigned)
1966
if (!correctRoundings() || !signed) return 'Math.floor(' + value + ')';
1967
// We are left with >32 bits
1968
return makeInlineCalculation(makeComparison('VALUE', '>=', '0', 'float') + ' ? Math.floor(VALUE) : Math.ceil(VALUE)', value, 'tempBigIntR');
1972
function makeIsNaN(value) {
1973
if (ASM_JS) return makeInlineCalculation('((VALUE) != (VALUE))', value, 'tempDouble');
1974
return 'isNaN(' + value + ')';
1977
// fptoui and fptosi are not in these, because we need to be careful about what we do there. We can't
1978
// just sign/unsign the input first.
1979
var UNSIGNED_OP = set('udiv', 'urem', 'uitofp', 'zext', 'lshr');
1980
var SIGNED_OP = set('sdiv', 'srem', 'sitofp', 'sext', 'ashr');
1982
function isUnsignedOp(op, variant) {
1983
return op in UNSIGNED_OP || (variant && variant[0] == 'u');
1985
function isSignedOp(op, variant) {
1986
return op in SIGNED_OP || (variant && variant[0] == 's');
1989
var legalizedI64s = USE_TYPED_ARRAYS == 2; // We do not legalize globals, but do legalize function lines. This will be true in the latter case
1991
function processMathop(item) {
1993
var variant = item.variant;
1994
var type = item.type;
1995
var paramTypes = ['', '', '', ''];
1997
for (var i = 0; i < 3; i++) {
1998
if (item.params[i]) {
1999
paramTypes[i] = item.params[i].type || type;
2000
idents[i] = finalizeLLVMParameter(item.params[i]);
2001
if (!isNumber(idents[i]) && !isNiceIdent(idents[i])) {
2002
idents[i] = '(' + idents[i] + ')'; // we may have nested expressions. So enforce the order of operations we want
2005
idents[i] = null; // just so it exists for purposes of reading idents[1] etc. later on, and no exception is thrown
2008
var originalIdents = idents.slice(0);
2009
if (isUnsignedOp(op, variant)) {
2010
idents[0] = makeSignOp(idents[0], paramTypes[0], 'un');
2011
idents[1] = makeSignOp(idents[1], paramTypes[1], 'un');
2012
} else if (isSignedOp(op, variant)) {
2013
idents[0] = makeSignOp(idents[0], paramTypes[0], 're');
2014
idents[1] = makeSignOp(idents[1], paramTypes[1], 're');
2017
if (item.type[0] === 'i') {
2018
bits = parseInt(item.type.substr(1));
2020
var bitsBefore = parseInt((item.params[0] ? item.params[0].type : item.type).substr(1)); // remove i to leave the number of bits left after this
2021
var bitsLeft = parseInt(((item.params[1] && item.params[1].ident) ? item.params[1].ident : item.type).substr(1)); // remove i to leave the number of bits left after this operation
2023
function integerizeBignum(value) {
2024
return makeInlineCalculation('VALUE-VALUE%1', value, 'tempBigIntI');
2027
if ((type == 'i64' || paramTypes[0] == 'i64' || paramTypes[1] == 'i64' || idents[1] == '(i64)') && USE_TYPED_ARRAYS == 2) {
2028
var warnI64_1 = function() {
2029
warnOnce('Arithmetic on 64-bit integers in mode 1 is rounded and flaky, like mode 0!');
2031
// In ops that can be either legalized or not, we need to differentiate how we access low and high parts
2032
var low1 = idents[0] + (legalizedI64s ? '$0' : '[0]');
2033
var high1 = idents[0] + (legalizedI64s ? '$1' : '[1]');
2034
var low2 = idents[1] + (legalizedI64s ? '$0' : '[0]');
2035
var high2 = idents[1] + (legalizedI64s ? '$1' : '[1]');
2036
function finish(result) {
2037
// If this is in legalization mode, steal the assign and assign into two vars
2038
if (legalizedI64s) {
2039
assert(item.assignTo);
2040
var ret = 'var ' + item.assignTo + '$0 = ' + result[0] + '; var ' + item.assignTo + '$1 = ' + result[1] + ';';
2041
item.assignTo = null;
2047
function i64PreciseOp(type, lastArg) {
2048
Types.preciseI64MathUsed = true;
2049
return finish(['(i64Math' + (ASM_JS ? '_' : '.') + type + '(' + asmCoercion(low1, 'i32') + ',' + asmCoercion(high1, 'i32') + ',' + asmCoercion(low2, 'i32') + ',' + asmCoercion(high2, 'i32') +
2050
(lastArg ? ',' + asmCoercion(+lastArg, 'i32') : '') + '),' + makeGetValue('tempDoublePtr', 0, 'i32') + ')', makeGetValue('tempDoublePtr', Runtime.getNativeTypeSize('i32'), 'i32')]);
2052
function preciseCall(name) {
2053
Types.preciseI64MathUsed = true;
2054
return finish([asmCoercion(name + '(' + low1 + ',' + high1 + ',' + low2 + ',' + high2 + ')', 'i32'), 'tempRet0']);
2056
function i64PreciseLib(type) {
2057
return preciseCall('_i64' + type[0].toUpperCase() + type.substr(1));
2060
// basic integer ops
2062
return '[' + idents[0] + '[0] | ' + idents[1] + '[0], ' + idents[0] + '[1] | ' + idents[1] + '[1]]';
2065
return '[' + idents[0] + '[0] & ' + idents[1] + '[0], ' + idents[0] + '[1] & ' + idents[1] + '[1]]';
2068
return '[' + idents[0] + '[0] ^ ' + idents[1] + '[0], ' + idents[0] + '[1] ^ ' + idents[1] + '[1]]';
2073
throw 'shifts should have been legalized!';
2075
case 'uitofp': case 'sitofp': return RuntimeGenerator.makeBigInt(low1, high1, op[0] == 'u');
2076
case 'fptoui': case 'fptosi': return finish(splitI64(idents[0], true));
2079
case 'uge': return '((' + high1 + '>>>0) >= (' + high2 + '>>>0)) & ((((' + high1 + '>>>0) > (' + high2 + '>>>0)) | ' +
2080
'(' + low1 + '>>>0) >= (' + low2 + '>>>0)))';
2081
case 'sge': return '((' + high1 + '|0) >= (' + high2 + '|0)) & ((((' + high1 + '|0) > (' + high2 + '|0)) | ' +
2082
'(' + low1 + '>>>0) >= (' + low2 + '>>>0)))';
2083
case 'ule': return '((' + high1 + '>>>0) <= (' + high2 + '>>>0)) & ((((' + high1 + '>>>0) < (' + high2 + '>>>0)) | ' +
2084
'(' + low1 + '>>>0) <= (' + low2 + '>>>0)))';
2085
case 'sle': return '((' + high1 + '|0) <= (' + high2 + '|0)) & ((((' + high1 + '|0) < (' + high2 + '|0)) | ' +
2086
'(' + low1 + '>>>0) <= (' + low2 + '>>>0)))';
2087
case 'ugt': return '((' + high1 + '>>>0) > (' + high2 + '>>>0)) | ((((' + high1 + '>>>0) == (' + high2 + '>>>0) & ' +
2088
'(' + low1 + '>>>0) > (' + low2 + '>>>0))))';
2089
case 'sgt': return '((' + high1 + '|0) > (' + high2 + '|0)) | ((((' + high1 + '|0) == (' + high2 + '|0) & ' +
2090
'(' + low1 + '>>>0) > (' + low2 + '>>>0))))';
2091
case 'ult': return '((' + high1 + '>>>0) < (' + high2 + '>>>0)) | ((((' + high1 + '>>>0) == (' + high2 + '>>>0) & ' +
2092
'(' + low1 + '>>>0) < (' + low2 + '>>>0))))';
2093
case 'slt': return '((' + high1 + '|0) < (' + high2 + '|0)) | ((((' + high1 + '|0) == (' + high2 + '|0) & ' +
2094
'(' + low1 + '>>>0) < (' + low2 + '>>>0))))';
2095
case 'ne': return '((' + low1 + '|0) != (' + low2 + '|0)) | ((' + high1 + '|0) != (' + high2 + '|0))';
2096
case 'eq': return '((' + low1 + '|0) == (' + low2 + '|0)) & ((' + high1 + '|0) == (' + high2 + '|0))';
2097
default: throw 'Unknown icmp variant: ' + variant;
2100
case 'zext': return makeI64(idents[0], 0);
2101
case 'sext': return makeInlineCalculation(makeI64('VALUE', 'VALUE<0 ? 4294967295 : 0'), idents[0], 'tempBigIntD');
2103
return '((' + idents[0] + '[0]) & ' + (Math.pow(2, bitsLeft)-1) + ')';
2105
case 'select': return idents[0] + ' ? ' + makeCopyI64(idents[1]) + ' : ' + makeCopyI64(idents[2]);
2106
case 'ptrtoint': return makeI64(idents[0], 0);
2107
case 'inttoptr': return '(' + idents[0] + '[0])'; // just directly truncate the i64 to a 'pointer', which is an i32
2108
// Dangerous, rounded operations. TODO: Fully emulate
2110
if (PRECISE_I64_MATH) {
2111
return i64PreciseLib('add');
2114
return finish(splitI64(mergeI64(idents[0]) + '+' + mergeI64(idents[1]), true));
2118
if (PRECISE_I64_MATH) {
2119
return i64PreciseLib('subtract');
2122
return finish(splitI64(mergeI64(idents[0]) + '-' + mergeI64(idents[1]), true));
2125
case 'sdiv': case 'udiv': {
2126
if (PRECISE_I64_MATH) {
2127
return preciseCall(op[0] === 'u' ? '___udivdi3' : '___divdi3');
2130
return finish(splitI64(makeRounding(mergeI64(idents[0], op[0] === 'u') + '/' + mergeI64(idents[1], op[0] === 'u'), bits, op[0] === 's'), true));
2134
if (PRECISE_I64_MATH) {
2135
return preciseCall('___muldi3');
2138
return finish(splitI64(mergeI64(idents[0], op[0] === 'u') + '*' + mergeI64(idents[1], op[0] === 'u'), true));
2141
case 'urem': case 'srem': {
2142
if (PRECISE_I64_MATH) {
2143
return preciseCall(op[0] === 'u' ? '___uremdi3' : '___remdi3');
2146
return finish(splitI64(mergeI64(idents[0], op[0] === 'u') + '%' + mergeI64(idents[1], op[0] === 'u'), true));
2150
// Pointers are not 64-bit, so there is really only one possible type of bitcast here, int to float or vice versa
2151
assert(USE_TYPED_ARRAYS == 2, 'Can only bitcast ints <-> floats with typed arrays mode 2');
2152
var inType = item.params[0].type;
2153
var outType = item.type;
2154
if (inType in Runtime.INT_TYPES && outType in Runtime.FLOAT_TYPES) {
2155
if (legalizedI64s) {
2156
return '(' + makeSetTempDouble(0, 'i32', idents[0] + '$0') + ', ' + makeSetTempDouble(1, 'i32', idents[0] + '$1') + ', ' + makeGetTempDouble(0, 'double') + ')';
2158
return makeInlineCalculation(makeSetTempDouble(0, 'i32', 'VALUE[0]') + ',' + makeSetTempDouble(1, 'i32', 'VALUE[1]') + ',' + makeGetTempDouble(0, 'double'), idents[0], 'tempI64');
2160
} else if (inType in Runtime.FLOAT_TYPES && outType in Runtime.INT_TYPES) {
2161
if (legalizedI64s) {
2162
return makeSetTempDouble(0, 'double', idents[0]) + '; ' + finish([makeGetTempDouble(0, 'i32'), makeGetTempDouble(1, 'i32')]);
2164
return '(' + makeSetTempDouble(0, 'double', idents[0]) + ',[' + makeGetTempDouble(0, 'i32') + ',' + makeGetTempDouble(1, 'i32') + '])';
2167
throw 'Invalid USE_TYPED_ARRAYS == 2 bitcast: ' + dump(item) + ' : ' + item.params[0].type;
2170
default: throw 'Unsupported i64 mode 1 op: ' + item.op + ' : ' + dump(item);
2175
// basic integer ops
2176
case 'add': return handleOverflow(getFastValue(idents[0], '+', idents[1], item.type), bits);
2177
case 'sub': return handleOverflow(getFastValue(idents[0], '-', idents[1], item.type), bits);
2178
case 'sdiv': case 'udiv': return makeRounding(getFastValue(idents[0], '/', idents[1], item.type), bits, op[0] === 's');
2179
case 'mul': return getFastValue(idents[0], '*', idents[1], item.type); // overflow handling is already done in getFastValue for '*'
2180
case 'urem': case 'srem': return getFastValue(idents[0], '%', idents[1], item.type);
2183
assert(bits === 64, 'Too many bits for or: ' + bits);
2184
dprint('Warning: 64 bit OR - precision limit may be hit on llvm line ' + item.lineNum);
2185
return 'Runtime.or64(' + idents[0] + ', ' + idents[1] + ')';
2187
return idents[0] + ' | ' + idents[1];
2191
assert(bits === 64, 'Too many bits for and: ' + bits);
2192
dprint('Warning: 64 bit AND - precision limit may be hit on llvm line ' + item.lineNum);
2193
return 'Runtime.and64(' + idents[0] + ', ' + idents[1] + ')';
2195
return idents[0] + ' & ' + idents[1];
2199
assert(bits === 64, 'Too many bits for xor: ' + bits);
2200
dprint('Warning: 64 bit XOR - precision limit may be hit on llvm line ' + item.lineNum);
2201
return 'Runtime.xor64(' + idents[0] + ', ' + idents[1] + ')';
2203
return idents[0] + ' ^ ' + idents[1];
2206
if (bits > 32) return idents[0] + '*' + getFastValue(2, 'pow', idents[1]);
2207
return idents[0] + ' << ' + idents[1];
2210
if (bits > 32) return integerizeBignum(idents[0] + '/' + getFastValue(2, 'pow', idents[1]));
2211
if (bits === 32) return originalIdents[0] + ' >> ' + idents[1]; // No need to reSign in this case
2212
return idents[0] + ' >> ' + idents[1];
2215
if (bits > 32) return integerizeBignum(idents[0] + '/' + getFastValue(2, 'pow', idents[1]));
2216
if (bits === 32) return originalIdents[0] + ' >>> ' + idents[1]; // No need to unSign in this case
2217
return idents[0] + ' >>> ' + idents[1];
2220
case 'fadd': return getFastValue(idents[0], '+', idents[1], item.type);
2221
case 'fsub': return getFastValue(idents[0], '-', idents[1], item.type);
2222
case 'fdiv': return getFastValue(idents[0], '/', idents[1], item.type);
2223
case 'fmul': return getFastValue(idents[0], '*', idents[1], item.type);
2224
case 'frem': return getFastValue(idents[0], '%', idents[1], item.type);
2225
case 'uitofp': case 'sitofp': return asmCoercion(idents[0], 'double', op[0]);
2226
case 'fptoui': case 'fptosi': return makeRounding(idents[0], bitsLeft, op === 'fptosi', true);
2228
// TODO: We sometimes generate false instead of 0, etc., in the *cmps. It seemed slightly faster before, but worth rechecking
2229
// Note that with typed arrays, these become 0 when written. So that is a potential difference with non-typed array runs.
2232
case 'uge': case 'sge': return idents[0] + ' >= ' + idents[1];
2233
case 'ule': case 'sle': return idents[0] + ' <= ' + idents[1];
2234
case 'ugt': case 'sgt': return idents[0] + ' > ' + idents[1];
2235
case 'ult': case 'slt': return idents[0] + ' < ' + idents[1];
2236
// We use loose comparisons, which allows false == 0 to be true, etc. Ditto in fcmp
2237
case 'ne': case 'eq': {
2238
// We must sign them, so we do not compare -1 to 255 (could have unsigned them both too)
2239
// since LLVM tells us if <=, >= etc. comparisons are signed, but not == and !=.
2240
idents[0] = makeSignOp(idents[0], paramTypes[0], 're');
2241
idents[1] = makeSignOp(idents[1], paramTypes[1], 're');
2242
return idents[0] + (variant === 'eq' ? '==' : '!=') + idents[1];
2244
default: throw 'Unknown icmp variant: ' + variant;
2249
// TODO 'o' ones should be 'ordered (no NaN) and',
2250
// 'u' ones should be 'unordered or'.
2251
case 'uge': case 'oge': return idents[0] + ' >= ' + idents[1];
2252
case 'ule': case 'ole': return idents[0] + ' <= ' + idents[1];
2253
case 'ugt': case 'ogt': return idents[0] + ' > ' + idents[1];
2254
case 'ult': case 'olt': return idents[0] + ' < ' + idents[1];
2255
case 'une': case 'one': return idents[0] + ' != ' + idents[1];
2256
case 'ueq': case 'oeq': return idents[0] + ' == ' + idents[1];
2257
case 'ord': return '!' + makeIsNaN(idents[0]) + ' & !' + makeIsNaN(idents[1]);
2258
case 'uno': return makeIsNaN(idents[0]) + ' | ' + makeIsNaN(idents[1]);
2259
case 'true': return '1';
2260
default: throw 'Unknown fcmp variant: ' + variant;
2263
// Note that zext has sign checking, see above. We must guard against -33 in i8 turning into -33 in i32
2264
// then unsigning that i32... which would give something huge.
2266
if (EXPLICIT_ZEXT && bitsBefore == 1 && bitsLeft > 1) {
2267
return '(' + originalIdents[0] + '?1:0)'; // explicit bool-to-int conversion, work around v8 issue 2513
2270
// otherwise, fall through
2272
case 'fpext': case 'sext': return idents[0];
2273
case 'fptrunc': return idents[0];
2274
case 'select': return idents[0] + ' ? ' + asmEnsureFloat(idents[1], item.type) + ' : ' + asmEnsureFloat(idents[2], item.type);
2275
case 'ptrtoint': case 'inttoptr': {
2277
if (QUANTUM_SIZE == 1) {
2278
warnOnce('.ll contains ptrtoint and/or inttoptr. These may be dangerous in QUANTUM == 1. ' +
2279
'The safest thing is to investigate every appearance, and modify the source code to avoid this. ' +
2280
'Emscripten will print a list of the .ll lines, and also annotate the .js.');
2281
dprint(' ' + op + ' on .ll line ' + item.lineNum);
2282
idents[0] += ' /* Warning: ' + op + ', .ll line ' + item.lineNum + ' */';
2284
if (op == 'inttoptr' || bitsLeft >= 32) return idents[0];
2285
// For ptrtoint and <32 bits, fall through into trunc since we need to truncate here
2288
// Unlike extending, which we just 'do' (by doing nothing),
2289
// truncating can change the number, e.g. by truncating to an i1
2290
// in order to get the first bit
2291
assert(bitsLeft <= 32, 'Cannot truncate to more than 32 bits, since we use a native & op');
2292
return '((' + idents[0] + ') & ' + (Math.pow(2, bitsLeft)-1) + ')';
2295
// Most bitcasts are no-ops for us. However, the exception is int to float and float to int
2296
var inType = item.params[0].type;
2297
var outType = item.type;
2298
if ((inType in Runtime.INT_TYPES && outType in Runtime.FLOAT_TYPES) ||
2299
(inType in Runtime.FLOAT_TYPES && outType in Runtime.INT_TYPES)) {
2300
assert(USE_TYPED_ARRAYS == 2, 'Can only bitcast ints <-> floats with typed arrays mode 2');
2301
if (inType in Runtime.INT_TYPES) {
2302
return '(' + makeSetTempDouble(0, 'i32', idents[0]) + ',' + makeGetTempDouble(0, 'float') + ')';
2304
return '(' + makeSetTempDouble(0, 'float', idents[0]) + ',' + makeGetTempDouble(0, 'i32') + ')';
2309
default: throw 'Unknown mathcmp op: ' + item.op;
2313
// Walks through some intertype data, calling a function at every item. If
2314
// the function returns true, will stop the walk.
2315
// TODO: Use this more in analyzer, possibly also in jsifier
2316
function walkInterdata(item, pre, post, obj) {
2317
if (!item || !item.intertype) return false;
2318
if (pre && pre(item, obj)) return true;
2319
var originalObj = obj;
2320
if (obj && obj.replaceWith) obj = obj.replaceWith; // allow pre to replace the object we pass to all its children
2321
if (item.value && walkInterdata(item.value, pre, post, obj)) return true;
2322
// TODO if (item.pointer && walkInterdata(item.pointer, pre, post, obj)) return true;
2323
if (item.dependent && walkInterdata(item.dependent, pre, post, obj)) return true;
2326
for (i = 0; i <= item.params.length; i++) {
2327
if (walkInterdata(item.params[i], pre, post, obj)) return true;
2330
if (item.possibleVars) { // other attributes that might contain interesting data; here, variables
2331
var box = { intertype: 'value', ident: '' };
2332
for (i = 0; i <= item.possibleVars.length; i++) {
2333
box.ident = item[item.possibleVars[i]];
2334
if (walkInterdata(box, pre, post, obj)) return true;
2337
return post && post(item, originalObj, obj);
2340
// Separate from walkInterdata so that the former is as fast as possible
2341
// If the callback returns a value, we replace the current item with that
2342
// value, and do *not* walk the children.
2343
function walkAndModifyInterdata(item, pre) {
2344
if (!item || !item.intertype) return false;
2345
var ret = pre(item);
2346
if (ret) return ret;
2348
if (item.value && (repl = walkAndModifyInterdata(item.value, pre))) item.value = repl;
2349
if (item.pointer && (repl = walkAndModifyInterdata(item.pointer, pre))) item.pointer = repl;
2350
if (item.dependent && (repl = walkAndModifyInterdata(item.dependent, pre))) item.dependent = repl;
2352
for (var i = 0; i <= item.params.length; i++) {
2353
if (repl = walkAndModifyInterdata(item.params[i], pre)) item.params[i] = repl;
2356
// Ignore possibleVars because we can't replace them anyhow
2359
function parseBlockAddress(segment) {
2360
return { intertype: 'blockaddress', func: toNiceIdent(segment[2].item.tokens[0].text), label: toNiceIdent(segment[2].item.tokens[2].text), type: 'i32' };
2363
function finalizeBlockAddress(param) {
2364
return '{{{ BA_' + param.func + '|' + param.label + ' }}}'; // something python will replace later
2367
function stripCorrections(param) {
2370
if (m = /^\((.*)\)$/.exec(param)) {
2374
if (m = /^\(([$_\w]+)\)&\d+$/.exec(param)) {
2378
if (m = /^\(([$_\w()]+)\)\|0$/.exec(param)) {
2382
if (m = /^\(([$_\w()]+)\)\>>>0$/.exec(param)) {
2386
if (m = /CHECK_OVERFLOW\(([^,)]*),.*/.exec(param)) {
2395
function getImplementationType(varInfo) {
2396
if (varInfo.impl == 'nativized') {
2397
return removePointing(varInfo.type);
2399
return varInfo.type;
2402
function charCode(char) {
2403
return char.charCodeAt(0);
2406
function getTypeFromHeap(suffix) {
2408
case '8': return 'i8';
2409
case '16': return 'i16';
2410
case '32': return 'i32';
2411
case 'F32': return 'float';
2412
case 'F64': return 'double';
2413
default: throw 'getTypeFromHeap? ' + suffix;
2417
// Generates code that prints without printf(), but just putchar (so can be directly inline in asm.js)
2418
function makePrintChars(s, sep) {
2421
for (var i = 0; i < s.length; i++) {
2422
ret += '_putchar(' + s.charCodeAt(i) + ')' + sep;
2424
ret += '_putchar(10)';