aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xemscripten.py28
-rw-r--r--settings.py2
-rw-r--r--src/analyzer.js31
-rw-r--r--src/intertyper.js94
-rw-r--r--src/jsifier.js66
-rw-r--r--src/library.js38
-rw-r--r--src/modules.js45
-rw-r--r--src/parseTools.js67
-rw-r--r--src/preamble.js3
-rw-r--r--src/runtime.js4
-rw-r--r--src/settings.js2
-rw-r--r--tests/cases/aliasbitcast.ll37
-rw-r--r--tests/cases/gepoverflow_q1.txt1
-rw-r--r--tests/cases/storestruct_q1.txt3
-rw-r--r--tests/dlmalloc.c32
-rw-r--r--tests/runner.py177
-rw-r--r--tests/sqlite/benchmark.c116
-rw-r--r--tests/sqlite/benchmark.txt10
-rw-r--r--tests/sqlite/sqlite-autooptimize.fails.txt3436
-rw-r--r--tests/sqlite/sqlite3.c128434
-rw-r--r--tests/sqlite/sqlite3.h6731
-rw-r--r--tests/sqlite/test.c44
-rw-r--r--tools/autodebugger.py37
-rwxr-xr-xtools/exec_llvm.py2
-rw-r--r--tools/shared.py37
25 files changed, 139294 insertions, 183 deletions
diff --git a/emscripten.py b/emscripten.py
index 022068c8..21abcc1d 100755
--- a/emscripten.py
+++ b/emscripten.py
@@ -11,11 +11,6 @@ from tools import shared
# Temporary files that should be deleted once the program is finished.
TEMP_FILES_TO_CLEAN = []
-# The data layout used by llvm-gcc (as opposed to clang, which doesn't have the
-# f128:128:128 part).
-GCC_DATA_LAYOUT = ('target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16'
- '-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64'
- '-v128:128:128-a0:0:64-f80:32:32-f128:128:128-n8:16:32"')
def path_from_root(*target):
@@ -98,37 +93,20 @@ def link(*objects):
return out.name
-def compile_malloc(compiler):
+def compile_malloc():
"""Compiles dlmalloc to LLVM bitcode.
- Args:
- compiler: The compiler command to use, a path to either clang or llvm-gcc.
-
Returns:
The path to the compiled dlmalloc as an LLVM bitcode (.bc) file.
"""
src = path_from_root('src', 'dlmalloc.c')
includes = '-I' + path_from_root('src', 'include')
- command = [compiler, '-c', '-g', '-emit-llvm', '-m32', '-o-', includes, src]
+ command = [shared.CLANG, '-c', '-g', '-emit-llvm', '-m32', '-o-', includes, src]
with get_temp_file('.bc') as out: ret = subprocess.call(command, stdout=out)
if ret != 0: raise RuntimeError('Could not compile dlmalloc.')
return out.name
-def determine_compiler(filepath):
- """Determines whether a given file uses llvm-gcc or clang data layout.
-
- Args:
- filepath: The .bc or .ll file containing the bitcode/assembly to test.
-
- Returns:
- The path to the compiler, either llvm-gcc or clang.
- """
- assembly = open(disassemble(filepath)).read()
- is_gcc = GCC_DATA_LAYOUT in assembly
- return shared.to_cc(shared.LLVM_GCC if is_gcc else shared.CLANG)
-
-
def has_annotations(filepath):
"""Tests whether an assembly file contains annotations.
@@ -164,7 +142,7 @@ def main(args):
if args.dlmalloc or args.optimize or not has_annotations(args.infile):
args.infile = assemble(args.infile)
if args.dlmalloc:
- malloc = compile_malloc(determine_compiler(args.infile))
+ malloc = compile_malloc()
args.infile = link(args.infile, malloc)
if args.optimize: args.infile = optimize(args.infile)
args.infile = disassemble(args.infile)
diff --git a/settings.py b/settings.py
index c6d63341..fe9297f7 100644
--- a/settings.py
+++ b/settings.py
@@ -7,8 +7,6 @@ TEMP_DIR='/dev/shm'
LLVM_ROOT=os.path.expanduser('~/Dev/llvm-2.9/cbuild/bin')
-LLVM_GCC=os.path.expanduser('~/Dev/llvm-gcc-2.9/cbuild/install/bin/llvm-g++')
-
COMPILER_OPTS = ['-m32'] # Need to build as 32bit arch, for now -
# various errors on 64bit compilation
# WARNING: '-g' here will generate llvm bitcode that lli will crash on!
diff --git a/src/analyzer.js b/src/analyzer.js
index 824e7903..9d542e2c 100644
--- a/src/analyzer.js
+++ b/src/analyzer.js
@@ -46,8 +46,10 @@ function analyzer(data) {
// Functions & labels
item.functions = [];
var currLabelFinished; // Sometimes LLVM puts a branch in the middle of a label. We need to ignore all lines after that.
+ item.items.sort(function(a, b) { return a.lineNum - b.lineNum });
for (var i = 0; i < item.items.length; i++) {
var subItem = item.items[i];
+ assert(subItem.lineNum);
if (subItem.intertype == 'function') {
item.functions.push(subItem);
subItem.endLineNum = null;
@@ -58,7 +60,7 @@ function analyzer(data) {
if (LLVM_STYLE == 'new' && item.items[i+1].intertype !== 'label') {
item.items.splice(i+1, 0, {
intertype: 'label',
- ident: '_entry',
+ ident: toNiceIdent('%0'),
lineNum: subItem.lineNum + '.5'
});
}
@@ -77,10 +79,10 @@ function analyzer(data) {
currLabelFinished = true;
}
} else {
- print('// WARNING: content after a branch in a label, line: ' + subItem.lineNum);
+ print('// WARNING: content after a branch in a label, line: ' + subItem.lineNum + '::' + dump(subItem));
}
} else {
- print("ERROR: what is this? " + JSON.stringify(subItem));
+ throw "ERROR: what is this? " + JSON.stringify(subItem);
}
}
delete item.items;
@@ -107,6 +109,8 @@ function analyzer(data) {
// check that we never allocate with this (either as a child structure
// in the analyzer, or in calcSize in alloca).
var subType = check[2];
+ addTypeInternal(subType, data); // needed for anonymous structure definitions (see below)
+
Types.types[nonPointing] = {
name_: nonPointing,
fields: range(num).map(function() { return subType }),
@@ -124,6 +128,20 @@ function analyzer(data) {
return;
}
+ // anonymous structure definition, for example |{ i32, i8*, void ()*, i32 }|
+ if (type[0] == '{' || type[0] == '<') {
+ var packed = type[0] == '<';
+ Types.types[type] = {
+ name_: type,
+ fields: splitTokenList(tokenize(type.substr(2 + packed, type.length - 4 - 2*packed)).tokens).map(function(segment) {
+ return segment[0].text;
+ }),
+ packed: packed,
+ lineNum: '?'
+ };
+ return;
+ }
+
if (isPointerType(type)) return;
if (['['].indexOf(type) != -1) return;
Types.types[type] = {
@@ -333,7 +351,7 @@ function analyzer(data) {
// Decision time
- var pointedType = removePointing(variable.type);
+ var pointedType = pointingLevels(variable.type) > 0 ? removePointing(variable.type) : null;
if (variable.origin == 'getelementptr') {
// Use our implementation that emulates pointers etc.
// TODO Can we perhaps nativize some of these? However to do so, we need to discover their
@@ -563,7 +581,7 @@ function analyzer(data) {
func.labelsDict[label.ident] = label;
func.labelIds[label.ident] = func.labelIdCounter++;
});
- func.labelIds[toNiceIdent('%entry')] = -1; // entry is always -1
+ func.labelIds[toNiceIdent('%0')] = -1; // entry is always -1
func.hasPhi = false;
func.hasIndirectBr = false;
@@ -575,8 +593,9 @@ function analyzer(data) {
var remarkableLabelId = line.value.params[i].label;
func.remarkableLabels.push(remarkableLabelId);
var remarkableLabel = func.labelsDict[remarkableLabelId];
+ assert(remarkableLabel);
var lastLine = remarkableLabel.lines.slice(-1)[0];
- if (lastLine.value) {
+ if (lastLine.intertype === 'assign') {
lastLine.value.currLabelId = remarkableLabelId;
} else {
lastLine.currLabelId = remarkableLabelId;
diff --git a/src/intertyper.js b/src/intertyper.js
index 83a49645..280b8a3f 100644
--- a/src/intertyper.js
+++ b/src/intertyper.js
@@ -2,6 +2,9 @@
// to be processed by the later stages.
var tokenizer; // TODO: Clean this up/out
+function tokenize(text) {
+ return tokenizer.processItem({ lineText: text }, true);
+}
//! @param parseFunctions We parse functions only on later passes, since we do not
//! want to parse all of them at once, and have all their
@@ -48,8 +51,11 @@ function intertyper(data, parseFunctions, baseLineNum) {
currFunctionLineNum = i + 1;
}
if (!inFunction || parseFunctions) {
- if (inContinual || new RegExp(/^\ +to.*/g).test(line)) {
- // to after invoke
+ if (inContinual || new RegExp(/^\ +to.*/g).test(line)
+ || new RegExp(/^\ +catch .*/g).test(line)
+ || new RegExp(/^\ +filter .*/g).test(line)
+ || new RegExp(/^\ +cleanup .*/g).test(line)) {
+ // to after invoke or landingpad second line
ret.slice(-1)[0].lineText += line;
if (new RegExp(/^\ +\]/g).test(line)) { // end of llvm switch
inContinual = false;
@@ -137,13 +143,15 @@ function intertyper(data, parseFunctions, baseLineNum) {
// merge certain tokens
if (lastToken && isType(lastToken.text) && isFunctionDef(token)) {
lastToken.text += ' ' + text;
- } else if (lastToken && text[text.length-1] == '}') {
+ } else if (lastToken && /^}\**$/.exec(text)) { // }, }*, etc.
var openBrace = tokens.length-1;
- while (tokens[openBrace].text != '{') openBrace --;
+ while (tokens[openBrace].text.substr(-1) != '{') openBrace --;
token = combineTokens(tokens.slice(openBrace+1));
tokens.splice(openBrace, tokens.length-openBrace+1);
tokens.push(token);
token.type = '{';
+ token.text = '{ ' + token.text + ' }';
+ while (pointingLevels(text) > pointingLevels(token.text)) token.text += '*'; // TODO: optimize
lastToken = token;
} else {
tokens.push(token);
@@ -265,6 +273,8 @@ function intertyper(data, parseFunctions, baseLineNum) {
return 'Unreachable';
if (tokensLength >= 3 && token0Text == 'indirectbr')
return 'IndirectBr';
+ if (tokensLength >= 2 && token0Text == 'resume')
+ return 'Resume';
} else if (item.indent === -1) {
if (tokensLength >= 3 &&
(token0Text == 'load' || token1Text == 'load'))
@@ -280,8 +290,12 @@ function intertyper(data, parseFunctions, baseLineNum) {
return 'Alloca';
if (tokensLength >= 3 && token0Text == 'extractvalue')
return 'ExtractValue';
+ if (tokensLength >= 3 && token0Text == 'insertvalue')
+ return 'InsertValue';
if (tokensLength >= 3 && token0Text == 'phi')
return 'Phi';
+ if (tokensLength >= 3 && token0Text == 'landingpad')
+ return 'Landingpad';
} else if (item.indent === 0) {
if ((tokensLength >= 1 && token0Text.substr(-1) == ':') || // LLVM 2.7 format, or llvm-gcc in 2.8
(tokensLength >= 3 && token1Text == '<label>'))
@@ -320,6 +334,7 @@ function intertyper(data, parseFunctions, baseLineNum) {
processItem: function(item) {
function scanConst(value, type) {
//dprint('inter-const: ' + item.lineNum + ' : ' + JSON.stringify(value) + ',' + type + '\n');
+ Types.needAnalysis[type] = 0;
if (Runtime.isNumberType(type) || pointingLevels(type) >= 1) {
return { value: toNiceIdent(value.text), type: type };
} else if (value.text in set('zeroinitializer', 'undef')) { // undef doesn't really need initting, but why not
@@ -334,16 +349,21 @@ function intertyper(data, parseFunctions, baseLineNum) {
if (segment[1].text == 'null') {
return { intertype: 'value', value: 0, type: 'i32' };
} else if (segment[1].text == 'zeroinitializer') {
+ Types.needAnalysis[segment[0].text] = 0;
return { intertype: 'emptystruct', type: segment[0].text };
} else if (segment[1].text in PARSABLE_LLVM_FUNCTIONS) {
return parseLLVMFunctionCall(segment);
} else if (segment[1].type && segment[1].type == '{') {
+ Types.needAnalysis[segment[0].text] = 0;
return { intertype: 'struct', type: segment[0].text, contents: handleSegments(segment[1].tokens) };
} else if (segment[1].type && segment[1].type == '<') {
+ Types.needAnalysis[segment[0].text] = 0;
return { intertype: 'struct', type: segment[0].text, contents: handleSegments(segment[1].item.tokens[0].tokens) };
} else if (segment[1].type && segment[1].type == '[') {
+ Types.needAnalysis[segment[0].text] = 0;
return { intertype: 'list', type: segment[0].text, contents: handleSegments(segment[1].item.tokens) };
} else if (segment.length == 2) {
+ Types.needAnalysis[segment[0].text] = 0;
return { intertype: 'value', type: segment[0].text, value: toNiceIdent(segment[1].text) };
} else if (segment[1].text === 'c') {
// string
@@ -378,15 +398,18 @@ function intertyper(data, parseFunctions, baseLineNum) {
}
if (item.tokens[2].text == 'alias') {
- cleanOutTokensSet(LLVM.LINKAGES, item.tokens, 3);
- cleanOutTokensSet(LLVM.VISIBILITIES, item.tokens, 3);
- return [{
+ cleanOutTokens(LLVM.LINKAGES, item.tokens, 3);
+ cleanOutTokens(LLVM.VISIBILITIES, item.tokens, 3);
+ var last = getTokenIndexByText(item.tokens, ';');
+ var ret = {
intertype: 'alias',
ident: toNiceIdent(item.tokens[0].text),
- aliasee: toNiceIdent(item.tokens[4].text),
- type: item.tokens[3].text,
+ value: parseLLVMSegment(item.tokens.slice(3, last)),
lineNum: item.lineNum
- }];
+ };
+ ret.type = ret.value.type;
+ Types.needAnalysis[ret.type] = 0;
+ return [ret];
}
if (item.tokens[2].text == 'type') {
var fields = [];
@@ -397,7 +420,7 @@ function intertyper(data, parseFunctions, baseLineNum) {
} else if (item.tokens[3].text != 'opaque') {
if (item.tokens[3].type == '<') {
packed = true;
- item.tokens[3] = tokenizer.processItem({ lineText: '{ ' + item.tokens[3].item.tokens[0].text + ' }' }, true).tokens[0];
+ item.tokens[3] = item.tokens[3].item.tokens[0];
}
var subTokens = item.tokens[3].tokens;
subTokens.push({text:','});
@@ -418,13 +441,13 @@ function intertyper(data, parseFunctions, baseLineNum) {
} else {
// variable
var ident = item.tokens[0].text;
- cleanOutTokensSet(LLVM.GLOBAL_MODIFIERS, item.tokens, 3);
- cleanOutTokensSet(LLVM.GLOBAL_MODIFIERS, item.tokens, 2);
+ cleanOutTokens(LLVM.GLOBAL_MODIFIERS, item.tokens, [2, 3]);
var external = false;
if (item.tokens[2].text === 'external') {
external = true;
item.tokens.splice(2, 1);
}
+ Types.needAnalysis[item.tokens[2].text] = 0;
var ret = {
intertype: 'globalVariable',
ident: toNiceIdent(ident),
@@ -515,7 +538,7 @@ function intertyper(data, parseFunctions, baseLineNum) {
substrate.addActor('Load', {
processItem: function(item) {
item.intertype = 'load';
- if (item.tokens[0].text == 'volatile') item.tokens.shift(0);
+ cleanOutTokens(LLVM.ACCESS_OPTIONS, item.tokens, [0, 1]);
item.pointerType = item.tokens[1].text;
item.valueType = item.type = removePointing(item.pointerType);
Types.needAnalysis[item.type] = 0;
@@ -537,6 +560,20 @@ function intertyper(data, parseFunctions, baseLineNum) {
this.forwardItem(item, 'Reintegrator');
}
});
+ // 'insertvalue'
+ substrate.addActor('InsertValue', {
+ processItem: function(item) {
+ var last = getTokenIndexByText(item.tokens, ';');
+ item.intertype = 'insertvalue';
+ item.type = item.tokens[1].text; // Of the origin aggregate, as well as the result
+ Types.needAnalysis[item.type] = 0;
+ item.ident = toNiceIdent(item.tokens[2].text);
+ var segments = splitTokenList(item.tokens.slice(4, last));
+ item.value = parseLLVMSegment(segments[0]);
+ item.indexes = segments.slice(1);
+ this.forwardItem(item, 'Reintegrator');
+ }
+ });
// 'bitcast'
substrate.addActor('Bitcast', {
processItem: function(item) {
@@ -607,9 +644,10 @@ function intertyper(data, parseFunctions, baseLineNum) {
}
item.ident = toNiceIdent(item.ident);
if (type === 'invoke') {
- cleanOutTokens(['alignstack', 'alwaysinline', 'inlinehint', 'naked', 'noimplicitfloat', 'noinline', 'alwaysinline attribute.', 'noredzone', 'noreturn', 'nounwind', 'optsize', 'readnone', 'readonly', 'ssp', 'sspreq'], item.tokens, 4);
- item.toLabel = toNiceIdent(item.tokens[6].text);
- item.unwindLabel = toNiceIdent(item.tokens[9].text);
+ var toIndex = findTokenText(item, 'to');
+ item.toLabel = toNiceIdent(item.tokens[toIndex+2].text);
+ item.unwindLabel = toNiceIdent(item.tokens[toIndex+5].text);
+ assert(item.toLabel && item.unwindLabel);
}
if (item.indent == 2) {
// standalone call - not in assign
@@ -629,6 +667,15 @@ function intertyper(data, parseFunctions, baseLineNum) {
return makeCall.call(this, item, 'invoke');
}
});
+ // 'landingpad' - just a stub implementation
+ substrate.addActor('Landingpad', {
+ processItem: function(item) {
+ item.intertype = 'landingpad';
+ item.type = item.tokens[1].text;
+ Types.needAnalysis[item.type] = 0;
+ this.forwardItem(item, 'Reintegrator');
+ }
+ });
// 'alloca'
var allocaPossibleVars = ['allocatedNum'];
substrate.addActor('Alloca', {
@@ -704,7 +751,7 @@ function intertyper(data, parseFunctions, baseLineNum) {
// 'store'
substrate.addActor('Store', {
processItem: function(item) {
- if (item.tokens[0].text == 'volatile') item.tokens.shift(0);
+ cleanOutTokens(LLVM.ACCESS_OPTIONS, item.tokens, [0, 1]);
var segments = splitTokenList(item.tokens.slice(1));
var ret = {
intertype: 'store',
@@ -733,7 +780,7 @@ function intertyper(data, parseFunctions, baseLineNum) {
var commaIndex = findTokenText(item, ',');
return [{
intertype: 'branch',
- condition: parseLLVMSegment(item.tokens.slice(1, commaIndex)),
+ value: parseLLVMSegment(item.tokens.slice(1, commaIndex)),
labelTrue: toNiceIdent(item.tokens[commaIndex+2].text),
labelFalse: toNiceIdent(item.tokens[commaIndex+5].text),
lineNum: item.lineNum
@@ -754,6 +801,15 @@ function intertyper(data, parseFunctions, baseLineNum) {
}];
}
});
+ // 'resume' - partial implementation
+ substrate.addActor('Resume', {
+ processItem: function(item) {
+ return [{
+ intertype: 'resume',
+ lineNum: item.lineNum
+ }];
+ }
+ });
// 'switch'
substrate.addActor('Switch', {
processItem: function(item) {
diff --git a/src/jsifier.js b/src/jsifier.js
index 9a2a82c4..ab5c8720 100644
--- a/src/jsifier.js
+++ b/src/jsifier.js
@@ -26,6 +26,8 @@ function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) {
ident: '_' + ident
});
});
+
+ Functions.implementedFunctions = set(data.unparsedFunctions.map(function(func) { return func.ident }));
}
// Does simple 'macro' substitution, using Django-like syntax,
@@ -279,17 +281,18 @@ function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) {
item.intertype = 'GlobalVariableStub';
var ret = [item];
item.JS = 'var ' + item.ident + ';';
- // Set the actual value in a postset, since it may be a global variable. TODO: handle alias of alias (needs ordering)
+ // Set the actual value in a postset, since it may be a global variable. We also order by dependencies there
+ var value = finalizeLLVMParameter(item.value, true); // do *not* indexize functions here
ret.push({
intertype: 'GlobalVariablePostSet',
- JS: item.ident + ' = ' + item.aliasee + ';'
+ ident: item.ident,
+ dependencies: set([value]),
+ JS: item.ident + ' = ' + value + ';'
});
return ret;
}
});
- var moduleFunctions = set(data.unparsedFunctions.map(function(func) { return func.ident }));
-
var addedLibraryItems = {};
// functionStub
@@ -305,7 +308,7 @@ function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) {
if (ident in addedLibraryItems) return '';
// Don't replace implemented functions with library ones (which can happen when we add dependencies).
// Note: We don't return the dependencies here. Be careful not to end up where this matters
- if (('_' + ident) in moduleFunctions) return '';
+ if (('_' + ident) in Functions.implementedFunctions) return '';
addedLibraryItems[ident] = true;
var snippet = LibraryManager.library[ident];
@@ -340,6 +343,9 @@ function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) {
snippet = snippet.toString();
// name the function; overwrite if it's already named
snippet = snippet.replace(/function(?:\s+([^(]+))?\s*\(/, 'function _' + ident + '(');
+ if (LIBRARY_DEBUG) {
+ snippet = snippet.replace('{', '{ print("[library call:' + ident + ']"); ');
+ }
}
var postsetId = ident + '__postset';
@@ -674,10 +680,10 @@ function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) {
makeFuncLineActor('branch', function(item) {
if (item.stolen) return ';'; // We will appear where we were stolen to
- if (!item.condition) {
+ if (!item.value) {
return makeBranch(item.label, item.currLabelId);
} else {
- var condition = finalizeLLVMParameter(item.condition);
+ var condition = finalizeLLVMParameter(item.value);
var labelTrue = makeBranch(item.labelTrue, item.currLabelId);
var labelFalse = makeBranch(item.labelFalse, item.currLabelId);
if (labelTrue == ';' && labelFalse == ';') return ';';
@@ -707,9 +713,9 @@ function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) {
ret += ' ' + makeBranch(switchLabel.label, item.currLabelId || null) + '\n';
ret += '}\n';
});
- ret += 'else {\n';
+ if (item.switchLabels.length > 0) ret += 'else {\n';
ret += makeBranch(item.defaultLabel, item.currLabelId) + '\n';
- ret += '}\n';
+ if (item.switchLabels.length > 0) ret += '}\n';
if (item.value) {
ret += ' ' + toNiceIdent(item.value);
}
@@ -727,6 +733,9 @@ function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) {
}
return ret + ';';
});
+ makeFuncLineActor('resume', function(item) {
+ return (EXCEPTION_DEBUG ? 'print("Resuming exception");' : '') + 'throw [0,0];';
+ });
makeFuncLineActor('invoke', function(item) {
// Wrapping in a function lets us easily return values if we are
// in an assignment
@@ -743,6 +752,10 @@ function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) {
+ ' } else { ' + makeBranch(item.unwindLabel, item.currLabelId) + ' }';
return ret;
});
+ makeFuncLineActor('landingpad', function(item) {
+ // Just a stub
+ return '{ f0: 0, f1: 0 }';
+ });
makeFuncLineActor('load', function(item) {
var value = finalizeLLVMParameter(item.pointer);
var impl = item.ident ? getVarImpl(item.funcData, item.ident) : VAR_EMULATED;
@@ -759,6 +772,15 @@ function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) {
// and we emulate them using simple JS objects { f1: , f2: , } etc., for speed
return item.ident + '.f' + item.indexes[0][0].text;
});
+ makeFuncLineActor('insertvalue', function(item) {
+ assert(item.indexes.length == 1); // TODO: see extractvalue
+ var ret = '(', ident;
+ if (item.ident === 'undef') {
+ item.ident = 'tempValue';
+ ret += item.ident + ' = [' + makeEmptyStruct(item.type) + '], ';
+ }
+ return ret + item.ident + '.f' + item.indexes[0][0].text + ' = ' + finalizeLLVMParameter(item.value) + ', ' + item.ident + ')';
+ });
makeFuncLineActor('indirectbr', function(item) {
return makeBranch(finalizeLLVMParameter(item.pointer), item.currLabelId, true);
});
@@ -841,6 +863,7 @@ function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) {
}
makeFuncLineActor('getelementptr', function(item) { return finalizeLLVMFunctionCall(item) });
makeFuncLineActor('call', function(item) {
+ if (item.standalone && LibraryManager.isStubFunction(item.ident)) return ';';
return makeFunctionCall(item.ident, item.params, item.funcData) + (item.standalone ? ';' : '');
});
@@ -853,11 +876,34 @@ function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) {
var itemsDict = { type: [], GlobalVariableStub: [], functionStub: [], function: [], GlobalVariable: [], GlobalVariablePostSet: [] };
items.forEach(function(item) {
item.lines = null;
- var small = { intertype: item.intertype, JS: item.JS }; // Release memory
+ var small = { intertype: item.intertype, JS: item.JS, ident: item.ident, dependencies: item.dependencies }; // Release memory
itemsDict[small.intertype].push(small);
});
items = null;
+ var splitPostSets = splitter(itemsDict.GlobalVariablePostSet, function(x) { return x.ident && x.dependencies });
+ itemsDict.GlobalVariablePostSet = splitPostSets.leftIn;
+ var orderedPostSets = splitPostSets.splitOut;
+
+ var limit = orderedPostSets.length * orderedPostSets.length;
+ for (var i = 0; i < orderedPostSets.length; i++) {
+ for (var j = i+1; j < orderedPostSets.length; j++) {
+ if (orderedPostSets[j].ident in orderedPostSets[i].dependencies) {
+ var temp = orderedPostSets[i];
+ orderedPostSets[i] = orderedPostSets[j];
+ orderedPostSets[j] = temp;
+ i--;
+ limit--;
+ assert(limit > 0, 'Could not sort postsets!');
+ break;
+ }
+ }
+ }
+
+ itemsDict.GlobalVariablePostSet = itemsDict.GlobalVariablePostSet.concat(orderedPostSets);
+
+ //
+
var generated = [];
if (mainPass) {
generated = generated.concat(itemsDict.type).concat(itemsDict.GlobalVariableStub).concat(itemsDict.functionStub);
diff --git a/src/library.js b/src/library.js
index a628e323..1f32678d 100644
--- a/src/library.js
+++ b/src/library.js
@@ -802,9 +802,12 @@ LibraryManager.library = {
_umask.cmask = newMask;
return oldMask;
},
+ stat64: 'stat',
+ fstat64: 'fstat',
__01fstat64_: 'fstat',
__01stat64_: 'stat',
__01lstat64_: 'lstat',
+
// TODO: Check if other aliases are needed.
// ==========================================================================
@@ -998,6 +1001,7 @@ LibraryManager.library = {
// Synchronization and blocking flags are irrelevant to us.
return 0;
case 5: // F_GETLK.
+ case 12: // F_GETLK64.
var arg = {{{ makeGetValue('varargs', 0, 'i32') }}};
var offset = ___flock_struct_layout.l_type;
// We're always unlocked.
@@ -1005,6 +1009,8 @@ LibraryManager.library = {
return 0;
case 6: // F_SETLK.
case 7: // F_SETLKW.
+ case 13: // F_SETLK64.
+ case 14: // F_SETLKW64.
// Pretend that the locking is successful.
return 0;
case 8: // F_SETOWN.
@@ -2101,6 +2107,9 @@ LibraryManager.library = {
self.DATASIZE += alignMemoryPage(bytes);
return ret; // Previous break location.
},
+ open64: 'open',
+ lseek64: 'lseek',
+ ftruncate64: 'ftruncate',
__01open64_: 'open',
__01lseek64_: 'lseek',
__01truncate64_: 'truncate',
@@ -2330,9 +2339,9 @@ LibraryManager.library = {
var argText;
var prefix = '';
if (next == 'd'.charCodeAt(0) || next == 'i'.charCodeAt(0)) {
- argText = currAbsArg.toString(10);
+ argText = reSign(currArg, 8 * argSize, 1).toString(10);
} else if (next == 'u'.charCodeAt(0)) {
- argText = unSign(currArg, 8 * argSize).toString(10);
+ argText = unSign(currArg, 8 * argSize, 1).toString(10);
currArg = Math.abs(currArg);
} else if (next == 'o'.charCodeAt(0)) {
argText = (flagAlternative ? '0' : '') + currAbsArg.toString(8);
@@ -2369,11 +2378,13 @@ LibraryManager.library = {
}
}
- // Add sign.
- if (currArg < 0) {
- prefix = '-' + prefix;
- } else if (flagAlwaysSigned) {
- prefix = '+' + prefix;
+ // Add sign if needed
+ if (flagAlwaysSigned) {
+ if (currArg < 0) {
+ prefix = '-' + prefix;
+ } else {
+ prefix = '+' + prefix;
+ }
}
// Add padding.
@@ -2815,6 +2826,7 @@ LibraryManager.library = {
}
},
fseeko: 'fseek',
+ fseeko64: 'fseek',
fsetpos__deps: ['$FS', 'lseek', '__setErrNo', '$ERRNO_CODES'],
fsetpos: function(stream, pos) {
// int fsetpos(FILE *stream, const fpos_t *pos);
@@ -2853,6 +2865,7 @@ LibraryManager.library = {
}
},
ftello: 'ftell',
+ ftello64: 'ftell',
fwrite__deps: ['$FS', 'write'],
fwrite: function(ptr, size, nitems, stream) {
// size_t fwrite(const void *restrict ptr, size_t size, size_t nitems, FILE *restrict stream);
@@ -3078,6 +3091,7 @@ LibraryManager.library = {
vscanf: 'scanf',
vfscanf: 'fscanf',
vsscanf: 'sscanf',
+ fopen64: 'fopen',
__01fopen64_: 'fopen',
__01freopen64_: 'freopen',
__01fseeko64_: 'fseek',
@@ -4131,6 +4145,13 @@ LibraryManager.library = {
return ret;
},
+ llvm_expect_i32: function(x, y) {
+ return x == y; // TODO: inline this
+ },
+
+ llvm_lifetime_start: function() {},
+ llvm_lifetime_end: function() {},
+
// ==========================================================================
// iostream.h
// ==========================================================================
@@ -5294,6 +5315,9 @@ LibraryManager.library = {
pthread_mutex_init: function() {},
pthread_mutex_destroy: function() {},
+ pthread_mutexattr_init: function() {},
+ pthread_mutexattr_settype: function() {},
+ pthread_mutexattr_destroy: function() {},
pthread_mutex_lock: function() {},
pthread_mutex_unlock: function() {},
pthread_cond_broadcast: function() {},
diff --git a/src/modules.js b/src/modules.js
index f613c20b..8205e9ff 100644
--- a/src/modules.js
+++ b/src/modules.js
@@ -8,7 +8,9 @@ var LLVM = {
'weak_odr', 'externally_visible', 'dllimport', 'dllexport', 'unnamed_addr'),
VISIBILITIES: set('default', 'hidden', 'protected'),
PARAM_ATTR: set('noalias', 'signext', 'zeroext', 'inreg', 'sret', 'nocapture', 'nest'),
- CALLING_CONVENTIONS: set('ccc', 'fastcc', 'coldcc', 'cc10', 'x86_fastcallcc')
+ CALLING_CONVENTIONS: set('ccc', 'fastcc', 'coldcc', 'cc10', 'x86_fastcallcc'),
+ ACCESS_OPTIONS: set('volatile', 'atomic'),
+ INVOKE_MODIFIERS: set('alignstack', 'alwaysinline', 'inlinehint', 'naked', 'noimplicitfloat', 'noinline', 'alwaysinline attribute.', 'noredzone', 'noreturn', 'nounwind', 'optsize', 'readnone', 'readonly', 'ssp', 'sspreq')
};
LLVM.GLOBAL_MODIFIERS = set(keys(LLVM.LINKAGES).concat(['constant', 'global', 'hidden']));
@@ -27,18 +29,19 @@ var Debugging = {
var form1 = new RegExp(/^ .*, !dbg !(\d+) *$/);
var form2 = new RegExp(/^ .*, !dbg !(\d+) *; .*$/);
- var form3 = new RegExp(/^!(\d+) = metadata !{i32 (\d+), i32 \d+, metadata !(\d+), .*}$/);
- var form3a = new RegExp(/^!(\d+) = metadata !{i32 \d+, metadata !\d+, i32 \d+, i32 \d+, metadata !(\d+), i32 \d+} ; \[ DW_TAG_lexical_block \]$/);
- var form3ab = ne