[pypy-svn] r40547 - in pypy/branch/jit-virtual-world/pypy/jit/codegen: i386 llgraph/test test

arigo at codespeak.net arigo at codespeak.net
Thu Mar 15 17:18:02 CET 2007


Author: arigo
Date: Thu Mar 15 17:18:00 2007
New Revision: 40547

Modified:
   pypy/branch/jit-virtual-world/pypy/jit/codegen/i386/operation.py
   pypy/branch/jit-virtual-world/pypy/jit/codegen/i386/regalloc.py
   pypy/branch/jit-virtual-world/pypy/jit/codegen/i386/rgenop.py
   pypy/branch/jit-virtual-world/pypy/jit/codegen/llgraph/test/test_rgenop.py
   pypy/branch/jit-virtual-world/pypy/jit/codegen/test/operation_tests.py
   pypy/branch/jit-virtual-world/pypy/jit/codegen/test/rgenop_tests.py
Log:
(arigo, pedronis, arre) Support for some of the _ovf operations in the 386 backend.


Modified: pypy/branch/jit-virtual-world/pypy/jit/codegen/i386/operation.py
==============================================================================
--- pypy/branch/jit-virtual-world/pypy/jit/codegen/i386/operation.py	(original)
+++ pypy/branch/jit-virtual-world/pypy/jit/codegen/i386/operation.py	Thu Mar 15 17:18:00 2007
@@ -50,8 +50,9 @@
         self.emit(allocator.mc, dstop)
 
 class OpIntNeg(UnaryOp):
-    opname = 'int_neg'
+    opname = 'int_neg', 'int_neg_ovf'
     emit = staticmethod(I386CodeBuilder.NEG)
+    ccexcflag = Conditions['O']
 
 class OpIntInvert(UnaryOp):
     opname = 'int_invert', 'uint_invert'
@@ -76,6 +77,14 @@
         mc.XOR(dstop, tmpop)
         allocator.end_clobber(tmpop)
 
+class OpIntAbsOvf(OpIntAbs):
+    opname = 'int_abs_ovf'
+    ccexcflag = Conditions['E']
+    def generate(self, allocator):
+        OpIntAbs.generate(self, allocator)
+        mc = allocator.mc
+        mc.CMP(allocator.var2loc[self], imm(-sys.maxint-1))
+
 class OpSameAs(Op1):
     clobbers_cc = False    # special handling of the cc
     side_effects = False
@@ -134,6 +143,17 @@
     suggested_cc = Conditions['E']
     inverted = True
 
+class OpFetchCC(Operation):
+    clobbers_cc = False
+    side_effects = False
+    def __init__(self, cc):
+        self.cc = cc
+    def mark_used_vars(self, allocator):
+        pass
+    def generate(self, allocator):
+        ccop = ccflags[self.cc]
+        allocator.create_in_cc(self, ccop)
+
 class Op2(Operation):
     def __init__(self, x, y):
         self.x = x
@@ -185,13 +205,15 @@
         self.emit(allocator.mc, dstop, op2)
 
 class OpIntAdd(BinaryOp):
-    opname = 'int_add', 'uint_add'
+    opname = 'int_add', 'uint_add', 'int_add_ovf'
     emit = staticmethod(I386CodeBuilder.ADD)
     commutative = True
+    ccexcflag = Conditions['O']
 
 class OpIntSub(BinaryOp):
-    opname = 'int_sub', 'uint_sub'
+    opname = 'int_sub', 'uint_sub', 'int_sub_ovf'
     emit = staticmethod(I386CodeBuilder.SUB)
+    ccexcflag = Conditions['O']
 
 class OpIntAnd(BinaryOp):
     opname = 'int_and', 'uint_and'
@@ -206,8 +228,9 @@
     emit = staticmethod(I386CodeBuilder.XOR)
 
 class OpIntMul(Op2):
-    opname = 'int_mul'
+    opname = 'int_mul', 'int_mul_ovf'
     side_effects = False
+    ccexcflag = Conditions['O']
 
     def generate(self, allocator):
         op1 = allocator.get_operand(self.x)
@@ -939,6 +962,15 @@
         return self.cond
 
 
+def load_into_cc_o(mc, srcop):
+    mc.MOV(ecx, srcop)
+    mc.ADD(ecx, imm(sys.maxint))
+
+def load_into_cc_no(self, srcop):
+    mc.MOV(ecx, imm(-sys.maxint-1))
+    mc.ADD(ecx, srcop)
+    mc.DEC(ecx)
+
 def load_into_cc_lt(mc, srcop):
     mc.XOR(ecx, ecx)
     mc.CMP(ecx, srcop)
@@ -956,6 +988,9 @@
 load_into_cc_gt = load_into_cc_ne
 load_into_cc_ge = load_into_cc_eq
 
+ccflag_o  = CCFLAG('O',  load_into_cc_o)
+ccflag_no = CCFLAG('O',  load_into_cc_no)
+
 ccflag_lt = CCFLAG('L',  load_into_cc_lt)
 ccflag_le = CCFLAG('LE', load_into_cc_le)
 ccflag_eq = CCFLAG('E',  load_into_cc_eq)
@@ -969,6 +1004,8 @@
 ccflag_uge = CCFLAG('AE', load_into_cc_ge)
 
 ccflags = [None] * 16
+ccflags[Conditions['O']]  = ccflag_o
+ccflags[Conditions['NO']] = ccflag_no
 ccflags[Conditions['L']]  = ccflag_lt
 ccflags[Conditions['LE']] = ccflag_le
 ccflags[Conditions['E']]  = ccflag_eq

Modified: pypy/branch/jit-virtual-world/pypy/jit/codegen/i386/regalloc.py
==============================================================================
--- pypy/branch/jit-virtual-world/pypy/jit/codegen/i386/regalloc.py	(original)
+++ pypy/branch/jit-virtual-world/pypy/jit/codegen/i386/regalloc.py	Thu Mar 15 17:18:00 2007
@@ -302,6 +302,7 @@
 
     def _created(self, v, loc):
         assert v not in self.var2loc
+        assert loc is not None
         self.vars_in_use[v] = ltime = self.lifetime[v]
         assert ltime > self.operationindex
         self.var2loc[v] = loc

Modified: pypy/branch/jit-virtual-world/pypy/jit/codegen/i386/rgenop.py
==============================================================================
--- pypy/branch/jit-virtual-world/pypy/jit/codegen/i386/rgenop.py	(original)
+++ pypy/branch/jit-virtual-world/pypy/jit/codegen/i386/rgenop.py	Thu Mar 15 17:18:00 2007
@@ -371,12 +371,30 @@
         return op
 
     @specialize.arg(1)
+    def genraisingop1(self, opname, gv_arg):
+        cls = getopclass1(opname)
+        op = cls(gv_arg)
+        self.operations.append(op)
+        op_excflag = OpFetchCC(op.ccexcflag)
+        self.operations.append(op_excflag)
+        return op, op_excflag
+
+    @specialize.arg(1)
     def genop2(self, opname, gv_arg1, gv_arg2):
         cls = getopclass2(opname)
         op = cls(gv_arg1, gv_arg2)
         self.operations.append(op)
         return op
 
+    @specialize.arg(1)
+    def genraisingop2(self, opname, gv_arg1, gv_arg2):
+        cls = getopclass2(opname)
+        op = cls(gv_arg1, gv_arg2)
+        self.operations.append(op)
+        op_excflag = OpFetchCC(op.ccexcflag)
+        self.operations.append(op_excflag)
+        return op, op_excflag
+
     def genop_ptr_iszero(self, kind, gv_ptr):
         cls = getopclass1('ptr_iszero')
         op = cls(gv_ptr)

Modified: pypy/branch/jit-virtual-world/pypy/jit/codegen/llgraph/test/test_rgenop.py
==============================================================================
--- pypy/branch/jit-virtual-world/pypy/jit/codegen/llgraph/test/test_rgenop.py	(original)
+++ pypy/branch/jit-virtual-world/pypy/jit/codegen/llgraph/test/test_rgenop.py	Thu Mar 15 17:18:00 2007
@@ -9,6 +9,10 @@
 class TestLLGraphRGenop(AbstractRGenOpTests):
     RGenOp = RGenOp
 
