fround support in emterpreter
This commit is contained in:
Родитель
2b776f6970
Коммит
1976f9d68c
2
emcc
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';
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче