This commit is contained in:
Alon Zakai 2015-02-11 17:48:43 -08:00
Родитель 2b776f6970
Коммит 1976f9d68c
4 изменённых файлов: 73 добавлений и 10 удалений

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

@ -1594,6 +1594,8 @@ try:
args += ['PROFILING=1']
if shared.Settings.ASSERTIONS:
args += ['ASSERTIONS=1']
if shared.Settings.PRECISE_F32:
args += ['FROUND=1']
execute(args)
final = final + '.em.js'
finally:

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

@ -482,8 +482,6 @@ class T(RunnerCore): # Short name, to make it more fun to use manually on the co
self.do_run_from_file(src, output)
def test_float32_precise(self):
if self.is_emterpreter(): return self.skip('todo')
Settings.PRECISE_F32 = 1
test_path = path_from_root('tests', 'core', 'test_float32_precise')
src, output = (test_path + s for s in ('.in', '.out'))
@ -5124,7 +5122,6 @@ int main(void) {
for precision in [0, 1, 2]:
Settings.PRECISE_F32 = precision
for t in ['float', 'double']:
if self.is_emterpreter() and precision > 0: continue
print precision, t
src = open(path_from_root('tests', 'fasta.cpp'), 'r').read().replace('double', t)
for i, j in results:

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

@ -22,15 +22,17 @@ ASYNC = False
ASSERTIONS = False
PROFILING = False
SWAPPABLE = False
FROUND = False
def handle_arg(arg):
global ZERO, ASYNC, ASSERTIONS, PROFILING
global ZERO, ASYNC, ASSERTIONS, PROFILING, FROUND
if '=' in arg:
l, r = arg.split('=')
if l == 'ZERO': ZERO = int(r)
elif l == 'ASYNC': ASYNC = int(r)
elif l == 'ASSERTIONS': ASSERTIONS = int(r)
elif l == 'PROFILING': PROFILING = int(r)
elif l == 'FROUND': FROUND = int(r)
return False
return True
@ -42,6 +44,9 @@ temp_files = config.get_temp_files()
if DEBUG:
print >> sys.stderr, 'running emterpretify on', sys.argv
if FROUND:
shared.Settings.PRECISE_F32 = 1
sys.argv = filter(handle_arg, sys.argv)
# consts
@ -218,6 +223,11 @@ OPCODES = [ # l, lx, ly etc - one of 256 locals
'TSLOWD', # [lxl, lxh, ly] lx = ly (double; lx = lxl,lxh)
]
if FROUND:
OPCODES.append(
'FROUND', # [lx, ly] lx = Math.fround(ly), rounds doubles to floats
)
def randomize_opcodes():
global OPCODES
import random
@ -255,7 +265,7 @@ def get_access(l, s='i', base='sp', offset=None):
offset = ''
if s == 'i':
return 'HEAP32[' + str(base) + ' + (' + l + ' << 3) ' + offset + '>> 2]'
elif s == 'd':
elif s == 'd' or s == 'f':
return 'HEAPF64[' + str(base) + ' + (' + l + ' << 3) ' + offset + '>> 3]'
else:
assert 0
@ -266,7 +276,7 @@ def get_coerced_access(l, s='i', unsigned=False, base='sp', offset=None):
return get_access(l, s, base, offset) + '|0'
else:
return get_access(l, s, base, offset) + '>>>0'
elif s == 'd':
elif s == 'd' or s == 'f':
return '+' + get_access(l, s, base, offset)
else:
assert 0
@ -420,6 +430,9 @@ CASES[ROPCODES['GETTDP']] = get_access('lx') + ' = tempDoublePtr;'
CASES[ROPCODES['GETTR0']] = get_access('lx') + ' = tempRet0;'
CASES[ROPCODES['SETTR0']] = 'tempRet0 = ' + get_coerced_access('lx') + ';'
if FROUND:
CASES[ROPCODES['FROUND']] = get_access('lx', s='d') + ' = Math_fround(' + get_coerced_access('ly', s='d') + ');'
# stacktop handling: if allowing async, the very bottom will contain the function being executed,
# for stack trace reconstruction. We store [pc of function, curr pc]
# where curr pc is the current position in that function, when asyncing

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

@ -2307,6 +2307,14 @@ function detectSign(node) {
case 'conditional': case 'seq': {
return detectSign(node[2]);
}
case 'call': {
if (node[1][0] === 'name') {
switch (node[1][1]) {
case 'Math_fround': return ASM_NONSIGNED
default: break;
}
}
}
}
assert(0 , 'badd ' + JSON.stringify(node));
}
@ -6165,12 +6173,12 @@ function emterpretify(ast) {
return Array.prototype.slice.call(tempUint8, 0, 8);
}
function verifyCode(code) {
function verifyCode(code, stat) {
if (code.length % 4 !== 0) assert(0, JSON.stringify(code));
var len = code.length;
for (var i = 0; i < len; i++) {
if (typeof code[i] !== 'string' && typeof code[i] !== 'number' && !(typeof code[i] === 'object' && code[i].what)) {
assert(0, i + ' : ' + JSON.stringify(code));
assert(0, i + ' : ' + JSON.stringify(code) + ' from ' + JSON.stringify(stat));
}
}
}
@ -6861,6 +6869,7 @@ function emterpretify(ast) {
case '>>>': opcode = 'LSHR'; tryNumAsymmetrical(true); break;
default: throw 'bad ' + node[1];
}
if (!opcode) assert(0, JSON.stringify([node, type, sign]));
var x, y, z;
var usingNumValue = numValue !== null && ((!numValueUnsigned && ((numValue << 24 >> 24) === numValue)) ||
( numValueUnsigned && ((numValue & 255) === numValue)));
@ -7113,6 +7122,13 @@ function emterpretify(ast) {
assert(mul[0] === lx);
return mul[1];
}
case 'Math_fround': {
assert(node[2].length === 1);
var child = getReg(node[2][0], undefined, ASM_DOUBLE, ASM_NONSIGNED, lx);
child[1].push('FROUND', lx, child[0], 0);
releaseIfFree(child[0], lx);
return child[1];
}
}
if ((target in EMTERPRETED_FUNCS) && !PROFILING) internal = true;
} else {
@ -7167,7 +7183,7 @@ function emterpretify(ast) {
if (freeLocals.length !== before) assert(0, [before, freeLocals.length] + ' due to ' + astToSrc(stat)); // the statement is done - nothing should still be held on to
var curr = raw[1];
//printErr('stat: ' + JSON.stringify(curr));
verifyCode(curr);
verifyCode(curr, stat);
ret = ret.concat(curr);
});
return ret;
@ -7455,6 +7471,39 @@ function emterpretify(ast) {
//printErr('emterpretifying ' + func[1]);
// we implement floats as doubles, and just decrease precision when fround is called. flip floats to doubles, but we
// must restore this at the end when we emit the trampolines
var trueParams = asmData.params;
asmData.params = {};
for (var t in trueParams) {
if (trueParams[t] === ASM_FLOAT) {
asmData.params[t] = ASM_DOUBLE;
} else {
asmData.params[t] = trueParams[t];
}
}
var trueVars = asmData.vars;
asmData.vars = {};
for (var t in trueVars) {
if (trueVars[t] === ASM_FLOAT) {
asmData.vars[t] = ASM_DOUBLE;
} else {
asmData.vars[t] = trueVars[t];
}
}
traverse(func, function() {} , function(node, type) {
// Math_fround(x) => +Math_fround(+x), so that see no float types on temp values; types are double or int, and fround is just a function we emit
if (type === 'call' && node[1][0] === 'name' && node[1][1] === 'Math_fround') {
assert(node[2].length === 1);
old = ['call', node[1], [['unary-prefix', '+', node[2][0]]]];
node[0] = 'unary-prefix';
node[1] = '+';
node[2] = old;
}
});
// consider locals
var locals = {};
var numLocals = 0; // ignores slow locals, they are over 255 and not directly accessible
@ -7546,6 +7595,7 @@ function emterpretify(ast) {
if ((func[1] in EXTERNAL_EMTERPRETED_FUNCS) || PROFILING) {
// this is reachable from outside emterpreter code, set up a trampoline
asmData.params = trueParams; // restore them, we altered float=>double
asmData.vars = {};
if (zero && !onlyLeavesAreZero) {
// emterpreters run using the stack starting at 0. we must copy it so we can restore it later
@ -7564,8 +7614,8 @@ function emterpretify(ast) {
var code;
switch (asmData.params[arg]) {
case ASM_INT: code = 'HEAP32[' + (zero ? (bump >> 2) : ('EMTSTACKTOP + ' + bump + ' >> 2')) + '] = ' + arg + ';'; break;
case ASM_FLOAT:
case ASM_DOUBLE: code = 'HEAPF64[' + (zero ? (bump >> 3) : ('EMTSTACKTOP + ' + bump + ' >> 3')) + '] = ' + arg + ';'; break;
case ASM_FLOAT: code = 'HEAPF32[' + (zero ? (bump >> 2) : ('EMTSTACKTOP + ' + bump + ' >> 2')) + '] = ' + arg + ';'; break;
default: throw 'bad';
}
argStats.push(srcToStat(code));
@ -7594,6 +7644,7 @@ function emterpretify(ast) {
var ret;
switch (asmData.ret) {
case ASM_INT: ret = srcToExp('HEAP32[EMTSTACKTOP >> 2]'); break;
case ASM_FLOAT:
case ASM_DOUBLE: ret = srcToExp('HEAPF64[EMTSTACKTOP >> 3]'); break;
default: throw 'bad';
}