[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