~ubuntu-branches/ubuntu/vivid/emscripten/vivid

« back to all changes in this revision

Viewing changes to src/parseTools.js

  • Committer: Package Import Robot
  • Author(s): Sylvestre Ledru
  • Date: 2013-05-02 13:11:51 UTC
  • Revision ID: package-import@ubuntu.com-20130502131151-q8dvteqr1ef2x7xz
Tags: upstream-1.4.1~20130504~adb56cb
ImportĀ upstreamĀ versionĀ 1.4.1~20130504~adb56cb

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
//"use strict";
 
2
 
 
3
// Various tools for parsing LLVM. Utilities of various sorts, that are
 
4
// specific to Emscripten (and hence not in utility.js).
 
5
 
 
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);
 
11
    var ret = eval(str);
 
12
    return ret ? ret.toString() : '';
 
13
  });
 
14
}
 
15
 
 
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');
 
20
  var ret = '';
 
21
  var showStack = [];
 
22
  for (var i = 0; i < lines.length; i++) {
 
23
    var line = lines[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'
 
26
    }
 
27
    if (!line[0] || line[0] != '#') {
 
28
      if (showStack.indexOf(false) == -1) {
 
29
        ret += line + '\n';
 
30
      }
 
31
    } else {
 
32
      if (line[1] && line[1] == 'i') { // if
 
33
        var parts = line.split(' ');
 
34
        var ident = parts[1];
 
35
        var op = parts[2];
 
36
        var value = parts[3];
 
37
        if (op) {
 
38
          assert(op === '==')
 
39
          showStack.push(ident in this && this[ident] == value);
 
40
        } else {
 
41
          showStack.push(ident in this && this[ident] > 0);
 
42
        }
 
43
      } else if (line[2] && line[2] == 'l') { // else
 
44
        showStack.push(!showStack.pop());
 
45
      } else if (line[2] && line[2] == 'n') { // endif
 
46
        showStack.pop();
 
47
      } else {
 
48
        throw "Unclear preprocessor command: " + line;
 
49
      }
 
50
    }
 
51
  }
 
52
  assert(showStack.length == 0);
 
53
  return ret;
 
54
}
 
55
 
 
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));
 
61
}
 
62
 
 
63
function pointingLevels(type) {
 
64
  if (!type) return 0;
 
65
  var ret = 0;
 
66
  var len1 = type.length - 1;
 
67
  while (type[len1-ret] && type[len1-ret] === '*') {
 
68
    ret++;
 
69
  }
 
70
  return ret;
 
71
}
 
72
 
 
73
function removeAllPointing(type) {
 
74
  return removePointing(type, pointingLevels(type));
 
75
}
 
76
 
 
77
function toNiceIdent(ident) {
 
78
  assert(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, '_');
 
83
}
 
84
 
 
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);
 
94
  return ident;
 
95
}
 
96
 
 
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) {
 
100
  if (loose) {
 
101
    return /^\(?[$_]+[\w$_\d ]*\)?$/.test(ident);
 
102
  } else {
 
103
    return /^[$_]+[\w$_\d]*$/.test(ident);
 
104
  }
 
105
}
 
106
 
 
107
function isJSVar(ident) {
 
108
  return /^\(?[$_]?[\w$_\d ]*\)+$/.test(ident);
 
109
 
 
110
}
 
111
 
 
112
function isLocalVar(ident) {
 
113
  return ident[0] == '$';
 
114
}
 
115
 
 
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] == '%';
 
126
}
 
127
 
 
128
function isPointerType(type) {
 
129
  return type[type.length-1] == '*';
 
130
}
 
131
 
 
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] == '%';
 
138
}
 
139
 
 
140
function isStructuralType(type) {
 
141
  return /^{ ?[^}]* ?}$/.test(type); // { i32, i8 } etc. - anonymous struct types
 
142
}
 
143
 
 
144
function getStructuralTypeParts(type) { // split { i32, i8 } etc. into parts
 
145
  return type.replace(/[ {}]/g, '').split(',');
 
146
}
 
147
 
 
148
function getStructureTypeParts(type) {
 
149
  if (isStructuralType(type)) {
 
150
    return type.replace(/[ {}]/g, '').split(',');
 
151
  } else {
 
152
    var typeData = Types.types[type];
 
153
    assert(typeData, type);
 
154
    return typeData.fields;
 
155
  }
 
156
}
 
157
 
 
158
function getStructuralTypePartBits(part) {
 
159
  return Math.ceil((getBits(part) || 32)/32)*32; // simple 32-bit alignment. || 32 is for pointers
 
160
}
 
161
 
 
162
function isIntImplemented(type) {
 
163
  return type[0] == 'i' || isPointerType(type);
 
164
}
 
165
 
 
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;
 
169
  if (!type) return 0;
 
170
  if (type[0] == 'i') {
 
171
    var left = type.substr(1);
 
172
    if (!isNumber(left)) return 0;
 
173
    return parseInt(left);
 
174
  }
 
175
  if (isStructuralType(type)) {
 
176
    return sum(getStructuralTypeParts(type).map(getStructuralTypePartBits));
 
177
  }
 
178
  if (isStructType(type)) {
 
179
    var typeData = Types.types[type];
 
180
    if (typeData === undefined) return 0;
 
181
    return typeData.flatSize*8;
 
182
  }
 
183
  return 0;
 
184
}
 
185
 
 
186
function getNumIntChunks(type) {
 
187
  return Math.ceil(getBits(type, true)/32);
 
188
}
 
189
 
 
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);
 
195
}
 
196
 
 
197
function isIllegalType(type) {
 
198
  var bits = getBits(type);
 
199
  return bits > 0 && (bits >= 64 || !isPowerOfTwo(bits));
 
200
}
 
201
 
 
202
function isVoidType(type) {
 
203
  return type == 'void';
 
204
}
 
205
 
 
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) != ')')
 
211
    return false;
 
212
  if (nonPointing === '()') return true;
 
213
  if (!token.item) return false;
 
214
  var fail = 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 == '...');
 
219
  });
 
220
  if (out) {
 
221
    out.segments = segments;
 
222
    out.numArgs = segments.length;
 
223
  }
 
224
  return !fail;
 
225
}
 
226
 
 
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] == '*';
 
231
}
 
232
 
 
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('(');
 
240
  var returnType;
 
241
  if (firstOpen == lastOpen) {
 
242
    returnType = getReturnType(type);
 
243
    if (!isType(returnType)) return false;
 
244
  } else {
 
245
    returnType = 'i8*'; // some pointer type, no point in analyzing further
 
246
  }
 
247
  if (out) out.returnType = returnType;
 
248
  // find ( that starts the arguments
 
249
  var depth = 0, i = type.length-1, argText = null;
 
250
  while (i >= 0) {
 
251
    var curr = type[i];
 
252
    if (curr == ')') depth++;
 
253
    else if (curr == '(') {
 
254
      depth--;
 
255
      if (depth == 0) {
 
256
        argText = type.substr(i);
 
257
        break;
 
258
      }
 
259
    }
 
260
    i--;
 
261
  }
 
262
  assert(argText);
 
263
  return isFunctionDef({ text: argText, item: tokenize(argText.substr(1, argText.length-2), true) }, out);
 
264
}
 
265
 
 
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('(');
 
269
  if (lastOpen > 0) {
 
270
    return type.substr(0, lastOpen-1);
 
271
  }
 
272
  return type;
 
273
}
 
274
 
 
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;
 
280
  return ret;
 
281
}
 
282
 
 
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;
 
287
}
 
288
 
 
289
function countNormalArgs(type, out) {
 
290
  out = out || {};
 
291
  if (!isFunctionType(type, out)) return -1;
 
292
  if (isVarArgsFunctionType(type)) out.numArgs--;
 
293
  return out.numArgs;
 
294
}
 
295
 
 
296
function addIdent(token) {
 
297
  token.ident = token.text;
 
298
  return token;
 
299
}
 
300
 
 
301
function combineTokens(tokens) {
 
302
  var ret = {
 
303
    lineNum: tokens[0].lineNum,
 
304
    text: '',
 
305
    tokens: []
 
306
  };
 
307
  tokens.forEach(function(token) {
 
308
    ret.text += token.text;
 
309
    ret.tokens.push(token);
 
310
  });
 
311
  return ret;
 
312
}
 
