Author: Armin Rigo <[email protected]>
Branch:
Changeset: r85035:f91ba52ae29e
Date: 2016-06-08 19:02 +0200
http://bitbucket.org/pypy/pypy/changeset/f91ba52ae29e/
Log: Reintroduce some JIT support for int_floordiv() in a way that makes
it at least half efficient. Add rarithmetic.int_c_div() as an
explicit interface.
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
@@ -521,6 +521,7 @@
# XXX some of the following functions should not become residual calls
# but be really compiled
rewrite_op_int_abs = _do_builtin_call
+ rewrite_op_int_floordiv = _do_builtin_call
rewrite_op_llong_abs = _do_builtin_call
rewrite_op_llong_floordiv = _do_builtin_call
rewrite_op_llong_mod = _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
@@ -248,6 +248,19 @@
mask = x >> (LONG_BIT - 1)
return (x ^ mask) - mask
+
+def _ll_2_int_floordiv(x, y):
+ # this is used only if the RPython program uses llop.int_floordiv()
+ # explicitly. For 'a // b', see _handle_int_special() in jtransform.py.
+ # This is the reverse of rpython.rtyper.rint.ll_int_floordiv(), i.e.
+ # the same logic as rpython.rtyper.lltypesystem.opimpl.op_int_floordiv
+ # but written in a no-branch style.
+ r = x // y
+ p = r * y
+ # 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_1_cast_uint_to_float(x):
# XXX on 32-bit platforms, this should be done using cast_longlong_to_float
# (which is a residual call right now in the x86 backend)
@@ -417,6 +430,7 @@
# in the following calls to builtins, the JIT is allowed to look inside:
inline_calls_to = [
('int_abs', [lltype.Signed], lltype.Signed),
+ ('int_floordiv', [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
@@ -3,7 +3,6 @@
from rpython.rtyper.annlowlevel import llstr
from rpython.flowspace.model import Variable, Constant, SpaceOperation
from rpython.jit.codewriter.support import decode_builtin_call, LLtypeHelpers
-from rpython.jit.codewriter.support import _ll_1_int_abs
def newconst(x):
return Constant(x, lltype.typeOf(x))
@@ -136,6 +135,7 @@
py.test.raises(AttributeError, func, llstr(None), p2)
def test_int_abs():
+ from rpython.jit.codewriter.support import _ll_1_int_abs
assert _ll_1_int_abs(0) == 0
assert _ll_1_int_abs(1) == 1
assert _ll_1_int_abs(10) == 10
@@ -143,3 +143,12 @@
assert _ll_1_int_abs(-1) == 1
assert _ll_1_int_abs(-10) == 10
assert _ll_1_int_abs(-sys.maxint) == sys.maxint
+
+def test_int_floordiv():
+ from rpython.rtyper.lltypesystem.lloperation import llop
+ from rpython.jit.codewriter.support import _ll_2_int_floordiv
+ 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))
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
@@ -5252,6 +5252,47 @@
"""
self.optimize_loop(ops, ops)
+ def test_int_xor_positive_is_positive(self):
+ ops = """
+ [i0, i1]
+ i2 = int_lt(i0, 0)
+ guard_false(i2) []
+ i3 = int_lt(i1, 0)
+ guard_false(i3) []
+ i4 = int_xor(i0, i1)
+ i5 = int_lt(i4, 0)
+ guard_false(i5) []
+ jump(i4, i0)
+ """
+ expected = """
+ [i0, i1]
+ i2 = int_lt(i0, 0)
+ guard_false(i2) []
+ i3 = int_lt(i1, 0)
+ guard_false(i3) []
+ i4 = int_xor(i0, i1)
+ jump(i4, i0)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_positive_rshift_bits_minus_1(self):
+ ops = """
+ [i0]
+ i2 = int_lt(i0, 0)
+ guard_false(i2) []
+ i3 = int_rshift(i2, %d)
+ escape_n(i3)
+ jump(i0)
+ """ % (LONG_BIT - 1,)
+ expected = """
+ [i0]
+ i2 = int_lt(i0, 0)
+ guard_false(i2) []
+ escape_n(0)
+ jump(i0)
+ """
+ self.optimize_loop(ops, expected)
+
def test_int_or_same_arg(self):
ops = """
[i0]
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
@@ -955,6 +955,23 @@
res = self.meta_interp(f, [-5])
assert res == 5+4+3+2+1+0+1+2+3+4+5+6+7+8+9
+ def test_int_c_div(self):
+ from rpython.rlib.rarithmetic import int_c_div
+ 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_div(-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_DIV)
+
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
@@ -650,6 +650,18 @@
from rpython.rtyper.lltypesystem.lloperation import llop
return llop.int_force_ge_zero(lltype.Signed, n)
+def int_c_div(x, y):
+ """Return the result of the C-style 'x / y'. This differs from the
+ Python-style division if (x < 0 xor y < 0). The JIT implements it
+ with a Python-style division followed by correction code. This
+ is not that bad, because the JIT removes the correction code if
+ x and y are both nonnegative, and if y is any nonnegative constant
+ then the division turns into a rshift or a mul.
+ """
+ from rpython.rtyper.lltypesystem import lltype
+ from rpython.rtyper.lltypesystem.lloperation import llop
+ return llop.int_floordiv(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
@@ -2,6 +2,7 @@
from rpython.rtyper.test.test_llinterp import interpret
from rpython.rlib.rarithmetic import *
from rpython.rlib.rstring import ParseStringError, ParseStringOverflowError
+from hypothesis import given, strategies
import sys
import py
@@ -393,6 +394,18 @@
assert not int_between(1, 2, 2)
assert not int_between(1, 1, 1)
+def test_int_force_ge_zero():
+ assert int_force_ge_zero(42) == 42
+ assert int_force_ge_zero(0) == 0
+ assert int_force_ge_zero(-42) == 0
+
+@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):
+ 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)
+
# these can't be prebuilt on 32bit
U1 = r_ulonglong(0x0102030405060708L)
U2 = r_ulonglong(0x0807060504030201L)
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit