[pypy-commit] pypy default: Reintroduce some JIT support for int_mod(). Add rarithmetic.int_c_mod().

arigo pypy.commits at gmail.com
Wed Jun 8 13:57:00 EDT 2016


Author: Armin Rigo <arigo at tunes.org>
Branch: 
Changeset: r85037:f0e47a0437e8
Date: 2016-06-08 19:47 +0200
http://bitbucket.org/pypy/pypy/changeset/f0e47a0437e8/

Log:	Reintroduce some JIT support for int_mod(). Add
	rarithmetic.int_c_mod().

diff --git a/rpython/jit/codewriter/jtransform.py b/rpython/jit/codewriter/jtransform.py
--- a/rpython/jit/codewriter/jtransform.py
+++ b/rpython/jit/codewriter/jtransform.py
@@ -522,6 +522,7 @@
     # but be really compiled
     rewrite_op_int_abs                = _do_builtin_call
     rewrite_op_int_floordiv           = _do_builtin_call
+    rewrite_op_int_mod                = _do_builtin_call
     rewrite_op_llong_abs              = _do_builtin_call
     rewrite_op_llong_floordiv         = _do_builtin_call
     rewrite_op_llong_mod              = _do_builtin_call
@@ -531,7 +532,6 @@
     rewrite_op_gc_id                  = _do_builtin_call
     rewrite_op_gc_pin                 = _do_builtin_call
     rewrite_op_gc_unpin               = _do_builtin_call
-    rewrite_op_uint_mod               = _do_builtin_call
     rewrite_op_cast_float_to_uint     = _do_builtin_call
     rewrite_op_cast_uint_to_float     = _do_builtin_call
     rewrite_op_weakref_create         = _do_builtin_call
diff --git a/rpython/jit/codewriter/support.py b/rpython/jit/codewriter/support.py
--- a/rpython/jit/codewriter/support.py
+++ b/rpython/jit/codewriter/support.py
@@ -260,6 +260,13 @@
     # the JIT knows that if x and y are both positive, this is just 'r'
     return r + (((x ^ y) >> (LONG_BIT - 1)) & (p != x))
 
+def _ll_2_int_mod(x, y):
+    # same comments as _ll_2_int_floordiv()
+    r = x % y
+    # the JIT knows that if x and y are both positive, this doesn't change 'r'
+    r -= y & (((x ^ y) & (r | -r)) >> (LONG_BIT - 1))
+    return r
+
 
 def _ll_1_cast_uint_to_float(x):
     # XXX on 32-bit platforms, this should be done using cast_longlong_to_float
@@ -431,6 +438,7 @@
 inline_calls_to = [
     ('int_abs',              [lltype.Signed],                lltype.Signed),
     ('int_floordiv',         [lltype.Signed, lltype.Signed], lltype.Signed),
+    ('int_mod',              [lltype.Signed, lltype.Signed], lltype.Signed),
     ('ll_math.ll_math_sqrt', [lltype.Float],                 lltype.Float),
 ]
 
diff --git a/rpython/jit/codewriter/test/test_support.py b/rpython/jit/codewriter/test/test_support.py
--- a/rpython/jit/codewriter/test/test_support.py
+++ b/rpython/jit/codewriter/test/test_support.py
@@ -144,11 +144,13 @@
     assert _ll_1_int_abs(-10) == 10
     assert _ll_1_int_abs(-sys.maxint) == sys.maxint
 
-def test_int_floordiv():
+def test_int_floordiv_mod():
     from rpython.rtyper.lltypesystem.lloperation import llop
-    from rpython.jit.codewriter.support import _ll_2_int_floordiv
+    from rpython.jit.codewriter.support import _ll_2_int_floordiv, _ll_2_int_mod
     for x in range(-6, 7):
         for y in range(-3, 4):
             if y != 0:
                 assert (_ll_2_int_floordiv(x, y) ==
                         llop.int_floordiv(lltype.Signed, x, y))
+                assert (_ll_2_int_mod(x, y) ==
+                        llop.int_mod(lltype.Signed, x, y))
diff --git a/rpython/jit/metainterp/optimizeopt/intbounds.py b/rpython/jit/metainterp/optimizeopt/intbounds.py
--- a/rpython/jit/metainterp/optimizeopt/intbounds.py
+++ b/rpython/jit/metainterp/optimizeopt/intbounds.py
@@ -97,17 +97,14 @@
         self.emit_operation(op)
 
         r = self.getintbound(op)
-        if b2.is_constant():
-            val = b2.lower
-            if val >= 0:
-                r.intersect(IntBound(0, val))
-        elif b1.is_constant():
-            val = b1.lower
-            if val >= 0:
-                r.intersect(IntBound(0, val))
-        elif b1.known_ge(IntBound(0, 0)) and b2.known_ge(IntBound(0, 0)):
-            lesser = min(b1.upper, b2.upper)
-            r.intersect(IntBound(0, next_pow2_m1(lesser)))
+        pos1 = b1.known_ge(IntBound(0, 0))
+        pos2 = b2.known_ge(IntBound(0, 0))
+        if pos1 or pos2:
+            r.make_ge(IntBound(0, 0))
+        if pos1:
+            r.make_le(b1)
+        if pos2:
+            r.make_le(b2)
 
     def optimize_INT_SUB(self, op):
         self.emit_operation(op)
diff --git a/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py b/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py
--- a/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py
+++ b/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py
@@ -5188,6 +5188,25 @@
         """
         self.optimize_loop(ops, ops)
 
+    def test_int_and_positive(self):
+        ops = """
+        [i0, i1]
+        i2 = int_ge(i1, 0)
+        guard_true(i2) []
+        i3 = int_and(i0, i1)
+        i4 = int_ge(i3, 0)
+        guard_true(i4) []
+        jump(i3)
+        """
+        expected = """
+        [i0, i1]
+        i2 = int_ge(i1, 0)
+        guard_true(i2) []
+        i3 = int_and(i0, i1)
+        jump(i3)
+        """
+        self.optimize_loop(ops, expected)
+
     def test_int_or_cmp_above_bounds(self):
         ops = """
         [p0,p1]
diff --git a/rpython/jit/metainterp/test/test_ajit.py b/rpython/jit/metainterp/test/test_ajit.py
--- a/rpython/jit/metainterp/test/test_ajit.py
+++ b/rpython/jit/metainterp/test/test_ajit.py
@@ -972,6 +972,41 @@
         assert res == expected
         # should contain a call_i(..., OS=OS_INT_PY_DIV)
 
+    def test_int_c_mod(self):
+        from rpython.rlib.rarithmetic import int_c_mod
+        myjitdriver = JitDriver(greens = [], reds = ['i', 't'])
+        def f(i):
+            t = 0
+            while i < 10:
+                myjitdriver.can_enter_jit(i=i, t=t)
+                myjitdriver.jit_merge_point(i=i, t=t)
+                t += int_c_mod(-100, i)
+                i += 1
+            return t
+        expected = -sum([100 % n for n in range(1, 10)])
+        assert f(1) == expected
+        res = self.meta_interp(f, [1])
+        assert res == expected
+        # should contain a call_i(..., OS=OS_INT_PY_MOD)
+
+    def test_positive_c_div_mod(self):
+        from rpython.rlib.rarithmetic import int_c_div, int_c_mod
+        myjitdriver = JitDriver(greens = [], reds = ['i', 't'])
+        def f(i):
+            t = 0
+            while i < 10:
+                myjitdriver.can_enter_jit(i=i, t=t)
+                myjitdriver.jit_merge_point(i=i, t=t)
+                assert i > 0
+                t += int_c_div(100, i) - int_c_mod(100, i)
+                i += 1
+            return t
+        expected = sum([100 // n - 100 % n for n in range(1, 10)])
+        assert f(1) == expected
+        res = self.meta_interp(f, [1])
+        assert res == expected
+        # all the correction code should be dead now, xxx test that
+
     def test_float(self):
         myjitdriver = JitDriver(greens = [], reds = ['x', 'y', 'res'])
         def f(x, y):
diff --git a/rpython/rlib/rarithmetic.py b/rpython/rlib/rarithmetic.py
--- a/rpython/rlib/rarithmetic.py
+++ b/rpython/rlib/rarithmetic.py
@@ -662,6 +662,14 @@
     from rpython.rtyper.lltypesystem.lloperation import llop
     return llop.int_floordiv(lltype.Signed, x, y)
 
+def int_c_mod(x, y):
+    """Return the result of the C-style 'x % y'.  This differs from the
+    Python-style division if (x < 0  xor y < 0).
+    """
+    from rpython.rtyper.lltypesystem import lltype
+    from rpython.rtyper.lltypesystem.lloperation import llop
+    return llop.int_mod(lltype.Signed, x, y)
+
 @objectmodel.specialize.ll()
 def byteswap(arg):
     """ Convert little->big endian and the opposite
diff --git a/rpython/rlib/test/test_rarithmetic.py b/rpython/rlib/test/test_rarithmetic.py
--- a/rpython/rlib/test/test_rarithmetic.py
+++ b/rpython/rlib/test/test_rarithmetic.py
@@ -401,10 +401,13 @@
 
 @given(strategies.integers(min_value=0, max_value=sys.maxint),
        strategies.integers(min_value=1, max_value=sys.maxint))
-def test_int_c_div(x, y):
+def test_int_c_div_mod(x, y):
     assert int_c_div(~x, y) == -(abs(~x) // y)
     assert int_c_div( x,-y) == -(x // y)
     assert int_c_div(~x,-y) == +(abs(~x) // y)
+    for x1 in [x, ~x]:
+        for y1 in [y, -y]:
+            assert int_c_div(x1, y1) * y1 + int_c_mod(x1, y1) == x1
 
 # these can't be prebuilt on 32bit
 U1 = r_ulonglong(0x0102030405060708L)


More information about the pypy-commit mailing list