313
 
 
314
function compareTokens(a, b) {
 
315
  var aId = a.__uid__;
 
316
  var bId = b.__uid__;
 
317
  a.__uid__ = 0;
 
318
  b.__uid__ = 0;
 
319
  var ret = JSON.stringify(a) == JSON.stringify(b);
 
320
  a.__uid__ = aId;
 
321
  b.__uid__ = bId;
 
322
  return ret;
 
323
}
 
324
 
 
325
function getTokenIndexByText(tokens, text) {
 
326
  var i = 0;
 
327
  while (tokens[i] && tokens[i].text != text) i++;
 
328
  return i;
 
329
}
 
330
 
 
331
function findTokenText(item, text) {
 
332
  return findTokenTextAfter(item, text, 0);
 
333
}
 
334
 
 
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;
 
338
  }
 
339
  return -1;
 
340
}
 
341
 
 
342
var SPLIT_TOKEN_LIST_SPLITTERS = set(',', 'to'); // 'to' can separate parameters as well...
 
343
 
 
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:','});
 
349
  var ret = [];
 
350
  var seg = [];
 
351
  for (var i = 0; i < tokens.length; i++) {
 
352
    var token = tokens[i];
 
353
    if (token.text in SPLIT_TOKEN_LIST_SPLITTERS) {
 
354
      ret.push(seg);
 
355
      seg = [];
 
356
    } else if (token.text == ';') {
 
357
      ret.push(seg);
 
358
      break;
 
359
    } else {
 
360
      seg.push(token);
 
361
    }
 
362
  }
 
363
  return ret;
 
364
}
 
365
 
 
366
function parseParamTokens(params) {
 
367
  if (params.length === 0) return [];
 
368
  var ret = [];
 
369
  if (params[params.length-1].text != ',') {
 
370
    params.push({ text: ',' });
 
371
  }
 
372
  var anonymousIndex = 0;
 
373
  while (params.length > 0) {
 
374
    var i = 0;
 
375
    while (params[i].text != ',') i++;
 
376
    var segment = params.slice(0, i);
 
377
    params = params.slice(i+1);
 
378
    segment = cleanSegment(segment);
 
379
    var byVal = 0;
 
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);
 
388
      }
 
389
    }
 
390
    if (segment.length == 1) {
 
391
      if (segment[0].text == '...') {
 
392
        ret.push({
 
393
          intertype: 'varargs',
 
394
          type: 'i8*',
 
395
          ident: 'varrp' // the conventional name we have for this
 
396
        });
 
397
      } else {
 
398
        // Clang sometimes has a parameter with just a type,
 
399
        // no name... the name is implied to be %{the index}
 
400
        ret.push({
 
401
          intertype: 'value',
 
402
          type: segment[0].text,
 
403
          ident: toNiceIdent('%') + anonymousIndex
 
404
        });
 
405
        Types.needAnalysis[ret[ret.length-1].type] = 0;
 
406
        anonymousIndex ++;
 
407
      }
 
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));
 
412
    } else {
 
413
      if (segment[2] && segment[2].text == 'to') { // part of bitcast params
 
414
        segment = segment.slice(0, 2);
 
415
      }
 
416
      while (segment.length > 2) {
 
417
        segment[0].text += segment[1].text;
 
418
        segment.splice(1, 1); // TODO: merge tokens nicely
 
419
      }
 
420
      ret.push({
 
421
        intertype: 'value',
 
422
        type: segment[0].text,
 
423
        ident: toNiceIdent(parseNumerical(segment[1].text, segment[0].text))
 
424
      });
 
425
      Types.needAnalysis[removeAllPointing(ret[ret.length-1].type)] = 0;
 
426
    }
 
427
    ret[ret.length-1].byVal = byVal;
 
428
  }
 
429
  return ret;
 
430
}
 
431
 
 
432
function hasVarArgs(params) {
 
433
  for (var i = 0; i < params.length; i++) {
 
434
    if (params[i].intertype == 'varargs') {
 
435
      return true;
 
436
    }
 
437
  }
 
438
  return false;
 
439
}
 
440
 
 
441
var UNINDEXABLE_GLOBALS = set(
 
442
  '_llvm_global_ctors' // special-cased
 
443
);
 
444
 
 
445
function isIndexableGlobal(ident) {
 
446
  if (!(ident in Variables.globals)) return false;
 
447
  if (ident in UNINDEXABLE_GLOBALS) {
 
448
    Variables.globals[ident].unIndexable = true;
 
449
    return false;
 
450
  }
 
451
  var data = Variables.globals[ident];
 
452
  return !data.alias && !data.external;
 
453
}
 
454
 
 
455
function makeGlobalDef(ident) {
 
456
  if (!NAMED_GLOBALS && isIndexableGlobal(ident)) return '';
 
457
  return 'var ' + ident + ';';
 
458
}
 
459
 
 
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;
 
466
      return ident;
 
467
    }
 
468
    // We know and assert on TOTAL_STACK being equal to GLOBAL_BASE
 
469
    return (TOTAL_STACK + index).toString();
 
470
  }
 
471
  return ident;
 
472
}
 
473
 
 
474
function sortGlobals(globals) {
 
475
  var ks = keys(globals);
 
476
  ks.sort();
 
477
  var inv = invertArray(ks);
 
478
  return values(globals).sort(function(a, b) {
 
479
    return inv[b.ident] - inv[a.ident];
 
480
  });
 
481
}
 
482
 
 
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') {
 
489
    return param.ident;
 
490
  } else {
 
491
    if (param.type == 'i64' && USE_TYPED_ARRAYS == 2) {
 
492
      return parseI64Constant(param.ident);
 
493
    }
 
494
    var ret = toNiceIdent(param.ident);
 
495
    if (ret in Variables.globals) {
 
496
      ret = makeGlobalUse(ret);
 
497
    }
 
498
    return ret;
 
499
  }
 
500
}
 
501
 
 
502
// Segment ==> Parameter
 
503
function parseLLVMSegment(segment) {
 
504
  var type;
 
505
  if (segment.length == 1) {
 
506
    if (isType(segment[0].text)) {
 
507
      Types.needAnalysis[segment[0].text] = 0;
 
508
      return {
 
509
        intertype: 'type',
 
510
        ident: toNiceIdent(segment[0].text),
 
511
        type: segment[0].text
 
512
      };
 
513
    } else {
 
514
      return {
 
515
        intertype: 'value',
 
516
        ident: toNiceIdent(segment[0].text),
 
517
        type: 'i32'
 
518
      };
 
519
    }
 
520
  } else if (segment[1].type && segment[1].type == '{') {
 
521
    type = segment[0].text;
 
522
    Types.needAnalysis[type] = 0;
 
523
    return {
 
524
      intertype: 'structvalue',
 
525
      params: splitTokenList(segment[1].tokens).map(parseLLVMSegment),
 
526
      type: type
 
527
    };
 
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);
 
534
  } else {
 
535
    type = segment[0].text;
 
536
    Types.needAnalysis[type] = 0;
 
537
    return {
 
538
      intertype: 'value',
 
539
      ident: toNiceIdent(segment[1].text),
 
540
      type: type
 
541
    };
 
542
  }
 
543
}
 
544
 
 
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);
 
548
  }
 
549
  return segment;
 
550
}
 
551
 
 
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']);
 
553
 
 
554
var PARSABLE_LLVM_FUNCTIONS = set('getelementptr', 'bitcast');
 
555
mergeInto(PARSABLE_LLVM_FUNCTIONS, MATHOPS);
 
556
 
 
557
// Parses a function call of form
 
558
//         TYPE functionname MODIFIERS (...)
 
559
// e.g.
 
560
//         i32* getelementptr inbounds (...)
 
561
function parseLLVMFunctionCall(segment) {
 
562
  segment = segment.slice(0);
 
563
  segment = cleanSegment(segment);
 
564
  // Remove additional modifiers
 
565
  var variant = null;
 
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
 
569
  }
 
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!';
 
575
  }
 
576
  var intertype = segment[1].text;
 
577
  var type = segment[0].text;
 
578
  if (type === '?') {
 
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;
 
583
    }
 
584
  }
 
585
  var ret = {
 
586
    intertype: intertype,
 
587
    variant: variant,
 
588
    type: type,
 
589
    params: parseParamTokens(segment[2].item.tokens)
 
590
  };
 
591
  Types.needAnalysis[ret.type] = 0;
 
592
  ret.ident = toNiceIdent(ret.params[0].ident || 'NOIDENT');
 
593
  return ret;
 
594
}
 
595
 
 
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
 
600
// we ate.
 
601
function eatLLVMIdent(tokens) {
 
602
  var ret;
 
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);
 
606
    ret = item.ident;
 
607
    tokens.shift();
 
608
    tokens.shift();
 
609
  } else {
 
610
    ret = tokens[0].text;
 
611
    tokens.shift();
 
612
  }
 
613
  return ret;
 
614
}
 
615
 
 
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);
 
622
    }
 
623
  }
 
624
}
 
625
 
 
626
function _IntToHex(x) {
 
627
  assert(x >= 0 && x <= 15);
 
628
  if (x <= 9) {
 
629
    return String.fromCharCode('0'.charCodeAt(0) + x);
 
630
  } else {
 
631
    return String.fromCharCode('A'.charCodeAt(0) + x - 10);
 
632
  }
 
633
}
 
634
 
 
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!');
 
642
  }
 
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
 
646
  if (neg) {
 
647
    stringy = _IntToHex(top & ~8) + stringy.substr(1);
 
648
  }
 
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
 
652
  a = a & 0xfffff;
 
653
  if (e === 0x7ff) {
 
654
    if (a == 0 && b == 0) {
 
655
      return neg ? '-Infinity' : 'Infinity';
 
656
    } else {
 
657
      return 'NaN';
 
658
    }
 
659
  }
 
660
  e -= 1023; // offset
 
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();
 
663
}
 
664
 
 
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;
 
671
    value = tempVar;
 
672
  }
 
673
  return '(' + expression.replace(/VALUE/g, value) + ')';
 
674
}
 
675
 
 
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) {
 
678
  high = high || '0';
 
679
  if (USE_TYPED_ARRAYS == 2) {
 
680
    return '[' + makeSignOp(low, 'i32', 'un', 1, 1) + ',' + makeSignOp(high, 'i32', 'un', 1, 1) + ']';
 
681
  } else {
 
682
    if (high) return RuntimeGenerator.makeBigInt(low, high);
 
683
    return low;
 
684
  }
 
685
}
 
686
 
 
687
// XXX Make all i64 parts signed
 
688
 
 
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);
 
697
  if (legalizedI64s) {
 
698
    return [lowInput + '>>>0', 'Math.min(Math.floor((' + value + ')/' + asmEnsureFloat(4294967296, 'float') + '), ' + asmEnsureFloat(4294967295, 'float') + ')>>>0'];
 
699
  } else {
 
700
    return makeInlineCalculation(makeI64(lowInput + '>>>0', 'Math.min(Math.floor(VALUE/' + asmEnsureFloat(4294967296, 'float') + '), ' + asmEnsureFloat(4294967295, 'float') + ')>>>0'), value, 'tempBigIntP');
 
701
  }
 
702
}
 
703
function mergeI64(value, unsigned) {
 
704
  assert(USE_TYPED_ARRAYS == 2);
 
705
  if (legalizedI64s) {
 
706
    return RuntimeGenerator.makeBigInt(value + '$0', value + '$1', unsigned);
 
707
  } else {
 
708
    return makeInlineCalculation(RuntimeGenerator.makeBigInt('VALUE[0]', 'VALUE[1]', unsigned), value, 'tempI64');
 
709
  }
 
710
}
 
711
 
 
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);
 
717
}
 
718
 
 
719
function makeCopyI64(value) {
 
720
  assert(USE_TYPED_ARRAYS == 2);
 
721
  return value + '.slice(0)';
 
722
}
 
723
 
 
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.
 
728
 
 
729
  assert(bits > 0); // NB: we don't check that the value in str can fit in this amount of bits
 
730
 
 
731
  function str2vec(s) { // index 0 is the highest value
 
732
    var ret = [];
 
733
    for (var i = 0; i < s.length; i++) {
 
734
      ret.push(s.charCodeAt(i) - '0'.charCodeAt(0));
 
735
    }
 
736
    return ret;
 
737
  }
 
738
 
 
739
  function divide2(v) { // v /= 2
 
740
    for (var i = v.length-1; i >= 0; i--) {
 
741
      var d = v[i];
 
742
      var r = d % 2;
 
743
      d = Math.floor(d/2);
 
744
      v[i] = d;
 
745
      if (r) {
 
746
        assert(i+1 < v.length);
 
747
        var d2 = v[i+1];
 
748
        d2 += 5;
 
749
        if (d2 >= 10) {
 
750
          v[i] = d+1;
 
751
          d2 -= 10;
 
752
        }
 
753
        v[i+1] = d2;
 
754
      }
 
755
    }
 
756
  }
 
757
 
 
758
  function mul2(v) { // v *= 2
 
759
    for (var i = v.length-1; i >= 0; i--) {
 
760
      var d = v[i]*2;
 
761
      r = d >= 10;
 
762
      v[i] = d%10;
 
763
      var j = i-1;
 
764
      if (r) {
 
765
        if (j < 0) {
 
766
          v.unshift(1);
 
767
          break;
 
768
        }
 
769
        v[j] += 0.5; // will be multiplied
 
770
      }
 
771
    }
 
772
  }
 
773
 
 
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++) {
 
777
      v[i] -= w[i];
 
778
      if (v[i] < 0) {
 
779
        v[i] += 10;
 
780
        // find something to take from
 
781
        var j = i-1;
 
782
        while (v[j] == 0) {
 
783
          v[j] = 9;
 
784
          j--;
 
785
          assert(j >= 0);
 
786
        }
 
787
        v[j]--;
 
788
      }
 
789
    }
 
790
  }
 
791
 
 
792
  function isZero(v) {
 
793
    for (var i = 0; i < v.length; i++) {
 
794
      if (v[i] > 0) return false;
 
795
    }
 
796
    return true;
 
797
  }
 
798
 
 
799
  var v;
 
800
 
 
801
  if (str[0] == '-') {
 
802
    // twos-complement is needed
 
803
    str = str.substr(1);
 
804
    v = str2vec('1');
 
805
    for (var i = 0; i < bits; i++) {
 
806
      mul2(v);
 
807
    }
 
808
    subtract(v, str2vec(str));
 
809
  } else {
 
810
    v = str2vec(str);
 
811
  }
 
812
 
 
813
  var bitsv = [];
 
814
  while (!isZero(v)) {
 
815
    bitsv.push((v[v.length-1] % 2 != 0)+0);
 
816
    v[v.length-1] = v[v.length-1] & 0xfe;
 
817
    divide2(v);
 
818
  }
 
819
 
 
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);
 
823
  }
 
824
  return ret;
 
825
}
 
826
 
 
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);
 
831
  }
 
832
 
 
833
  var parsed = parseArbitraryInt(str, 64);
 
834
  if (legalizedI64s || legalized) return parsed;
 
835
  return '[' + parsed[0] + ',' + parsed[1] + ']';
 
836
}
 
837
 
 
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.)
 
847
    value = '0';
 
848
  } else if (value === 'true') {
 
849
    return '1';
 
850
  } else if (value === 'false') {
 
851
    return '0';
 
852
  }
 
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();
 
857
  } else {
 
858
    return value;
 
859
  }
 
860
}
 
861
 
 
862
// \0Dsometext is really '\r', then sometext
 
863
// This function returns an array of int values
 
864
function parseLLVMString(str) {
 
865
  var ret = [];
 
866
  var i = 0;
 
867
  while (i < str.length) {
 
868
    var chr = str[i];
 
869
    if (chr != '\\') {
 
870
      ret.push(chr.charCodeAt(0));
 
871
      i++;
 
872
    } else {
 
873
      ret.push(eval('0x' + str[i+1]+str[i+2]));
 
874
      i += 3;
 
875
    }
 
876
  }
 
877
  return ret;
 
878
}
 
879
 
 
880
function getLabelIds(labels) {
 
881
  return labels.map(function(label) { return label.ident });
 
882
}
 
883
 
 
884
function cleanLabel(label) {
 
885
  if (label[0] == 'B') {
 
886
    return label.substr(5);
 
887
  } else {
 
888
    return label;
 
889
  }
 
890
}
 
891
 
 
892
function getOldLabel(label) {
 
893
  var parts = label.split('|');
 
894
  return parts[parts.length-1];
 
895
}
 
896
 
 
897
function calcAllocatedSize(type) {
 
898
  if (pointingLevels(type) == 0 && isStructType(type)) {
 
899
    return Types.types[type].flatSize; // makeEmptyStruct(item.allocatedType).length;
 
900
  } else {
 
901
    return Runtime.getNativeTypeSize(type); // We can really get away with '1', though, at least on the stack...
 
902
  }
 
903
}
 