+    def setup_method(self, meth):
+        if 'ovfcheck' in meth.__name__:
+            py.test.skip("no chance (the llinterpreter has no rtyper)")
+
     def getcompiled(self, runner, argtypes, annotatorpolicy):
         def quasi_compiled_runner(*args):
             return interpret(runner, args, policy=annotatorpolicy)

Modified: pypy/branch/jit-virtual-world/pypy/jit/codegen/test/operation_tests.py
==============================================================================
--- pypy/branch/jit-virtual-world/pypy/jit/codegen/test/operation_tests.py	(original)
+++ pypy/branch/jit-virtual-world/pypy/jit/codegen/test/operation_tests.py	Thu Mar 15 17:18:00 2007
@@ -3,7 +3,7 @@
 from pypy.jit.codegen import graph2rgenop
 from pypy.rpython.lltypesystem import lltype
 from pypy.rpython.lltypesystem.lloperation import llop
-from pypy.rlib.rarithmetic import r_uint, intmask
+from pypy.rlib.rarithmetic import r_uint, intmask, ovfcheck
 from ctypes import cast, c_void_p, CFUNCTYPE, c_int, c_float
 from pypy import conftest
 

Modified: pypy/branch/jit-virtual-world/pypy/jit/codegen/test/rgenop_tests.py
==============================================================================
--- pypy/branch/jit-virtual-world/pypy/jit/codegen/test/rgenop_tests.py	(original)
+++ pypy/branch/jit-virtual-world/pypy/jit/codegen/test/rgenop_tests.py	Thu Mar 15 17:18:00 2007
@@ -1,5 +1,6 @@
-import random
+import random, sys
 from pypy.rpython.annlowlevel import MixLevelAnnotatorPolicy, llhelper
+from pypy.rlib.rarithmetic import intmask
 from pypy.rlib.objectmodel import keepalive_until_here
 from pypy.rpython.lltypesystem import lltype, llmemory
 from pypy.translator.c.test import test_boehm
@@ -757,6 +758,29 @@
         return res
     return read_frame_place_runner
 
+def make_ovfcheck_adder(rgenop, n):
+    sigtoken = rgenop.sigToken(FUNC)
+    builder, gv_fn, [gv_x] = rgenop.newgraph(sigtoken, "ovfcheck_adder")
+    builder.start_writing()
+    gv_result, gv_flag = builder.genraisingop2("int_add_ovf", gv_x,
+                                               rgenop.genconst(n))
+    gv_flag = builder.genop1("cast_bool_to_int", gv_flag)
+    gv_result = builder.genop2("int_lshift", gv_result, rgenop.genconst(1))
+    gv_result = builder.genop2("int_or", gv_result, gv_flag)
+    builder.finish_and_return(sigtoken, gv_result)
+    builder.end()
+    return gv_fn
+
+def get_ovfcheck_adder_runner(RGenOp):
+    def runner(x, y):
+        rgenop = RGenOp()
+        gv_add_x = make_ovfcheck_adder(rgenop, x)
+        add_x = gv_add_x.revealconst(lltype.Ptr(FUNC))
+        res = add_x(y)
+        keepalive_until_here(rgenop)    # to keep the code blocks alive
+        return res
+    return runner
+
 
 class AbstractRGenOpTests(test_boehm.AbstractGCTestClass):
     RGenOp = None
@@ -1765,3 +1789,98 @@
         P = lltype.Ptr(lltype.Struct('S'))
         gv = RGenOp.genzeroconst(RGenOp.kindToken(P))
         assert gv.revealconst(llmemory.Address) == llmemory.NULL
