~ubuntu-branches/ubuntu/trusty/emscripten/trusty-proposed

« back to all changes in this revision

Viewing changes to src/parseTools.js

  • Committer: Package Import Robot
  • Author(s): Sylvestre Ledru
  • Date: 2014-01-19 14:12:40 UTC
  • mfrom: (1.2.4)
  • Revision ID: package-import@ubuntu.com-20140119141240-jg1l42cc158j59tn
Tags: 1.9.0~20140119~7dc8c2f-1
* New snapshot release (Closes: #733714)
* Provide sources for javascript and flash. Done in orig-tar.sh
  Available in third_party/websockify/include/web-socket-js/src/
  (Closes: #735903)

Show diffs side-by-side

added added

removed removed

Lines of Context:
5
5
 
6
6
// Does simple 'macro' substitution, using Django-like syntax,
7
7
// {{{ code }}} will be replaced with |eval(code)|.
 
8
// NOTE: Be careful with that ret check. If ret is |0|, |ret ? ret.toString() : ''| would result in ''!
8
9
function processMacros(text) {
9
10
  return text.replace(/{{{([^}]|}(?!}))+}}}/g, function(str) {
10
11
    str = str.substr(3, str.length-6);
11
12
    var ret = eval(str);
12
 
    return ret ? ret.toString() : '';
 
13
    return ret !== null ? ret.toString() : '';
13
14
  });
14
15
}
15
16
 
16
17
// Simple #if/else/endif preprocessing for a file. Checks if the
17
18
// ident checked is true in our global.
 
19
// Also handles #include x.js (similar to C #include <file>)
18
20
function preprocess(text) {
19
21
  var lines = text.split('\n');
20
22
  var ret = '';
29
31
        ret += line + '\n';
30
32
      }
31
33
    } 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
 
          if (op === '==') {
39
 
            showStack.push(ident in this && this[ident] == value);
40
 
          } else if (op === '!=') {
41
 
            showStack.push(!(ident in this && this[ident] == value));
 
34
      if (line[1] == 'i') {
 
35
        if (line[2] == 'f') { // if
 
36
          var parts = line.split(' ');
 
37
          var ident = parts[1];
 
38
          var op = parts[2];
 
39
          var value = parts[3];
 
40
          if (op) {
 
41
            if (op === '==') {
 
42
              showStack.push(ident in this && this[ident] == value);
 
43
            } else if (op === '!=') {
 
44
              showStack.push(!(ident in this && this[ident] == value));
 
45
            } else {
 
46
              error('unsupported preprecessor op ' + op);
 
47
            }
42
48
          } else {
43
 
            error('unsupported preprecessor op ' + op);
 
49
            showStack.push(ident in this && this[ident] > 0);
44
50
          }
45
 
        } else {
46
 
          showStack.push(ident in this && this[ident] > 0);
 
51
        } else if (line[2] == 'n') { // include
 
52
          var included = read(line.substr(line.indexOf(' ')+1));
 
53
          ret += '\n' + preprocess(included) + '\n'
47
54
        }
48
 
      } else if (line[2] && line[2] == 'l') { // else
 
55
      } else if (line[2] == 'l') { // else
49
56
        showStack.push(!showStack.pop());
50
 
      } else if (line[2] && line[2] == 'n') { // endif
 
57
      } else if (line[2] == 'n') { // endif
51
58
        showStack.pop();
52
59
      } else {
53
60
        throw "Unclear preprocessor command: " + line;
110
117
}
111
118
 
112
119
function isJSVar(ident) {
113
 
  return /^\(?[$_]?[\w$_\d ]*\)+$/.test(ident);
114
 
 
 
120
  if (ident[0] === '(') {
 
121
    if (ident[ident.length-1] !== ')') return false;
 
122
    ident = ident.substr(1, ident.length-2);
 
123
  }
 
124
  return /^[$_]?[\w$_\d]* *$/.test(ident);
115
125
}
116
126
 
117
127
function isLocalVar(ident) {
118
 
  return ident[0] == '$';
 
128
  return ident[0] === '$';
 
129
}
 
130
 
 
131
// Simple variables or numbers, or things already quoted, do not need to be quoted
 
132
function needsQuoting(ident) {
 
133
  if (/^[-+]?[$_]?[\w$_\d]*$/.test(ident)) return false; // number or variable
 
134
  if (ident[0] === '(' && ident[ident.length-1] === ')' && ident.indexOf('(', 1) < 0) return false; // already fully quoted
 
135
  return true;
119
136
}
120
137
 
121
138
function isStructPointerType(type) {
146
163
  return type[0] == '%';
147
164
}
148
165
 
 
166
function isVectorType(type) {
 
167
  return type[type.length-1] === '>';
 
168
}
 
169
 
149
170
function isStructuralType(type) {
150
171
  return /^{ ?[^}]* ?}$/.test(type); // { i32, i8 } etc. - anonymous struct types
151
172
}
204
225
}
205
226
 
206
227
function isIllegalType(type) {
207
 
  var bits = getBits(type);
208
 
  return bits > 0 && (bits >= 64 || !isPowerOfTwo(bits));
 
228
  switch (type) {
 
229
    case 'i1':
 
230
    case 'i8':
 
231
    case 'i16':
 
232
    case 'i32':
 
233
    case 'float':
 
234
    case 'double':
 
235
    case 'rawJS':
 
236
    case '<2 x float>':
 
237
    case '<4 x float>':
 
238
    case '<2 x i32>':
 
239
    case '<4 x i32>':
 
240
    case 'void': return false;
 
241
  }
 
242
  if (!type || type[type.length-1] === '*') return false;
 
243
  return true;
209
244
}
210
245
 
211
246
function isVoidType(type) {
219
254
  if (nonPointing[0] != '(' || nonPointing.substr(-1) != ')')
220
255
    return false;
221
256
  if (nonPointing === '()') return true;
222
 
  if (!token.item) return false;
 
257
  if (!token.tokens) return false;
223
258
  var fail = false;
224
 
  var segments = splitTokenList(token.item.tokens);
 
259
  var segments = splitTokenList(token.tokens);
225
260
  segments.forEach(function(segment) {
226
261
    var subtext = segment[0].text;
227
262
    fail = fail || segment.length > 1 || !(isType(subtext) || subtext == '...');
269
304
    i--;
270
305
  }
271
306
  assert(argText);
272
 
  return isFunctionDef({ text: argText, item: tokenize(argText.substr(1, argText.length-2), true) }, out);
 
307
  return isFunctionDef({ text: argText, tokens: tokenize(argText.substr(1, argText.length-2)) }, out);
273
308
}
274
309
 
275
310
function getReturnType(type) {
276
311
  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
277
312
  var lastOpen = type.lastIndexOf('(');
278
313
  if (lastOpen > 0) {
 
314
    // handle things like   void (i32)* (i32, void (i32)*)*
 
315
    var closeStar = type.indexOf(')*');
 
316
    if (closeStar > 0 && closeStar < type.length-2) lastOpen = closeStar+3;
279
317
    return type.substr(0, lastOpen-1);
280
318
  }
281
319
  return type;
313
351
  return ret;
314
352
}
315
353
 
 
354
function getVectorSize(type) {
 
355
  return parseInt(type.substring(1, type.indexOf(' ')));
 
356
}
 
357
 
 
358
function getVectorNativeType(type) {
 
359
  Types.usesSIMD = true;
 
360
  switch (type) {
 
361
    case '<2 x float>':
 
362
    case '<4 x float>': return 'float';
 
363
    case '<2 x i32>':
 
364
    case '<4 x i32>': return 'i32';
 
365
    default: throw 'unknown vector type ' + type;
 
366
  }
 
367
}
 
368
 
 
369
function getSIMDName(type) {
 
370
  switch (type) {
 
371
    case 'i32': return 'int';
 
372
    case 'float': return 'float';
 
373
    default: throw 'getSIMDName ' + type;
 
374
  }
 
375
}
 
376
 
 
377
function getVectorBaseType(type) {
 
378
  return getSIMDName(getVectorNativeType(type));
 
379
}
 
380
 
316
381
function addIdent(token) {
317
382
  token.ident = token.text;
318
383
  return token;
365
430
function splitTokenList(tokens) {
366
431
  if (tokens.length == 0) return [];
367
432
  if (!tokens.slice) tokens = tokens.tokens;
368
 
  if (tokens.slice(-1)[0].text != ',') tokens.push({text:','});
369
433
  var ret = [];
370
434
  var seg = [];
371
435
  for (var i = 0; i < tokens.length; i++) {
375
439
      seg = [];
376
440
    } else if (token.text == ';') {
377
441
      ret.push(seg);
378
 
      break;
 
442
      return ret;
379
443
    } else {
380
444
      seg.push(token);
381
445
    }
382
446
  }
 
447
  if (seg.length) ret.push(seg);
383
448
  return ret;
384
449
}
385
450
 
386
451
function parseParamTokens(params) {
387
452
  if (params.length === 0) return [];
388
453
  var ret = [];
389
 
  if (params[params.length-1].text != ',') {
390
 
    params.push({ text: ',' });
391
 
  }
392
454
  var anonymousIndex = 0;
393
455
  while (params.length > 0) {
394
456
    var i = 0;
395
 
    while (params[i].text != ',') i++;
 
457
    while (i < params.length && params[i].text != ',') i++;
396
458
    var segment = params.slice(0, i);
397
459
    params = params.slice(i+1);
398
460
    segment = cleanSegment(segment);
401
463
      // handle 'byval' and 'byval align X'. We store the alignment in 'byVal'
402
464
      byVal = QUANTUM_SIZE;
403
465
      segment.splice(1, 1);
404
 
      if (segment[1] && segment[1].text === 'nocapture') {
 
466
      if (segment[1] && (segment[1].text === 'nocapture' || segment[1].text === 'readonly')) {
405
467
        segment.splice(1, 1);
406
468
      }
407
469
      if (segment[1] && segment[1].text === 'align') {
410
472
        segment.splice(1, 2);
411
473
      }
412
474
    }
413
 
    if (segment[1] && segment[1].text === 'nocapture') {
 
475
    if (segment[1] && (segment[1].text === 'nocapture' || segment[1].text === 'readonly')) {
414
476
      segment.splice(1, 1);
415
477
    }
416
478
    if (segment.length == 1) {
431
493
        Types.needAnalysis[ret[ret.length-1].type] = 0;
432
494
        anonymousIndex ++;
433
495
      }
434
 
    } else if (segment[1].text in PARSABLE_LLVM_FUNCTIONS) {
435
 
      ret.push(parseLLVMFunctionCall(segment));
436
 
    } else if (segment[1].text === 'blockaddress') {
437
 
      ret.push(parseBlockAddress(segment));
438
 
    } else if (segment[1].type && segment[1].type == '{') {
439
 
      ret.push(parseLLVMSegment(segment));
440
496
    } else {
441
497
      if (segment[2] && segment[2].text == 'to') { // part of bitcast params
442
498
        segment = segment.slice(0, 2);
443
499
      }
444
 
      while (segment.length > 2) {
445
 
        segment[0].text += segment[1].text;
446
 
        segment.splice(1, 1); // TODO: merge tokens nicely
447
 
      }
448
 
      ret.push({
449
 
        intertype: 'value',
450
 
        type: segment[0].text,
451
 
        ident: toNiceIdent(parseNumerical(segment[1].text, segment[0].text))
452
 
      });
453
 
      Types.needAnalysis[removeAllPointing(ret[ret.length-1].type)] = 0;
 
500
      var parsed = parseLLVMSegment(segment);
 
501
      if (parsed.intertype === 'value' && !isIllegalType(parsed.type)) parsed.ident = parseNumerical(parsed.ident, parsed.type);
 
502
      ret.push(parsed);
454
503
    }
455
504
    ret[ret.length-1].byVal = byVal;
456
505
  }
524
573
  });