904
 
 
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];
 
912
    }
 
913
    return [type].concat(zeros(Runtime.getNativeFieldSize(type)-1));
 
914
  }
 
915
 
 
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);
 
920
  var index = 0;
 
921
  function add(typeData) {
 
922
    var start = index;
 
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';
 
929
          ret[index++] = 0;
 
930
          ret[index++] = 0;
 
931
          ret[index++] = 0;
 
932
          ret[index++] = 'i32';
 
933
          ret[index++] = 0;
 
934
          ret[index++] = 0;
 
935
          ret[index++] = 0;
 
936
          continue;
 
937
        }
 
938
        ret[index++] = type;
 
939
      } else {
 
940
        add(Types.types[type]);
 
941
      }
 
942
      var more = (i+1 < typeData.fields.length ? typeData.flatIndexes[i+1] : typeData.flatSize) - (index - start);
 
943
      for (var j = 0; j < more; j++) {
 
944
        ret[index++] = 0;
 
945
      }
 
946
    }
 
947
  }
 
948
  add(typeData);
 
949
  assert(index == size);
 
950
  return ret;
 
951
}
 
952
 
 
953
// Flow blocks
 
954
 
 
955
function recurseBlock(block, func) {
 
956
  var ret = [];
 
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)) });
 
961
  }
 
962
  ret.push(func(block.next));
 
963
  return ret;
 
964
}
 
965
 
 
966
function getActualLabelId(labelId) {
 
967
  return labelId.split('|').slice(-1)[0];
 
968
}
 
969
 
 
970
// Misc
 
971
 
 
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') {
 
975
    var len = indent;
 
976
    indent = '';
 
977
    for (var i = 0; i < len; i++) indent += ' ';
 
978
  }
 
979
  return text.replace(/\n/g, '\n' + indent);
 
980
}
 
981
 
 
982
// Correction tools
 
983
 
 
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));
 
989
}
 
990
function correctSigns() {
 
991
  return CORRECT_SIGNS === 1 || correctSpecificSign();
 
992
}
 
993
 
 
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));
 
998
}
 
999
function correctOverflows() {
 
1000
  return CORRECT_OVERFLOWS === 1 || correctSpecificOverflow();
 
1001
}
 
1002
 
 
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));
 
1007
}
 
1008
function correctRoundings() {
 
1009
  return CORRECT_ROUNDINGS === 1 || correctSpecificRounding();
 
1010
}
 
1011
 
 
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));
 
1016
}
 
1017
function checkSafeHeap() {
 
1018
  return SAFE_HEAP === 1 || checkSpecificSafeHeap();
 
1019
}
 
1020
 
 
1021
function getHeapOffset(offset, type, forceAsm) {
 
1022
  if (USE_TYPED_ARRAYS !== 2) {
 
1023
    return offset;
 
1024
  }
 
1025
 
 
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
 
1029
    }
 
1030
  }
 
1031
 
 
1032
  var sz = Runtime.getNativeTypeSize(type);
 
1033
  var shifts = Math.log(sz)/Math.LN2;
 
1034
  offset = '(' + offset + ')';
 
1035
  if (shifts != 0) {
 
1036
    if (CHECK_HEAP_ALIGN) {
 
1037
      return '(CHECK_ALIGN_' + sz + '(' + offset + '|0)>>' + shifts + ')';
 
1038
    } else {
 
1039
      return '(' + offset + '>>' + shifts + ')';
 
1040
    }
 
1041
  } else {
 
1042
    // we need to guard against overflows here, HEAP[U]8 expects a guaranteed int
 
1043
    return isJSVar(offset) ? offset : '(' + offset + '|0)';
 
1044
  }
 
1045
}
 
1046
 
 
1047
function makeVarDef(js) {
 
1048
  if (!ASM_JS) js = 'var ' + js;
 
1049
  return js;
 
1050
}
 
1051
 
 
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 + '))';
 
1057
  } else {
 
1058
    return value;
 
1059
  }
 
1060
}
 
1061
 
 
1062
function asmInitializer(type, impl) {
 
1063
  if (type in Runtime.FLOAT_TYPES) {
 
1064
    return '+0';
 
1065
  } else {
 
1066
    return '0';
 
1067
  }
 
1068
}
 
1069
 
 
1070
function asmCoercion(value, type, signedness) {
 
1071
  if (!ASM_JS) return value;
 
1072
  if (type == 'void') {
 
1073
    return value;
 
1074
  } else if (type in Runtime.FLOAT_TYPES) {
 
1075
    if (isNumber(value)) {
 
1076
      return asmEnsureFloat(value, type);
 
1077
    } else {
 
1078
      if (signedness) {
 
1079
        if (signedness == 'u') {
 
1080
          value = '(' + value + ')>>>0';
 
1081
        } else {
 
1082
          value = '(' + value + ')|0';
 
1083
        }
 
1084
      }
 
1085
      return '(+(' + value + '))';
 
1086
    }
 
1087
  } else {
 
1088
    return '((' + value + ')|0)';
 
1089
  }
 
1090
}
 
1091
 
 
1092
function asmFloatToInt(x) {
 
1093
  return '(~~(' + x + '))';
 
1094
}
 
1095
 
 
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);
 
1101
  var offset;
 
1102
  if (type == 'double') {
 
1103
    offset = '(' + ptr + ')>>3';
 
1104
  } else {
 
1105
    offset = getHeapOffset(ptr, type);
 
1106
  }
 
1107
  var ret = slab + '[' + offset + ']';
 
1108
  if (!forSet) ret = asmCoercion(ret, type);
 
1109
  return ret;
 
1110
}
 
1111
 
 
1112
function makeSetTempDouble(i, type, value) {
 
1113
  return makeGetTempDouble(i, type, true) + '=' + asmEnsureFloat(value, type);
 
1114
}
 
1115
 
 
1116
var asmPrintCounter = 0;
 
1117
 
 
1118
// See makeSetValue
 
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];
 
1123
    var ret = [];
 
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));
 
1126
    }
 
1127
    return '{ ' + ret.join(', ') + ' }';
 
1128
  }
 
1129
 
 
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') + ')';
 
1136
  }
 
1137
 
 
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) {
 
1143
      var ret = '(';
 
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)
 
1150
          ret = '';
 
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 += '|';
 
1154
          }
 
1155
          ret = '(' + makeSignOp(ret, type, unsigned ? 'un' : 're', true);
 
1156
        }
 
1157
      } else {
 
1158
        if (type == 'float') {
 
1159
          ret += 'copyTempFloat(' + asmCoercion(getFastValue(ptr, '+', pos), 'i32') + '),' + makeGetTempDouble(0, 'float');
 
1160
        } else {
 
1161
          ret += 'copyTempDouble(' + asmCoercion(getFastValue(ptr, '+', pos), 'i32') + '),' + makeGetTempDouble(0, 'double');
 
1162
        }
 
1163
      }
 
1164
      ret += ')';
 
1165
      return ret;
 
1166
    }
 
1167
  }
 
1168
 
 
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);
 
1175
  } else {
 
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);
 
1179
    }
 
1180
    if (ASM_HEAP_LOG) {
 
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'));
 
1183
    }
 
1184
    return ret;
 
1185
  }
 
1186
}
 
1187
 
 
1188
function makeGetValueAsm(ptr, pos, type, unsigned) {
 
1189
  return makeGetValue(ptr, pos, type, null, unsigned, null, null, null, true);
 
1190
}
 
1191
 
 
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');
 
1195
  var out = {};
 
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 }) : []);
 
1200
    }
 
1201
 
 
1202
    if (BUILD_AS_SHARED_LIB) {
 
1203
      return '(FUNCTION_TABLE_OFFSET + ' + Functions.getIndex(value) + ')';
 
1204
    } else {
 
1205
      return Functions.getIndex(value);
 
1206
    }
 
1207
  }
 
1208
  return value;
 
1209
}
 
1210
 
 
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;
 
1223
  sep = sep || ';';
 
1224
  if (isStructType(type)) {
 
1225
    var typeData = Types.types[type];
 
1226
    var ret = [];
 
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 });
 
1231
    }
 
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));
 
1234
    }
 
1235
    return ret.join('; ');
 
1236
  }
 
1237
 
 
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, ',') + ')';
 
1246
  }
 
1247
 
 
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) {
 
1255
      var ret = '';
 
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);
 
1262
        } else {
 
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;
 
1267
          }
 
1268
        }
 
1269
      } else {
 
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);
 
1272
      }
 
1273
      return ret;
 
1274
    }
 
1275
  }
 
1276
 
 
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) + ')';
 
1284
  } else {
 
1285
    return makeGetSlabs(ptr, type, true).map(function(slab) { return slab + '[' + getHeapOffset(offset, type, forceAsm) + ']=' + value }).join(sep);
 
1286
  }
 
1287
}
 
1288
 
 
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);
 
1291
}
 
1292
 
 
1293
var UNROLL_LOOP_MAX = 8;
 
1294
 
 
1295
function makeSetValues(ptr, pos, value, type, num, align) {
 
1296
  function unroll(type, num, jump, value$) {
 
1297
    jump = jump || 1;
 
1298
    value$ = value$ || value;
 
1299
    return range(num).map(function(i) {
 
1300
      return makeSetValue(ptr, getFastValue(pos, '+', i*jump), value$, type);
 
1301
    }).join('; ');
 
1302
  }
 
1303
  if (USE_TYPED_ARRAYS <= 1) {
 
1304
    if (isNumber(num) && parseInt(num) <= UNROLL_LOOP_MAX) {
 
1305
      return unroll(type, num);
 
1306
    }
 
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') + ')';
 
1314
    }
 
1315
    num = parseInt(num);
 
1316
    value = parseInt(value);
 
1317
    if (value < 0) value += 256; // make it unsigned
 
1318
    var values = {
 
1319
      1: value,
 
1320
      2: value | (value << 8), 
 
1321
      4: value | (value << 8) | (value << 16) | (value << 24)
 
1322
    };
 
1323
    var ret = [];
 
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;
 
1330
      }
 
1331
    });
 
1332
    return ret.join('; ');
 
1333
  }
 
1334
}
 
1335
 
 
1336
var TYPED_ARRAY_SET_MIN = Infinity; // .set() as memcpy seems to just slow us down
 
1337
 
 
1338
function makeCopyValues(dest, src, num, type, modifier, align, sep) {
 
1339
  sep = sep || ';';
 
1340
  function unroll(type, num, jump) {
 
1341
    jump = jump || 1;
 
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) + ')' : '');
 
1348
      } else {
 
1349
        return makeSetValue(dest, i*jump, makeGetValue(src, i*jump, type), type);
 
1350
      }
 
1351
    }).join(sep);
 
1352
  }
 
1353
  if (USE_TYPED_ARRAYS <= 1) {
 
1354
    if (isNumber(num) && parseInt(num) <= UNROLL_LOOP_MAX) {
 
1355
      return unroll(type, num);
 
1356
    }
 
1357
    var oldDest = dest, oldSrc = src;
 
1358
    dest = '$$dest';
 
1359
    src = '$$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 + ')';
 
1368
    }
 
1369
    num = parseInt(num);
 
1370
    if (ASM_JS) {
 
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
 
1373
    }
 
1374
    var ret = [];
 
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;
 
1382
      }
 
1383
    });
 
1384
    return ret.join(sep);
 
1385
  }
 
1386
}
 
1387
 
 
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 + ')';
 
1393
}
 
1394
 
 
1395
var PLUS_MUL = set('+', '*');
 
1396
var MUL_DIV = set('*', '/');
 
1397
var PLUS_MINUS = set('+', '-');
 
1398
var TWO_TWENTY = Math.pow(2, 20);
 
1399
 
 
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) {
 
1404
  a = a.toString();
 
1405
  b = b.toString();
 
1406
  a = a == 'true' ? '1' : (a == 'false' ? '0' : a);
 
1407
  b = b == 'true' ? '1' : (b == 'false' ? '0' : b);
 
1408
  if (isNumber(a) && isNumber(b)) {
 
1409
    if (op == 'pow') {
 
1410
      return Math.pow(a, b).toString();
 
1411
    } else {
 
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();
 
1415
    }
 
1416
  }
 
1417
  if (op == 'pow') {
 
1418
    if (a == '2' && isIntImplemented(type)) {
 
1419
      return '(1 << (' + b + '))';
 
1420
    }
 
1421
    return 'Math.pow(' + a + ', ' + b + ')';
 
1422
  }
 
1423
  if (op in PLUS_MUL && isNumber(a)) { // if one of them is a number, keep it last
 
1424
    var c = b;
 
1425
    b = a;
 
1426
    a = c;
 
1427
  }
 
1428
  if (op in MUL_DIV) {
 
1429
    if (op == '*') {
 
1430
      if (a == 0 || b == 0) {
 
1431
        return '0';
 
1432
      } else if (a == 1) {
 
1433
        return b;
 
1434
      } else if (b == 1) {
 
1435
        return a;
 
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 + ')';
 
1440
        }
 
1441
      }
 
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
 
1448
        }
 
1449
        return 'Math.imul(' + a + ',' + b + ')';
 
1450
      }
 
1451
    } else {
 
1452
      if (a == '0') {
 
1453
        return '0';
 
1454
      } else if (b == 1) {
 
1455
        return a;
 
1456
      } // Doing shifts for division is problematic, as getting the rounding right on negatives is tricky
 
1457
    }
 
1458
  } else if (op in PLUS_MINUS) {
 
1459
    if (b[0] == '-') {
 
1460
      op = op == '+' ? '-' : '+';
 
1461
      b = b.substr(1);
 
1462
    }
 
1463
    if (a == 0) {
 
1464
      return op == '+' ? b : '(-' + b + ')';
 
1465
    } else if (b == 0) {
 
1466
      return a;
 
1467
    }
 
1468
  }
 
1469
  return '(' + a + ')' + op + '(' + b + ')';
 
1470
}
 
1471
 
 
1472
function getFastValues(list, op, type) {
 
1473
  assert(op == '+');
 
1474
  var changed = true;
 
1475
  while (changed) {
 
1476
    changed = false;
 
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) {
 
1481
        list[i] = fast;
 
1482
        list.splice(i+1, 1);
 
1483
        i--;
 
1484
        changed = true;
 
1485
        break;
 
1486
      }
 
1487
    }
 
1488
  }
 
1489
  if (list.length == 1) return list[0];
 
1490
  return list.reduce(function(a, b) { return a + op + b });
 
1491
}
 
1492
 
 
1493
function calcFastOffset(ptr, pos, noNeedFirst) {
 
1494
  var offset = noNeedFirst ? '0' : makeGetPos(ptr);
 
1495
  return getFastValue(offset, '+', pos, 'i32');
 
1496
}
 
1497
 
 
1498
function makeGetPos(ptr) {
 
1499
  return ptr;
 
1500
}
 
1501
 
 
1502
var IHEAP_FHEAP = set('IHEAP', 'IHEAPU', 'FHEAP');
 
1503
 
 
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 = [];
 
1510
 
 
1511
function writeInt8s(slab, i, value, type) {
 
1512
  var currSize;
 
1513
  switch (type) {
 
1514
    case 'i1':
 
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
 
1521
    default: {
 
1522
      if (type == 'i32' || type == 'i64' || type[type.length-1] == '*') {
 
1523
        if (!isNumber(value)) { // function table stuff, etc.
 
1524
          slab[i] = value;
 
1525
          slab[i+1] = slab[i+2] = slab[i+3] = 0;
 
1526
          return 4;
 
1527
        }
 
1528
        temp32[0] = value;
 
1529
        currSize = 4;
 
1530
      } else {
 
1531
        throw 'what? ' + types[i];
 
1532
      }
 
1533
    }
 
1534
  }
 
1535
  for (var j = 0; j < currSize; j++) {
 
1536
    slab[i+j] = temp8[j];
 
1537
  }
 
1538
  return currSize;
 
1539
}
 
1540
 
 
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++) {
 
1547
      var curr = slab[i];
 
1548
      if (isNumber(curr)) {
 
1549
        slab[i] = parseFloat(curr); // fix "5" to 5 etc.
 
1550
      } else if (curr == 'undef') {
 
1551
        slab[i] = 0;
 
1552
      }
 
1553
    }
 
1554
  }
 
1555
  // compress type info and data if possible
 
1556
  if (USE_TYPED_ARRAYS != 2) {
 
1557
    var de;
 
1558
    try {
 
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;
 
1562
      de = dedup(evaled);
 
1563
      if (de.length === 1 && de[0] == 0) {
 
1564
        slab = types.length;
 
1565
      }
 
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
 
1568
    } catch(e){}
 
1569
    de = dedup(types);
 
1570
    if (de.length === 1) {
 
1571
      types = de[0];
 
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) {
 
1576
        types = de[0];
 
1577
      }
 
1578
    }
 
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
 
1582
      var i = 0;
 
1583
      while (i < slab.length) {
 
1584
        var currType = types[i];
 
1585
        if (!currType) { i++; continue }
 
1586
        i += writeInt8s(slab, i, slab[i], currType);
 
1587
      }
 
1588
      types = 'i8';
 
1589
    }
 
1590
  }
 
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];
 
1599
      }
 
1600
      return '';
 
1601
    }
 
1602
    // This is the final memory initialization
 
1603
    types = 'i8';
 
1604
  }
 
1605
 
 
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
 
1610
    var ret = '';
 
1611
    var index = 0;
 
1612
    while (index < array.length) {
 
1613
      ret = (ret ? ret + '.concat(' : '') + '[' + array.slice(index, index + chunkSize).map(JSON.stringify) + ']' + (ret ? ')\n' : '');
 
1614
      index += chunkSize;
 
1615
    }
 
1616
    return ret;
 
1617
  }
 
1618
  if (typeof slab == 'object' && slab.length > chunkSize) {
 
1619
    slab = chunkify(slab);
 
1620
  }
 
1621
  if (typeof types == 'object') {
 
1622
    while (types.length < slab.length) types.push(0);
 
1623
  }
 
1624
  if (typeof types != 'string' && types.length > chunkSize) {
 
1625
    types = chunkify(types);
 
1626
  } else {
 
1627
    types = JSON.stringify(types);
 
1628
  }
 
1629
  if (typeof slab == 'object') slab = '[' + slab.join(',') + ']';
 
1630
  return 'allocate(' + slab + ', ' + types + (allocator ? ', ' + allocator : '') + (allocator == 'ALLOC_NONE' ? ', ' + ptr : '') + ')';
 
1631
}
 
1632
 
 
1633
function makeGetSlabs(ptr, type, allowMultiple, unsigned) {
 
1634
  assert(type);
 
1635
  if (!USE_TYPED_ARRAYS) {
 
1636
    return ['HEAP'];
 
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'];
 
1642
    } else {
 
1643
      assert(allowMultiple, 'Unknown slab type and !allowMultiple: ' + type);
 
1644
      if (USE_FHEAP) {
 
1645
        return ['IHEAP', 'FHEAP']; // unknown, so assign to both typed arrays
 
1646
      } else {
 
1647
        return ['IHEAP'];
 
1648
      }
 
1649
    }
 
1650
  } else { // USE_TYPED_ARRAYS == 2)
 
1651
    if (isPointerType(type)) type = 'i32'; // Hardcoded 32-bit
 
1652
    switch(type) {
 
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;
 
1656
      case 'double': {
 
1657
        if (TARGET_LE32) return ['HEAPF64']; // in le32, we do have the ability to assume 64-bit alignment
 
1658
        // otherwise, fall through to float
 
1659
      }
 
1660
      case 'float': return ['HEAPF32'];
 
1661
      default: {
 
1662
        throw 'what, exactly, can we do for unknown types in TA2?! ' + new Error().stack;
 
1663
      }
 
1664
    }
 
1665
  }
 
1666
  return [];
 
1667
}
 
1668
 
 
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);
 
1677
    var warned = false;
 
1678
    function showWarning() {
 
1679
      if (warned) return;
 
1680
      warned = true;
 
1681
      if (VERBOSE || ASM_JS) {
 
1682
        warnOnce('Casting potentially incompatible function pointer ' + oldType + ' to ' + newType + ', for ' + item.params[0].ident.slice(1));
 
1683
      } else {
 
1684
        warnOnce('Casting a function pointer type to a potentially incompatible one (use VERBOSE=1 to see more)');
 
1685
      }
 
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');
 
1688
    }
 
1689
    if (oldCount != newCount && oldCount && newCount) showWarning();
 
1690
    if (ASM_JS) {
 
1691
      if (oldCount != newCount) showWarning();
 
1692
      else if (!isIdenticallyImplemented(oldInfo.returnType, newInfo.returnType)) {
 
1693
        showWarning();
 
1694
      } else {
 
1695
        for (var i = 0; i < oldCount; i++) {
 
1696
          if (!isIdenticallyImplemented(oldInfo.segments[i][0].text, newInfo.segments[i][0].text)) {
 
1697
            showWarning();
 
1698
            break;
 
1699
          }
 
1700
        }
 
1701
      }
 
1702
    }
 
1703
  }
 
1704
}
 
1705
 
 
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);
 
1709
  }
 
1710
  if (item.intertype == 'bitcast') checkBitcast(item);
 
1711
  var temp = {
 
1712
    op: item.intertype,
 
1713
    variant: item.variant,
 
1714
    type: item.type,
 
1715
    params: item.params.slice(0) // XXX slice?
 
1716
  };
 
1717
  return processMathop(temp);
 
1718
}
 
1719
 
 
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' });
 
1725
  }
 
1726
  item.params = item.params.map(finalizeLLVMParameter);
 
1727
  var ident = item.params[0];
 
1728
 
 
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];
 
1735
  if (offset != 0) {
 
1736
    if (isStructType(type)) {
 
1737
      indexes.push(getFastValue(Types.types[type].flatSize, '*', offset, 'i32'));
 
1738
    } else {
 
1739
      indexes.push(getFastValue(Runtime.getNativeTypeSize(type), '*', offset, 'i32'));
 
1740
    }
 
1741
  }
 
1742
  item.params.slice(2, item.params.length).forEach(function(arg) {
 
1743
    var curr = 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'));
 
1749
      } else {
 
1750
        if (isNumber(curr)) {
 
1751
          indexes.push(typeData.flatIndexes[curr]);
 
1752
        } else {
 
1753
          indexes.push(toNiceIdent(type) + '___FLATTENER[' + curr + ']'); // TODO: If curr is constant, optimize out the flattener struct
 
1754
        }
 
1755
      }
 
1756
    } else {
 
1757
      if (curr != 0) {
 
1758
        indexes.push(curr);
 
1759
      }
 
1760
    }
 
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]);
 
1767
      }
 
1768
      curr = 0;
 
1769
    }
 
1770
    type = typeData && typeData.fields[curr] ? typeData.fields[curr] : '';
 
1771
  });
 
1772
 
 
1773
  var ret = getFastValues(indexes, '+', 'i32');
 
1774
 
 
1775
  ret = handleOverflow(ret, 32); // XXX - we assume a 32-bit arch here. If you fail on this, change to 64
 
1776
 
 
1777
  return ret;
 
1778
}
 
1779
 
 
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;
 
1787
  if (bits == 32) {
 
1788
    return '((' + text + ')|0)';
 
1789
  } else if (bits < 32) {
 
1790
    return '((' + text + ')&' + (Math.pow(2, bits) - 1) + ')';
 
1791
  } else {
 
1792
    return text; // We warned about this earlier
 
1793
  }
 
1794
}
 
1795
 
 
1796
function makeLLVMStruct(values) {
 
1797
  if (USE_TYPED_ARRAYS == 2) {
 
1798
    return 'DEPRECATED' + (new Error().stack) + 'XXX';
 
1799
  } else {
 
1800
    return '{ ' + values.map(function(value, i) { return 'f' + i + ': ' + value }).join(', ') + ' }'
 
1801
  }
 
1802
}
 
1803
 
 
1804
function makeStructuralReturn(values, inAsm) {
 
1805
  if (USE_TYPED_ARRAYS == 2) {
 
1806
    var i = -1;
 
1807
    return 'return ' + asmCoercion(values.slice(1).map(function(value) {
 
1808
      i++;
 
1809
      return ASM_JS ? (inAsm ? 'tempRet' + i + ' = ' + value : 'asm.setTempRet' + i + '(' + value + ')')
 
1810
                    : 'tempRet' + i + ' = ' + value;
 
1811
    }).concat([values[0]]).join(','), 'i32');
 
1812
  } else {
 
1813
    var i = 0;
 
1814
    return 'return { ' + values.map(function(value) {
 
1815
      return 'f' + (i++) + ': ' + value;
 
1816
    }).join(', ') + ' }';
 
1817
  }
 
1818
}
 