+
+    def test_ovfcheck_adder_direct(self):
+        rgenop = self.RGenOp()
+        gv_add_5 = make_ovfcheck_adder(rgenop, 5)
+        fnptr = self.cast(gv_add_5, 1)
+        res = fnptr(37)
+        assert res == (42 << 1) | 0
+        res = fnptr(sys.maxint-2)
+        assert (res & 1) == 1
+
+    def test_ovfcheck_adder_compile(self):
+        fn = self.compile(get_ovfcheck_adder_runner(self.RGenOp), [int, int])
+        res = fn(9080983, -9080941)
+        assert res == (42 << 1) | 0
+        res = fn(-sys.maxint, -10)
+        assert (res & 1) == 1
+
+    def test_ovfcheck1_direct(self):
+        yield self.ovfcheck1_direct, "int_neg_ovf", [(18, -18),
+                                                     (-18, 18),
+                                                     (sys.maxint, -sys.maxint),
+                                                     (-sys.maxint, sys.maxint),
+                                                     (-sys.maxint-1, None)]
+        yield self.ovfcheck1_direct, "int_abs_ovf", [(18, 18),
+                                                     (-18, 18),
+                                                     (sys.maxint, sys.maxint),
+                                                     (-sys.maxint, sys.maxint),
+                                                     (-sys.maxint-1, None)]
+
+    def ovfcheck1_direct(self, opname, testcases):
+        rgenop = self.RGenOp()
+        sigtoken = rgenop.sigToken(FUNC)
+        builder, gv_fn, [gv_x] = rgenop.newgraph(sigtoken, "ovfcheck1")
+        builder.start_writing()
+        gv_result, gv_flag = builder.genraisingop1(opname, gv_x)
+        gv_flag = builder.genop1("cast_bool_to_int", gv_flag)
+        gv_result = builder.genop2("int_lshift", gv_result, rgenop.genconst(1))
+        gv_result = builder.genop2("int_or", gv_result, gv_flag)
+        builder.finish_and_return(sigtoken, gv_result)
+        builder.end()
+
+        fnptr = self.cast(gv_fn, 1)
+        for x, expected in testcases:
+            res = fnptr(x)
+            if expected is None:
+                assert (res & 1) == 1
+            else:
+                assert res == intmask(expected << 1) | 0
+
+    def test_ovfcheck2_direct(self):
+        yield self.ovfcheck2_direct, "int_sub_ovf", [(18, 25, -7),
+                                                     (sys.maxint, -1, None),
+                                                     (-2, sys.maxint, None)]
+        yield self.ovfcheck2_direct, "int_mul_ovf", [(6, 7, 42),
+                                                     (sys.maxint-100, 2, None),
+                                                    (-2, sys.maxint-100, None)]
+        # XXX the rest in-progress
+        # XXX also missing the _zer versions
+##        yield self.ovfcheck2_direct, "int_mod_ovf", [
+##            (100, 8, 4),
+##            (-sys.maxint-1, 1, 0),
+##            (-sys.maxint-1, -1, None)]
+##        yield self.ovfcheck2_direct, "int_floordiv_ovf", [
+##            (100, 2, 50),
+##            (-sys.maxint-1, 1, -sys.maxint-1),
+##            (-sys.maxint-1, -1, None)]
+##        yield self.ovfcheck2_direct, "int_lshift_ovf", [
+##            (1, 30, 1<<30),
+##            (1, 31, None),
+##            (0xf23c, 14, 0xf23c << 14),
+##            (0xf23c, 15, None),
+##            (-1, 31, (-1) << 31),
+##            (-2, 31, None),
+##            (-3, 31, None),
+##            (-sys.maxint-1, 0, -sys.maxint-1)]
+
+    def ovfcheck2_direct(self, opname, testcases):
+        rgenop = self.RGenOp()
+        sigtoken = rgenop.sigToken(FUNC2)
+        builder, gv_fn, [gv_x, gv_y] = rgenop.newgraph(sigtoken, "ovfcheck2")
+        builder.start_writing()
+        gv_result, gv_flag = builder.genraisingop2(opname, gv_x, gv_y)
+        gv_flag = builder.genop1("cast_bool_to_int", gv_flag)
+        gv_result = builder.genop2("int_lshift", gv_result, rgenop.genconst(1))
+        gv_result = builder.genop2("int_or", gv_result, gv_flag)
+        builder.finish_and_return(sigtoken, gv_result)
+        builder.end()
+
+        fnptr = self.cast(gv_fn, 1)
+        for x, y, expected in testcases:
+            res = fnptr(x, y)
+            if expected is None:
+                assert (res & 1) == 1
+            else:
+                assert res == intmask(expected << 1) | 0



More information about the Pypy-commit mailing list