525
574
}
526
575
 
527
 
function finalizeParam(param) {
528
 
  if (param.intertype in PARSABLE_LLVM_FUNCTIONS) {
529
 
    return finalizeLLVMFunctionCall(param);
530
 
  } else if (param.intertype === 'blockaddress') {
531
 
    return finalizeBlockAddress(param);
532
 
  } else if (param.intertype === 'jsvalue') {
533
 
    return param.ident;
534
 
  } else {
535
 
    if (param.type == 'i64' && USE_TYPED_ARRAYS == 2) {
536
 
      return parseI64Constant(param.ident);
537
 
    }
538
 
    var ret = toNiceIdent(param.ident);
539
 
    if (ret in Variables.globals) {
540
 
      ret = makeGlobalUse(ret);
541
 
    }
542
 
    return ret;
543
 
  }
544
 
}
545
 
 
546
576
// Segment ==> Parameter
547
577
function parseLLVMSegment(segment) {
548
578
  var type;
577
607
    return parseBlockAddress(segment);
578
608
  } else {
579
609
    type = segment[0].text;
 
610
    if (type[type.length-1] === '>' && segment[1].text[0] === '<') {
 
611
      // vector literal
 
612
      var nativeType = getVectorNativeType(type);
 
613
      return {
 
614
        intertype: 'vector',
 
615
        idents: splitTokenList(segment[1].tokens).map(function(pair) {
 
616
          return parseNumerical(pair[1].text, nativeType);
 
617
        }),
 
618
        type: type
 
619
      };
 
620
    }
580
621
    Types.needAnalysis[type] = 0;
581
622
    return {
582
623
      intertype: 'value',
587
628
}
588
629
 
589
630
function cleanSegment(segment) {
590
 
  while (segment.length >= 2 && ['noalias', 'sret', 'nocapture', 'nest', 'zeroext', 'signext'].indexOf(segment[1].text) != -1) {
 
631
  while (segment.length >= 2 && ['noalias', 'sret', 'nocapture', 'nest', 'zeroext', 'signext', 'readnone'].indexOf(segment[1].text) != -1) {
591
632
    segment.splice(1, 1);
592
633
  }
593
634
  return segment;
595
636
 
596
637
var MATHOPS = set(['add', 'sub', 'sdiv', 'udiv', 'mul', 'icmp', 'zext', 'urem', 'srem', 'fadd', 'fsub', 'fmul', 'fdiv', 'fcmp', 'frem', 'uitofp', 'sitofp', 'fpext', 'fptrunc', 'fptoui', 'fptosi', 'trunc', 'sext', 'select', 'shl', 'shr', 'ashl', 'ashr', 'lshr', 'lshl', 'xor', 'or', 'and', 'ptrtoint', 'inttoptr']);
597
638
 
 
639
var JS_MATH_BUILTINS = set(['Math_sin', 'Math_cos', 'Math_tan', 'Math_asin', 'Math_acos', 'Math_atan', 'Math_ceil', 'Math_floor', 'Math_exp', 'Math_log', 'Math_sqrt']);
 
640
 
598
641
var PARSABLE_LLVM_FUNCTIONS = set('getelementptr', 'bitcast');
599
642
mergeInto(PARSABLE_LLVM_FUNCTIONS, MATHOPS);
600
643
 
607
650
  segment = cleanSegment(segment);
608
651
  // Remove additional modifiers
609
652
  var variant = null;
610
 
  if (!segment[2] || !segment[2].item) {
 
653
  if (!segment[2] || !segment[2].tokens) {
611
654
    variant = segment.splice(2, 1)[0];
612
655
    if (variant && variant.text) variant = variant.text; // needed for mathops
613
656
  }
614
657
  assertTrue(['inreg', 'byval'].indexOf(segment[1].text) == -1);
615
658
  assert(segment[1].text in PARSABLE_LLVM_FUNCTIONS);
616
 
  while (!segment[2].item) {
 
659
  while (!segment[2].tokens) {
617
660
    segment.splice(2, 1); // Remove modifiers
618
661
    if (!segment[2]) throw 'Invalid segment!';
619
662
  }
622
665
  if (type === '?') {
623
666
    if (intertype === 'getelementptr') {
624
667
      type = '*'; // a pointer, we can easily say, this is
625
 
    } else if (segment[2].item.tokens.slice(-2)[0].text === 'to') {
626
 
      type = segment[2].item.tokens.slice(-1)[0].text;
 
668
    } else if (segment[2].tokens.slice(-2)[0].text === 'to') {
 
669
      type = segment[2].tokens.slice(-1)[0].text;
627
670
    }
628
671
  }
629
672
  var ret = {
630
673
    intertype: intertype,
631
674
    variant: variant,
632
675
    type: type,
633
 
    params: parseParamTokens(segment[2].item.tokens)
 
676
    params: parseParamTokens(segment[2].tokens)
634
677
  };
635
678
  Types.needAnalysis[ret.type] = 0;
636
679
  ret.ident = toNiceIdent(ret.params[0].ident || 'NOIDENT');
752
795
  if (floatConversion && ASM_JS) lowInput = asmFloatToInt(lowInput);
753
796
  var low = lowInput + '>>>0';
754
797
  var high = makeInlineCalculation(
755
 
    asmCoercion('Math.abs(VALUE)', 'double') + ' >= ' + asmEnsureFloat('1', 'double') + ' ? ' +
 
798
    asmCoercion('Math_abs(VALUE)', 'double') + ' >= ' + asmEnsureFloat('1', 'double') + ' ? ' +
756
799
      '(VALUE > ' + asmEnsureFloat('0', 'double') + ' ? ' +
757
 
               asmCoercion('Math.min(' + asmCoercion('Math.floor((VALUE)/' + asmEnsureFloat(4294967296, 'float') + ')', 'double') + ', ' + asmEnsureFloat(4294967295, 'float') + ')', 'i32') + '>>>0' +
758
 
               ' : ' + asmFloatToInt(asmCoercion('Math.ceil((VALUE - +((' + asmFloatToInt('VALUE') + ')>>>0))/' + asmEnsureFloat(4294967296, 'float') + ')', 'double')) + '>>>0' + 
 
800
               asmCoercion('Math_min(' + asmCoercion('Math_floor((VALUE)/' + asmEnsureFloat(4294967296, 'double') + ')', 'double') + ', ' + asmEnsureFloat(4294967295, 'double') + ')', 'i32') + '>>>0' +
 
801
               ' : ' + asmFloatToInt(asmCoercion('Math_ceil((VALUE - +((' + asmFloatToInt('VALUE') + ')>>>0))/' + asmEnsureFloat(4294967296, 'double') + ')', 'double')) + '>>>0' + 
759
802
      ')' +
760
803
    ' : 0',
761
804
    value,
903
946
}
904
947
 
905
948
function parseNumerical(value, type) {
906
 
  if ((!type || type == 'double' || type == 'float') && (value.substr && value.substr(0,2) == '0x')) {
 
949
  if ((!type || type === 'double' || type === 'float') && /^0x/.test(value)) {
907
950
    // Hexadecimal double value, as the llvm docs say,
908
951
    // "The one non-intuitive notation for constants is the hexadecimal form of floating point constants."
909
952
    value = IEEEUnHex(value);
910
953
  } else if (USE_TYPED_ARRAYS == 2 && isIllegalType(type)) {
911
954
    return value; // do not parseFloat etc., that can lead to loss of precision
912
 
  } else if (value == 'null') {
 
955
  } else if (value === 'null') {
913
956
    // NULL *is* 0, in C/C++. No JS null! (null == 0 is false, etc.)
914
957
    value = '0';
915
958
  } else if (value === 'true') {
919
962
  }
920
963
  if (isNumber(value)) {
921
964
    var ret = parseFloat(value); // will change e.g. 5.000000e+01 to 50
922
 
    if (type in Runtime.FLOAT_TYPES && value[0] == '-' && ret === 0) return '-0'; // fix negative 0, toString makes it 0
 
965
    // type may be undefined here, like when this is called from makeConst with a single argument.
 
966
    // but if it is a number, then we can safely assume that this should handle negative zeros
 
967
    // correctly.
 
968
    if (type === undefined || type === 'double' || type === 'float') {
 
969
      if (value[0] === '-' && ret === 0) { return '-.0'; } // fix negative 0, toString makes it 0
 
970
    }
 
971
    if (type === 'double' || type === 'float') {
 
972
      if (!RUNNING_JS_OPTS) ret = asmEnsureFloat(ret, type);
 
973
    }
923
974
    return ret.toString();
924
975
  } else {
925
976
    return value;
932
983
  var ret = [];
933
984
  var i = 0;
934
985
  while (i < str.length) {
935
 
    var chr = str[i];
936
 
    if (chr != '\\') {
937
 
      ret.push(chr.charCodeAt(0));
 
986
    var chr = str.charCodeAt(i);
 
987
    if (chr !== 92) { // 92 === '//'.charCodeAt(0)
 
988
      ret.push(chr);
938
989
      i++;
939
990
    } else {
940
 
      ret.push(eval('0x' + str[i+1]+str[i+2]));
 
991
      ret.push(parseInt(str[i+1]+str[i+2], '16'));
941
992
      i += 3;
942
993
    }
943
994
  }
944
995
  return ret;
945
996
}
946
997
 
 
998
function expandLLVMString(str) {
 
999
  return str.replace(/\\../g, function(m) {
 
1000
    return String.fromCharCode(parseInt(m.substr(1), '16'));
 
1001
  });
 
1002
}
 
1003
 
947
1004
function getLabelIds(labels) {
948
1005
  return labels.map(function(label) { return label.ident });
949
1006
}
962
1019
}
963
1020
 
964
1021
function calcAllocatedSize(type) {
965
 
  if (pointingLevels(type) == 0 && isStructType(type)) {
966
 
    return Types.types[type].flatSize; // makeEmptyStruct(item.allocatedType).length;
967
 
  } else {
968
 
    return Runtime.getNativeTypeSize(type); // We can really get away with '1', though, at least on the stack...
969
 
  }
 
1022
  var ret = Runtime.getNativeTypeSize(type);
 
1023
  if (ret) return ret;
 
1024
  return Types.types[type].flatSize; // known type
970
1025
}
971
1026
 
972
1027
// Generates the type signature for a structure, for each byte, the type that is there.
986
1041
  var ret = new Array(size);
987
1042
  var index = 0;
988
1043
  function add(typeData) {
 
1044
    var array = typeData.name_[0] === '['; // arrays just have 2 elements in their fields, see calculateStructAlignment
 
1045
    var num = array ? parseInt(typeData.name_.substr(1)) : typeData.fields.length;
989
1046
    var start = index;
990
 
    for (var i = 0; i < typeData.fields.length; i++) {
991
 
      var type = typeData.fields[i];
 
1047
    for (var i = 0; i < num; i++) {
 
1048
      var type = array ? typeData.fields[0] : typeData.fields[i];
992
1049
      if (!SAFE_HEAP && isPointerType(type)) type = '*'; // do not include unneeded type names without safe heap
993
1050
      if (Runtime.isNumberType(type) || isPointerType(type)) {
994
1051
        if (USE_TYPED_ARRAYS == 2 && type == 'i64') {
1011
1068
        }
1012
1069
        add(Types.types[type]);
1013
1070
      }
1014
 
      var more = (i+1 < typeData.fields.length ? typeData.flatIndexes[i+1] : typeData.flatSize) - (index - start);
 
1071
      var more = array ? (i+1)*typeData.flatSize/num : (
 
1072
        (i+1 < typeData.fields.length ? typeData.flatIndexes[i+1] : typeData.flatSize)
 
1073
      );
 
1074
      more -= index - start;
1015
1075
      for (var j = 0; j < more; j++) {
1016
1076
        ret[index++] = 0;
1017
1077
      }
1121
1181
  return js;
1122
1182
}
1123
1183
 
 
1184
function ensureDot(value) {
 
1185
  value = value.toString();
 
1186
  // if already dotted, or Infinity or NaN, nothing to do here
 
1187
  // if smaller than 1 and running js opts, we always need to force a coercion (0.001 will turn into 1e-3, which has no .)
 
1188
  if ((value.indexOf('.') >= 0 || /[IN]/.test(value)) && (!RUNNING_JS_OPTS || Math.abs(value) >= 1)) return value;
 
1189
  if (RUNNING_JS_OPTS) return '(+' + value + ')'; // JS optimizer will run, we must do +x, and it will be corrected later
 
1190
  var e = value.indexOf('e');
 
1191
  if (e < 0) return value + '.0';
 
1192
  return value.substr(0, e) + '.0' + value.substr(e);
 
1193
}
 
1194
 
1124
1195
function asmEnsureFloat(value, type) { // ensures that a float type has either 5.5 (clearly a float) or +5 (float due to asm coercion)
1125
1196
  if (!ASM_JS) return value;
1126
 
  // coerce if missing a '.', or if smaller than 1, so could be 1e-5 which has no .
1127
 
  if (type in Runtime.FLOAT_TYPES && isNumber(value) && (value.toString().indexOf('.') < 0 || Math.abs(value) < 1)) {
1128
 
    return '(+(' + value + '))';
 
1197
  if (!isNumber(value)) return value;
 
1198
  if (PRECISE_F32 && type === 'float') {
 
1199
    // normally ok to just emit Math_fround(0), but if the constant is large we may need a .0 (if it can't fit in an int)
 
1200
    if (value == 0) return 'Math_fround(0)';
 
1201
    value = ensureDot(value);
 
1202
    return 'Math_fround(' + value + ')';
 
1203
  }
 
1204
  if (type in Runtime.FLOAT_TYPES) {
 
1205
    return ensureDot(value);
1129
1206
  } else {
1130
1207
    return value;
1131
1208
  }
1132
1209
}
1133
1210
 
1134
 
function asmInitializer(type, impl) {
 
1211
function asmInitializer(type) {
1135
1212
  if (type in Runtime.FLOAT_TYPES) {
1136
 
    return '+0';
 
1213
    if (PRECISE_F32 && type === 'float') return 'Math_fround(0)';
 
1214
    return RUNNING_JS_OPTS ? '+0' : '.0';
1137
1215
  } else {
1138
1216
    return '0';
1139
1217
  }
1154
1232
          value = '(' + value + ')|0';
1155
1233
        }
1156
1234
      }
1157
 
      return '(+(' + value + '))';
 
1235
      if (PRECISE_F32 && type === 'float') {
 
1236
        return 'Math_fround(' + value + ')';
 
1237
      } else {
 
1238
        return '(+(' + value + '))';
 
1239
      }
1158
1240
    }
1159
1241
  } else {
1160
1242
    return '((' + value + ')|0)';
1196
1278
    var typeData = Types.types[type];
1197
1279
    var ret = [];
1198
1280
    for (var i = 0; i < typeData.fields.length; i++) {
1199
 
      ret.push('f' + i + ': ' + makeGetValue(ptr, pos + typeData.flatIndexes[i], typeData.fields[i], noNeedFirst, unsigned));
 
1281
      ret.push('f' + i + ': ' + makeGetValue(ptr, pos + typeData.flatIndexes[i], typeData.fields[i], noNeedFirst, unsigned, 0, 0, noSafe));
1200
1282
    }
1201
1283
    return '{ ' + ret.join(', ') + ' }';
1202
1284
  }
1204
1286
  // In double mode 1, in x86 we always assume unaligned because we can't trust that; otherwise in le32
1205
1287
  // we need this code path if we are not fully aligned.
1206
1288
  if (DOUBLE_MODE == 1 && USE_TYPED_ARRAYS == 2 && type == 'double' && (TARGET_X86 || align < 8)) {
1207
 
    return '(' + makeSetTempDouble(0, 'i32', makeGetValue(ptr, pos, 'i32', noNeedFirst, unsigned, ignore, align)) + ',' +
1208
 
                 makeSetTempDouble(1, 'i32', makeGetValue(ptr, getFastValue(pos, '+', Runtime.getNativeTypeSize('i32')), 'i32', noNeedFirst, unsigned, ignore, align)) + ',' +
 
1289
    return '(' + makeSetTempDouble(0, 'i32', makeGetValue(ptr, pos, 'i32', noNeedFirst, unsigned, ignore, align, noSafe)) + ',' +
 
1290
                 makeSetTempDouble(1, 'i32', makeGetValue(ptr, getFastValue(pos, '+', Runtime.getNativeTypeSize('i32')), 'i32', noNeedFirst, unsigned, ignore, align, noSafe)) + ',' +
1209
1291
            makeGetTempDouble(0, 'double') + ')';
1210
1292
  }
1211
1293
 
1218
1300
      if (isIntImplemented(type)) {
1219
1301
        if (bytes == 4 && align == 2) {
1220
1302
          // Special case that we can optimize
1221
 
          ret += makeGetValue(ptr, pos, 'i16', noNeedFirst, 2, ignore) + '|' +
1222
 
                 '(' + makeGetValue(ptr, getFastValue(pos, '+', 2), 'i16', noNeedFirst, 2, ignore) + '<<16)';
 
1303
          ret += makeGetValue(ptr, pos, 'i16', noNeedFirst, 2, ignore, 2, noSafe) + '|' +
 
1304
                 '(' + makeGetValue(ptr, getFastValue(pos, '+', 2), 'i16', noNeedFirst, 2, ignore, 2, noSafe) + '<<16)';
1223
1305
        } else { // XXX we cannot truly handle > 4... (in x86)
1224
1306
          ret = '';
1225
1307
          for (var i = 0; i < bytes; i++) {
1226
 
            ret += '(' + makeGetValue(ptr, getFastValue(pos, '+', i), 'i8', noNeedFirst, 1, ignore) + (i > 0 ? '<<' + (8*i) : '') + ')';
 
1308
            ret += '(' + makeGetValue(ptr, getFastValue(pos, '+', i), 'i8', noNeedFirst, 1, ignore, 1, noSafe) + (i > 0 ? '<<' + (8*i) : '') + ')';
1227
1309
            if (i < bytes-1) ret += '|';
1228
1310
          }
1229
1311
          ret = '(' + makeSignOp(ret, type, unsigned ? 'un' : 're', true);
1302
1384
      value = range(typeData.fields.length).map(function(i) { return value + '.f' + i });
1303
1385
    }
1304
1386
    for (var i = 0; i < typeData.fields.length; i++) {
1305
 
      ret.push(makeSetValue(ptr, getFastValue(pos, '+', typeData.flatIndexes[i]), value[i], typeData.fields[i], noNeedFirst));
 
1387
      ret.push(makeSetValue(ptr, getFastValue(pos, '+', typeData.flatIndexes[i]), value[i], typeData.fields[i], noNeedFirst, 0, 0, noSafe));
1306
1388
    }
1307
1389
    return ret.join('; ');
1308
1390
  }
1329
1411
        if (bytes == 4 && align == 2) {
1330
1412
          // Special case that we can optimize
1331
1413
          ret += 'tempBigInt=' + value + sep;
1332
 
          ret += makeSetValue(ptr, pos, 'tempBigInt&0xffff', 'i16', noNeedFirst, ignore, 2) + sep;
1333
 
          ret += makeSetValue(ptr, getFastValue(pos, '+', 2), 'tempBigInt>>16', 'i16', noNeedFirst, ignore, 2);
 
1414
          ret += makeSetValue(ptr, pos, 'tempBigInt&0xffff', 'i16', noNeedFirst, ignore, 2, noSafe) + sep;
 
1415
          ret += makeSetValue(ptr, getFastValue(pos, '+', 2), 'tempBigInt>>16', 'i16', noNeedFirst, ignore, 2, noSafe);
1334
1416
        } else {
1335
1417
          ret += 'tempBigInt=' + value + sep;
1336
1418
          for (var i = 0; i < bytes; i++) {
1337
 
            ret += makeSetValue(ptr, getFastValue(pos, '+', i), 'tempBigInt&0xff', 'i8', noNeedFirst, ignore, 1);
 
1419
            ret += makeSetValue(ptr, getFastValue(pos, '+', i), 'tempBigInt&0xff', 'i8', noNeedFirst, ignore, 1, noSafe);
1338
1420
            if (i < bytes-1) ret += sep + 'tempBigInt = tempBigInt>>8' + sep;
1339
1421
          }
1340
1422
        }
1341
1423
      } else {
1342
 
        ret += makeSetValue('tempDoublePtr', 0, value, type, noNeedFirst, ignore, 8, null, null, true) + sep;
 
1424
        ret += makeSetValue('tempDoublePtr', 0, value, type, noNeedFirst, ignore, 8, noSafe, null, true) + sep;
1343
1425
        ret += makeCopyValues(getFastValue(ptr, '+', pos), 'tempDoublePtr', Runtime.getNativeTypeSize(type), type, null, align, sep);
1344
1426
      }
1345
1427
      return ret;
1348
1430
 
1349
1431
  value = indexizeFunctions(value, type);
1350
1432
  var offset = calcFastOffset(ptr, pos, noNeedFirst);
 
1433
  if (phase === 'pre' && isNumber(offset)) offset += ' '; // avoid pure numeric strings, seem to be perf issues with overly-aggressive interning or slt in pre processing of heap inits
1351
1434
  if (SAFE_HEAP && !noSafe) {
1352
1435
    var printType = type;
1353
1436
    if (printType !== 'null' && printType[0] !== '#') printType = '"' + safeQuote(printType) + '"';
1382
1465
    // 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
1383
1466
    // TODO: optimize the case of numeric num but non-numeric value
1384
1467
    if (!isNumber(num) || !isNumber(value) || (parseInt(num)/align >= UNROLL_LOOP_MAX)) {
1385
 
      return '_memset(' + asmCoercion(getFastValue(ptr, '+', pos), 'i32') + ', ' + asmCoercion(value, 'i32') + ', ' + asmCoercion(num, 'i32') + ')';
 
1468
      return '_memset(' + asmCoercion(getFastValue(ptr, '+', pos), 'i32') + ', ' + asmCoercion(value, 'i32') + ', ' + asmCoercion(num, 'i32') + ')|0';
1386
1469
    }
1387
1470
    num = parseInt(num);
1388
1471
    value = parseInt(value);
1464
1547
  return 'HEAP' + which + '.subarray((' + start + ')' + mod + ',(' + end + ')' + mod + ')';
1465
1548
}
1466
1549
 
1467
 
var PLUS_MUL = set('+', '*');
1468
 
var MUL_DIV = set('*', '/');
1469
 
var PLUS_MINUS = set('+', '-');
1470
1550
var TWO_TWENTY = Math.pow(2, 20);
1471
1551
 
1472
1552
// Given two values and an operation, returns the result of that operation.
1473
1553
// Tries to do as much as possible at compile time.
1474
1554
// Leaves overflows etc. unhandled, *except* for integer multiply, in order to be efficient with Math.imul
1475
1555
function getFastValue(a, op, b, type) {
1476
 
  a = a.toString();
1477
 
  b = b.toString();
1478
 
  a = a == 'true' ? '1' : (a == 'false' ? '0' : a);
1479
 
  b = b == 'true' ? '1' : (b == 'false' ? '0' : b);
1480
 
  if (isNumber(a) && isNumber(b)) {
1481
 
    if (op == 'pow') {
1482
 
      return Math.pow(a, b).toString();
1483
 
    } else {
1484
 
      var value = eval(a + op + '(' + b + ')'); // parens protect us from "5 - -12" being seen as "5--12" which is "(5--)12"
1485
 
      if (op == '/' && type in Runtime.INT_TYPES) value = value|0; // avoid emitting floats
1486
 
      return value.toString();
 
1556
  a = a === 'true' ? '1' : (a === 'false' ? '0' : a);
 
1557
  b = b === 'true' ? '1' : (b === 'false' ? '0' : b);
 
1558
 
 
1559
  var aNumber = null, bNumber = null;
 
1560
  if (typeof a === 'number') {
 
1561
    aNumber = a;
 
1562
    a = a.toString();
 
1563
  } else if (isNumber(a)) aNumber = parseFloat(a);
 
1564
  if (typeof b === 'number') {
 
1565
    bNumber = b;
 
1566
    b = b.toString();
 
1567
  } else if (isNumber(b)) bNumber = parseFloat(b);
 
1568
 
 
1569
  if (aNumber !== null && bNumber !== null) {
 
1570
    switch (op) {
 
1571
      case '+': return (aNumber + bNumber).toString();
 
1572
      case '-': return (aNumber - bNumber).toString();
 
1573
      case '*': return (aNumber * bNumber).toString();
 
1574
      case '/': {
 
1575
        if (type[0] === 'i') {
 
1576
          return ((aNumber / bNumber)|0).toString();
 
1577
        } else {
 
1578
          return (aNumber / bNumber).toString();
 
1579
        }
 
1580
      }
 
1581
      case '%': return (aNumber % bNumber).toString();
 
1582
      case '|': return (aNumber | bNumber).toString();
 
1583
      case '>>>': return (aNumber >>> bNumber).toString();
 
1584
      case '&': return (aNumber & bNumber).toString();
 
1585
      case 'pow': return Math.pow(aNumber, bNumber).toString();
 
1586
      default: throw 'need to implement getFastValue pn ' + op;
1487
1587
    }
1488
1588
  }
1489
 
  if (op == 'pow') {
1490
 
    if (a == '2' && isIntImplemented(type)) {
 
1589
  if (op === 'pow') {
 
1590
    if (a === '2' && isIntImplemented(type)) {
1491
1591
      return '(1 << (' + b + '))';
1492
1592
    }
1493
 
    return 'Math.pow(' + a + ', ' + b + ')';
 
1593
    return 'Math_pow(' + a + ', ' + b + ')';
1494
1594
  }
1495
 
  if (op in PLUS_MUL && isNumber(a)) { // if one of them is a number, keep it last
 
1595
  if ((op === '+' || op === '*') && aNumber !== null) { // if one of them is a number, keep it last
1496
1596
    var c = b;
1497
1597
    b = a;
1498
1598
    a = c;
 
1599
    var cNumber = bNumber;
 
1600
    bNumber = aNumber;
 
1601
    aNumber = cNumber;
1499
1602
  }
1500
 
  if (op in MUL_DIV) {
1501
 
    if (op == '*') {
1502
 
      if (a == 0 || b == 0) {
1503
 
        return '0';
1504
 
      } else if (a == 1) {
1505
 
        return b;
1506
 
      } else if (b == 1) {
1507
 
        return a;
1508
 
      } else if (isNumber(b) && type && isIntImplemented(type) && Runtime.getNativeTypeSize(type) <= 32) {
1509
 
        var shifts = Math.log(parseFloat(b))/Math.LN2;
1510
 
        if (shifts % 1 == 0) {
1511
 
          return '(' + a + '<<' + shifts + ')';
1512
 
        }
1513
 
      }
1514
 
      if (!(type in Runtime.FLOAT_TYPES)) {
1515
 
        // if guaranteed small enough to not overflow into a double, do a normal multiply
1516
 
        var bits = getBits(type) || 32; // default is 32-bit multiply for things like getelementptr indexes
1517
 
        // Note that we can emit simple multiple in non-asm.js mode, but asm.js will not parse "16-bit" multiple, so must do imul there
1518
 
        if ((isNumber(a) && Math.abs(a) < TWO_TWENTY) || (isNumber(b) && Math.abs(b) < TWO_TWENTY) || (bits < 32 && !ASM_JS)) {
1519
 
          return '(((' + a + ')*(' + b + '))&' + ((Math.pow(2, bits)-1)|0) + ')'; // keep a non-eliminatable coercion directly on this
1520
 
        }
1521
 
        return '(Math.imul(' + a + ',' + b + ')|0)';
1522
 
      }
1523
 
    } else {
1524
 
      if (a == '0') {
1525
 
        return '0';
1526
 
      } else if (b == 1) {
1527
 
        return a;
1528
 
      } // Doing shifts for division is problematic, as getting the rounding right on negatives is tricky
1529
 
    }
1530
 
  } else if (op in PLUS_MINUS) {
1531
 
    if (b[0] == '-') {
1532
 
      op = op == '+' ? '-' : '+';
 
1603
  if (op === '*') {
 
1604
    // We can't eliminate where a or b are 0 as that would break things for creating
 
1605
    // a negative 0.
 
1606
    if ((aNumber === 0 || bNumber === 0) && !(type in Runtime.FLOAT_TYPES)) {
 
1607
      return '0';
 
1608
    } else if (aNumber === 1) {
 
1609
      return b;
 
1610
    } else if (bNumber === 1) {
 
1611
      return a;
 
1612
    } else if (bNumber !== null && type && isIntImplemented(type) && Runtime.getNativeTypeSize(type) <= 32) {
 
1613
      var shifts = Math.log(bNumber)/Math.LN2;
 
1614
      if (shifts % 1 === 0) {
 
1615
        return '(' + a + '<<' + shifts + ')';
 
1616
      }
 
1617
    }
 
1618
    if (!(type in Runtime.FLOAT_TYPES)) {
 
1619
      // if guaranteed small enough to not overflow into a double, do a normal multiply
 
1620
      var bits = getBits(type) || 32; // default is 32-bit multiply for things like getelementptr indexes
 
1621
      // Note that we can emit simple multiple in non-asm.js mode, but asm.js will not parse "16-bit" multiple, so must do imul there
 
1622
      if ((aNumber !== null && Math.abs(a) < TWO_TWENTY) || (bNumber !== null && Math.abs(b) < TWO_TWENTY) || (bits < 32 && !ASM_JS)) {
 
1623
        return '(((' + a + ')*(' + b + '))&' + ((Math.pow(2, bits)-1)|0) + ')'; // keep a non-eliminatable coercion directly on this
 
1624
      }
 
1625
      return '(Math_imul(' + a + ',' + b + ')|0)';
 
1626
    }
 
1627
  } else if (op === '/') {
 
1628
    if (a === '0' && !(type in Runtime.FLOAT_TYPES)) { // careful on floats, since 0*NaN is not 0
 
1629
      return '0';
 
1630
    } else if (b === 1) {
 
1631
      return a;
 
1632
    } // Doing shifts for division is problematic, as getting the rounding right on negatives is tricky
 
1633
  } else if (op === '+' || op === '-') {
 
1634
    if (b[0] === '-') {
 
1635
      op = op === '+' ? '-' : '+';
1533
1636
      b = b.substr(1);
1534
1637
    }
1535
 
    if (a == 0) {
1536
 
      return op == '+' ? b : '(-' + b + ')';
1537
 
    } else if (b == 0) {
 
1638
    if (aNumber === 0) {
 
1639
      return op === '+' ? b : '(-' + b + ')';
 
1640
    } else if (bNumber === 0) {
1538
1641
      return a;
1539
1642
    }
1540
1643
  }
1542
1645
}
1543
1646
 
1544
1647
function getFastValues(list, op, type) {
1545
 
  assert(op == '+');
 
1648
  assert(op === '+' && type === 'i32');
 
1649
  for (var i = 0; i < list.length; i++) {
 
1650
    if (isNumber(list[i])) list[i] = (list[i]|0) + '';
 
1651
  }
1546
1652
  var changed = true;
1547
1653
  while (changed) {
1548
1654
    changed = false;
1550
1656
      var fast = getFastValue(list[i], op, list[i+1], type);
1551
1657
      var raw = list[i] + op + list[i+1];
1552
1658
      if (fast.length < raw.length || fast.indexOf(op) < 0) {
 
1659
        if (isNumber(fast)) fast = (fast|0) + '';
1553
1660
        list[i] = fast;
1554
1661
        list.splice(i+1, 1);
1555
1662
        i--;
1563
1670
}
1564
1671
 
1565
1672
function calcFastOffset(ptr, pos, noNeedFirst) {
1566
 
  var offset = noNeedFirst ? '0' : makeGetPos(ptr);
1567
 
  return getFastValue(offset, '+', pos, 'i32');
1568
 
}
1569
 
 
1570
 
function makeGetPos(ptr) {
1571
 
  return ptr;
 
1673
  assert(!noNeedFirst);
 
1674
  return getFastValue(ptr, '+', pos, 'i32');
1572
1675
}
1573
1676
 
1574
1677
var IHEAP_FHEAP = set('IHEAP', 'IHEAPU', 'FHEAP');
1727
1830
    switch(type) {
1728
1831
      case 'i1': case 'i8': return [unsigned ? 'HEAPU8' : 'HEAP8']; break;
1729
1832
      case 'i16': return [unsigned ? 'HEAPU16' : 'HEAP16']; break;
 
1833
      case '<4 x i32>':
1730
1834
      case 'i32': case 'i64': return [unsigned ? 'HEAPU32' : 'HEAP32']; break;
1731
1835
      case 'double': {
1732
1836
        if (TARGET_LE32) return ['HEAPF64']; // in le32, we do have the ability to assume 64-bit alignment
1733
1837
        // otherwise, fall through to float
1734
1838
      }
 
1839
      case '<4 x float>':
1735
1840
      case 'float': return ['HEAPF32'];
1736
1841
      default: {
1737
1842
        throw 'what, exactly, can we do for unknown types in TA2?! ' + [new Error().stack, ptr, type, allowMultiple, unsigned];
1758
1863
      } else {
1759
1864
        warnOnce('Casting a function pointer type to a potentially incompatible one (use -s VERBOSE=1 to see more)');
1760
1865
      }
1761
 
      warnOnce('See https://github.com/kripken/emscripten/wiki/CodeGuidlinesAndLimitations#function-pointer-issues for more information on dangerous function pointer casts');
 
1866
      warnOnce('See https://github.com/kripken/emscripten/wiki/CodeGuidelinesAndLimitations#function-pointer-issues for more information on dangerous function pointer casts');
1762
1867
      if (ASM_JS) warnOnce('Incompatible function pointer casts are very dangerous with ASM_JS=1, you should investigate and correct these');
1763
1868
    }
1764
1869
    if (oldCount != newCount && oldCount && newCount) showWarning();
1805
1910
  // struct, and possibly further substructures, all embedded
1806
1911
  // can also be to 'blocks': [8 x i32]*, not just structs
1807
1912
  type = removePointing(type);
1808
 
  var indexes = [makeGetPos(ident)];
 
1913
  var indexes = [ident];
1809
1914
  var offset = item.params[1];
1810
1915
  if (offset != 0) {
1811
1916
    if (isStructType(type)) {
1860
1965
  if (CHECK_OVERFLOWS) return 'CHECK_OVERFLOW(' + text + ', ' + bits + ', ' + Math.floor(correctSpecificOverflow()) + ')';
1861
1966
  if (!correct) return text;
1862
1967
  if (bits == 32) {
 
1968
    if (isNumber(text)) return text | 0;
1863
1969
    return '((' + text + ')|0)';
1864
1970
  } else if (bits < 32) {
 
1971
    if (isNumber(text)) return text & (Math.pow(2, bits) - 1);
1865
1972
    return '((' + text + ')&' + (Math.pow(2, bits) - 1) + ')';
1866
1973
  } else {
1867
1974
    return text; // We warned about this earlier
1916
2023
  } else if (param.ident == 'zeroinitializer') {
1917
2024
    if (isStructType(param.type)) {
1918
2025
      return makeLLVMStruct(zeros(Types.types[param.type].fields.length));
 
2026
    } else if (isVectorType(param.type)) {
 
2027
      return ensureVector(0, getVectorBaseType(param.type));
1919
2028
    } else {
1920
2029
      return '0';
1921
2030
    }
1937
2046
    return param.ident; // we don't really want the type here
1938
2047
  } else if (param.intertype == 'mathop') {
1939
2048
    return processMathop(param);
 
2049
  } else if (param.intertype === 'vector') {
 
2050
    return getVectorBaseType(param.type) + '32x4(' + param.idents.join(',') + ')';
1940
2051
  } else {
1941
2052
    throw 'invalid llvm parameter: ' + param.intertype;
1942
2053
  }
1951
2062
    return asmCoercion(a, type) + op + asmCoercion(b, type);
1952
2063
  } else {
1953
2064
    assert(type == 'i64');
1954
 
    return asmCoercion(a + '$0', 'i32') + op + asmCoercion(b + '$0', 'i32') + ' & ' +
 
2065
    return asmCoercion(a + '$0', 'i32') + op + asmCoercion(b + '$0', 'i32') + '&' +
1955
2066
           asmCoercion(a + '$1', 'i32') + op + asmCoercion(b + '$1', 'i32');
1956
2067
  }
1957
2068
}
1960
2071
  if (USE_TYPED_ARRAYS == 2 && type == 'i64') {
1961
2072
    return value; // these are always assumed to be two 32-bit unsigneds.
1962
2073
  }
1963
 
 
1964
2074
  if (isPointerType(type)) type = 'i32'; // Pointers are treated as 32-bit ints
1965
2075
  if (!value) return value;
1966
2076
  var bits, full;
1967
 
  if (type in Runtime.INT_TYPES) {
 
2077
  if (type[0] === 'i') {
1968
2078
    bits = parseInt(type.substr(1));
1969
 
    full = op + 'Sign(' + value + ', ' + bits + ', ' + Math.floor(ignore || (correctSpecificSign())) + ')';
 
2079
    full = op + 'Sign(' + value + ', ' + bits + ', ' + Math.floor(ignore || correctSpecificSign()) + ')';
1970
2080
    // Always sign/unsign constants at compile time, regardless of CHECK/CORRECT
1971
2081
    if (isNumber(value)) {
1972
2082
      return eval(full).toString();
1973
2083
    }
1974
2084
  }
1975
2085
  if ((ignore || !correctSigns()) && !CHECK_SIGNS && !force) return value;
1976
 
  if (type in Runtime.INT_TYPES) {
 
2086
  if (type[0] === 'i') {
 
2087
    // this is an integer, but not a number (or we would have already handled it)
1977
2088
    // shortcuts
1978
2089
    if (!CHECK_SIGNS || ignore) {
 
2090
      if (value === 'true') {
 
2091
        value = '1';
 
2092
      } else if (value === 'false') {
 
2093
        value = '0';
 
2094
      } else if (needsQuoting(value)) value = '(' + value + ')';
1979
2095
      if (bits === 32) {
1980
2096
        if (op === 're') {
1981
 
          return '(' + getFastValue(value, '|', '0') + ')';
 
2097
          return '(' + value + '|0)';
1982
2098
        } else {
1983
 
 
1984
 
          return '(' + getFastValue(value, '>>>', '0') + ')';
1985
 
          // Alternatively, we can consider the lengthier
1986
 
          //    return makeInlineCalculation('VALUE >= 0 ? VALUE : ' + Math.pow(2, bits) + ' + VALUE', value, 'tempBigInt');
1987
 
          // which does not always turn us into a 32-bit *un*signed value
 
2099
          return '(' + value +  '>>>0)';
1988
2100
        }
1989
2101
      } else if (bits < 32) {
1990
2102
        if (op === 're') {
1991
 
          return makeInlineCalculation('(VALUE << ' + (32-bits) + ') >> ' + (32-bits), value, 'tempInt');
 
2103
          return '((' + value + '<<' + (32-bits) + ')>>' + (32-bits) + ')';
1992
2104
        } else {
1993
 
          return '(' + getFastValue(value, '&', Math.pow(2, bits)-1) + ')';
 
2105
          return '(' + value + '&' + (Math.pow(2, bits)-1) + ')';
1994
2106
        }
1995
2107
      } else { // bits > 32
1996
2108
        if (op === 're') {
2018
2130
                                                             // as |0, but &-1 hints to the js optimizer that this is a rounding correction
2019
2131
    // Do Math.floor, which is reasonably fast, if we either don't care, or if we can be sure
2020
2132
    // the value is non-negative
2021
 
    if (!correctRoundings() || (!signed && !floatConversion)) return 'Math.floor(' + value + ')';
 
2133
    if (!correctRoundings() || (!signed && !floatConversion)) return 'Math_floor(' + value + ')';
2022
2134
    // We are left with >32 bits signed, or a float conversion. Check and correct inline
2023
2135
    // Note that if converting a float, we may have the wrong sign at this point! But, we have
2024
2136
    // been rounded properly regardless, and we will be sign-corrected later when actually used, if
2025
2137
    // necessary.
2026
 
    return makeInlineCalculation(makeComparison('VALUE', '>=', '0', 'float') + ' ? Math.floor(VALUE) : Math.ceil(VALUE)', value, 'tempBigIntR');
 
2138
    return makeInlineCalculation(makeComparison('VALUE', '>=', '0', 'float') + ' ? Math_floor(VALUE) : Math_ceil(VALUE)', value, 'tempBigIntR');
2027
2139
  } else {
2028
2140
    // asm.js mode, cleaner refactoring of this function as well. TODO: use in non-asm case, most of this
2029
2141
    if (floatConversion && bits <= 32) {
2038
2150
      }
2039
2151
    }
2040
2152
    // Math.floor is reasonably fast if we don't care about corrections (and even correct if unsigned)
2041
 
    if (!correctRoundings() || !signed) return 'Math.floor(' + value + ')';
 
2153
    if (!correctRoundings() || !signed) return '(+Math_floor(' + value + '))';
2042
2154
    // We are left with >32 bits
2043
 
    return makeInlineCalculation(makeComparison('VALUE', '>=', '0', 'float') + ' ? Math.floor(VALUE) : Math.ceil(VALUE)', value, 'tempBigIntR');
 
2155
    return makeInlineCalculation(makeComparison('VALUE', '>=', '0', 'float') + ' ? +Math_floor(VALUE) : +Math_ceil(VALUE)', value, 'tempBigIntR');
2044
2156
  }
2045
2157
}
2046
2158
 
2047
 
function makeIsNaN(value) {
2048
 
  if (ASM_JS) return makeInlineCalculation('((VALUE) != (VALUE))', value, 'tempDouble');
 
2159
function makeIsNaN(value, type) {
 
2160
  if (ASM_JS) return makeInlineCalculation('((VALUE) != (VALUE))', value, type === 'float' ? 'tempFloat' : 'tempDouble');
2049
2161
  return 'isNaN(' + value + ')';
2050
2162
}
2051
2163
 
2052
2164
function makeFloat(value, type) {
2053
 
  if (TO_FLOAT32 && type == 'float') {
2054
 
    return 'Math.toFloat32(' + value + ')';
 
2165
  if (PRECISE_F32 && type == 'float') {
 
2166
    return 'Math_fround(' + value + ')';
2055
2167
  }
2056
2168
  return value;
2057
2169
}
2080
2192
    if (item.params[i]) {
2081
2193
      paramTypes[i] = item.params[i].type || type;
2082
2194
      idents[i] = finalizeLLVMParameter(item.params[i]);
2083
 
      if (!isNumber(idents[i]) && !isNiceIdent(idents[i])) {
 
2195
      if (needsQuoting(idents[i])) {
2084
2196
        idents[i] = '(' + idents[i] + ')'; // we may have nested expressions. So enforce the order of operations we want
2085
2197
      }
2086
2198
    } else {
2127
2239
      // If this is in legalization mode, steal the assign and assign into two vars
2128
2240
      if (legalizedI64s) {
2129
2241
        assert(item.assignTo);
2130
 
        var ret = 'var ' + item.assignTo + '$0 = ' + result[0] + '; var ' + item.assignTo + '$1 = ' + result[1] + ';';
 
2242
        if (ASM_JS) {
 
2243
          var ret = item.assignTo + '$0=' + result[0] + ';' + item.assignTo + '$1=' + result[1] + ';';
 
2244
          addVariable(item.assignTo + '$0', 'i32');
 
2245
          addVariable(item.assignTo + '$1', 'i32');
 
2246
        } else {
 
2247
          var ret = 'var ' + item.assignTo + '$0=' + result[0] + ';var ' + item.assignTo + '$1=' + result[1] + ';';
 
2248
        } 
2131
2249
        item.assignTo = null;
2132
2250
        return ret;
2133
2251
      } else {
2162
2280
      case 'lshr': {
2163
2281
                                throw 'shifts should have been legalized!';
2164
2282
      }
2165
 
      case 'uitofp': case 'sitofp': return RuntimeGenerator.makeBigInt(low1, high1, op[0] == 'u');
2166
 
      case 'fptoui': case 'fptosi': return finish(splitI64(idents[0], true));
 
2283
      case 'uitofp': case 'sitofp': return makeFloat(RuntimeGenerator.makeBigInt(low1, high1, op[0] == 'u'), item.type);
 
2284
      case 'fptoui': case 'fptosi': return finish(splitI64(asmCoercion(idents[0], 'double'), true)); // coerce to double before conversion to i64
2167
2285
      case 'icmp': {
2168
2286
        switch (variant) {
2169
2287
          case 'uge': return '((' + high1 + '>>>0) >= (' + high2 + '>>>0)) & ((((' + high1 + '>>>0) >  ('  + high2 + '>>>0)) | ' +
2192
2310
      case 'trunc': {
2193
2311
        return '((' + idents[0] + '[0]) & ' + (Math.pow(2, bitsLeft)-1) + ')';
2194
2312
      }
2195
 
      case 'select': return idents[0] + ' ? ' + makeCopyI64(idents[1]) + ' : ' + makeCopyI64(idents[2]);
 
2313
      case 'select': return '(' + idents[0] + ' ? ' + makeCopyI64(idents[1]) + ' : ' + makeCopyI64(idents[2]) + ')';;
2196
2314
      case 'ptrtoint': return makeI64(idents[0], 0);
2197
2315
      case 'inttoptr': {
2198
2316
        var m = /\(?\[(\d+),\d+\]\)?/.exec(idents[0]);
2265
2383
    }
2266
2384
  }
2267
2385
 
 
2386
  if (type[0] === '<' && type[type.length-1] !== '*') {
 
2387
    // vector/SIMD operation
 
2388
    Types.usesSIMD = true;
 
2389
    switch (op) {
 
2390
      case 'fadd': return 'SIMD.float32x4.add(' + idents[0] + ',' + idents[1] + ')';
 
2391
      case 'fsub': return 'SIMD.float32x4.sub(' + idents[0] + ',' + idents[1] + ')';
 
2392
      case 'fmul': return 'SIMD.float32x4.mul(' + idents[0] + ',' + idents[1] + ')';
 
2393
      case 'fdiv': return 'SIMD.float32x4.div(' + idents[0] + ',' + idents[1] + ')';
 
2394
      case 'add' : return 'SIMD.int32x4.add(' + idents[0] + ',' + idents[1] + ')';
 
2395
      case 'sub' : return 'SIMD.int32x4.sub(' + idents[0] + ',' + idents[1] + ')';
 
2396
      case 'mul' : return 'SIMD.int32x4.mul(' + idents[0] + ',' + idents[1] + ')';
 
2397
      case 'bitcast': {
 
2398
        var inType = item.params[0].type;
 
2399
        var outType = item.type;
 
2400
        if (inType === '<4 x float>') {
 
2401
          assert(outType === '<4 x i32>');
 
2402
          return 'SIMD.float32x4.bitsToInt32x4(' + idents[0] + ')';
 
2403
        } else {
 
2404
          assert(inType === '<4 x i32>');
 
2405
          assert(outType === '<4 x float>');
 
2406
          return 'SIMD.int32x4.bitsToFloat32x4(' + idents[0] + ')';
 
2407
        }
 
2408
      }
 
2409
      case 'and': return 'SIMD.int32x4.and(' + idents[0] + ',' + idents[1] + ')';
 
2410
      case 'or': return 'SIMD.int32x4.or(' + idents[0] + ',' + idents[1] + ')';
 
2411
      case 'xor': return 'SIMD.int32x4.xor(' + idents[0] + ',' + idents[1] + ')';
 
2412
      default: throw 'vector op todo: ' + dump(item);
 
2413
    }
 
2414
  }
 
2415
 
2268
2416
  switch (op) {
2269
2417
    // basic integer ops
2270
2418
    case 'add': return handleOverflow(getFastValue(idents[0], '+', idents[1], item.type), bits);
2278
2426
        dprint('Warning: 64 bit OR - precision limit may be hit on llvm line ' + item.lineNum);
2279
2427
        return 'Runtime.or64(' + idents[0] + ', ' + idents[1] + ')';
2280
2428
      }
2281
 
      return idents[0] + ' | ' + idents[1];
 
2429
      return idents[0] + '|' + idents[1];
2282
2430
    }
2283
2431
    case 'and': {
2284
2432
      if (bits > 32) {
2286
2434
        dprint('Warning: 64 bit AND - precision limit may be hit on llvm line ' + item.lineNum);
2287
2435
        return 'Runtime.and64(' + idents[0] + ', ' + idents[1] + ')';
2288
2436
      }
2289
 
      return idents[0] + ' & ' + idents[1];
 
2437
      return idents[0] + '&' + idents[1];
2290
2438
    }
2291
2439
    case 'xor': {
2292
2440
      if (bits > 32) {
2294
2442
        dprint('Warning: 64 bit XOR - precision limit may be hit on llvm line ' + item.lineNum);
2295
2443
        return 'Runtime.xor64(' + idents[0] + ', ' + idents[1] + ')';
2296
2444
      }
2297
 
      return idents[0] + ' ^ ' + idents[1];
 
2445
      return idents[0] + '^' + idents[1];
2298
2446
    }
2299
2447
    case 'shl': {
2300
2448
      if (bits > 32) return idents[0] + '*' + getFastValue(2, 'pow', idents[1]);
2301
 
      return idents[0] + ' << ' + idents[1];
 
2449
      return idents[0] + '<<' + idents[1];
2302
2450
    }
2303
2451
    case 'ashr': {
2304
2452
      if (bits > 32) return integerizeBignum(idents[0] + '/' + getFastValue(2, 'pow', idents[1]));
2305
 
      if (bits === 32) return originalIdents[0] + ' >> ' + idents[1]; // No need to reSign in this case
2306
 
      return idents[0] + ' >> ' + idents[1];
 
2453
      if (bits === 32) return originalIdents[0] + '>>' + idents[1]; // No need to reSign in this case
 
2454
      return idents[0] + '>>' + idents[1];
2307
2455
    }
2308
2456
    case 'lshr': {
2309
2457
      if (bits > 32) return integerizeBignum(idents[0] + '/' + getFastValue(2, 'pow', idents[1]));
2310
 
      if (bits === 32) return originalIdents[0] + ' >>> ' + idents[1]; // No need to unSign in this case
2311
 
      return idents[0] + ' >>> ' + idents[1];
 
2458
      if (bits === 32) return originalIdents[0] + '>>>' + idents[1]; // No need to unSign in this case
 
2459
      return idents[0] + '>>>' + idents[1];
2312
2460
    }
2313
2461
    // basic float ops
2314
2462
    case 'fadd': return makeFloat(getFastValue(idents[0], '+', idents[1], item.type), item.type);
2316
2464
    case 'fdiv': return makeFloat(getFastValue(idents[0], '/', idents[1], item.type), item.type);
2317
2465
    case 'fmul': return makeFloat(getFastValue(idents[0], '*', idents[1], item.type), item.type);
2318
2466
    case 'frem': return makeFloat(getFastValue(idents[0], '%', idents[1], item.type), item.type);
2319
 
    case 'uitofp': case 'sitofp': return asmCoercion(idents[0], 'double', op[0]);
 
2467
    case 'uitofp': case 'sitofp': return asmCoercion(idents[0], item.type, op[0]);
2320
2468
    case 'fptoui': case 'fptosi': return makeRounding(idents[0], bitsLeft, op === 'fptosi', true);
2321
2469
 
2322
2470
    // TODO: We sometimes generate false instead of 0, etc., in the *cmps. It seemed slightly faster before, but worth rechecking
2323
2471
    //       Note that with typed arrays, these become 0 when written. So that is a potential difference with non-typed array runs.
2324
2472
    case 'icmp': {
 
2473
      // unsigned coercions can be (X&Y), which is not a valid asm coercion for comparisons
 
2474
      if (ASM_JS && variant[0] === 'u') {
 
2475
        if (idents[0].indexOf('>>>') < 0) idents[0] = '((' + idents[0] + ')>>>0)';
 
2476
        if (idents[1].indexOf('>>>') < 0) idents[1] = '((' + idents[1] + ')>>>0)';
 
2477
      }
2325
2478
      switch (variant) {
2326
 
        case 'uge': case 'sge': return idents[0] + ' >= ' + idents[1];
2327
 
        case 'ule': case 'sle': return idents[0] + ' <= ' + idents[1];
2328
 
        case 'ugt': case 'sgt': return idents[0] + ' > ' + idents[1];
2329
 
        case 'ult': case 'slt': return idents[0] + ' < ' + idents[1];
 
2479
        case 'uge': case 'sge': return idents[0] + '>=' + idents[1];
 
2480
        case 'ule': case 'sle': return idents[0] + '<=' + idents[1];
 
2481
        case 'ugt': case 'sgt': return idents[0] + '>' + idents[1];
 
2482
        case 'ult': case 'slt': return idents[0] + '<' + idents[1];
2330
2483
        // We use loose comparisons, which allows false == 0 to be true, etc. Ditto in fcmp
2331
2484
        case 'ne': case 'eq': {
2332
2485
          // We must sign them, so we do not compare -1 to 255 (could have unsigned them both too)
2342
2495
      switch (variant) {
2343
2496
        // TODO 'o' ones should be 'ordered (no NaN) and',
2344
2497
        //      'u' ones should be 'unordered or'.
2345
 
        case 'uge': case 'oge': return idents[0] + ' >= ' + idents[1];
2346
 
        case 'ule': case 'ole': return idents[0] + ' <= ' + idents[1];
2347
 
        case 'ugt': case 'ogt': return idents[0] + ' > ' + idents[1];
2348
 
        case 'ult': case 'olt': return idents[0] + ' < ' + idents[1];
2349
 
        case 'une': case 'one': return idents[0] + ' != ' + idents[1];
2350
 
        case 'ueq': case 'oeq': return idents[0] + ' == ' + idents[1];
2351
 
        case 'ord': return '!' + makeIsNaN(idents[0]) + ' & !' + makeIsNaN(idents[1]);
2352
 
        case 'uno': return makeIsNaN(idents[0]) + ' | ' + makeIsNaN(idents[1]);
 
2498
        case 'uge': case 'oge': return idents[0] + '>=' + idents[1];
 
2499
        case 'ule': case 'ole': return idents[0] + '<=' + idents[1];
 
2500
        case 'ugt': case 'ogt': return idents[0] + '>' + idents[1];
 
2501
        case 'ult': case 'olt': return idents[0] + '<' + idents[1];
 
2502
        case 'une': case 'one': return idents[0] + '!=' + idents[1];
 
2503
        case 'ueq': case 'oeq': return idents[0] + '==' + idents[1];
 
2504
        case 'ord': return '!' + makeIsNaN(idents[0], paramTypes[0]) + '&!' + makeIsNaN(idents[1], paramTypes[0]);
 
2505
        case 'uno': return makeIsNaN(idents[0], paramTypes[0]) + '|' + makeIsNaN(idents[1], paramTypes[0]);
2353
2506
        case 'true': return '1';
2354
2507
        default: throw 'Unknown fcmp variant: ' + variant;
2355
2508
      }
2363
2516
      }
2364
2517
      // otherwise, fall through
2365
2518
    }
2366
 
    case 'fpext': case 'sext': return idents[0];
2367
 
    case 'fptrunc': return idents[0];
2368
 
    case 'select': return idents[0] + ' ? ' + asmEnsureFloat(idents[1], item.type) + ' : ' + asmEnsureFloat(idents[2], item.type);
 
2519
    case 'sext': return idents[0];
 
2520
    case 'fpext': {
 
2521
      if (PRECISE_F32) return '+(' + idents[0] + ')';
 
2522
      return idents[0];
 
2523
    }
 
2524
    case 'fptrunc': {
 
2525
      if (PRECISE_F32) return 'Math_fround(' + idents[0] + ')';
 
2526
      return idents[0];
 
2527
    }
 
2528
    case 'select': return '(' + idents[0] + '?' + asmEnsureFloat(idents[1], item.type) + ':' + asmEnsureFloat(idents[2], item.type) + ')';
2369
2529
    case 'ptrtoint': case 'inttoptr': {
2370
2530
      var ret = '';
2371
2531
      if (QUANTUM_SIZE == 1) {
2383
2543
      // truncating can change the number, e.g. by truncating to an i1
2384
2544
      // in order to get the first bit
2385
2545
      assert(bitsLeft <= 32, 'Cannot truncate to more than 32 bits, since we use a native & op');
2386
 
      return '((' + idents[0] + ') & ' + (Math.pow(2, bitsLeft)-1) + ')';
 
2546
      return '((' + idents[0] + ')&' + (Math.pow(2, bitsLeft)-1) + ')';
2387
2547
    }
2388
2548
    case 'bitcast': {
2389
2549
      // Most bitcasts are no-ops for us. However, the exception is int to float and float to int
2421
2581
      if (walkInterdata(item.params[i], pre, post,  obj)) return true;
2422
2582
    }
2423
2583
  }
2424
 
  if (item.possibleVars) { // other attributes that might contain interesting data; here, variables
2425
 
    var box = { intertype: 'value', ident: '' };
2426
 
    for (i = 0; i <= item.possibleVars.length; i++) {
2427
 
      box.ident = item[item.possibleVars[i]];
2428
 
      if (walkInterdata(box, pre, post,  obj)) return true;
2429
 
    }
2430
 
  }
2431
2584
  return post && post(item, originalObj, obj);
2432
2585
}
2433
2586
 
2447
2600
      if (repl = walkAndModifyInterdata(item.params[i], pre)) item.params[i] = repl;
2448
2601
    }
2449
2602
  }
2450
 
  // Ignore possibleVars because we can't replace them anyhow
2451
2603
}
2452
2604
 
2453
2605
function parseBlockAddress(segment) {
2454
 
  return { intertype: 'blockaddress', func: toNiceIdent(segment[2].item.tokens[0].text), label: toNiceIdent(segment[2].item.tokens[2].text), type: 'i32' };
 
2606
  return { intertype: 'blockaddress', func: toNiceIdent(segment[2].tokens[0].text), label: toNiceIdent(segment[2].tokens[2].text), type: 'i32' };
2455
2607
}
2456
2608
 
2457
2609
function finalizeBlockAddress(param) {
2519
2671
  return ret;
2520
2672
}
2521
2673
 
 
2674
function parseAlign(text) { // parse ", align \d+"
 
2675
  if (!text) return QUANTUM_SIZE;
 
2676
  return parseInt(text.substr(8));
 
2677
}
 
2678
 
 
2679
function deParen(text) {
 
2680
  if (text[0] === '(') return text.substr(1, text.length-2);
 
2681
  return text;
 
2682
}
 
2683
 
 
2684
function deParenCarefully(text) {
 
2685
  if (text[0] === '(' && text.indexOf('(', 1) < 0 && text[text.length-1] === ')') return text.substr(1, text.length-2);
 
2686
  return text;
 
2687
}
 
2688
 
 
2689
function addVariable(ident, type, funcData) {
 
2690
  funcData = funcData || Framework.currItem.funcData;
 
2691
  assert(type);
 
2692
  var old = funcData.variables[ident];
 
2693
  if (old) {
 
2694
    assert(old.type === type);
 
2695
  } else {
 
2696
    funcData.variables[ident] = {
 
2697
      ident: ident,
 
2698
      type: type,
 
2699
      origin: 'added',
 
2700
      lineNum: 0,
 
2701
      rawLinesIndex: 0,
 
2702
      hasValueTaken: false,
 
2703
      pointingLevels: 0,
 
2704
      uses: 0,
 
2705
      impl: VAR_EMULATED
 
2706
    };
 
2707
  }
 
2708
}
 
2709
 
 
2710
var SIMDLane = ['X', 'Y', 'Z', 'W'];
 
2711
var simdLane = ['x', 'y', 'z', 'w'];
 
2712
 
 
2713
function ensureVector(ident, base) {
 
2714
  Types.usesSIMD = true;
 
2715
  return ident == 0 ? base + '32x4.splat(0)' : ident;
 
2716
}
 
2717
 
 
2718
function ensureValidFFIType(type) {
 
2719
  return type === 'float' ? 'double' : type; // ffi does not tolerate float XXX
 
2720
}
 
2721
 
 
2722
// FFI return values must arrive as doubles, and we can force them to floats afterwards
 
2723
function asmFFICoercion(value, type) {
 
2724
  value = asmCoercion(value, ensureValidFFIType(type));
 
2725
  if (PRECISE_F32 && type === 'float') value = asmCoercion(value, 'float');
 
2726
  return value;
 
2727
}
 
2728