3
// LLVM assembly => internal intermediate representation, which is ready
4
// to be processed by the later stages.
6
var tokenizer; // TODO: Clean this up/out
7
// XXX In particular, this closes over the substrate, which can keep stuff in memory, which is bad
8
function tokenize(text) {
9
return tokenizer.processItem({ lineText: text }, true);
14
var ENCLOSER_STARTERS = set('[', '(', '<');
15
var ENCLOSER_ENDERS = {
20
var ZEROINIT_UNDEF = set('zeroinitializer', 'undef');
21
var NSW_NUW = set('nsw', 'nuw');
25
function intertyper(data, sidePass, baseLineNums) {
26
var mainPass = !sidePass;
27
baseLineNums = baseLineNums || [[0,0]]; // each pair [#0,#1] means "starting from line #0, the base line num is #1"
29
dprint('framework', 'Big picture: Starting intertyper, main pass=' + mainPass);
33
var substrate = new Substrate('Intertyper');
35
// Line splitter. We break off some bunches of lines into unparsedBundles, which are
36
// parsed in separate passes later. This helps to keep memory usage low - we can start
37
// from raw lines and end up with final JS for each function individually that way, instead
38
// of intertyping them all, then analyzing them all, etc.
39
substrate.addActor('LineSplitter', {
40
processItem: function _lineSplitter(item) {
41
var lines = item.llvmLines;
43
var inContinual = false;
44
var inFunction = false;
45
var currFunctionLines;
46
var currFunctionLineNum;
47
var unparsedBundles = [];
48
var unparsedTypes, unparsedGlobals;
51
intertype: 'unparsedTypes',
54
unparsedBundles.push(unparsedTypes);
56
intertype: 'unparsedGlobals',
59
unparsedBundles.push(unparsedGlobals);
61
var baseLineNumPosition = 0;
62
for (var i = 0; i < lines.length; i++) {
64
if (singlePhase) lines[i] = null; // lines may be very very large. Allow GCing to occur in the loop by releasing refs here
66
while (baseLineNumPosition < baseLineNums.length-1 && i >= baseLineNums[baseLineNumPosition+1][0]) {
67
baseLineNumPosition++;
70
if (mainPass && (line[0] == '%' || line[0] == '@')) {
71
// If this isn't a type, it's a global variable, make a note of the information now, we will need it later
72
var parts = line.split(' = ');
73
assert(parts.length >= 2);
74
var left = parts[0], right = parts.slice(1).join(' = ');
75
var testType = /^type .*/.exec(right);
77
var globalIdent = toNiceIdent(left);
78
var testAlias = /^(hidden )?alias .*/.exec(right);
79
Variables.globals[globalIdent] = {
84
unparsedGlobals.lines.push(line);
86
unparsedTypes.lines.push(line);
90
if (mainPass && /^define .*/.test(line)) {
92
currFunctionLines = [];
93
currFunctionLineNum = i + 1;
95
if (!inFunction || !mainPass) {
96
if (inContinual || /^\ +(to|catch |filter |cleanup).*/.test(line)) {
97
// to after invoke or landingpad second line
98
ret.slice(-1)[0].lineText += line;
99
if (/^\ +\]/.test(line)) { // end of llvm switch
105
lineNum: i + 1 + baseLineNums[baseLineNumPosition][1] - baseLineNums[baseLineNumPosition][0]
107
if (/^\ +switch\ .*/.test(line)) {
108
// beginning of llvm switch
113
currFunctionLines.push(line);
115
if (mainPass && /^}.*/.test(line)) {
118
var func = funcHeader.processItem(tokenizer.processItem({ lineText: currFunctionLines[0], lineNum: currFunctionLineNum }, true))[0];
120
if (SKIP_STACK_IN_SMALL && /emscripten_autodebug/.exec(func.ident)) {
121
warnOnce('Disabling SKIP_STACK_IN_SMALL because we are apparently processing autodebugger data');
122
SKIP_STACK_IN_SMALL = 0;
125
var ident = toNiceIdent(func.ident);
126
if (!(ident in DEAD_FUNCTIONS)) {
127
unparsedBundles.push({
128
intertype: 'unparsedFunction',
129
// We need this early, to know basic function info - ident, params, varargs
132
returnType: func.returnType,
133
hasVarArgs: func.hasVarArgs,
134
lineNum: currFunctionLineNum,
135
lines: currFunctionLines
138
currFunctionLines = [];
142
// We need lines beginning with ';' inside functions, because older LLVM versions generated labels that way. But when not
143
// parsing functions, we can ignore all such lines and save some time that way.
144
this.forwardItems(ret.filter(function(item) { return item.lineText && (item.lineText[0] != ';' || !mainPass); }), 'Tokenizer');
145
return unparsedBundles;
150
tokenizer = substrate.addActor('Tokenizer', {
151
processItem: function _tokenizer(item, inner) {
152
//assert(item.lineNum != 40000);
153
//if (item.lineNum) print(item.lineNum);
156
var lastToken = null;
157
var CHUNKSIZE = 64; // How much forward to peek forward. Too much means too many string segments copied
158
// Note: '{' is not an encloser, as its use in functions is split over many lines
167
var totalEnclosing = 0;
169
function makeToken(text) {
170
if (text.length == 0) return;
171
// merge certain tokens
172
if (lastToken && ( (lastToken.text == '%' && text[0] == '"') || /^\**$/.test(text) ) ) {
173
lastToken.text += text;
180
if (text[0] in enclosers) {
181
token.item = that.processItem({
182
lineText: text.substr(1, text.length-2)
184
token.type = text[0];
186
// merge certain tokens
187
if (lastToken && isType(lastToken.text) && isFunctionDef(token)) {
188
lastToken.text += ' ' + text;
189
} else if (lastToken && text[0] == '}') { // }, }*, etc.
190
var openBrace = tokens.length-1;
191
while (tokens[openBrace].text.substr(-1) != '{') openBrace --;
192
token = combineTokens(tokens.slice(openBrace+1));
193
tokens.splice(openBrace, tokens.length-openBrace+1);
196
token.text = '{ ' + token.text + ' }';
197
var pointingLevelsToAdd = pointingLevels(text) - pointingLevels(token.text);
198
while (pointingLevelsToAdd > 0) {
200
pointingLevelsToAdd--;
208
// Split using meaningful characters
209
var lineText = item.lineText + ' ';
210
var re = /[\[\]\(\)<>, "]/g;
211
var segments = lineText.split(re);
213
var len = segments.length;
217
for (var s = 0; s < len; s++) {
218
segment = segments[s];
219
i += segment.length + 1;
220
letter = lineText[i];
224
if (totalEnclosing == 0 && quotes == 0) {
232
if (totalEnclosing == 0) {
234
if (curr == '@' || curr == '%') {
241
makeToken(curr + '"');
250
if (totalEnclosing == 0 && quotes == 0) {
253
tokens.push({ text: ',' });
259
assert(letter in enclosers);
264
if (letter in ENCLOSER_STARTERS) {
265
if (totalEnclosing == 0) {
273
enclosers[enclosers[letter]]--;
275
if (totalEnclosing == 0) {
276
makeToken(curr + letter);
286
indent: lineText.search(/[^ ]/),
287
lineNum: item.lineNum
292
this.forwardItem(newItem, 'Triager');
298
substrate.addActor('Triager', {
299
processItem: function _triager(item) {
301
assert(!item.intertype);
302
var token0Text = item.tokens[0].text;
303
var token1Text = item.tokens[1] ? item.tokens[1].text : null;
304
var tokensLength = item.tokens.length;
305
if (item.indent === 2) {
306
if (tokensLength >= 5 &&
307
(token0Text == 'store' || token1Text == 'store'))
309
if (tokensLength >= 3 && token0Text == 'br')
311
if (tokensLength >= 2 && token0Text == 'ret')
313
if (tokensLength >= 2 && token0Text == 'switch')
315
if (token0Text == 'unreachable')
316
return 'Unreachable';
317
if (tokensLength >= 3 && token0Text == 'indirectbr')
319
if (tokensLength >= 2 && token0Text == 'resume')
321
if (tokensLength >= 3 &&
322
(token0Text == 'load' || token1Text == 'load'))
324
if (tokensLength >= 3 &&
325
token0Text in MATHOPS)
327
if (tokensLength >= 3 && token0Text == 'bitcast')
329
if (tokensLength >= 3 && token0Text == 'getelementptr')
331
if (tokensLength >= 2 && token0Text == 'alloca')
333
if (tokensLength >= 3 && token0Text == 'extractvalue')
334
return 'ExtractValue';
335
if (tokensLength >= 3 && token0Text == 'insertvalue')
336
return 'InsertValue';
337
if (tokensLength >= 3 && token0Text == 'phi')
339
if (tokensLength >= 3 && token0Text == 'va_arg')
341
if (tokensLength >= 3 && token0Text == 'landingpad')
343
if (token0Text == 'fence')
345
} else if (item.indent === 0) {
346
if ((tokensLength >= 1 && token0Text.substr(-1) == ':') ||
347
(tokensLength >= 3 && token1Text == '<label>') ||
348
(tokensLength >= 2 && token1Text == ':'))
350
if (tokensLength >= 4 && token0Text == 'declare')
352
if (tokensLength >= 3 && token1Text == '=')
354
if (tokensLength >= 4 && token0Text == 'define' &&
355
item.tokens.slice(-1)[0].text == '{')
357
if (tokensLength >= 1 && token0Text == '}')
359
if (token0Text == 'module' && token1Text == 'asm') {
360
warn('Ignoring module asm: ' + item.tokens[2].text);
364
if (tokensLength >= 3 && (token0Text == 'call' || token1Text == 'call'))
366
if (token0Text == 'target')
368
if (token0Text == ';')
370
if (tokensLength >= 3 && token0Text == 'invoke')
372
if (tokensLength >= 3 && token0Text == 'atomicrmw' || token0Text == 'cmpxchg')
374
throw 'Invalid token, cannot triage: ' + dump(item);
377
if (item.indent == 2 && (eq = findTokenText(item, '=')) >= 0) {
378
item.assignTo = toNiceIdent(combineTokens(item.tokens.slice(0, eq)).text);
379
item.tokens = item.tokens.slice(eq+1);
381
this.forwardItem(item, triage());
385
// Line parsers to intermediate form
387
// globals: type or variable
388
substrate.addActor('Global', {
389
processItem: function _global(item) {
390
function scanConst(value, type) {
391
// Gets an array of constant items, separated by ',' tokens
392
function handleSegments(tokens) {
393
// Handle a single segment (after comma separation)
394
function handleSegment(segment) {
395
if (segment[1].text == 'null') {
396
return { intertype: 'value', ident: '0', type: 'i32' };
397
} else if (segment[1].text == 'zeroinitializer') {
398
Types.needAnalysis[segment[0].text] = 0;
399
return { intertype: 'emptystruct', type: segment[0].text };
400
} else if (segment[1].text in PARSABLE_LLVM_FUNCTIONS) {
401
return parseLLVMFunctionCall(segment);
402
} else if (segment[1].type && segment[1].type == '{') {
403
Types.needAnalysis[segment[0].text] = 0;
404
return { intertype: 'struct', type: segment[0].text, contents: handleSegments(segment[1].tokens) };
405
} else if (segment[1].type && segment[1].type == '<') {
406
Types.needAnalysis[segment[0].text] = 0;
407
return { intertype: 'struct', type: segment[0].text, contents: handleSegments(segment[1].item.tokens[0].tokens) };
408
} else if (segment[1].type && segment[1].type == '[') {
409
Types.needAnalysis[segment[0].text] = 0;
410
return { intertype: 'list', type: segment[0].text, contents: handleSegments(segment[1].item.tokens) };
411
} else if (segment.length == 2) {
412
Types.needAnalysis[segment[0].text] = 0;
413
return { intertype: 'value', type: segment[0].text, ident: toNiceIdent(segment[1].text) };
414
} else if (segment[1].text === 'c') {
416
var text = segment[2].text;
417
text = text.substr(1, text.length-2);
418
return { intertype: 'string', text: text, type: 'i8*' };
419
} else if (segment[1].text === 'blockaddress') {
420
return parseBlockAddress(segment);
422
throw 'Invalid segment: ' + dump(segment);
425
return splitTokenList(tokens).map(handleSegment);
428
Types.needAnalysis[type] = 0;
429
if (Runtime.isNumberType(type) || pointingLevels(type) >= 1) {
430
return { value: toNiceIdent(value.text), type: type };
431
} else if (value.text in ZEROINIT_UNDEF) { // undef doesn't really need initting, but why not
432
return { intertype: 'emptystruct', type: type };
433
} else if (value.text && value.text[0] == '"') {
434
return { intertype: 'string', text: value.text.substr(1, value.text.length-2) };
436
if (value.type == '<') { // <{ i8 }> etc.
437
value = value.item.tokens;
442
contents = value.item.tokens;
443
} else if (value.type == '{') {
445
contents = value.tokens;
446
} else if (value[0]) {
449
throw '// interfailzzzzzzzzzzzzzz ' + dump(value.item) + ' ::: ' + dump(value);
451
return { intertype: 'segments', contents: handleSegments(contents) };
455
cleanOutTokens(LLVM.VISIBILITIES, item.tokens, 2);
456
if (item.tokens[2].text == 'alias') {
457
cleanOutTokens(LLVM.LINKAGES, item.tokens, 3);
458
cleanOutTokens(LLVM.VISIBILITIES, item.tokens, 3);
459
var last = getTokenIndexByText(item.tokens, ';');
462
ident: toNiceIdent(item.tokens[0].text),
463
value: parseLLVMSegment(item.tokens.slice(3, last)),
464
lineNum: item.lineNum
466
ret.type = ret.value.type;
467
Types.needAnalysis[ret.type] = 0;
468
if (!NAMED_GLOBALS) {
469
Variables.globals[ret.ident].type = ret.type;
473
if (item.tokens[2].text == 'type') {
476
if (Runtime.isNumberType(item.tokens[3].text)) {
477
// Clang sometimes has |= i32| instead of |= { i32 }|
478
fields = [item.tokens[3].text];
479
} else if (item.tokens[3].text != 'opaque') {
480
if (item.tokens[3].type == '<') {
482
item.tokens[3] = item.tokens[3].item.tokens[0];
484
var subTokens = item.tokens[3].tokens;
486
subTokens.push({text:','});
487
while (subTokens[0]) {
489
while ([','].indexOf(subTokens[stop].text) == -1) stop ++;
490
fields.push(combineTokens(subTokens.slice(0, stop)).text);
491
subTokens.splice(0, stop+1);
497
name_: item.tokens[0].text,
500
lineNum: item.lineNum
504
var ident = item.tokens[0].text;
505
var private_ = findTokenText(item, 'private') >= 0;
506
cleanOutTokens(LLVM.GLOBAL_MODIFIERS, item.tokens, [2, 3]);
507
var external = false;
508
if (item.tokens[2].text === 'external') {
510
item.tokens.splice(2, 1);
512
Types.needAnalysis[item.tokens[2].text] = 0;
514
intertype: 'globalVariable',
515
ident: toNiceIdent(ident),
516
type: item.tokens[2].text,
519
lineNum: item.lineNum
521
if (!NAMED_GLOBALS) {
522
Variables.globals[ret.ident].type = ret.type;
523
Variables.globals[ret.ident].external = external;
525
Types.needAnalysis[ret.type] = 0;
526
if (ident == '@llvm.global_ctors') {
528
if (item.tokens[3].item) {
529
var subTokens = item.tokens[3].item.tokens;
530
splitTokenList(subTokens).forEach(function(segment) {
531
var ctor = toNiceIdent(segment[1].tokens.slice(-1)[0].text);
532
ret.ctors.push(ctor);
533
if (ASM_JS) { // must export the global constructors from asm.js module, so mark as implemented and exported
534
Functions.implementedFunctions[ctor] = 'v';
535
EXPORTED_FUNCTIONS[ctor] = 1;
539
} else if (!external) {
540
if (item.tokens[3].text == 'c')
541
item.tokens.splice(3, 1);
542
if (item.tokens[3].text in PARSABLE_LLVM_FUNCTIONS) {
543
ret.value = parseLLVMFunctionCall(item.tokens.slice(2));
545
ret.value = scanConst(item.tokens[3], ret.type);
553
var funcHeader = substrate.addActor('FuncHeader', {
554
processItem: function(item) {
555
item.tokens = item.tokens.filter(function(token) {
556
return !(token.text in LLVM.LINKAGES || token.text in LLVM.PARAM_ATTR || token.text in LLVM.FUNC_ATTR || token.text in LLVM.CALLING_CONVENTIONS);
558
var params = parseParamTokens(item.tokens[2].item.tokens);
559
if (sidePass) dprint('unparsedFunctions', 'Processing function: ' + item.tokens[1].text);
561
intertype: 'function',
562
ident: toNiceIdent(item.tokens[1].text),
563
returnType: item.tokens[0].text,
565
hasVarArgs: hasVarArgs(params),
566
lineNum: item.lineNum,
571
substrate.addActor('Label', {
572
processItem: function(item) {
573
var rawLabel = item.tokens[0].text.substr(-1) == ':' ?
574
'%' + item.tokens[0].text.substr(0, item.tokens[0].text.length-1) :
575
(item.tokens[1].text == '<label>' ?
576
'%' + item.tokens[2].text.substr(1) :
577
'%' + item.tokens[0].text)
578
var niceLabel = toNiceIdent(rawLabel);
582
lineNum: item.lineNum
588
substrate.addActor('Reintegrator', {
589
processItem: function(item) {
590
this.forwardItem(item, '/dev/stdout');
595
substrate.addActor('Load', {
596
processItem: function(item) {
597
item.intertype = 'load';
598
cleanOutTokens(LLVM.ACCESS_OPTIONS, item.tokens, [0, 1]);
599
item.pointerType = item.tokens[1].text;
600
item.valueType = item.type = removePointing(item.pointerType);
601
Types.needAnalysis[item.type] = 0;
602
var last = getTokenIndexByText(item.tokens, ';');
603
var segments = splitTokenList(item.tokens.slice(1, last));
604
item.pointer = parseLLVMSegment(segments[0]);
605
if (segments.length > 1) {
606
assert(segments[1][0].text == 'align');
607
item.align = parseInt(segments[1][1].text) || QUANTUM_SIZE; // 0 means preferred arch align
609
item.align = QUANTUM_SIZE;
611
item.ident = item.pointer.ident || null;
612
this.forwardItem(item, 'Reintegrator');
616
substrate.addActor('ExtractValue', {
617
processItem: function(item) {
618
var last = getTokenIndexByText(item.tokens, ';');
619
item.intertype = 'extractvalue';
620
item.type = item.tokens[1].text; // Of the origin aggregate - not what we extract from it. For that, can only infer it later
621
Types.needAnalysis[item.type] = 0;
622
item.ident = toNiceIdent(item.tokens[2].text);
623
item.indexes = splitTokenList(item.tokens.slice(4, last));
624
this.forwardItem(item, 'Reintegrator');
628
substrate.addActor('InsertValue', {
629
processItem: function(item) {
630
var last = getTokenIndexByText(item.tokens, ';');
631
item.intertype = 'insertvalue';
632
item.type = item.tokens[1].text; // Of the origin aggregate, as well as the result
633
Types.needAnalysis[item.type] = 0;
634
item.ident = toNiceIdent(item.tokens[2].text);
635
var segments = splitTokenList(item.tokens.slice(4, last));
636
item.value = parseLLVMSegment(segments[0]);
637
item.indexes = segments.slice(1);
638
this.forwardItem(item, 'Reintegrator');
642
substrate.addActor('Bitcast', {
643
processItem: function(item) {
644
item.intertype = 'bitcast';
645
item.type = item.tokens[4].text; // The final type
646
Types.needAnalysis[item.type] = 0;
647
var to = getTokenIndexByText(item.tokens, 'to');
648
item.params = [parseLLVMSegment(item.tokens.slice(1, to))];
649
item.ident = item.params[0].ident;
650
item.type2 = item.tokens[1].text; // The original type
651
Types.needAnalysis[item.type2] = 0;
652
this.forwardItem(item, 'Reintegrator');
656
substrate.addActor('GEP', {
657
processItem: function(item) {
659
while (!isType(item.tokens[first].text)) first++;
660
Types.needAnalysis[item.tokens[first].text] = 0;
661
var last = getTokenIndexByText(item.tokens, ';');
662
var segment = [ item.tokens[first], { text: 'getelementptr' }, null, { item: {
663
tokens: item.tokens.slice(first, last)
665
var data = parseLLVMFunctionCall(segment);
666
item.intertype = 'getelementptr';
667
item.type = '*'; // We need type info to determine this - all we know is it's a pointer
668
item.params = data.params;
669
item.ident = data.ident;
670
this.forwardItem(item, 'Reintegrator');
674
function makeCall(item, type) {
675
item.intertype = type;
676
if (['tail'].indexOf(item.tokens[0].text) != -1) {
677
item.tokens.splice(0, 1);
679
while (item.tokens[1].text in LLVM.PARAM_ATTR || item.tokens[1].text in LLVM.CALLING_CONVENTIONS) {
680
item.tokens.splice(1, 1);
682
item.type = item.tokens[1].text;
683
Types.needAnalysis[item.type] = 0;
684
while (['@', '%'].indexOf(item.tokens[2].text[0]) == -1 && !(item.tokens[2].text in PARSABLE_LLVM_FUNCTIONS) &&
685
item.tokens[2].text != 'null' && item.tokens[2].text != 'asm' && item.tokens[2].text != 'undef') {
686
assert(item.tokens[2].text != 'asm', 'Inline assembly cannot be compiled to JavaScript!');
687
item.tokens.splice(2, 1);
689
var tokensLeft = item.tokens.slice(2);
690
item.ident = eatLLVMIdent(tokensLeft);
691
if (item.ident == 'asm') {
692
// Inline assembly is just JavaScript that we paste into the code
693
item.intertype = 'value';
694
if (tokensLeft[0].text == 'sideeffect') tokensLeft.splice(0, 1);
695
item.ident = tokensLeft[0].text.substr(1, tokensLeft[0].text.length-2) || ';'; // use ; for empty inline assembly
696
return { forward: null, ret: [item], item: item };
698
if (item.ident.substr(-2) == '()') {
699
// See comment in isStructType()
700
item.ident = item.ident.substr(0, item.ident.length-2);
701
// Also, we remove some spaces which might occur.
702
while (item.ident[item.ident.length-1] == ' ') {
703
item.ident = item.ident.substr(0, item.ident.length-1);
707
item.params = parseParamTokens(tokensLeft[0].item.tokens);
709
item.ident = toNiceIdent(item.ident);
710
if (type === 'invoke') {
711
var toIndex = findTokenText(item, 'to');
712
item.toLabel = toNiceIdent(item.tokens[toIndex+2].text);
713
item.unwindLabel = toNiceIdent(item.tokens[toIndex+5].text);
714
assert(item.toLabel && item.unwindLabel);
716
if (item.indent == 2) {
717
// standalone call - not in assign
718
item.standalone = true;
719
return { forward: null, ret: [item], item: item };
721
return { forward: item, ret: [], item: item };
723
substrate.addActor('Call', {
724
processItem: function(item) {
725
var result = makeCall.call(this, item, 'call');
726
if (result.forward) this.forwardItem(result.forward, 'Reintegrator');
730
substrate.addActor('Invoke', {
731
processItem: function(item) {
732
var result = makeCall.call(this, item, 'invoke');
733
if (DISABLE_EXCEPTION_CATCHING == 1) {
734
result.item.intertype = 'call';
737
label: result.item.toLabel,
738
lineNum: (result.forward ? item.parentLineNum : item.lineNum) + 0.5
741
if (result.forward) this.forwardItem(result.forward, 'Reintegrator');
745
substrate.addActor('Atomic', {
746
processItem: function(item) {
747
item.intertype = 'atomic';
748
if (item.tokens[0].text == 'atomicrmw') {
749
if (item.tokens[1].text == 'volatile') item.tokens.splice(1, 1);
750
item.op = item.tokens[1].text;
751
item.tokens.splice(1, 1);
753
assert(item.tokens[0].text == 'cmpxchg')
754
if (item.tokens[1].text == 'volatile') item.tokens.splice(1, 1);
757
var last = getTokenIndexByText(item.tokens, ';');
758
item.params = splitTokenList(item.tokens.slice(1, last)).map(parseLLVMSegment);
759
item.type = item.params[1].type;
760
this.forwardItem(item, 'Reintegrator');
764
substrate.addActor('Landingpad', {
765
processItem: function(item) {
766
item.intertype = 'landingpad';
767
item.type = item.tokens[1].text;
768
item.catchables = [];
769
var catchIdx = findTokenText(item, "catch");
770
if (catchIdx != -1) {
772
var nextCatchIdx = findTokenTextAfter(item, "catch", catchIdx+1);
773
if (nextCatchIdx == -1)
774
nextCatchIdx = item.tokens.length;
775
item.catchables.push(parseLLVMSegment(item.tokens.slice(catchIdx+2, nextCatchIdx)));
776
catchIdx = nextCatchIdx;
777
} while (catchIdx != item.tokens.length);
779
Types.needAnalysis[item.type] = 0;
780
this.forwardItem(item, 'Reintegrator');
784
var allocaPossibleVars = ['allocatedNum'];
785
substrate.addActor('Alloca', {
786
processItem: function(item) {
787
item.intertype = 'alloca';
788
item.allocatedType = item.tokens[1].text;
789
if (item.tokens.length > 3 && Runtime.isNumberType(item.tokens[3].text)) {
790
item.allocatedNum = toNiceIdent(item.tokens[4].text);
791
item.possibleVars = allocaPossibleVars;
793
item.allocatedNum = 1;
795
item.type = addPointing(item.tokens[1].text); // type of pointer we will get
796
Types.needAnalysis[item.type] = 0;
797
item.type2 = item.tokens[1].text; // value we will create, and get a pointer to
798
Types.needAnalysis[item.type2] = 0;
799
this.forwardItem(item, 'Reintegrator');
803
substrate.addActor('Phi', {
804
processItem: function(item) {
805
item.intertype = 'phi';
806
item.type = item.tokens[1].text;
807
var typeToken = [item.tokens[1]];
808
Types.needAnalysis[item.type] = 0;
809
var last = getTokenIndexByText(item.tokens, ';');
810
item.params = splitTokenList(item.tokens.slice(2, last)).map(function(segment) {
811
var subSegments = splitTokenList(segment[0].item.tokens);
813
intertype: 'phiparam',
814
label: toNiceIdent(subSegments[1][0].text),
815
value: parseLLVMSegment(typeToken.concat(subSegments[0]))
818
}).filter(function(param) { return param.value && param.value.ident != 'undef' });
819
this.forwardItem(item, 'Reintegrator');
823
substrate.addActor('va_arg', {
824
processItem: function(item) {
825
item.intertype = 'va_arg';
826
var segments = splitTokenList(item.tokens.slice(1));
827
item.type = segments[1][0].text;
828
item.value = parseLLVMSegment(segments[0]);
829
this.forwardItem(item, 'Reintegrator');
833
substrate.addActor('Mathops', {
834
processItem: function(item) {
835
item.intertype = 'mathop';
836
item.op = item.tokens[0].text;
838
while (item.tokens[1].text in NSW_NUW) item.tokens.splice(1, 1);
839
if (['icmp', 'fcmp'].indexOf(item.op) != -1) {
840
item.variant = item.tokens[1].text;
841
item.tokens.splice(1, 1);
843
if (item.tokens[1].text == 'exact') item.tokens.splice(1, 1); // TODO: Implement trap values
844
var segments = splitTokenList(item.tokens.slice(1));
846
for (var i = 1; i <= 4; i++) {
848
if (i > 1 && segments[i-1].length == 1 && segments[0].length > 1 && !isType(segments[i-1][0].text)) {
849
segments[i-1].unshift(segments[0][0]); // Add the type from the first segment, they are all alike
851
item.params[i-1] = parseLLVMSegment(segments[i-1]);
854
var setParamTypes = true;
855
if (item.op === 'select') {
856
assert(item.params[1].type === item.params[2].type);
857
item.type = item.params[1].type;
858
} else if (item.op in LLVM.CONVERSIONS) {
859
item.type = item.params[1].type;
860
setParamTypes = false;
862
item.type = item.params[0].type;
865
for (var i = 0; i < 4; i++) {
866
if (item.params[i]) item.params[i].type = item.type; // All params have the same type, normally
869
if (item.op in LLVM.EXTENDS) {
870
item.type = item.params[1].ident;
871
item.params[0].type = item.params[1].type;
872
// TODO: also remove 2nd param?
873
} else if (item.op in LLVM.COMPS) {
876
if (USE_TYPED_ARRAYS == 2) {
877
// Some specific corrections, since 'i64' is special
878
if (item.op in LLVM.SHIFTS) {
879
item.params[1].type = 'i32';
880
} else if (item.op == 'select') {
881
item.params[0].type = 'i1';
884
Types.needAnalysis[item.type] = 0;
885
this.forwardItem(item, 'Reintegrator');
889
substrate.addActor('Store', {
890
processItem: function(item) {
891
cleanOutTokens(LLVM.ACCESS_OPTIONS, item.tokens, [0, 1]);
892
var segments = splitTokenList(item.tokens.slice(1));
895
valueType: item.tokens[1].text,
896
value: parseLLVMSegment(segments[0]),
897
pointer: parseLLVMSegment(segments[1]),
898
lineNum: item.lineNum
900
Types.needAnalysis[ret.valueType] = 0;
901
ret.ident = toNiceIdent(ret.pointer.ident);
902
ret.pointerType = ret.pointer.type;
903
Types.needAnalysis[ret.pointerType] = 0;
904
if (segments.length > 2) {
905
assert(segments[2][0].text == 'align');
906
ret.align = parseInt(segments[2][1].text) || QUANTUM_SIZE; // 0 means preferred arch align
908
ret.align = QUANTUM_SIZE;
914
substrate.addActor('Branch', {
915
processItem: function(item) {
916
if (item.tokens[1].text == 'label') {
919
label: toNiceIdent(item.tokens[2].text),
920
lineNum: item.lineNum
923
var commaIndex = findTokenText(item, ',');
926
value: parseLLVMSegment(item.tokens.slice(1, commaIndex)),
927
labelTrue: toNiceIdent(item.tokens[commaIndex+2].text),
928
labelFalse: toNiceIdent(item.tokens[commaIndex+5].text),
929
lineNum: item.lineNum
935
substrate.addActor('Return', {
936
processItem: function(item) {
937
var type = item.tokens[1].text;
938
Types.needAnalysis[type] = 0;
942
value: (item.tokens[2] && type !== 'void') ? parseLLVMSegment(item.tokens.slice(1)) : null,
943
lineNum: item.lineNum
947
// 'resume' - partial implementation
948
substrate.addActor('Resume', {
949
processItem: function(item) {
952
ident: toNiceIdent(item.tokens[2].text),
953
lineNum: item.lineNum
958
substrate.addActor('Switch', {
959
processItem: function(item) {
960
function parseSwitchLabels(item) {
962
var tokens = item.item.tokens;
963
while (tokens.length > 0) {
965
value: tokens[1].text,
966
label: toNiceIdent(tokens[4].text)
968
tokens = tokens.slice(5);
972
var type = item.tokens[1].text;
973
Types.needAnalysis[type] = 0;
977
ident: toNiceIdent(item.tokens[2].text),
978
defaultLabel: toNiceIdent(item.tokens[5].text),
979
switchLabels: parseSwitchLabels(item.tokens[6]),
980
lineNum: item.lineNum
985
substrate.addActor('FuncEnd', {
986
processItem: function(item) {
988
intertype: 'functionEnd',
989
lineNum: item.lineNum
993
// external function stub
994
substrate.addActor('External', {
995
processItem: function(item) {
996
while (item.tokens[1].text in LLVM.LINKAGES || item.tokens[1].text in LLVM.PARAM_ATTR || item.tokens[1].text in LLVM.VISIBILITIES || item.tokens[1].text in LLVM.CALLING_CONVENTIONS) {
997
item.tokens.splice(1, 1);
999
var params = parseParamTokens(item.tokens[3].item.tokens);
1001
intertype: 'functionStub',
1002
ident: toNiceIdent(item.tokens[2].text),
1003
returnType: item.tokens[1],
1005
hasVarArgs: hasVarArgs(params),
1006
lineNum: item.lineNum
1011
substrate.addActor('Unreachable', {
1012
processItem: function(item) {
1014
intertype: 'unreachable',
1015
lineNum: item.lineNum
1020
substrate.addActor('IndirectBr', {
1021
processItem: function(item) {
1023
intertype: 'indirectbr',
1024
value: parseLLVMSegment(splitTokenList(item.tokens.slice(1))[0]),
1025
type: item.tokens[1].text,
1026
lineNum: item.lineNum
1028
Types.needAnalysis[ret.type] = 0;
1039
substrate.onResult = function(result) {
1040
if (result.tokens) result.tokens = null; // We do not need tokens, past the intertyper. Clean them up as soon as possible here.
1043
return substrate.solve();