1819
 
 
1820
function makeStructuralAccess(ident, i) {
 
1821
  if (USE_TYPED_ARRAYS == 2) {
 
1822
    return ident + '$' + i;
 
1823
  } else {
 
1824
    return ident + '.f' + i;
 
1825
  }
 
1826
}
 
1827
 
 
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."' : '') + ';';
 
1830
}
 
1831
 
 
1832
// From parseLLVMSegment
 
1833
function finalizeLLVMParameter(param, noIndexizeFunctions) {
 
1834
  var ret;
 
1835
  if (isNumber(param)) {
 
1836
    return 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));
 
1844
    } else {
 
1845
      return '0';
 
1846
    }
 
1847
  } else if (param.intertype == 'value') {
 
1848
    ret = param.ident;
 
1849
    if (ret in Variables.globals) {
 
1850
      ret = makeGlobalUse(ret);
 
1851
    }
 
1852
    if (param.type == 'i64' && USE_TYPED_ARRAYS == 2) {
 
1853
      ret = parseI64Constant(ret);
 
1854
    }
 
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);
 
1865
  } else {
 
1866
    throw 'invalid llvm parameter: ' + param.intertype;
 
1867
  }
 
1868
  assert(param.type || (typeof param === 'string' && param.substr(0, 6) === 'CHECK_'), 'Missing type for param!');
 
1869
  if (!noIndexizeFunctions) ret = indexizeFunctions(ret, param.type);
 
1870
  return ret;
 
1871
}
 
1872
 
 
1873
function makeComparison(a, op, b, type) {
 
1874
  assert(type);
 
1875
  if (!isIllegalType(type)) {
 
1876
    return asmCoercion(a, type) + op + asmCoercion(b, type);
 
1877
  } else {
 
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');
 
1881
  }
 
1882
}
 
1883
 
 
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.
 
1887
  }
 
1888
 
 
1889
  if (isPointerType(type)) type = 'i32'; // Pointers are treated as 32-bit ints
 
1890
  if (!value) return value;
 
1891
  var bits, full;
 
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();
 
1898
    }
 
1899
  }
 
1900
  if ((ignore || !correctSigns()) && !CHECK_SIGNS && !force) return value;
 
1901
  if (type in Runtime.INT_TYPES) {
 
1902
    // shortcuts
 
1903
    if (!CHECK_SIGNS || ignore) {
 
1904
      if (bits === 32) {
 
1905
        if (op === 're') {
 
1906
          return '(' + getFastValue(value, '|', '0') + ')';
 
1907
        } else {
 
1908
 
 
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
 
1913
        }
 
1914
      } else if (bits < 32) {
 
1915
        if (op === 're') {
 
1916
          return makeInlineCalculation('(VALUE << ' + (32-bits) + ') >> ' + (32-bits), value, 'tempInt');
 
1917
        } else {
 
1918
          return '(' + getFastValue(value, '&', Math.pow(2, bits)-1) + ')';
 
1919
        }
 
1920
      } else { // bits > 32
 
1921
        if (op === 're') {
 
1922
          return makeInlineCalculation('VALUE >= ' + Math.pow(2, bits-1) + ' ? VALUE-' + Math.pow(2, bits) + ' : VALUE', value, 'tempBigIntS');
 
1923
        } else {
 
1924
          return makeInlineCalculation('VALUE >= 0 ? VALUE : ' + Math.pow(2, bits) + '+VALUE', value, 'tempBigIntS');
 
1925
        }
 
1926
      }
 
1927
    }
 
1928
    return full;
 
1929
  }
 
1930
  return value;
 
1931
}
 
1932
 
 
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
 
1939
  assert(bits);
 
1940
  if (!ASM_JS) {
 
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
 
1950
    // necessary.
 
1951
    return makeInlineCalculation(makeComparison('VALUE', '>=', '0', 'float') + ' ? Math.floor(VALUE) : Math.ceil(VALUE)', value, 'tempBigIntR');
 
1952
  } else {
 
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
 
1956
    }
 
1957
 
 
1958
    if (bits <= 32) {
 
1959
      if (signed) {
 
1960
        return '((' + value + ')&-1)'; // &-1 (instead of |0) hints to the js optimizer that this is a rounding correction
 
1961
      } else {
 
1962
        return '((' + value + ')>>>0)';
 
1963
      }
 
1964
    }
 
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');
 
1969
  }
 
1970
}
 
1971
 
 
1972
function makeIsNaN(value) {
 
1973
  if (ASM_JS) return makeInlineCalculation('((VALUE) != (VALUE))', value, 'tempDouble');
 
1974
  return 'isNaN(' + value + ')';
 
1975
}
 
1976
 
 
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');
 
1981
 
 
1982
function isUnsignedOp(op, variant) {
 
1983
  return op in UNSIGNED_OP || (variant && variant[0] == 'u');
 
1984
}
 
1985
function isSignedOp(op, variant) {
 
1986
  return op in SIGNED_OP || (variant && variant[0] == 's');
 
1987
}
 
1988
 
 
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
 
1990
 
 
1991
function processMathop(item) {
 
1992
  var op = item.op;
 
1993
  var variant = item.variant;
 
1994
  var type = item.type;
 
1995
  var paramTypes = ['', '', '', ''];
 
1996
  var idents = [];
 
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
 
2003
      }
 
2004
    } else {
 
2005
      idents[i] = null; // just so it exists for purposes of reading idents[1] etc. later on, and no exception is thrown
 
2006
    }
 
2007
  }
 
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');
 
2015
  }
 
2016
  var bits = null;
 
2017
  if (item.type[0] === 'i') {
 
2018
    bits = parseInt(item.type.substr(1));
 
2019
  }
 
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
 
2022
 
 
2023
  function integerizeBignum(value) {
 
2024
    return makeInlineCalculation('VALUE-VALUE%1', value, 'tempBigIntI');
 
2025
  }
 
2026
 
 
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!');
 
2030
    };
 
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;
 
2042
        return ret;
 
2043
      } else {
 
2044
        return result;
 
2045
      }
 
2046
    }
 
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')]);
 
2051
    }
 
2052
    function preciseCall(name) {
 
2053
      Types.preciseI64MathUsed = true;
 
2054
      return finish([asmCoercion(name + '(' + low1 + ',' + high1 + ',' + low2 + ',' + high2 + ')', 'i32'), 'tempRet0']);
 
2055
    }
 
2056
    function i64PreciseLib(type) {
 
2057
      return preciseCall('_i64' + type[0].toUpperCase() + type.substr(1));
 
2058
    }
 
2059
    switch (op) {
 
2060
      // basic integer ops
 
2061
      case 'or': {
 
2062
        return '[' + idents[0] + '[0] | ' + idents[1] + '[0], ' + idents[0] + '[1] | ' + idents[1] + '[1]]';
 
2063
      }
 
2064
      case 'and': {
 
2065
        return '[' + idents[0] + '[0] & ' + idents[1] + '[0], ' + idents[0] + '[1] & ' + idents[1] + '[1]]';
 
2066
      }
 
2067
      case 'xor': {
 
2068
        return '[' + idents[0] + '[0] ^ ' + idents[1] + '[0], ' + idents[0] + '[1] ^ ' + idents[1] + '[1]]';
 
2069
      }
 
2070
      case 'shl':
 
2071
      case 'ashr':
 
2072
      case 'lshr': {
 
2073
                                throw 'shifts should have been legalized!';
 
2074
      }
 
2075
      case 'uitofp': case 'sitofp': return RuntimeGenerator.makeBigInt(low1, high1, op[0] == 'u');
 
2076
      case 'fptoui': case 'fptosi': return finish(splitI64(idents[0], true));
 
2077
      case 'icmp': {
 
2078
        switch (variant) {
 
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;
 
2098
        }
 
2099
      }
 
2100
      case 'zext': return makeI64(idents[0], 0);
 
2101
      case 'sext': return makeInlineCalculation(makeI64('VALUE', 'VALUE<0 ? 4294967295 : 0'), idents[0], 'tempBigIntD');
 
2102
      case 'trunc': {
 
2103
        return '((' + idents[0] + '[0]) & ' + (Math.pow(2, bitsLeft)-1) + ')';
 
2104
      }
 
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
 
2109
      case 'add': {
 
2110
        if (PRECISE_I64_MATH) {
 
2111
          return i64PreciseLib('add');
 
2112
        } else {
 
2113
          warnI64_1();
 
2114
          return finish(splitI64(mergeI64(idents[0]) + '+' + mergeI64(idents[1]), true));
 
2115
        }
 
2116
      }
 
2117
      case 'sub': {
 
2118
        if (PRECISE_I64_MATH) {
 
2119
          return i64PreciseLib('subtract');
 
2120
        } else {
 
2121
          warnI64_1();
 
2122
          return finish(splitI64(mergeI64(idents[0]) + '-' + mergeI64(idents[1]), true));
 
2123
        }
 
2124
      }
 
2125
      case 'sdiv': case 'udiv': {
 
2126
        if (PRECISE_I64_MATH) {
 
2127
          return preciseCall(op[0] === 'u' ? '___udivdi3' : '___divdi3');
 
2128
        } else {
 
2129
          warnI64_1();
 
2130
          return finish(splitI64(makeRounding(mergeI64(idents[0], op[0] === 'u') + '/' + mergeI64(idents[1], op[0] === 'u'), bits, op[0] === 's'), true));
 
2131
        }
 
2132
      }
 
2133
      case 'mul': {
 
2134
        if (PRECISE_I64_MATH) {
 
2135
          return preciseCall('___muldi3');
 
2136
        } else {
 
2137
          warnI64_1();
 
2138
          return finish(splitI64(mergeI64(idents[0], op[0] === 'u') + '*' + mergeI64(idents[1], op[0] === 'u'), true));
 
2139
        }
 
2140
      }
 
2141
      case 'urem': case 'srem': {
 
2142
        if (PRECISE_I64_MATH) {
 
2143
          return preciseCall(op[0] === 'u' ? '___uremdi3' : '___remdi3');
 
2144
        } else {
 
2145
          warnI64_1();
 
2146
          return finish(splitI64(mergeI64(idents[0], op[0] === 'u') + '%' + mergeI64(idents[1], op[0] === 'u'), true));
 
2147
        }
 
2148
      }
 
2149
      case 'bitcast': {
 
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') + ')';
 
2157
          } else {
 
2158
            return makeInlineCalculation(makeSetTempDouble(0, 'i32', 'VALUE[0]') + ',' + makeSetTempDouble(1, 'i32', 'VALUE[1]') + ',' + makeGetTempDouble(0, 'double'), idents[0], 'tempI64');
 
2159
          }
 
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')]);
 
2163
          } else {
 
2164
            return '(' + makeSetTempDouble(0, 'double', idents[0]) + ',[' + makeGetTempDouble(0, 'i32') + ',' + makeGetTempDouble(1, 'i32') + '])';
 
2165
          }
 
2166
        } else {
 
2167
          throw 'Invalid USE_TYPED_ARRAYS == 2 bitcast: ' + dump(item) + ' : ' + item.params[0].type;
 
2168
        }
 
2169
      }
 
2170
      default: throw 'Unsupported i64 mode 1 op: ' + item.op + ' : ' + dump(item);
 
2171
    }
 
2172
  }
 
2173
 
 
2174
  switch (op) {
 
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);
 
2181
    case 'or': {
 
2182
      if (bits > 32) {
 
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] + ')';
 
2186
      }
 
2187
      return idents[0] + ' | ' + idents[1];
 
2188
    }
 
2189
    case 'and': {
 
2190
      if (bits > 32) {
 
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] + ')';
 
2194
      }
 
2195
      return idents[0] + ' & ' + idents[1];
 
2196
    }
 
2197
    case 'xor': {
 
2198
      if (bits > 32) {
 
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] + ')';
 
2202
      }
 
2203
      return idents[0] + ' ^ ' + idents[1];
 
2204
    }
 
2205
    case 'shl': {
 
2206
      if (bits > 32) return idents[0] + '*' + getFastValue(2, 'pow', idents[1]);
 
2207
      return idents[0] + ' << ' + idents[1];
 
2208
    }
 
2209
    case 'ashr': {
 
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];
 
2213
    }
 
2214
    case 'lshr': {
 
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];
 
2218
    }
 
2219
    // basic float ops
 
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);
 
2227
 
 
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.
 
2230
    case 'icmp': {
 
2231
      switch (variant) {
 
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];
 
2243
        }
 
2244
        default: throw 'Unknown icmp variant: ' + variant;
 
2245
      }
 
2246
    }
 
2247
    case 'fcmp': {
 
2248
      switch (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;
 
2261
      }
 
2262
    }
 
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.
 
2265
    case 'zext': {
 
2266
      if (EXPLICIT_ZEXT && bitsBefore == 1 && bitsLeft > 1) {
 
2267
        return '(' + originalIdents[0] + '?1:0)'; // explicit bool-to-int conversion, work around v8 issue 2513
 
2268
        break;
 
2269
      }
 
2270
      // otherwise, fall through
 
2271
    }
 
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': {
 
2276
      var ret = '';
 
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 + ' */';
 
2283
      }
 
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
 
2286
    }
 
2287
    case 'trunc': {
 
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) + ')';
 
2293
    }
 
2294
    case 'bitcast': {
 
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') + ')';
 
2303
        } else {
 
2304
          return '(' + makeSetTempDouble(0, 'float', idents[0]) + ',' + makeGetTempDouble(0, 'i32') + ')';
 
2305
        }
 
2306
      }
 
2307
      return idents[0];
 
2308
    }
 
2309
    default: throw 'Unknown mathcmp op: ' + item.op;
 
2310
  }
 
2311
}
 
2312
 
 
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;
 
2324
  var i;
 
2325
  if (item.params) {
 
2326
    for (i = 0; i <= item.params.length; i++) {
 
2327
      if (walkInterdata(item.params[i], pre, post,  obj)) return true;
 
2328
    }
 
2329
  }
 
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;
 
2335
    }
 
2336
  }
 
2337
  return post && post(item, originalObj, obj);
 
2338
}
 
2339
 
 
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;
 
2347
  var repl;
 
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;
 
2351
  if (item.params) {
 
2352
    for (var i = 0; i <= item.params.length; i++) {
 
2353
      if (repl = walkAndModifyInterdata(item.params[i], pre)) item.params[i] = repl;
 
2354
    }
 
2355
  }
 
2356
  // Ignore possibleVars because we can't replace them anyhow
 
2357
}
 
2358
 
 
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' };
 
2361
}
 
2362
 
 
2363
function finalizeBlockAddress(param) {
 
2364
  return '{{{ BA_' + param.func + '|' + param.label + ' }}}'; // something python will replace later
 
2365
}
 
2366
 
 
2367
function stripCorrections(param) {
 
2368
  var m;
 
2369
  while (true) {
 
2370
    if (m = /^\((.*)\)$/.exec(param)) {
 
2371
      param = m[1];
 
2372
      continue;
 
2373
    }
 
2374
    if (m = /^\(([$_\w]+)\)&\d+$/.exec(param)) {
 
2375
      param = m[1];
 
2376
      continue;
 
2377
    }
 
2378
    if (m = /^\(([$_\w()]+)\)\|0$/.exec(param)) {
 
2379
      param = m[1];
 
2380
      continue;
 
2381
    }
 
2382
    if (m = /^\(([$_\w()]+)\)\>>>0$/.exec(param)) {
 
2383
      param = m[1];
 
2384
      continue;
 
2385
    }
 
2386
    if (m = /CHECK_OVERFLOW\(([^,)]*),.*/.exec(param)) {
 
2387
      param = m[1];
 
2388
      continue;
 
2389
    }
 
2390
    break;
 
2391
  }
 
2392
  return param;
 
2393
}
 
2394
 
 
2395
function getImplementationType(varInfo) {
 
2396
  if (varInfo.impl == 'nativized') {
 
2397
    return removePointing(varInfo.type);
 
2398
  }
 
2399
  return varInfo.type;
 
2400
}
 
2401
 
 
2402
function charCode(char) {
 
2403
  return char.charCodeAt(0);
 
2404
}
 
2405
 
 
2406
function getTypeFromHeap(suffix) {
 
2407
  switch (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;
 
2414
  }
 
2415
}
 
2416
 
 
2417
// Generates code that prints without printf(), but just putchar (so can be directly inline in asm.js)
 
2418
function makePrintChars(s, sep) {
 
2419
  sep = sep || ';';
 
2420
  var ret = '';
 
2421
  for (var i = 0; i < s.length; i++) {
 
2422
    ret += '_putchar(' + s.charCodeAt(i) + ')' + sep;
 
2423
  }
 
2424
  ret += '_putchar(10)';
 
2425
  return ret;
 
2426
}
 
2427