Author: Armin Rigo <ar...@tunes.org> 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 pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit