Author: David Schneider <david.schnei...@picle.org> Branch: arm-backed-float Changeset: r44645:d3279ad17fe6 Date: 2011-06-01 17:46 +0200 http://bitbucket.org/pypy/pypy/changeset/d3279ad17fe6/
Log: (arigo, bivab) add a resoperation for testing called force_spill, that forces a variable to be spilled. It is used to the generate different call patterns with variables that are currently spilled as arguments diff --git a/pypy/jit/backend/llsupport/regalloc.py b/pypy/jit/backend/llsupport/regalloc.py --- a/pypy/jit/backend/llsupport/regalloc.py +++ b/pypy/jit/backend/llsupport/regalloc.py @@ -226,6 +226,18 @@ else: raise ValueError + def force_spill_var(self, var): + self._sync_var(var) + try: + loc = self.reg_bindings[var] + del self.reg_bindings[var] + self.free_regs.append(loc) + except KeyError: + if not we_are_translated(): + import pdb; pdb.set_trace() + else: + raise ValueError + def loc(self, box): """ Return the location of 'box'. """ diff --git a/pypy/jit/backend/test/calling_convention_test.py b/pypy/jit/backend/test/calling_convention_test.py --- a/pypy/jit/backend/test/calling_convention_test.py +++ b/pypy/jit/backend/test/calling_convention_test.py @@ -1,4 +1,3 @@ -import py, sys, random, os, struct, operator, itertools from pypy.jit.metainterp.history import (AbstractFailDescr, AbstractDescr, BasicFailDescr, @@ -24,6 +23,7 @@ def constfloat(x): return ConstFloat(longlong.getfloatstorage(x)) + class FakeStats(object): pass class TestCallingConv(Runner): @@ -35,11 +35,127 @@ self.cpu = getcpuclass()(rtyper=None, stats=FakeStats()) self.cpu.setup_once() + def _prepare_args(self, args, floats, ints): + local_floats = list(floats) + local_ints = list(ints) + expected_result = 0.0 + for i in range(len(args)): + x = args[i] + if x[0] == 'f': + x = local_floats.pop() + t = longlong.getfloatstorage(x) + self.cpu.set_future_value_float(i, t) + else: + x = local_ints.pop() + self.cpu.set_future_value_int(i, x) + expected_result += x + return expected_result + @classmethod def get_funcbox(cls, cpu, func_ptr): addr = llmemory.cast_ptr_to_adr(func_ptr) return ConstInt(heaptracker.adr2int(addr)) + def test_call_aligned_with_spilled_values(self): + from pypy.rlib.libffi import types + cpu = self.cpu + if not cpu.supports_floats: + py.test.skip('requires floats') + + + def func(*args): + return float(sum(args)) + + F = lltype.Float + I = lltype.Signed + floats = [0.7, 5.8, 0.1, 0.3, 0.9, -2.34, -3.45, -4.56] + ints = [7, 11, 23, 13, -42, 1111, 95, 1] + for case in range(256): + local_floats = list(floats) + local_ints = list(ints) + args = [] + spills = [] + funcargs = [] + float_count = 0 + int_count = 0 + for i in range(8): + if case & (1<<i): + args.append('f%d' % float_count) + spills.append('force_spill(f%d)' % float_count) + float_count += 1 + funcargs.append(F) + else: + args.append('i%d' % int_count) + spills.append('force_spill(i%d)' % int_count) + int_count += 1 + funcargs.append(I) + + arguments = ', '.join(args) + spill_ops = '\n'.join(spills) + + FUNC = self.FuncType(funcargs, F) + FPTR = self.Ptr(FUNC) + func_ptr = llhelper(FPTR, func) + calldescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT) + funcbox = self.get_funcbox(cpu, func_ptr) + + ops = '[%s]\n' % arguments + ops += '%s\n' % spill_ops + ops += 'f99 = call(ConstClass(func_ptr), %s, descr=calldescr)\n' % arguments + ops += 'finish(f99, %s)\n' % arguments + + loop = parse(ops, namespace=locals()) + looptoken = LoopToken() + done_number = self.cpu.get_fail_descr_number(loop.operations[-1].getdescr()) + self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken) + expected_result = self._prepare_args(args, floats, ints) + + res = self.cpu.execute_token(looptoken) + x = longlong.getrealfloat(cpu.get_latest_value_float(0)) + assert abs(x - expected_result) < 0.0001 + + def test_call_aligned_with_imm_values(self): + from pypy.rlib.libffi import types + cpu = self.cpu + if not cpu.supports_floats: + py.test.skip('requires floats') + + + def func(*args): + return float(sum(args)) + + F = lltype.Float + I = lltype.Signed + floats = [0.7, 5.8, 0.1, 0.3, 0.9, -2.34, -3.45, -4.56] + ints = [7, 11, 23, 13, -42, 1111, 95, 1] + for case in range(256): + result = 0.0 + args = [] + argslist = [] + local_floats = list(floats) + local_ints = list(ints) + for i in range(8): + if case & (1<<i): + args.append(F) + arg = local_floats.pop() + result += arg + argslist.append(constfloat(arg)) + else: + args.append(I) + arg = local_ints.pop() + result += arg + argslist.append(ConstInt(arg)) + FUNC = self.FuncType(args, F) + FPTR = self.Ptr(FUNC) + func_ptr = llhelper(FPTR, func) + calldescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT) + funcbox = self.get_funcbox(cpu, func_ptr) + + res = self.execute_operation(rop.CALL, + [funcbox] + argslist, + 'float', descr=calldescr) + assert abs(res.getfloat() - result) < 0.0001 + def test_call_aligned_with_args_on_the_stack(self): from pypy.rlib.libffi import types cpu = self.cpu @@ -48,79 +164,46 @@ def func(*args): - return sum(args) + return float(sum(args)) F = lltype.Float I = lltype.Signed - base_args = [F, F] - floats = [0.7, 5.8, 0.1, 0.3, 0.9] - ints = [7, 11, 23] - result = sum(floats + ints) - for p in itertools.permutations([I, I, I, F, F, F]): - args = base_args + list(p) + floats = [0.7, 5.8, 0.1, 0.3, 0.9, -2.34, -3.45, -4.56] + ints = [7, 11, 23, 13, -42, 1111, 95, 1] + for case in range(256): + result = 0.0 + args = [] + argslist = [] local_floats = list(floats) local_ints = list(ints) + for i in range(8): + if case & (1<<i): + args.append(F) + arg = local_floats.pop() + result += arg + argslist.append(boxfloat(arg)) + else: + args.append(I) + arg = local_ints.pop() + result += arg + argslist.append(BoxInt(arg)) FUNC = self.FuncType(args, F) FPTR = self.Ptr(FUNC) func_ptr = llhelper(FPTR, func) calldescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT) funcbox = self.get_funcbox(cpu, func_ptr) - argslist = [] - for x in args: - if x is F: - argslist.append(boxfloat(local_floats.pop())) - else: - argslist.append(BoxInt(local_ints.pop())) res = self.execute_operation(rop.CALL, [funcbox] + argslist, 'float', descr=calldescr) assert abs(res.getfloat() - result) < 0.0001 - def test_call_alignment_register_args(self): - from pypy.rlib.libffi import types - cpu = self.cpu - if not cpu.supports_floats: - py.test.skip('requires floats') - - - def func(*args): - return sum(args) - - F = lltype.Float - I = lltype.Signed - floats = [0.7, 5.8] - ints = [7, 11] - result = sum(floats + ints) - for args in itertools.permutations([I, I, F, F]): - local_floats = list(floats) - local_ints = list(ints) - FUNC = self.FuncType(args, F) - FPTR = self.Ptr(FUNC) - func_ptr = llhelper(FPTR, func) - calldescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT) - funcbox = self.get_funcbox(cpu, func_ptr) - argslist = [] - for x in args: - if x is F: - argslist.append(boxfloat(local_floats.pop())) - else: - argslist.append(BoxInt(local_ints.pop())) - - res = self.execute_operation(rop.CALL, - [funcbox] + argslist, - 'float', descr=calldescr) - assert abs(res.getfloat() - result) < 0.0001 - - def test_call_alignment_call_assembler(self): from pypy.rlib.libffi import types cpu = self.cpu if not cpu.supports_floats: py.test.skip('requires floats') - fdescr1 = BasicFailDescr(1) - fdescr2 = BasicFailDescr(2) fdescr3 = BasicFailDescr(3) fdescr4 = BasicFailDescr(4) @@ -136,35 +219,34 @@ assembler_helper_adr = llmemory.cast_ptr_to_adr( _assembler_helper_ptr) - arglist = ['f0', 'f1', 'f2', 'i0', 'f3'] - floats = [0.7, 5.8, 0.1, 0.3] - ints = [7, 11, 23, 42] - def _prepare_args(args): - local_floats = list(floats) - local_ints = list(ints) - for i in range(len(args)): - x = args[i] - if x[0] == 'f': - t = longlong.getfloatstorage(local_floats.pop()) - cpu.set_future_value_float(i, t) + floats = [0.7, 5.8, 0.1, 0.3, 0.9, -2.34, -3.45, -4.56] + ints = [7, 11, 23, 42, -42, 1111, 95, 1] + + for case in range(256): + float_count = 0 + int_count = 0 + args = [] + called_ops = '' + total_index = -1 + for i in range(8): + if case & (1<<i): + args.append('f%d' % float_count) else: - cpu.set_future_value_int(i, (local_ints.pop())) - - for args in itertools.permutations(arglist): - args += ('i1', 'i2', 'i3') + args.append('i%d' % int_count) + called_ops += 'f%d = cast_int_to_float(i%d)\n' % ( + float_count, int_count) + int_count += 1 + if total_index == -1: + total_index = float_count + float_count += 1 + else: + called_ops += 'f%d = float_add(f%d, f%d)\n' % ( + float_count + 1, total_index, float_count) + total_index = float_count + 1 + float_count += 2 arguments = ', '.join(args) - called_ops = ''' - [%s] - i4 = int_add(i0, i1) - i5 = int_add(i4, i2) - i6 = int_add(i5, i3) - guard_value(i6, 83, descr=fdescr1) [i4, i5, i6] - f4 = float_add(f0, f1) - f5 = float_add(f4, f2) - f6 = float_add(f5, f3) - i7 = float_lt(f6, 6.99) - guard_true(i7, descr=fdescr2) [f4, f5, f6] - finish(i6, f6, descr=fdescr3)''' % arguments + called_ops = '[%s]\n' % arguments + called_ops + called_ops += 'finish(f%d, descr=fdescr3)\n' % total_index # compile called loop called_loop = parse(called_ops, namespace=locals()) called_looptoken = LoopToken() @@ -172,15 +254,14 @@ done_number = self.cpu.get_fail_descr_number(called_loop.operations[-1].getdescr()) self.cpu.compile_loop(called_loop.inputargs, called_loop.operations, called_looptoken) - _prepare_args(args) + expected_result = self._prepare_args(args, floats, ints) res = cpu.execute_token(called_looptoken) assert res.identifier == 3 - assert cpu.get_latest_value_int(0) == 83 - t = longlong.getrealfloat(cpu.get_latest_value_float(1)) - assert abs(t - 6.9) < 0.0001 + t = longlong.getrealfloat(cpu.get_latest_value_float(0)) + assert abs(t - expected_result) < 0.0001 ARGS = [] - RES = lltype.Signed + RES = lltype.Float for x in args: if x[0] == 'f': ARGS.append(lltype.Float) @@ -190,22 +271,23 @@ lltype.Ptr(lltype.FuncType(ARGS, RES)), ARGS, RES) ops = ''' [%s] - i10 = call_assembler(%s, descr=called_looptoken) + f99 = call_assembler(%s, descr=called_looptoken) guard_not_forced()[] - finish(i10, descr=fdescr4) + finish(f99, descr=fdescr4) ''' % (arguments, arguments) loop = parse(ops, namespace=locals()) # we want to take the fast path - self.cpu.done_with_this_frame_int_v = done_number + self.cpu.done_with_this_frame_float_v = done_number try: othertoken = LoopToken() self.cpu.compile_loop(loop.inputargs, loop.operations, othertoken) # prepare call to called_loop - _prepare_args(args) + self._prepare_args(args, floats, ints) res = cpu.execute_token(othertoken) - x = cpu.get_latest_value_int(0) + x = longlong.getrealfloat(cpu.get_latest_value_float(0)) assert res.identifier == 4 - assert x == 83 + assert abs(x - expected_result) < 0.0001 finally: - del self.cpu.done_with_this_frame_int_v + del self.cpu.done_with_this_frame_float_v + diff --git a/pypy/jit/backend/x86/regalloc.py b/pypy/jit/backend/x86/regalloc.py --- a/pypy/jit/backend/x86/regalloc.py +++ b/pypy/jit/backend/x86/regalloc.py @@ -266,6 +266,12 @@ return self.rm.force_allocate_reg(var, forbidden_vars, selected_reg, need_lower_byte) + def force_spill_var(self, var): + if var.type == FLOAT: + return self.xrm.force_spill_var(var) + else: + return self.rm.force_spill_var(var) + def load_xmm_aligned_16_bytes(self, var, forbidden_vars=[]): # Load 'var' in a register; but if it is a constant, we can return # a 16-bytes-aligned ConstFloatLoc. @@ -400,6 +406,8 @@ if self.can_merge_with_next_guard(op, i, operations): oplist_with_guard[op.getopnum()](self, op, operations[i + 1]) i += 1 + elif not we_are_translated() and op.getopnum() == -124: + self._consider_force_spill(op) else: oplist[op.getopnum()](self, op) if op.result is not None: @@ -1228,6 +1236,10 @@ def consider_jit_debug(self, op): pass + def _consider_force_spill(self, op): + # This operation is used only for testing + self.force_spill_var(op.getarg(0)) + def get_mark_gc_roots(self, gcrootmap, use_copy_area=False): shape = gcrootmap.get_basic_shape(IS_X86_64) for v, val in self.fm.frame_bindings.items(): diff --git a/pypy/jit/tool/oparser.py b/pypy/jit/tool/oparser.py --- a/pypy/jit/tool/oparser.py +++ b/pypy/jit/tool/oparser.py @@ -6,7 +6,9 @@ from pypy.jit.metainterp.history import TreeLoop, BoxInt, ConstInt,\ ConstObj, ConstPtr, Box, BasicFailDescr, BoxFloat, ConstFloat,\ LoopToken, get_const_ptr_for_string, get_const_ptr_for_unicode -from pypy.jit.metainterp.resoperation import rop, ResOperation, ResOpWithDescr, N_aryOp +from pypy.jit.metainterp.resoperation import rop, ResOperation, \ + ResOpWithDescr, N_aryOp, \ + UnaryOp, PlainResOp from pypy.jit.metainterp.typesystem import llhelper from pypy.jit.codewriter.heaptracker import adr2int from pypy.jit.codewriter import longlong @@ -35,6 +37,23 @@ def clone(self): return ESCAPE_OP(self.OPNUM, self.getarglist()[:], self.result, self.getdescr()) +class FORCE_SPILL(UnaryOp, PlainResOp): + + OPNUM = -124 + + def __init__(self, opnum, args, result=None, descr=None): + assert result is None + assert descr is None + assert opnum == self.OPNUM + self.result = result + self.initarglist(args) + + def getopnum(self): + return self.OPNUM + + def clone(self): + return FORCE_SPILL(self.OPNUM, self.getarglist()[:]) + class ExtendedTreeLoop(TreeLoop): def getboxes(self): @@ -220,6 +239,8 @@ except AttributeError: if opname == 'escape': opnum = ESCAPE_OP.OPNUM + elif opname == 'force_spill': + opnum = FORCE_SPILL.OPNUM else: raise ParseError("unknown op: %s" % opname) endnum = line.rfind(')') @@ -261,6 +282,8 @@ def create_op(self, opnum, args, result, descr): if opnum == ESCAPE_OP.OPNUM: return ESCAPE_OP(opnum, args, result, descr) + if opnum == FORCE_SPILL.OPNUM: + return FORCE_SPILL(opnum, args, result, descr) else: return ResOperation(opnum, args, result, descr) _______________________________________________ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit