infrastructure for implementing i64 math in asm.js, and implement i64Add and llvm_uadd_with_overflow_i64 that way

This commit is contained in:
Alon Zakai 2013-03-12 17:14:07 -07:00
Родитель 1706d67834
Коммит 9483f8b998
5 изменённых файлов: 78 добавлений и 36 удалений

Просмотреть файл

@ -313,6 +313,10 @@ def emscript(infile, settings, outfile, libraries=[], compiler_engine=None,
last_forwarded_json = json.loads(last_forwarded_data) last_forwarded_json = json.loads(last_forwarded_data)
if settings.get('ASM_JS'): if settings.get('ASM_JS'):
post_funcs, post_rest = post.split('// EMSCRIPTEN_END_FUNCS\n')
post = post_rest
funcs_js += '\n' + post_funcs + '// EMSCRIPTEN_END_FUNCS\n'
simple = os.environ.get('EMCC_SIMPLE_ASM') simple = os.environ.get('EMCC_SIMPLE_ASM')
class Counter: class Counter:
i = 0 i = 0

Просмотреть файл

@ -397,6 +397,20 @@ function JSify(data, functionsOnly, givenFunctions) {
} }
}); });
function processLibraryFunction(snippet, ident) {
snippet = snippet.toString();
assert(snippet.indexOf('XXX missing C define') == -1,
'Trying to include a library function with missing C defines: ' + ident + ' | ' + snippet);
// name the function; overwrite if it's already named
snippet = snippet.replace(/function(?:\s+([^(]+))?\s*\(/, 'function _' + ident + '(');
if (LIBRARY_DEBUG) {
snippet = snippet.replace('{', '{ var ret = (function() { if (Runtime.debug) Module.printErr("[library call:' + ident + ': " + Array.prototype.slice.call(arguments).map(Runtime.prettyPrint) + "]"); ');
snippet = snippet.substr(0, snippet.length-1) + '}).apply(this, arguments); if (Runtime.debug && typeof ret !== "undefined") Module.printErr(" [ return:" + Runtime.prettyPrint(ret)); return ret; \n}';
}
return snippet;
}
// functionStub // functionStub
substrate.addActor('FunctionStub', { substrate.addActor('FunctionStub', {
processItem: function(item) { processItem: function(item) {
@ -434,16 +448,7 @@ function JSify(data, functionsOnly, givenFunctions) {
snippet = stringifyWithFunctions(snippet); snippet = stringifyWithFunctions(snippet);
} else if (typeof snippet === 'function') { } else if (typeof snippet === 'function') {
isFunction = true; isFunction = true;
snippet = snippet.toString(); snippet = processLibraryFunction(snippet, ident);
assert(snippet.indexOf('XXX missing C define') == -1,
'Trying to include a library function with missing C defines: ' + ident + ' | ' + snippet);
// name the function; overwrite if it's already named
snippet = snippet.replace(/function(?:\s+([^(]+))?\s*\(/, 'function _' + ident + '(');
if (LIBRARY_DEBUG) {
snippet = snippet.replace('{', '{ var ret = (function() { if (Runtime.debug) Module.printErr("[library call:' + ident + ': " + Array.prototype.slice.call(arguments).map(Runtime.prettyPrint) + "]"); ');
snippet = snippet.substr(0, snippet.length-1) + '}).apply(this, arguments); if (Runtime.debug && typeof ret !== "undefined") Module.printErr(" [ return:" + Runtime.prettyPrint(ret)); return ret; \n}';
}
if (ASM_JS) Functions.libraryFunctions[ident] = 1; if (ASM_JS) Functions.libraryFunctions[ident] = 1;
} }
@ -1563,16 +1568,23 @@ function JSify(data, functionsOnly, givenFunctions) {
// This is the main 'post' pass. Print out the generated code that we have here, together with the // This is the main 'post' pass. Print out the generated code that we have here, together with the
// rest of the output that we started to print out earlier (see comment on the // rest of the output that we started to print out earlier (see comment on the
// "Final shape that will be created"). // "Final shape that will be created").
if (PRECISE_I64_MATH && Types.preciseI64MathUsed) {
['i64Add'].forEach(function(func) {
print(processLibraryFunction(LibraryManager.library[func], func)); // must be first to be close to generated code
Functions.implementedFunctions['_' + func] = LibraryManager.library[func + '__sig'];
});
print('// EMSCRIPTEN_END_FUNCS\n');
print(read('long.js'));
} else {
print('// EMSCRIPTEN_END_FUNCS\n');
print('// Warning: printing of i64 values may be slightly rounded! No deep i64 math used, so precise i64 code not included');
print('var i64Math = null;');
}
if (CORRUPTION_CHECK) { if (CORRUPTION_CHECK) {
assert(!ASM_JS); // cannot monkeypatch asm! assert(!ASM_JS); // cannot monkeypatch asm!
print(processMacros(read('corruptionCheck.js'))); print(processMacros(read('corruptionCheck.js')));
} }
if (PRECISE_I64_MATH && Types.preciseI64MathUsed) {
print(read('long.js'));
} else {
print('// Warning: printing of i64 values may be slightly rounded! No deep i64 math used, so precise i64 code not included');
print('var i64Math = null;');
}
if (HEADLESS) { if (HEADLESS) {
print('if (!ENVIRONMENT_IS_WEB) {'); print('if (!ENVIRONMENT_IS_WEB) {');
print(read('headless.js').replace("'%s'", "'http://emscripten.org'").replace("'?%s'", "''").replace('%s,', 'null,').replace('%d', '0')); print(read('headless.js').replace("'%s'", "'http://emscripten.org'").replace("'?%s'", "''").replace('%s,', 'null,').replace('%d', '0'));

Просмотреть файл

@ -5206,13 +5206,6 @@ LibraryManager.library = {
{{{ makeStructuralReturn(['(x*y)>>>0', 'x*y > 4294967295']) }}}; {{{ makeStructuralReturn(['(x*y)>>>0', 'x*y > 4294967295']) }}};
}, },
llvm_uadd_with_overflow_i64__deps: [function() { Types.preciseI64MathUsed = 1 }],
llvm_uadd_with_overflow_i64: function(xl, xh, yl, yh) {
i64Math.add(xl, xh, yl, yh);
{{{ makeStructuralReturn([makeGetTempDouble(0, 'i32'), makeGetTempDouble(1, 'i32'), '0']) }}};
// XXX Need to hack support for second param in long.js
},
llvm_umul_with_overflow_i64__deps: [function() { Types.preciseI64MathUsed = 1 }], llvm_umul_with_overflow_i64__deps: [function() { Types.preciseI64MathUsed = 1 }],
llvm_umul_with_overflow_i64: function(xl, xh, yl, yh) { llvm_umul_with_overflow_i64: function(xl, xh, yl, yh) {
i64Math.multiply(xl, xh, yl, yh); i64Math.multiply(xl, xh, yl, yh);
@ -7352,6 +7345,41 @@ LibraryManager.library = {
Module.print(intArrayToString(__formatString(_emscripten_jcache_printf_.buffer, varargs + i*4)).replace('\\n', '')); Module.print(intArrayToString(__formatString(_emscripten_jcache_printf_.buffer, varargs + i*4)).replace('\\n', ''));
Runtime.stackAlloc(-4*i); // free up the stack space we know is ok to free Runtime.stackAlloc(-4*i); // free up the stack space we know is ok to free
}, },
//============================
// i64 math
//============================
i64Add__asm: 'true',
i64Add__sig: 'iiiii',
i64Add: function(a, b, c, d) {
/*
x = a + b*2^32
y = c + d*2^32
result = l + h*2^32
*/
a = a|0; b = b|0; c = c|0; d = d|0;
var l = 0, h = 0;
l = (a + c)>>>0;
h = (b + d)>>>0;
if ((l>>>0) < (a>>>0)) { // iff we overflowed
h = (h+1)>>>0;
}
{{{ makeStructuralReturn(['l|0', 'h'], true) }}};
},
llvm_uadd_with_overflow_i64__asm: 'true',
llvm_uadd_with_overflow_i64__sig: 'iiiii',
llvm_uadd_with_overflow_i64: function(a, b, c, d) {
a = a|0; b = b|0; c = c|0; d = d|0;
var l = 0, h = 0, overflow = 0;
l = (a + c)>>>0;
h = (b + d)>>>0;
if ((l>>>0) < (a>>>0)) { // iff we overflowed
h = (h+1)>>>0;
overflow = 1;
}
{{{ makeStructuralReturn(['l|0', 'h', 'overflow'], true) }}};
},
}; };
function autoAddDeps(object, name) { function autoAddDeps(object, name) {

Просмотреть файл

@ -1530,13 +1530,6 @@ var i64Math = (function() { // Emscripten wrapper
// Emscripten wrapper // Emscripten wrapper
var Wrapper = { var Wrapper = {
add: function(xl, xh, yl, yh) {
var x = new goog.math.Long(xl, xh);
var y = new goog.math.Long(yl, yh);
var ret = x.add(y);
HEAP32[tempDoublePtr>>2] = ret.low_;
HEAP32[tempDoublePtr+4>>2] = ret.high_;
},
subtract: function(xl, xh, yl, yh) { subtract: function(xl, xh, yl, yh) {
var x = new goog.math.Long(xl, xh); var x = new goog.math.Long(xl, xh);
var y = new goog.math.Long(yl, yh); var y = new goog.math.Long(yl, yh);

Просмотреть файл

@ -1724,13 +1724,14 @@ function makeLLVMStruct(values) {
} }
} }
function makeStructuralReturn(values) { function makeStructuralReturn(values, inAsm) {
if (USE_TYPED_ARRAYS == 2) { if (USE_TYPED_ARRAYS == 2) {
var i = 0; var i = -1;
return 'return (' + values.slice(1).map(function(value) { return 'return ' + asmCoercion(values.slice(1).map(function(value) {
return ASM_JS ? 'asm.setTempRet' + (i++) + '(' + value + ')' i++;
return ASM_JS ? (inAsm ? 'tempRet' + i + ' = ' + value : 'asm.setTempRet' + i + '(' + value + ')')
: 'tempRet' + (i++) + ' = ' + value; : 'tempRet' + (i++) + ' = ' + value;
}).concat([values[0]]).join(',') + ')'; }).concat([values[0]]).join(','), 'i32');
} else { } else {
var i = 0; var i = 0;
return 'return { ' + values.map(function(value) { return 'return { ' + values.map(function(value) {
@ -1971,6 +1972,10 @@ function processMathop(item) {
return finish(['(i64Math' + (ASM_JS ? '_' : '.') + type + '(' + asmCoercion(low1, 'i32') + ',' + asmCoercion(high1, 'i32') + ',' + asmCoercion(low2, 'i32') + ',' + asmCoercion(high2, 'i32') + return finish(['(i64Math' + (ASM_JS ? '_' : '.') + type + '(' + asmCoercion(low1, 'i32') + ',' + asmCoercion(high1, 'i32') + ',' + asmCoercion(low2, 'i32') + ',' + asmCoercion(high2, 'i32') +
(lastArg ? ',' + asmCoercion(+lastArg, 'i32') : '') + '),' + makeGetValue('tempDoublePtr', 0, 'i32') + ')', makeGetValue('tempDoublePtr', Runtime.getNativeTypeSize('i32'), 'i32')]); (lastArg ? ',' + asmCoercion(+lastArg, 'i32') : '') + '),' + makeGetValue('tempDoublePtr', 0, 'i32') + ')', makeGetValue('tempDoublePtr', Runtime.getNativeTypeSize('i32'), 'i32')]);
} }
function i64PreciseLib(type) {
Types.preciseI64MathUsed = true;
return finish(['_i64' + type[0].toUpperCase() + type.substr(1) + '(' + low1 + ',' + high1 + ',' + low2 + ',' + high2 + ')', 'tempRet0']);
}
switch (op) { switch (op) {
// basic integer ops // basic integer ops
case 'or': { case 'or': {
@ -2059,7 +2064,7 @@ function processMathop(item) {
// Dangerous, rounded operations. TODO: Fully emulate // Dangerous, rounded operations. TODO: Fully emulate
case 'add': { case 'add': {
if (PRECISE_I64_MATH) { if (PRECISE_I64_MATH) {
return i64PreciseOp('add'); return i64PreciseLib('add');
} else { } else {
warnI64_1(); warnI64_1();
return finish(splitI64(mergeI64(idents[0]) + '+' + mergeI64(idents[1]), true)); return finish(splitI64(mergeI64(idents[0]) + '+' + mergeI64(idents[1]), true));