Author: David Schneider <[email protected]>
Branch: 
Changeset: r44627:a2b1a5150db3
Date: 2011-06-01 17:46 +0200
http://bitbucket.org/pypy/pypy/changeset/a2b1a5150db3/

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
@@ -213,6 +213,18 @@
         self.reg_bindings[v] = loc
         return loc
 
+    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
@@ -23,6 +23,7 @@
 
 def constfloat(x):
     return ConstFloat(longlong.getfloatstorage(x))
+
 class FakeStats(object):
     pass
 class TestCallingConv(Runner):
@@ -34,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
@@ -104,21 +221,6 @@
 
         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]
-        def _prepare_args(args):
-            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)
-                    cpu.set_future_value_float(i, t)
-                else:
-                    x = local_ints.pop()
-                    cpu.set_future_value_int(i, x)
-                expected_result += x
-            return expected_result
 
         for case in range(256):
             float_count = 0
@@ -152,7 +254,7 @@
             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)
 
-            expected_result = _prepare_args(args)
+            expected_result = self._prepare_args(args, floats, ints)
             res = cpu.execute_token(called_looptoken)
             assert res.identifier == 3
             t = longlong.getrealfloat(cpu.get_latest_value_float(0))
@@ -181,7 +283,7 @@
                 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 = longlong.getrealfloat(cpu.get_latest_value_float(0))
                 assert res.identifier == 4
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
@@ -268,6 +268,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.
@@ -418,6 +424,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:
@@ -1293,6 +1301,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
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to