Author: Armin Rigo <[email protected]>
Branch:
Changeset: r84727:a4bb2ae13c0a
Date: 2016-05-27 14:53 +0200
http://bitbucket.org/pypy/pypy/changeset/a4bb2ae13c0a/
Log: hg merge remove-raisingops
Kill many lines of code. This is done by removing most of the _ovf,
_zer and _val operations from RPython. Left: only int_add_ovf,
int_sub_ovf and int_mul_ovf. Handling of all the other cases is done
in rint.py.
This gives more flexibility, which we use in the JIT for '/' and
'%'. Now the JIT sees the Python-style behavior wrt negative
arguments to '/' and '%', instead of the C-style one.
This in turn allows the JIT to do better optimizations: for example,
app-level code like 'x % 2' can now be turned into 'int_and 1' even
if x is possibly negative.
The JIT backends no longer directly support div and mod, which
removes quite a lot of mess in the ARM case. In fact, even where the
CPU supports division, it's a very slow operation (particularly on
64-bit), so the overhead of calling a helper is small (and anyway it
is usually needed now, to do the C-to-Python-style corrections).
diff too long, truncating to 2000 out of 3566 lines
diff --git a/pypy/module/__pypy__/interp_intop.py
b/pypy/module/__pypy__/interp_intop.py
--- a/pypy/module/__pypy__/interp_intop.py
+++ b/pypy/module/__pypy__/interp_intop.py
@@ -2,6 +2,19 @@
from rpython.rtyper.lltypesystem import lltype
from rpython.rtyper.lltypesystem.lloperation import llop
from rpython.rlib.rarithmetic import r_uint, intmask
+from rpython.rlib import jit
+
+
+# XXX maybe temporary: hide llop.int_{floordiv,mod} from the JIT,
+# because now it expects only Python-style divisions, not the
+# C-style divisions of these two ll operations
[email protected]_look_inside
+def _int_floordiv(n, m):
+ return llop.int_floordiv(lltype.Signed, n, m)
+
[email protected]_look_inside
+def _int_mod(n, m):
+ return llop.int_mod(lltype.Signed, n, m)
@unwrap_spec(n=int, m=int)
@@ -18,11 +31,11 @@
@unwrap_spec(n=int, m=int)
def int_floordiv(space, n, m):
- return space.wrap(llop.int_floordiv(lltype.Signed, n, m))
+ return space.wrap(_int_floordiv(n, m))
@unwrap_spec(n=int, m=int)
def int_mod(space, n, m):
- return space.wrap(llop.int_mod(lltype.Signed, n, m))
+ return space.wrap(_int_mod(n, m))
@unwrap_spec(n=int, m=int)
def int_lshift(space, n, m):
diff --git a/pypy/module/pypyjit/test_pypy_c/test_00_model.py
b/pypy/module/pypyjit/test_pypy_c/test_00_model.py
--- a/pypy/module/pypyjit/test_pypy_c/test_00_model.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_00_model.py
@@ -262,7 +262,7 @@
[i0]
i1 = int_add(i0, 1)
i2 = int_sub(i1, 10)
- i3 = int_floordiv(i2, 100)
+ i3 = int_xor(i2, 100)
i4 = int_mul(i1, 1000)
jump(i4)
"""
@@ -298,7 +298,7 @@
[i0]
i1 = int_add(i0, 1)
i2 = int_sub(i1, 10)
- i3 = int_floordiv(i2, 100)
+ i3 = int_xor(i2, 100)
i4 = int_mul(i1, 1000)
jump(i4)
"""
diff --git a/pypy/module/pypyjit/test_pypy_c/test_shift.py
b/pypy/module/pypyjit/test_pypy_c/test_shift.py
--- a/pypy/module/pypyjit/test_pypy_c/test_shift.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_shift.py
@@ -47,26 +47,24 @@
res = 0
a = 0
while a < 300:
- assert a >= 0
- assert 0 <= b <= 10
- res = a/b # ID: div
+ res1 = a/b # ID: div
+ res2 = a/2 # ID: shift
+ res += res1 + res2
a += 1
return res
#
log = self.run(main, [3])
- assert log.result == 99
+ assert log.result == main(3)
loop, = log.loops_by_filename(self.filepath)
- if sys.maxint == 2147483647:
- SHIFT = 31
- else:
- SHIFT = 63
assert loop.match_by_id('div', """
- i10 = int_floordiv(i6, i7)
- i11 = int_mul(i10, i7)
- i12 = int_sub(i6, i11)
- i14 = int_rshift(i12, %d)
- i15 = int_add(i10, i14)
- """ % SHIFT)
+ i56 = int_eq(i48, %d)
+ i57 = int_and(i56, i37)
+ guard_false(i57, descr=...)
+ i1 = call_i(_, i48, i3, descr=...)
+ """ % (-sys.maxint-1,))
+ assert loop.match_by_id('shift', """
+ i1 = int_rshift(i2, 1)
+ """)
def test_division_to_rshift_allcases(self):
"""
diff --git a/pypy/module/pypyjit/test_pypy_c/test_string.py
b/pypy/module/pypyjit/test_pypy_c/test_string.py
--- a/pypy/module/pypyjit/test_pypy_c/test_string.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_string.py
@@ -1,11 +1,6 @@
import sys
from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC
-if sys.maxint == 2147483647:
- SHIFT = 31
-else:
- SHIFT = 63
-
# XXX review the <Call> descrs to replace some EF=5 with EF=4 (elidable)
@@ -28,10 +23,7 @@
guard_true(i14, descr=...)
guard_not_invalidated(descr=...)
i16 = int_eq(i6, %d)
- i15 = int_mod(i6, i10)
- i17 = int_rshift(i15, %d)
- i18 = int_and(i10, i17)
- i19 = int_add(i15, i18)
+ i19 = call_i(ConstClass(ll_int_mod__Signed_Signed), i6, i10,
descr=<Calli . ii EF=0 OS=14>)
i21 = int_lt(i19, 0)
guard_false(i21, descr=...)
i22 = int_ge(i19, i10)
@@ -49,7 +41,7 @@
i34 = int_add(i6, 1)
--TICK--
jump(..., descr=...)
- """ % (-sys.maxint-1, SHIFT))
+ """ % (-sys.maxint-1,))
def test_long(self):
def main(n):
@@ -67,14 +59,7 @@
guard_true(i11, descr=...)
guard_not_invalidated(descr=...)
i13 = int_eq(i6, %d) # value provided below
- i15 = int_mod(i6, 10)
- i17 = int_rshift(i15, %d) # value provided below
- i18 = int_and(10, i17)
- i19 = int_add(i15, i18)
- i21 = int_lt(i19, 0)
- guard_false(i21, descr=...)
- i22 = int_ge(i19, 10)
- guard_false(i22, descr=...)
+ i19 = call_i(ConstClass(ll_int_mod__Signed_Signed), i6, 10,
descr=<Calli . ii EF=0 OS=14>)
i23 = strgetitem(p10, i19)
p25 = newstr(1)
strsetitem(p25, 0, i23)
@@ -89,7 +74,7 @@
guard_no_overflow(descr=...)
--TICK--
jump(..., descr=...)
- """ % (-sys.maxint-1, SHIFT))
+ """ % (-sys.maxint-1,))
def test_str_mod(self):
def main(n):
diff --git a/pypy/objspace/std/newformat.py b/pypy/objspace/std/newformat.py
--- a/pypy/objspace/std/newformat.py
+++ b/pypy/objspace/std/newformat.py
@@ -7,6 +7,7 @@
from rpython.rlib import rstring, runicode, rlocale, rfloat, jit
from rpython.rlib.objectmodel import specialize
from rpython.rlib.rfloat import copysign, formatd
+from rpython.rlib.rarithmetic import r_uint, intmask
@specialize.argtype(1)
@@ -828,33 +829,37 @@
return s
# This part is slow.
negative = value < 0
- value = abs(value)
+ base = r_uint(base)
+ value = r_uint(value)
+ if negative: # change the sign on the unsigned number: otherwise,
+ value = -value # we'd risk overflow if value==-sys.maxint-1
+ #
buf = ["\0"] * (8 * 8 + 6) # Too much on 32 bit, but who cares?
i = len(buf) - 1
while True:
- div = value // base
- mod = value - div * base
- digit = abs(mod)
+ div = value // base # unsigned
+ mod = value - div * base # unsigned, always in range(0,base)
+ digit = intmask(mod)
digit += ord("0") if digit < 10 else ord("a") - 10
buf[i] = chr(digit)
- value = div
+ value = div # unsigned
i -= 1
if not value:
break
- if base == 2:
+ if base == r_uint(2):
buf[i] = "b"
buf[i - 1] = "0"
- elif base == 8:
+ elif base == r_uint(8):
buf[i] = "o"
buf[i - 1] = "0"
- elif base == 16:
+ elif base == r_uint(16):
buf[i] = "x"
buf[i - 1] = "0"
else:
buf[i] = "#"
- buf[i - 1] = chr(ord("0") + base % 10)
- if base > 10:
- buf[i - 2] = chr(ord("0") + base // 10)
+ buf[i - 1] = chr(ord("0") + intmask(base % r_uint(10)))
+ if base > r_uint(10):
+ buf[i - 2] = chr(ord("0") + intmask(base // r_uint(10)))
i -= 1
i -= 1
if negative:
diff --git a/rpython/config/translationoption.py
b/rpython/config/translationoption.py
--- a/rpython/config/translationoption.py
+++ b/rpython/config/translationoption.py
@@ -213,11 +213,6 @@
default=False),
BoolOption("merge_if_blocks", "Merge if ... elif chains",
cmdline="--if-block-merge", default=True),
- BoolOption("raisingop2direct_call",
- "Transform operations that can implicitly raise an "
- "exception into calls to functions that explicitly "
- "raise exceptions",
- default=False, cmdline="--raisingop2direct_call"),
BoolOption("mallocs", "Remove mallocs", default=True),
BoolOption("constfold", "Constant propagation",
default=True),
diff --git a/rpython/jit/backend/arm/codebuilder.py
b/rpython/jit/backend/arm/codebuilder.py
--- a/rpython/jit/backend/arm/codebuilder.py
+++ b/rpython/jit/backend/arm/codebuilder.py
@@ -1,6 +1,5 @@
from rpython.jit.backend.arm import conditions as cond
from rpython.jit.backend.arm import registers as reg
-from rpython.jit.backend.arm import support
from rpython.jit.backend.arm.arch import WORD, PC_OFFSET
from rpython.jit.backend.arm.instruction_builder import define_instructions
from rpython.jit.backend.llsupport.asmmemmgr import BlockBuilderMixin
@@ -17,17 +16,6 @@
sandboxsafe=True)
-def binary_helper_call(name):
- function = getattr(support, 'arm_%s' % name)
-
- def f(self, c=cond.AL):
- """Generates a call to a helper function, takes its
- arguments in r0 and r1, result is placed in r0"""
- addr = rffi.cast(lltype.Signed, function)
- self.BL(addr, c)
- return f
-
-
class AbstractARMBuilder(object):
def __init__(self, arch_version=7):
self.arch_version = arch_version
@@ -348,10 +336,6 @@
self.write32(c << 28
| 0x157ff05f)
- DIV = binary_helper_call('int_div')
- MOD = binary_helper_call('int_mod')
- UDIV = binary_helper_call('uint_div')
-
FMDRR = VMOV_cr # uh, there are synonyms?
FMRRD = VMOV_rc
diff --git a/rpython/jit/backend/arm/helper/assembler.py
b/rpython/jit/backend/arm/helper/assembler.py
--- a/rpython/jit/backend/arm/helper/assembler.py
+++ b/rpython/jit/backend/arm/helper/assembler.py
@@ -46,20 +46,6 @@
f.__name__ = 'emit_op_%s' % name
return f
-def gen_emit_op_by_helper_call(name, opname):
- helper = getattr(InstrBuilder, opname)
- def f(self, op, arglocs, regalloc, fcond):
- assert fcond is not None
- if op.type != 'v':
- regs = r.caller_resp[1:] + [r.ip]
- else:
- regs = r.caller_resp
- with saved_registers(self.mc, regs, r.caller_vfp_resp):
- helper(self.mc, fcond)
- return fcond
- f.__name__ = 'emit_op_%s' % name
- return f
-
def gen_emit_cmp_op(name, true_cond):
def f(self, op, arglocs, regalloc, fcond):
l0, l1, res = arglocs
diff --git a/rpython/jit/backend/arm/helper/regalloc.py
b/rpython/jit/backend/arm/helper/regalloc.py
--- a/rpython/jit/backend/arm/helper/regalloc.py
+++ b/rpython/jit/backend/arm/helper/regalloc.py
@@ -72,25 +72,6 @@
res = self.force_allocate_reg_or_cc(op)
return [loc1, loc2, res]
-def prepare_op_by_helper_call(name):
- def f(self, op, fcond):
- assert fcond is not None
- a0 = op.getarg(0)
- a1 = op.getarg(1)
- arg1 = self.rm.make_sure_var_in_reg(a0, selected_reg=r.r0)
- arg2 = self.rm.make_sure_var_in_reg(a1, selected_reg=r.r1)
- assert arg1 == r.r0
- assert arg2 == r.r1
- if not isinstance(a0, Const) and self.stays_alive(a0):
- self.force_spill_var(a0)
- self.possibly_free_vars_for_op(op)
- self.free_temp_vars()
- self.after_call(op)
- self.possibly_free_var(op)
- return []
- f.__name__ = name
- return f
-
def prepare_int_cmp(self, op, fcond):
assert fcond is not None
boxes = list(op.getarglist())
diff --git a/rpython/jit/backend/arm/opassembler.py
b/rpython/jit/backend/arm/opassembler.py
--- a/rpython/jit/backend/arm/opassembler.py
+++ b/rpython/jit/backend/arm/opassembler.py
@@ -3,7 +3,7 @@
from rpython.jit.backend.arm import registers as r
from rpython.jit.backend.arm import shift
from rpython.jit.backend.arm.arch import WORD, DOUBLE_WORD, JITFRAME_FIXED_SIZE
-from rpython.jit.backend.arm.helper.assembler import
(gen_emit_op_by_helper_call,
+from rpython.jit.backend.arm.helper.assembler import (
gen_emit_op_unary_cmp,
gen_emit_op_ri,
gen_emit_cmp_op,
@@ -132,10 +132,6 @@
self.guard_success_cc = c.VC
return fcond
- emit_op_int_floordiv = gen_emit_op_by_helper_call('int_floordiv', 'DIV')
- emit_op_int_mod = gen_emit_op_by_helper_call('int_mod', 'MOD')
- emit_op_uint_floordiv = gen_emit_op_by_helper_call('uint_floordiv', 'UDIV')
-
emit_op_int_and = gen_emit_op_ri('int_and', 'AND')
emit_op_int_or = gen_emit_op_ri('int_or', 'ORR')
emit_op_int_xor = gen_emit_op_ri('int_xor', 'EOR')
diff --git a/rpython/jit/backend/arm/regalloc.py
b/rpython/jit/backend/arm/regalloc.py
--- a/rpython/jit/backend/arm/regalloc.py
+++ b/rpython/jit/backend/arm/regalloc.py
@@ -7,7 +7,7 @@
from rpython.jit.backend.arm import conditions as c
from rpython.jit.backend.arm import locations
from rpython.jit.backend.arm.locations import imm, get_fp_offset
-from rpython.jit.backend.arm.helper.regalloc import (prepare_op_by_helper_call,
+from rpython.jit.backend.arm.helper.regalloc import (
prepare_unary_cmp,
prepare_op_ri,
prepare_int_cmp,
@@ -478,10 +478,6 @@
resloc = self.force_allocate_reg(op)
return [argloc, imm(numbytes), resloc]
- prepare_op_int_floordiv = prepare_op_by_helper_call('int_floordiv')
- prepare_op_int_mod = prepare_op_by_helper_call('int_mod')
- prepare_op_uint_floordiv = prepare_op_by_helper_call('unit_floordiv')
-
prepare_op_int_and = prepare_op_ri('int_and')
prepare_op_int_or = prepare_op_ri('int_or')
prepare_op_int_xor = prepare_op_ri('int_xor')
diff --git a/rpython/jit/backend/arm/support.py
b/rpython/jit/backend/arm/support.py
deleted file mode 100644
--- a/rpython/jit/backend/arm/support.py
+++ /dev/null
@@ -1,54 +0,0 @@
-from rpython.rtyper.lltypesystem import lltype, rffi, llmemory
-from rpython.rlib.rarithmetic import r_uint
-from rpython.translator.tool.cbuild import ExternalCompilationInfo
-
-eci = ExternalCompilationInfo(post_include_bits=["""
-static int pypy__arm_int_div(int a, int b) {
- return a/b;
-}
-static unsigned int pypy__arm_uint_div(unsigned int a, unsigned int b) {
- return a/b;
-}
-static int pypy__arm_int_mod(int a, int b) {
- return a % b;
-}
-"""])
-
-
-def arm_int_div_emulator(a, b):
- return int(a / float(b))
-arm_int_div_sign = lltype.Ptr(
- lltype.FuncType([lltype.Signed, lltype.Signed], lltype.Signed))
-arm_int_div = rffi.llexternal(
- "pypy__arm_int_div", [lltype.Signed, lltype.Signed], lltype.Signed,
- _callable=arm_int_div_emulator,
- compilation_info=eci,
- _nowrapper=True, elidable_function=True)
-
-
-def arm_uint_div_emulator(a, b):
- return r_uint(a) / r_uint(b)
-arm_uint_div_sign = lltype.Ptr(
- lltype.FuncType([lltype.Unsigned, lltype.Unsigned], lltype.Unsigned))
-arm_uint_div = rffi.llexternal(
- "pypy__arm_uint_div", [lltype.Unsigned, lltype.Unsigned], lltype.Unsigned,
- _callable=arm_uint_div_emulator,
- compilation_info=eci,
- _nowrapper=True, elidable_function=True)
-
-
-def arm_int_mod_emulator(a, b):
- sign = 1
- if a < 0:
- a = -1 * a
- sign = -1
- if b < 0:
- b = -1 * b
- res = a % b
- return sign * res
-arm_int_mod_sign = arm_int_div_sign
-arm_int_mod = rffi.llexternal(
- "pypy__arm_int_mod", [lltype.Signed, lltype.Signed], lltype.Signed,
- _callable=arm_int_mod_emulator,
- compilation_info=eci,
- _nowrapper=True, elidable_function=True)
diff --git a/rpython/jit/backend/arm/test/test_arch.py
b/rpython/jit/backend/arm/test/test_arch.py
deleted file mode 100644
--- a/rpython/jit/backend/arm/test/test_arch.py
+++ /dev/null
@@ -1,23 +0,0 @@
-from rpython.jit.backend.arm import support
-
-def test_mod():
- assert support.arm_int_mod(10, 2) == 0
- assert support.arm_int_mod(11, 2) == 1
- assert support.arm_int_mod(11, 3) == 2
-
-def test_mod2():
- assert support.arm_int_mod(-10, 2) == 0
- assert support.arm_int_mod(-11, 2) == -1
- assert support.arm_int_mod(-11, 3) == -2
-
-def test_mod3():
- assert support.arm_int_mod(10, -2) == 0
- assert support.arm_int_mod(11, -2) == 1
- assert support.arm_int_mod(11, -3) == 2
-
-
-def test_div():
- assert support.arm_int_div(-7, 2) == -3
- assert support.arm_int_div(9, 2) == 4
- assert support.arm_int_div(10, 5) == 2
-
diff --git a/rpython/jit/backend/arm/test/test_assembler.py
b/rpython/jit/backend/arm/test/test_assembler.py
--- a/rpython/jit/backend/arm/test/test_assembler.py
+++ b/rpython/jit/backend/arm/test/test_assembler.py
@@ -193,32 +193,6 @@
self.a.gen_func_epilog()
assert run_asm(self.a) == 61
- def test_DIV(self):
- self.a.gen_func_prolog()
- self.a.mc.MOV_ri(r.r0.value, 123)
- self.a.mc.MOV_ri(r.r1.value, 2)
- self.a.mc.DIV()
- self.a.gen_func_epilog()
- assert run_asm(self.a) == 61
-
- def test_DIV2(self):
- self.a.gen_func_prolog()
- self.a.mc.gen_load_int(r.r0.value, -110)
- self.a.mc.gen_load_int(r.r1.value, 3)
- self.a.mc.DIV()
- self.a.gen_func_epilog()
- assert run_asm(self.a) == -36
-
- def test_DIV3(self):
- self.a.gen_func_prolog()
- self.a.mc.gen_load_int(r.r8.value, 110)
- self.a.mc.gen_load_int(r.r9.value, -3)
- self.a.mc.MOV_rr(r.r0.value, r.r8.value)
- self.a.mc.MOV_rr(r.r1.value, r.r9.value)
- self.a.mc.DIV()
- self.a.gen_func_epilog()
- assert run_asm(self.a) == -36
-
def test_bl_with_conditional_exec(self):
functype = lltype.Ptr(lltype.FuncType([lltype.Signed], lltype.Signed))
call_addr = rffi.cast(lltype.Signed, llhelper(functype, callme))
diff --git a/rpython/jit/backend/llsupport/test/test_regalloc_integration.py
b/rpython/jit/backend/llsupport/test/test_regalloc_integration.py
--- a/rpython/jit/backend/llsupport/test/test_regalloc_integration.py
+++ b/rpython/jit/backend/llsupport/test/test_regalloc_integration.py
@@ -496,22 +496,6 @@
self.interpret(ops, [s, ord('a')])
assert s[1] == 'a'
- def test_division_optimized(self):
- ops = '''
- [i7, i6]
- label(i7, i6, descr=targettoken)
- i18 = int_floordiv(i7, i6)
- i19 = int_xor(i7, i6)
- i21 = int_lt(i19, 0)
- i22 = int_mod(i7, i6)
- i23 = int_is_true(i22)
- i24 = int_eq(i6, 4)
- guard_false(i24) [i18]
- jump(i18, i6, descr=targettoken)
- '''
- self.interpret(ops, [10, 4])
- assert self.getint(0) == 2
- # FIXME: Verify that i19 - i23 are removed
class TestRegallocFloats(BaseTestRegalloc):
def setup_class(cls):
diff --git a/rpython/jit/backend/ppc/opassembler.py
b/rpython/jit/backend/ppc/opassembler.py
--- a/rpython/jit/backend/ppc/opassembler.py
+++ b/rpython/jit/backend/ppc/opassembler.py
@@ -80,24 +80,6 @@
else:
self.mc.mulldox(*self.do_emit_int_binary_ovf(op, arglocs))
- def emit_int_floordiv(self, op, arglocs, regalloc):
- l0, l1, res = arglocs
- if IS_PPC_32:
- self.mc.divw(res.value, l0.value, l1.value)
- else:
- self.mc.divd(res.value, l0.value, l1.value)
-
- def emit_int_mod(self, op, arglocs, regalloc):
- l0, l1, res = arglocs
- if IS_PPC_32:
- self.mc.divw(r.r0.value, l0.value, l1.value)
- self.mc.mullw(r.r0.value, r.r0.value, l1.value)
- else:
- self.mc.divd(r.r0.value, l0.value, l1.value)
- self.mc.mulld(r.r0.value, r.r0.value, l1.value)
- self.mc.subf(r.r0.value, r.r0.value, l0.value)
- self.mc.mr(res.value, r.r0.value)
-
def emit_int_and(self, op, arglocs, regalloc):
l0, l1, res = arglocs
self.mc.and_(res.value, l0.value, l1.value)
@@ -130,13 +112,6 @@
self.mc.srw(res.value, l0.value, l1.value)
else:
self.mc.srd(res.value, l0.value, l1.value)
-
- def emit_uint_floordiv(self, op, arglocs, regalloc):
- l0, l1, res = arglocs
- if IS_PPC_32:
- self.mc.divwu(res.value, l0.value, l1.value)
- else:
- self.mc.divdu(res.value, l0.value, l1.value)
emit_int_le = gen_emit_cmp_op(c.LE)
emit_int_lt = gen_emit_cmp_op(c.LT)
diff --git a/rpython/jit/backend/ppc/regalloc.py
b/rpython/jit/backend/ppc/regalloc.py
--- a/rpython/jit/backend/ppc/regalloc.py
+++ b/rpython/jit/backend/ppc/regalloc.py
@@ -432,15 +432,12 @@
prepare_int_mul = helper.prepare_int_add_or_mul
prepare_nursery_ptr_increment = prepare_int_add
- prepare_int_floordiv = helper.prepare_binary_op
- prepare_int_mod = helper.prepare_binary_op
prepare_int_and = helper.prepare_binary_op
prepare_int_or = helper.prepare_binary_op
prepare_int_xor = helper.prepare_binary_op
prepare_int_lshift = helper.prepare_binary_op
prepare_int_rshift = helper.prepare_binary_op
prepare_uint_rshift = helper.prepare_binary_op
- prepare_uint_floordiv = helper.prepare_binary_op
prepare_int_add_ovf = helper.prepare_binary_op
prepare_int_sub_ovf = helper.prepare_binary_op
diff --git a/rpython/jit/backend/test/test_random.py
b/rpython/jit/backend/test/test_random.py
--- a/rpython/jit/backend/test/test_random.py
+++ b/rpython/jit/backend/test/test_random.py
@@ -548,8 +548,8 @@
]:
OPERATIONS.append(BinaryOperation(_op, boolres=True))
-OPERATIONS.append(BinaryOperation(rop.INT_FLOORDIV, ~3, 2))
-OPERATIONS.append(BinaryOperation(rop.INT_MOD, ~3, 2))
+#OPERATIONS.append(BinaryOperation(rop.INT_FLOORDIV, ~3, 2))
+#OPERATIONS.append(BinaryOperation(rop.INT_MOD, ~3, 2))
OPERATIONS.append(BinaryOperation(rop.INT_RSHIFT, LONG_BIT-1))
OPERATIONS.append(BinaryOperation(rop.INT_LSHIFT, LONG_BIT-1))
OPERATIONS.append(BinaryOperation(rop.UINT_RSHIFT, LONG_BIT-1))
diff --git a/rpython/jit/backend/x86/assembler.py
b/rpython/jit/backend/x86/assembler.py
--- a/rpython/jit/backend/x86/assembler.py
+++ b/rpython/jit/backend/x86/assembler.py
@@ -1444,20 +1444,6 @@
self.mov(imm0, resloc)
self.mc.CMOVNS(resloc, arglocs[0])
- def genop_int_mod(self, op, arglocs, resloc):
- if IS_X86_32:
- self.mc.CDQ()
- elif IS_X86_64:
- self.mc.CQO()
-
- self.mc.IDIV_r(ecx.value)
-
- genop_int_floordiv = genop_int_mod
-
- def genop_uint_floordiv(self, op, arglocs, resloc):
- self.mc.XOR_rr(edx.value, edx.value)
- self.mc.DIV_r(ecx.value)
-
genop_llong_add = _binaryop("PADDQ")
genop_llong_sub = _binaryop("PSUBQ")
genop_llong_and = _binaryop("PAND")
diff --git a/rpython/jit/backend/x86/regalloc.py
b/rpython/jit/backend/x86/regalloc.py
--- a/rpython/jit/backend/x86/regalloc.py
+++ b/rpython/jit/backend/x86/regalloc.py
@@ -585,29 +585,6 @@
consider_int_rshift = consider_int_lshift
consider_uint_rshift = consider_int_lshift
- def _consider_int_div_or_mod(self, op, resultreg, trashreg):
- l0 = self.rm.make_sure_var_in_reg(op.getarg(0), selected_reg=eax)
- l1 = self.rm.make_sure_var_in_reg(op.getarg(1), selected_reg=ecx)
- l2 = self.rm.force_allocate_reg(op, selected_reg=resultreg)
- # the register (eax or edx) not holding what we are looking for
- # will be just trash after that operation
- tmpvar = TempVar()
- self.rm.force_allocate_reg(tmpvar, selected_reg=trashreg)
- assert l0 is eax
- assert l1 is ecx
- assert l2 is resultreg
- self.rm.possibly_free_var(tmpvar)
-
- def consider_int_mod(self, op):
- self._consider_int_div_or_mod(op, edx, eax)
- self.perform(op, [eax, ecx], edx)
-
- def consider_int_floordiv(self, op):
- self._consider_int_div_or_mod(op, eax, edx)
- self.perform(op, [eax, ecx], eax)
-
- consider_uint_floordiv = consider_int_floordiv
-
def _consider_compop(self, op):
vx = op.getarg(0)
vy = op.getarg(1)
diff --git a/rpython/jit/codewriter/effectinfo.py
b/rpython/jit/codewriter/effectinfo.py
--- a/rpython/jit/codewriter/effectinfo.py
+++ b/rpython/jit/codewriter/effectinfo.py
@@ -28,6 +28,11 @@
OS_THREADLOCALREF_GET = 5 # llop.threadlocalref_get
OS_NOT_IN_TRACE = 8 # for calls not recorded in the jit
trace
#
+ OS_INT_PY_DIV = 12 # python signed division (neg.
corrected)
+ OS_INT_UDIV = 13 # regular unsigned division
+ OS_INT_PY_MOD = 14 # python signed modulo (neg. corrected)
+ OS_INT_UMOD = 15 # regular unsigned modulo
+ #
OS_STR_CONCAT = 22 # "stroruni.concat"
OS_STR_SLICE = 23 # "stroruni.slice"
OS_STR_EQUAL = 24 # "stroruni.equal"
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
@@ -436,6 +436,8 @@
# dispatch to various implementations depending on the oopspec_name
if oopspec_name.startswith('list.') or
oopspec_name.startswith('newlist'):
prepare = self._handle_list_call
+ elif oopspec_name.startswith('int.'):
+ prepare = self._handle_int_special
elif oopspec_name.startswith('stroruni.'):
prepare = self._handle_stroruni_call
elif oopspec_name == 'str.str2unicode':
@@ -518,23 +520,12 @@
# XXX some of the following functions should not become residual calls
# but be really compiled
- rewrite_op_int_floordiv_ovf_zer = _do_builtin_call
- rewrite_op_int_floordiv_ovf = _do_builtin_call
- rewrite_op_int_floordiv_zer = _do_builtin_call
- rewrite_op_int_mod_ovf_zer = _do_builtin_call
- rewrite_op_int_mod_ovf = _do_builtin_call
- rewrite_op_int_mod_zer = _do_builtin_call
- rewrite_op_int_lshift_ovf = _do_builtin_call
rewrite_op_int_abs = _do_builtin_call
rewrite_op_llong_abs = _do_builtin_call
rewrite_op_llong_floordiv = _do_builtin_call
- rewrite_op_llong_floordiv_zer = _do_builtin_call
rewrite_op_llong_mod = _do_builtin_call
- rewrite_op_llong_mod_zer = _do_builtin_call
rewrite_op_ullong_floordiv = _do_builtin_call
- rewrite_op_ullong_floordiv_zer = _do_builtin_call
rewrite_op_ullong_mod = _do_builtin_call
- rewrite_op_ullong_mod_zer = _do_builtin_call
rewrite_op_gc_identityhash = _do_builtin_call
rewrite_op_gc_id = _do_builtin_call
rewrite_op_gc_pin = _do_builtin_call
@@ -1532,12 +1523,6 @@
return self.rewrite_operation(op1)
''' % (_old, _new)).compile()
- def rewrite_op_int_neg_ovf(self, op):
- op1 = SpaceOperation('int_sub_ovf',
- [Constant(0, lltype.Signed), op.args[0]],
- op.result)
- return self.rewrite_operation(op1)
-
def rewrite_op_float_is_true(self, op):
op1 = SpaceOperation('float_ne',
[op.args[0], Constant(0.0, lltype.Float)],
@@ -1929,6 +1914,20 @@
llmemory.cast_ptr_to_adr(c_func.value))
self.callcontrol.callinfocollection.add(oopspecindex, calldescr, func)
+ def _handle_int_special(self, op, oopspec_name, args):
+ if oopspec_name == 'int.neg_ovf':
+ [v_x] = args
+ op0 = SpaceOperation('int_sub_ovf',
+ [Constant(0, lltype.Signed), v_x],
+ op.result)
+ return self.rewrite_operation(op0)
+ else:
+ # int.py_div, int.udiv, int.py_mod, int.umod
+ opname = oopspec_name.replace('.', '_')
+ os = getattr(EffectInfo, 'OS_' + opname.upper())
+ return self._handle_oopspec_call(op, args, os,
+ EffectInfo.EF_ELIDABLE_CANNOT_RAISE)
+
def _handle_stroruni_call(self, op, oopspec_name, args):
SoU = args[0].concretetype # Ptr(STR) or Ptr(UNICODE)
can_raise_memoryerror = {
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
@@ -243,45 +243,6 @@
return llop.jit_force_virtual(lltype.typeOf(inst), inst)
-def _ll_2_int_floordiv_ovf_zer(x, y):
- if y == 0:
- raise ZeroDivisionError
- return _ll_2_int_floordiv_ovf(x, y)
-
-def _ll_2_int_floordiv_ovf(x, y):
- # intentionally not short-circuited to produce only one guard
- # and to remove the check fully if one of the arguments is known
- if (x == -sys.maxint - 1) & (y == -1):
- raise OverflowError
- return llop.int_floordiv(lltype.Signed, x, y)
-
-def _ll_2_int_floordiv_zer(x, y):
- if y == 0:
- raise ZeroDivisionError
- return llop.int_floordiv(lltype.Signed, x, y)
-
-def _ll_2_int_mod_ovf_zer(x, y):
- if y == 0:
- raise ZeroDivisionError
- return _ll_2_int_mod_ovf(x, y)
-
-def _ll_2_int_mod_ovf(x, y):
- #see comment in _ll_2_int_floordiv_ovf
- if (x == -sys.maxint - 1) & (y == -1):
- raise OverflowError
- return llop.int_mod(lltype.Signed, x, y)
-
-def _ll_2_int_mod_zer(x, y):
- if y == 0:
- raise ZeroDivisionError
- return llop.int_mod(lltype.Signed, x, y)
-
-def _ll_2_int_lshift_ovf(x, y):
- result = x << y
- if (result >> y) != x:
- raise OverflowError
- return result
-
def _ll_1_int_abs(x):
# this version doesn't branch
mask = x >> (LONG_BIT - 1)
@@ -452,51 +413,9 @@
else:
return xll
-def _ll_2_llong_floordiv(xll, yll):
- return llop.llong_floordiv(lltype.SignedLongLong, xll, yll)
-
-def _ll_2_llong_floordiv_zer(xll, yll):
- if yll == 0:
- raise ZeroDivisionError
- return llop.llong_floordiv(lltype.SignedLongLong, xll, yll)
-
-def _ll_2_llong_mod(xll, yll):
- return llop.llong_mod(lltype.SignedLongLong, xll, yll)
-
-def _ll_2_llong_mod_zer(xll, yll):
- if yll == 0:
- raise ZeroDivisionError
- return llop.llong_mod(lltype.SignedLongLong, xll, yll)
-
-def _ll_2_ullong_floordiv(xll, yll):
- return llop.ullong_floordiv(lltype.UnsignedLongLong, xll, yll)
-
-def _ll_2_ullong_floordiv_zer(xll, yll):
- if yll == 0:
- raise ZeroDivisionError
- return llop.ullong_floordiv(lltype.UnsignedLongLong, xll, yll)
-
-def _ll_2_ullong_mod(xll, yll):
- return llop.ullong_mod(lltype.UnsignedLongLong, xll, yll)
-
-def _ll_2_ullong_mod_zer(xll, yll):
- if yll == 0:
- raise ZeroDivisionError
- return llop.ullong_mod(lltype.UnsignedLongLong, xll, yll)
-
-def _ll_2_uint_mod(xll, yll):
- return llop.uint_mod(lltype.Unsigned, xll, yll)
-
# in the following calls to builtins, the JIT is allowed to look inside:
inline_calls_to = [
- ('int_floordiv_ovf_zer', [lltype.Signed, lltype.Signed], lltype.Signed),
- ('int_floordiv_ovf', [lltype.Signed, lltype.Signed], lltype.Signed),
- ('int_floordiv_zer', [lltype.Signed, lltype.Signed], lltype.Signed),
- ('int_mod_ovf_zer', [lltype.Signed, lltype.Signed], lltype.Signed),
- ('int_mod_ovf', [lltype.Signed, lltype.Signed], lltype.Signed),
- ('int_mod_zer', [lltype.Signed, lltype.Signed], lltype.Signed),
- ('int_lshift_ovf', [lltype.Signed, lltype.Signed], lltype.Signed),
('int_abs', [lltype.Signed], lltype.Signed),
('ll_math.ll_math_sqrt', [lltype.Float], lltype.Float),
]
diff --git a/rpython/jit/codewriter/test/test_flatten.py
b/rpython/jit/codewriter/test/test_flatten.py
--- a/rpython/jit/codewriter/test/test_flatten.py
+++ b/rpython/jit/codewriter/test/test_flatten.py
@@ -478,7 +478,7 @@
except ZeroDivisionError:
return -42
self.encoding_test(f, [7, 2], """
- residual_call_ir_i $<* fn int_floordiv_ovf_zer>, I[%i0, %i1], R[],
<Descr> -> %i2
+ residual_call_ir_i $<* fn ll_int_floordiv_ovf_zer__Signed_Signed>,
I[%i0, %i1], R[], <Descr> -> %i2
-live-
catch_exception L1
int_return %i2
@@ -505,7 +505,7 @@
return 42
# XXX so far, this really produces a int_mod_ovf_zer...
self.encoding_test(f, [7, 2], """
- residual_call_ir_i $<* fn int_mod_ovf_zer>, I[%i0, %i1], R[],
<Descr> -> %i2
+ residual_call_ir_i $<* fn ll_int_mod_ovf_zer__Signed_Signed>,
I[%i0, %i1], R[], <Descr> -> %i2
-live-
catch_exception L1
int_return %i2
@@ -548,6 +548,36 @@
int_return $42
""", transform=True, liveness=True)
+ def test_int_sub_ovf(self):
+ def f(i, j):
+ try:
+ return ovfcheck(i - j)
+ except OverflowError:
+ return 42
+ self.encoding_test(f, [7, 2], """
+ -live- %i0, %i1
+ int_sub_jump_if_ovf L1, %i0, %i1 -> %i2
+ int_return %i2
+ ---
+ L1:
+ int_return $42
+ """, transform=True, liveness=True)
+
+ def test_int_mul_ovf(self):
+ def f(i, j):
+ try:
+ return ovfcheck(i * j)
+ except OverflowError:
+ return 42
+ self.encoding_test(f, [7, 2], """
+ -live- %i0, %i1
+ int_mul_jump_if_ovf L1, %i0, %i1 -> %i2
+ int_return %i2
+ ---
+ L1:
+ int_return $42
+ """, transform=True, liveness=True)
+
def test_multiple_int_add_ovf(self):
def f(i, j):
try:
diff --git a/rpython/jit/codewriter/test/test_jtransform.py
b/rpython/jit/codewriter/test/test_jtransform.py
--- a/rpython/jit/codewriter/test/test_jtransform.py
+++ b/rpython/jit/codewriter/test/test_jtransform.py
@@ -135,6 +135,10 @@
EI.OS_RAW_MALLOC_VARSIZE_CHAR: ([INT], ARRAYPTR),
EI.OS_RAW_FREE: ([ARRAYPTR], lltype.Void),
EI.OS_THREADLOCALREF_GET: ([INT], INT), # for example
+ EI.OS_INT_PY_DIV: ([INT, INT], INT),
+ EI.OS_INT_UDIV: ([INT, INT], INT),
+ EI.OS_INT_PY_MOD: ([INT, INT], INT),
+ EI.OS_INT_UMOD: ([INT, INT], INT),
}
argtypes = argtypes[oopspecindex]
assert argtypes[0] == [v.concretetype for v in op.args[1:]]
@@ -268,15 +272,17 @@
assert op1.result == v3
assert op1.opname == name2[0]
-def test_symmetric_int_add_ovf():
[email protected]('opname', ['add_ovf', 'sub_ovf', 'mul_ovf'])
+def test_int_op_ovf(opname):
v3 = varoftype(lltype.Signed)
for v1 in [varoftype(lltype.Signed), const(42)]:
for v2 in [varoftype(lltype.Signed), const(43)]:
- op = SpaceOperation('int_add_nonneg_ovf', [v1, v2], v3)
+ op = SpaceOperation('int_' + opname, [v1, v2], v3)
oplist = Transformer(FakeCPU()).rewrite_operation(op)
op1, op0 = oplist
- assert op0.opname == 'int_add_ovf'
- if isinstance(v1, Constant) and isinstance(v2, Variable):
+ assert op0.opname == 'int_' + opname
+ if (isinstance(v1, Constant) and isinstance(v2, Variable)
+ and opname != 'sub_ovf'):
assert op0.args == [v2, v1]
assert op0.result == v3
else:
@@ -286,6 +292,34 @@
assert op1.args == []
assert op1.result is None
+def test_neg_ovf():
+ v3 = varoftype(lltype.Signed)
+ for v1 in [varoftype(lltype.Signed), const(42)]:
+ op = SpaceOperation('direct_call', [Constant('neg_ovf'), v1], v3)
+ oplist = Transformer(FakeCPU())._handle_int_special(op, 'int.neg_ovf',
+ [v1])
+ op1, op0 = oplist
+ assert op0.opname == 'int_sub_ovf'
+ assert op0.args == [Constant(0), v1]
+ assert op0.result == v3
+ assert op1.opname == '-live-'
+ assert op1.args == []
+ assert op1.result is None
+
[email protected]('opname', ['py_div', 'udiv', 'py_mod', 'umod'])
+def test_int_op_residual(opname):
+ v3 = varoftype(lltype.Signed)
+ tr = Transformer(FakeCPU(), FakeBuiltinCallControl())
+ for v1 in [varoftype(lltype.Signed), const(42)]:
+ for v2 in [varoftype(lltype.Signed), const(43)]:
+ op = SpaceOperation('direct_call', [Constant(opname), v1, v2], v3)
+ op0 = tr._handle_int_special(op, 'int.'+opname, [v1, v2])
+ assert op0.opname == 'residual_call_ir_i'
+ assert op0.args[0].value == opname # pseudo-function as str
+ expected = ('int_' + opname).upper()
+ assert (op0.args[-1] == 'calldescr-%d' %
+ getattr(effectinfo.EffectInfo, 'OS_' + expected))
+
def test_calls():
for RESTYPE, with_void, with_i, with_r, with_f in product(
[lltype.Signed, rclass.OBJECTPTR, lltype.Float, lltype.Void],
diff --git a/rpython/jit/metainterp/blackhole.py
b/rpython/jit/metainterp/blackhole.py
--- a/rpython/jit/metainterp/blackhole.py
+++ b/rpython/jit/metainterp/blackhole.py
@@ -430,19 +430,6 @@
return 0, label
@arguments("i", "i", returns="i")
- def bhimpl_int_floordiv(a, b):
- return llop.int_floordiv(lltype.Signed, a, b)
-
- @arguments("i", "i", returns="i")
- def bhimpl_uint_floordiv(a, b):
- c = llop.uint_floordiv(lltype.Unsigned, r_uint(a), r_uint(b))
- return intmask(c)
-
- @arguments("i", "i", returns="i")
- def bhimpl_int_mod(a, b):
- return llop.int_mod(lltype.Signed, a, b)
-
- @arguments("i", "i", returns="i")
def bhimpl_int_and(a, b):
return a & b
diff --git a/rpython/jit/metainterp/optimizeopt/dependency.py
b/rpython/jit/metainterp/optimizeopt/dependency.py
--- a/rpython/jit/metainterp/optimizeopt/dependency.py
+++ b/rpython/jit/metainterp/optimizeopt/dependency.py
@@ -929,10 +929,10 @@
"""
exec py.code.Source(multiplicative_func_source
.format(name='INT_MUL', op='*', tgt='mul', cop='*')).compile()
- exec py.code.Source(multiplicative_func_source
- .format(name='INT_FLOORDIV', op='*', tgt='div', cop='/')).compile()
- exec py.code.Source(multiplicative_func_source
- .format(name='UINT_FLOORDIV', op='*', tgt='div',
cop='/')).compile()
+ #exec py.code.Source(multiplicative_func_source
+ # .format(name='INT_PY_DIV', op='*', tgt='div', cop='/')).compile()
+ #exec py.code.Source(multiplicative_func_source
+ # .format(name='UINT_FLOORDIV', op='*', tgt='div',
cop='/')).compile()
del multiplicative_func_source
array_access_source = """
@@ -1042,9 +1042,11 @@
var = ResOperation(rop.INT_MUL, args)
opt.emit_operation(var)
if self.coefficient_div != 1:
- args = [var, ConstInt(self.coefficient_div)]
- var = ResOperation(rop.INT_FLOORDIV, args)
- opt.emit_operation(var)
+ assert 0 # XXX for now; should never be the case with handling
+ # of INT_PY_DIV commented out in this file...
+ #args = [var, ConstInt(self.coefficient_div)]
+ #var = ResOperation(rop.INT_FLOORDIV, args)
+ #opt.emit_operation(var)
if self.constant > 0:
args = [var, ConstInt(self.constant)]
var = ResOperation(rop.INT_ADD, args)
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
@@ -8,6 +8,7 @@
from rpython.jit.metainterp.optimizeopt.util import make_dispatcher_method
from rpython.jit.metainterp.resoperation import rop, AbstractResOp
from rpython.jit.metainterp.optimizeopt import vstring
+from rpython.jit.codewriter.effectinfo import EffectInfo
from rpython.rlib.rarithmetic import intmask
def get_integer_min(is_unsigned, byte_size):
@@ -172,39 +173,50 @@
if b.bounded():
r.intersect(b)
- def optimize_INT_FLOORDIV(self, op):
- b1 = self.getintbound(op.getarg(0))
- b2 = self.getintbound(op.getarg(1))
+ def optimize_CALL_PURE_I(self, op):
+ # dispatch based on 'oopspecindex' to a method that handles
+ # specifically the given oopspec call.
+ effectinfo = op.getdescr().get_extra_info()
+ oopspecindex = effectinfo.oopspecindex
+ if oopspecindex == EffectInfo.OS_INT_PY_DIV:
+ self.opt_call_INT_PY_DIV(op)
+ return
+ elif oopspecindex == EffectInfo.OS_INT_PY_MOD:
+ self.opt_call_INT_PY_MOD(op)
+ return
+ self.emit_operation(op)
+
+ def opt_call_INT_PY_DIV(self, op):
+ b1 = self.getintbound(op.getarg(1))
+ b2 = self.getintbound(op.getarg(2))
self.emit_operation(op)
r = self.getintbound(op)
- r.intersect(b1.div_bound(b2))
+ r.intersect(b1.py_div_bound(b2))
- def optimize_INT_MOD(self, op):
- b1 = self.getintbound(op.getarg(0))
- b2 = self.getintbound(op.getarg(1))
- known_nonneg = (b1.known_ge(IntBound(0, 0)) and
- b2.known_ge(IntBound(0, 0)))
- if known_nonneg and b2.is_constant():
+ def opt_call_INT_PY_MOD(self, op):
+ b1 = self.getintbound(op.getarg(1))
+ b2 = self.getintbound(op.getarg(2))
+ if b2.is_constant():
val = b2.getint()
- if (val & (val-1)) == 0:
- # nonneg % power-of-two ==> nonneg & (power-of-two - 1)
- arg1 = op.getarg(0)
+ if val > 0 and (val & (val-1)) == 0:
+ # x % power-of-two ==> x & (power-of-two - 1)
+ # with Python's modulo, this is valid even if 'x' is negative.
+ from rpython.jit.metainterp.history import DONT_CHANGE
+ arg1 = op.getarg(1)
arg2 = ConstInt(val-1)
op = self.replace_op_with(op, rop.INT_AND,
- args=[arg1, arg2])
+ args=[arg1, arg2],
+ descr=DONT_CHANGE) # <- xxx rename?
self.emit_operation(op)
if b2.is_constant():
val = b2.getint()
r = self.getintbound(op)
- if val < 0:
- if val == -sys.maxint-1:
- return # give up
- val = -val
- if known_nonneg:
+ if val >= 0: # with Python's modulo: 0 <= (x % pos) < pos
r.make_ge(IntBound(0, 0))
- else:
- r.make_gt(IntBound(-val, -val))
- r.make_lt(IntBound(val, val))
+ r.make_lt(IntBound(val, val))
+ else: # with Python's modulo: neg < (x % neg) <= 0
+ r.make_gt(IntBound(val, val))
+ r.make_le(IntBound(0, 0))
def optimize_INT_LSHIFT(self, op):
arg0 = self.get_box_replacement(op.getarg(0))
@@ -613,10 +625,10 @@
b1 = self.getintbound(op.getarg(0))
b2 = self.getintbound(op.getarg(1))
r = self.getintbound(op)
- b = r.div_bound(b2)
+ b = r.py_div_bound(b2)
if b1.intersect(b):
self.propagate_bounds_backward(op.getarg(0))
- b = r.div_bound(b1)
+ b = r.py_div_bound(b1)
if b2.intersect(b):
self.propagate_bounds_backward(op.getarg(1))
diff --git a/rpython/jit/metainterp/optimizeopt/intutils.py
b/rpython/jit/metainterp/optimizeopt/intutils.py
--- a/rpython/jit/metainterp/optimizeopt/intutils.py
+++ b/rpython/jit/metainterp/optimizeopt/intutils.py
@@ -174,16 +174,21 @@
else:
return IntUnbounded()
- def div_bound(self, other):
+ def py_div_bound(self, other):
if self.has_upper and self.has_lower and \
other.has_upper and other.has_lower and \
- not other.contains(0) and self.lower > (-sys.maxint-1):
- vals = (
- llop.int_floordiv(lltype.Signed, self.upper, other.upper),
- llop.int_floordiv(lltype.Signed, self.upper, other.lower),
- llop.int_floordiv(lltype.Signed, self.lower, other.upper),
- llop.int_floordiv(lltype.Signed, self.lower, other.lower))
- return IntBound(min4(vals), max4(vals))
+ not other.contains(0):
+ try:
+ # this gives the bounds for 'int_py_div', so use the
+ # Python-style handling of negative numbers and not
+ # the C-style one
+ vals = (ovfcheck(self.upper / other.upper),
+ ovfcheck(self.upper / other.lower),
+ ovfcheck(self.lower / other.upper),
+ ovfcheck(self.lower / other.lower))
+ return IntBound(min4(vals), max4(vals))
+ except OverflowError:
+ return IntUnbounded()
else:
return IntUnbounded()
diff --git a/rpython/jit/metainterp/optimizeopt/rewrite.py
b/rpython/jit/metainterp/optimizeopt/rewrite.py
--- a/rpython/jit/metainterp/optimizeopt/rewrite.py
+++ b/rpython/jit/metainterp/optimizeopt/rewrite.py
@@ -168,13 +168,13 @@
break
self.emit_operation(op)
- def optimize_UINT_FLOORDIV(self, op):
- b2 = self.getintbound(op.getarg(1))
-
+ def _optimize_CALL_INT_UDIV(self, op):
+ b2 = self.getintbound(op.getarg(2))
if b2.is_constant() and b2.getint() == 1:
- self.make_equal_to(op, op.getarg(0))
- else:
- self.emit_operation(op)
+ self.make_equal_to(op, op.getarg(1))
+ self.last_emitted_operation = REMOVED
+ return True
+ return False
def optimize_INT_LSHIFT(self, op):
b1 = self.getintbound(op.getarg(0))
@@ -663,6 +663,16 @@
self.make_constant(op, result)
self.last_emitted_operation = REMOVED
return
+ # dispatch based on 'oopspecindex' to a method that handles
+ # specifically the given oopspec call.
+ effectinfo = op.getdescr().get_extra_info()
+ oopspecindex = effectinfo.oopspecindex
+ if oopspecindex == EffectInfo.OS_INT_UDIV:
+ if self._optimize_CALL_INT_UDIV(op):
+ return
+ elif oopspecindex == EffectInfo.OS_INT_PY_DIV:
+ if self._optimize_CALL_INT_PY_DIV(op):
+ return
self.emit_operation(op)
optimize_CALL_PURE_R = optimize_CALL_PURE_I
optimize_CALL_PURE_F = optimize_CALL_PURE_I
@@ -678,24 +688,31 @@
def optimize_GUARD_FUTURE_CONDITION(self, op):
self.optimizer.notice_guard_future_condition(op)
- def optimize_INT_FLOORDIV(self, op):
- arg0 = op.getarg(0)
- b1 = self.getintbound(arg0)
+ def _optimize_CALL_INT_PY_DIV(self, op):
arg1 = op.getarg(1)
- b2 = self.getintbound(arg1)
+ b1 = self.getintbound(arg1)
+ arg2 = op.getarg(2)
+ b2 = self.getintbound(arg2)
- if b2.is_constant() and b2.getint() == 1:
- self.make_equal_to(op, arg0)
- return
- elif b1.is_constant() and b1.getint() == 0:
+ if b1.is_constant() and b1.getint() == 0:
self.make_constant_int(op, 0)
- return
- if b1.known_ge(IntBound(0, 0)) and b2.is_constant():
+ self.last_emitted_operation = REMOVED
+ return True
+ # This is Python's integer division: 'x // (2**shift)' can always
+ # be replaced with 'x >> shift', even for negative values of x
+ if b2.is_constant():
val = b2.getint()
- if val & (val - 1) == 0 and val > 0: # val == 2**shift
+ if val == 1:
+ self.make_equal_to(op, arg1)
+ self.last_emitted_operation = REMOVED
+ return True
+ elif val > 0 and val & (val - 1) == 0: # val == 2**shift
+ from rpython.jit.metainterp.history import DONT_CHANGE
op = self.replace_op_with(op, rop.INT_RSHIFT,
- args = [op.getarg(0), ConstInt(highest_bit(val))])
+ args=[arg1, ConstInt(highest_bit(val))],
+ descr=DONT_CHANGE) # <- xxx rename? means "kill"
self.emit_operation(op)
+ return True
def optimize_CAST_PTR_TO_INT(self, op):
self.optimizer.pure_reverse(op)
diff --git a/rpython/jit/metainterp/optimizeopt/test/test_intbound.py
b/rpython/jit/metainterp/optimizeopt/test/test_intbound.py
--- a/rpython/jit/metainterp/optimizeopt/test/test_intbound.py
+++ b/rpython/jit/metainterp/optimizeopt/test/test_intbound.py
@@ -244,19 +244,18 @@
from rpython.rtyper.lltypesystem.lloperation import llop
for _, _, b1 in some_bounds():
for _, _, b2 in some_bounds():
- b3 = b1.div_bound(b2)
+ b3 = b1.py_div_bound(b2)
for n1 in nbr:
for n2 in nbr:
if b1.contains(n1) and b2.contains(n2):
if n2 != 0:
- assert b3.contains(
- llop.int_floordiv(lltype.Signed, n1, n2))
+ assert b3.contains(n1 / n2) # Python-style div
- a=bound(2, 4).div_bound(bound(1, 2))
+ a=bound(2, 4).py_div_bound(bound(1, 2))
assert not a.contains(0)
assert not a.contains(5)
- a=bound(-3, 2).div_bound(bound(1, 2))
+ a=bound(-3, 2).py_div_bound(bound(1, 2))
assert not a.contains(-4)
assert not a.contains(3)
assert a.contains(-3)
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
@@ -1849,7 +1849,7 @@
ops = """
[i0]
- i1 = int_floordiv(0, i0)
+ i1 = int_mul(0, i0)
jump(i1)
"""
expected = """
@@ -1858,6 +1858,17 @@
"""
self.optimize_loop(ops, expected)
+ ops = """
+ [i0]
+ i1 = int_mul(1, i0)
+ jump(i1)
+ """
+ expected = """
+ [i0]
+ jump(i0)
+ """
+ self.optimize_loop(ops, expected)
+
def test_fold_partially_constant_ops_ovf(self):
ops = """
[i0]
@@ -4111,21 +4122,6 @@
# ----------
def optimize_strunicode_loop_extradescrs(self, ops, optops):
- class FakeCallInfoCollection:
- def callinfo_for_oopspec(self, oopspecindex):
- calldescrtype = type(LLtypeMixin.strequaldescr)
- effectinfotype =
type(LLtypeMixin.strequaldescr.get_extra_info())
- for value in LLtypeMixin.__dict__.values():
- if isinstance(value, calldescrtype):
- extra = value.get_extra_info()
- if (extra and isinstance(extra, effectinfotype) and
- extra.oopspecindex == oopspecindex):
- # returns 0 for 'func' in this test
- return value, 0
- raise AssertionError("not found: oopspecindex=%d" %
- oopspecindex)
- #
- self.callinfocollection = FakeCallInfoCollection()
self.optimize_strunicode_loop(ops, optops)
def test_str_equal_noop1(self):
@@ -4642,102 +4638,89 @@
"""
self.optimize_strunicode_loop(ops, expected)
+ def test_intdiv_bounds(self):
+ ops = """
+ [i0]
+ i2 = call_pure_i(321, i0, 3, descr=int_py_div_descr)
+ i3 = int_add_ovf(i2, 50)
+ guard_no_overflow() []
+ jump(i3)
+ """
+ expected = """
+ [i0]
+ i2 = call_i(321, i0, 3, descr=int_py_div_descr)
+ i3 = int_add(i2, 50)
+ jump(i3)
+ """
+ self.optimize_loop(ops, expected)
+
def test_intmod_bounds(self):
ops = """
[i0, i1]
- i2 = int_mod(i0, 12)
- i3 = int_gt(i2, 12)
+ i2 = call_pure_i(321, i0, 12, descr=int_py_mod_descr)
+ i3 = int_ge(i2, 12)
guard_false(i3) []
- i4 = int_lt(i2, -12)
+ i4 = int_lt(i2, 0)
guard_false(i4) []
- i5 = int_mod(i1, -12)
- i6 = int_lt(i5, -12)
+ i5 = call_pure_i(321, i1, -12, descr=int_py_mod_descr)
+ i6 = int_le(i5, -12)
guard_false(i6) []
- i7 = int_gt(i5, 12)
+ i7 = int_gt(i5, 0)
guard_false(i7) []
jump(i2, i5)
"""
expected = """
[i0, i1]
- i2 = int_mod(i0, 12)
- i5 = int_mod(i1, -12)
+ i2 = call_i(321, i0, 12, descr=int_py_mod_descr)
+ i5 = call_i(321, i1, -12, descr=int_py_mod_descr)
jump(i2, i5)
"""
self.optimize_loop(ops, expected)
- # This the sequence of resoperations that is generated for a Python
- # app-level int % int. When the modulus is constant and when i0
- # is known non-negative it should be optimized to a single int_mod.
+ # same as above, but all guards are shifted by one so that they
+ # must stay
+ ops = """
+ [i8, i9]
+ i0 = escape_i()
+ i2 = call_pure_i(321, i0, 12, descr=int_py_mod_descr)
+ i3 = int_ge(i2, 11)
+ guard_false(i3) []
+ i4 = int_lt(i2, 1)
+ guard_false(i4) []
+ i1 = escape_i()
+ i5 = call_pure_i(321, i1, -12, descr=int_py_mod_descr)
+ i6 = int_le(i5, -11)
+ guard_false(i6) []
+ i7 = int_gt(i5, -1)
+ guard_false(i7) []
+ jump(i2, i5)
+ """
+ self.optimize_loop(ops, ops.replace('call_pure_i', 'call_i'))
+
+ # 'n % power-of-two' can always be turned into int_and(), even
+ # if n is possibly negative. That's by we handle 'int_py_mod'
+ # and not C-like mod.
ops = """
[i0]
- i5 = int_ge(i0, 0)
- guard_true(i5) []
- i1 = int_mod(i0, 42)
- i2 = int_rshift(i1, %d)
- i3 = int_and(42, i2)
- i4 = int_add(i1, i3)
- finish(i4)
- """ % (LONG_BIT-1)
+ i1 = call_pure_i(321, i0, 8, descr=int_py_mod_descr)
+ finish(i1)
+ """
expected = """
[i0]
- i5 = int_ge(i0, 0)
- guard_true(i5) []
- i1 = int_mod(i0, 42)
- finish(i1)
- """
- self.optimize_loop(ops, expected)
-
- # 'n % power-of-two' can be turned into int_and(); at least that's
- # easy to do now if n is known to be non-negative.
- ops = """
- [i0]
- i5 = int_ge(i0, 0)
- guard_true(i5) []
- i1 = int_mod(i0, 8)
- i2 = int_rshift(i1, %d)
- i3 = int_and(42, i2)
- i4 = int_add(i1, i3)
- finish(i4)
- """ % (LONG_BIT-1)
- expected = """
- [i0]
- i5 = int_ge(i0, 0)
- guard_true(i5) []
i1 = int_and(i0, 7)
finish(i1)
"""
self.optimize_loop(ops, expected)
- def test_intmod_bounds_harder(self):
- py.test.skip("harder")
- # Of course any 'maybe-negative % power-of-two' can be turned into
- # int_and(), but that's a bit harder to detect here because it turns
- # into several operations, and of course it is wrong to just turn
- # int_mod(i0, 16) into int_and(i0, 15).
+ def test_intmod_bounds_bug1(self):
ops = """
[i0]
- i1 = int_mod(i0, 16)
- i2 = int_rshift(i1, %d)
- i3 = int_and(16, i2)
- i4 = int_add(i1, i3)
- finish(i4)
- """ % (LONG_BIT-1)
- expected = """
- [i0]
- i4 = int_and(i0, 15)
- finish(i4)
- """
- self.optimize_loop(ops, expected)
-
- def test_intmod_bounds_bug1(self):
- ops = """
- [i0]
- i1 = int_mod(i0, %d)
+ i1 = call_pure_i(321, i0, %d, descr=int_py_mod_descr)
i2 = int_eq(i1, 0)
guard_false(i2) []
finish()
""" % (-(1<<(LONG_BIT-1)),)
- self.optimize_loop(ops, ops)
+ self.optimize_loop(ops, ops.replace('call_pure_i', 'call_i'))
def test_bounded_lazy_setfield(self):
ops = """
diff --git a/rpython/jit/metainterp/optimizeopt/test/test_optimizeopt.py
b/rpython/jit/metainterp/optimizeopt/test/test_optimizeopt.py
--- a/rpython/jit/metainterp/optimizeopt/test/test_optimizeopt.py
+++ b/rpython/jit/metainterp/optimizeopt/test/test_optimizeopt.py
@@ -3493,7 +3493,7 @@
def test_fold_partially_constant_uint_floordiv(self):
ops = """
[i0]
- i1 = uint_floordiv(i0, 1)
+ i1 = call_pure_i(321, i0, 1, descr=int_udiv_descr)
jump(i1)
"""
expected = """
@@ -5247,13 +5247,13 @@
guard_true(it1) []
it2 = int_gt(i2, 0)
guard_true(it2) []
- ix2 = int_floordiv(i0, i1)
+ ix2 = call_pure_i(321, i0, i1, descr=int_py_div_descr)
ix2t = int_ge(ix2, 0)
guard_true(ix2t) []
- ix3 = int_floordiv(i1, i0)
+ ix3 = call_pure_i(321, i1, i0, descr=int_py_div_descr)
ix3t = int_ge(ix3, 0)
guard_true(ix3t) []
- ix4 = int_floordiv(i1, i2)
+ ix4 = call_pure_i(321, i1, i2, descr=int_py_div_descr)
ix4t = int_ge(ix4, 0)
guard_true(ix4t) []
jump(i0, i1, i2)
@@ -5264,13 +5264,14 @@
guard_true(it1) []
it2 = int_gt(i2, 0)
guard_true(it2) []
- ix2 = int_floordiv(i0, i1)
+ ix2 = call_i(321, i0, i1, descr=int_py_div_descr)
ix2t = int_ge(ix2, 0)
guard_true(ix2t) []
- ix3 = int_floordiv(i1, i0)
+ ix3 = call_i(321, i1, i0, descr=int_py_div_descr)
ix3t = int_ge(ix3, 0)
guard_true(ix3t) []
- ix4 = int_floordiv(i1, i2)
+ ix4 = call_i(321, i1, i2, descr=int_py_div_descr)
+ # <== the check that ix4 is nonnegative was removed
jump(i0, i1, i2)
"""
expected = """
@@ -5314,92 +5315,38 @@
"""
self.optimize_loop(ops, expected, preamble)
- def test_division(self):
- ops = """
- [i7, i6, i8]
- it1 = int_gt(i7, 0)
- guard_true(it1) []
- it2 = int_gt(i6, 0)
- guard_true(it2) []
- i13 = int_is_zero(i6)
- guard_false(i13) []
- i15 = int_and(i8, i6)
- i17 = int_eq(i15, -1)
- guard_false(i17) []
- i18 = int_floordiv(i7, i6)
- i19 = int_xor(i7, i6)
- i21 = int_lt(i19, 0)
- i22 = int_mod(i7, i6)
- i23 = int_is_true(i22)
- i24 = int_and(i21, i23)
- i25 = int_sub(i18, i24)
- jump(i7, i25, i8)
- """
- preamble = """
- [i7, i6, i8]
- it1 = int_gt(i7, 0)
- guard_true(it1) []
- it2 = int_gt(i6, 0)
- guard_true(it2) []
- i15 = int_and(i8, i6)
- i17 = int_eq(i15, -1)
- guard_false(i17) []
- i18 = int_floordiv(i7, i6)
- i19 = int_xor(i7, i6)
- i22 = int_mod(i7, i6)
- i23 = int_is_true(i22)
- jump(i7, i18, i8)
- """
- expected = """
- [i7, i6, i8]
- it2 = int_gt(i6, 0)
- guard_true(it2) []
- i15 = int_and(i8, i6)
- i17 = int_eq(i15, -1)
- guard_false(i17) []
- i18 = int_floordiv(i7, i6)
- i19 = int_xor(i7, i6)
- i22 = int_mod(i7, i6)
- i23 = int_is_true(i22)
- jump(i7, i18, i8)
- """
- self.optimize_loop(ops, expected, preamble)
-
def test_division_to_rshift(self):
ops = """
[i1, i2]
- it = int_gt(i1, 0)
- guard_true(it)[]
- i3 = int_floordiv(i1, i2)
- i4 = int_floordiv(2, i2)
- i5 = int_floordiv(i1, 2)
- i6 = int_floordiv(3, i2)
- i7 = int_floordiv(i1, 3)
- i8 = int_floordiv(4, i2)
- i9 = int_floordiv(i1, 4)
- i10 = int_floordiv(i1, 0)
- i11 = int_floordiv(i1, 1)
- i12 = int_floordiv(i2, 2)
- i13 = int_floordiv(i2, 3)
- i14 = int_floordiv(i2, 4)
- jump(i5, i14)
+ i3 = call_pure_i(321, i1, i2, descr=int_py_div_descr)
+ i4 = call_pure_i(322, 2, i2, descr=int_py_div_descr)
+ i6 = call_pure_i(323, 3, i2, descr=int_py_div_descr)
+ i8 = call_pure_i(324, 4, i2, descr=int_py_div_descr)
+ i9b = call_pure_i(325, i1, -2, descr=int_py_div_descr)
+ i9c = call_pure_i(326, i1, -1, descr=int_py_div_descr)
+ i10 = call_pure_i(327, i1, 0, descr=int_py_div_descr)
+ i11 = call_pure_i(328, i1, 1, descr=int_py_div_descr)
+ i5 = call_pure_i(329, i1, 2, descr=int_py_div_descr)
+ i7 = call_pure_i(330, i1, 3, descr=int_py_div_descr)
+ i9 = call_pure_i(331, i1, 4, descr=int_py_div_descr)
+ i9d = call_pure_i(332, i1, 6, descr=int_py_div_descr)
+ jump(i5, i9)
"""
expected = """
[i1, i2]
- it = int_gt(i1, 0)
- guard_true(it)[]
- i3 = int_floordiv(i1, i2)
- i4 = int_floordiv(2, i2)
+ i3 = call_i(321, i1, i2, descr=int_py_div_descr)
+ i4 = call_i(322, 2, i2, descr=int_py_div_descr)
+ i6 = call_i(323, 3, i2, descr=int_py_div_descr)
+ i8 = call_i(324, 4, i2, descr=int_py_div_descr)
+ i9b = call_i(325, i1, -2, descr=int_py_div_descr)
+ i9c = call_i(326, i1, -1, descr=int_py_div_descr)
+ i10 = call_i(327, i1, 0, descr=int_py_div_descr)
+ # i11 = i1
i5 = int_rshift(i1, 1)
- i6 = int_floordiv(3, i2)
- i7 = int_floordiv(i1, 3)
- i8 = int_floordiv(4, i2)
+ i7 = call_i(330, i1, 3, descr=int_py_div_descr)
i9 = int_rshift(i1, 2)
- i10 = int_floordiv(i1, 0)
- i12 = int_floordiv(i2, 2)
- i13 = int_floordiv(i2, 3)
- i14 = int_floordiv(i2, 4)
- jump(i5, i14)
+ i9d = call_i(332, i1, 6, descr=int_py_div_descr)
+ jump(i5, i9)
"""
self.optimize_loop(ops, expected)
@@ -5475,7 +5422,7 @@
def test_int_div_1(self):
ops = """
[i0]
- i1 = int_floordiv(i0, 1)
+ i1 = call_pure_i(321, i0, 1, descr=int_py_div_descr)
jump(i1)
"""
expected = """
@@ -5484,48 +5431,16 @@
"""
self.optimize_loop(ops, expected)
- def test_division_nonneg(self):
- py.test.skip("harder")
- # this is how an app-level division turns into right now
- ops = """
- [i4]
- i1 = int_ge(i4, 0)
- guard_true(i1) []
- i16 = int_floordiv(i4, 3)
- i18 = int_mul(i16, 3)
- i19 = int_sub(i4, i18)
- i21 = int_rshift(i19, %d)
- i22 = int_add(i16, i21)
- finish(i22)
- """ % (LONG_BIT-1)
- expected = """
- [i4]
- i1 = int_ge(i4, 0)
- guard_true(i1) []
- i16 = int_floordiv(i4, 3)
- finish(i16)
- """
- self.optimize_loop(ops, expected)
-
- def test_division_by_2(self):
- py.test.skip("harder")
- ops = """
- [i4]
- i1 = int_ge(i4, 0)
- guard_true(i1) []
- i16 = int_floordiv(i4, 2)
- i18 = int_mul(i16, 2)
- i19 = int_sub(i4, i18)
- i21 = int_rshift(i19, %d)
- i22 = int_add(i16, i21)
- finish(i22)
- """ % (LONG_BIT-1)
- expected = """
- [i4]
- i1 = int_ge(i4, 0)
- guard_true(i1) []
- i16 = int_rshift(i4, 1)
- finish(i16)
+ ops = """
+ [i0]
+ i1 = call_pure_i(321, 0, i0, descr=int_py_div_descr)
+ escape_n(i1)
+ jump(i0)
+ """
+ expected = """
+ [i0]
+ escape_n(0)
+ jump(i0)
"""
self.optimize_loop(ops, expected)
@@ -5538,15 +5453,15 @@
guard_true(i2) []
# here, -50 <= i4 <= -40
- i5 = int_floordiv(i4, 30)
- # here, we know that that i5 == -1 (C-style handling of negatives!)
+ i5 = call_pure_i(321, i4, 30, descr=int_py_div_descr)
+ # here, we know that that i5 == -2 (Python-style handling of
negatives)
escape_n(i5)
jump(i4)
"""
expected = """
[i4, i5]
- escape_n(-1)
- jump(i4, -1)
+ escape_n(-2)
+ jump(i4, -2)
"""
self.optimize_loop(ops, expected)
@@ -6782,21 +6697,6 @@
# ----------
def optimize_strunicode_loop_extradescrs(self, ops, optops, preamble):
- class FakeCallInfoCollection:
- def callinfo_for_oopspec(self, oopspecindex):
- calldescrtype = type(LLtypeMixin.strequaldescr)
- effectinfotype =
type(LLtypeMixin.strequaldescr.get_extra_info())
- for value in LLtypeMixin.__dict__.values():
- if isinstance(value, calldescrtype):
- extra = value.get_extra_info()
- if (extra and isinstance(extra, effectinfotype) and
- extra.oopspecindex == oopspecindex):
- # returns 0 for 'func' in this test
- return value, 0
- raise AssertionError("not found: oopspecindex=%d" %
- oopspecindex)
- #
- self.callinfocollection = FakeCallInfoCollection()
self.optimize_strunicode_loop(ops, optops, preamble)
def test_str_equal_noop1(self):
diff --git a/rpython/jit/metainterp/optimizeopt/test/test_schedule.py
b/rpython/jit/metainterp/optimizeopt/test/test_schedule.py
--- a/rpython/jit/metainterp/optimizeopt/test/test_schedule.py
+++ b/rpython/jit/metainterp/optimizeopt/test/test_schedule.py
@@ -397,8 +397,8 @@
loop1 = self.parse_trace("""
i10 = int_and(255, i1)
i11 = int_and(255, i2)
- i12 = uint_floordiv(i10,1)
- i13 = uint_floordiv(i11,1)
+ i12 = call_pure_i(321, i10)
+ i13 = call_pure_i(321, i11)
i14 = int_and(i1, i12)
i15 = int_and(i2, i13)
""")
@@ -412,9 +412,9 @@
v4[2xi64] = vec_pack_i(v3[2xi64], i2, 1, 1)
v5[2xi64] = vec_int_and(v1[2xi64], v4[2xi64])
i10 = vec_unpack_i(v5[2xi64], 0, 1)
- i12 = uint_floordiv(i10,1)
+ i12 = call_pure_i(321, i10)
i11 = vec_unpack_i(v5[2xi64], 1, 1)
- i13 = uint_floordiv(i11,1)
+ i13 = call_pure_i(321, i11)
v6[0xi64] = vec_i()
v7[1xi64] = vec_pack_i(v6[2xi64], i12, 0, 1)
v8[2xi64] = vec_pack_i(v7[2xi64], i13, 1, 1)
diff --git a/rpython/jit/metainterp/optimizeopt/test/test_util.py
b/rpython/jit/metainterp/optimizeopt/test/test_util.py
--- a/rpython/jit/metainterp/optimizeopt/test/test_util.py
+++ b/rpython/jit/metainterp/optimizeopt/test/test_util.py
@@ -421,8 +421,43 @@
jvr_vtable_adr = llmemory.cast_ptr_to_adr(jit_virtual_ref_vtable)
vref_descr = cpu.sizeof(vrefinfo.JIT_VIRTUAL_REF, jit_virtual_ref_vtable)
+ FUNC = lltype.FuncType([lltype.Signed, lltype.Signed], lltype.Signed)
+ ei = EffectInfo([], [], [], [], [], [],
EffectInfo.EF_ELIDABLE_CANNOT_RAISE,
+ can_invalidate=False,
+ oopspecindex=EffectInfo.OS_INT_PY_DIV)
+ int_py_div_descr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, ei)
+ ei = EffectInfo([], [], [], [], [], [],
EffectInfo.EF_ELIDABLE_CANNOT_RAISE,
+ can_invalidate=False,
+ oopspecindex=EffectInfo.OS_INT_UDIV)
+ int_udiv_descr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, ei)
+ ei = EffectInfo([], [], [], [], [], [],
EffectInfo.EF_ELIDABLE_CANNOT_RAISE,
+ can_invalidate=False,
+ oopspecindex=EffectInfo.OS_INT_PY_MOD)
+ int_py_mod_descr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, ei)
+
namespace = locals()
+
+class FakeCallInfoCollection:
+ def callinfo_for_oopspec(self, oopspecindex):
+ calldescrtype = type(LLtypeMixin.strequaldescr)
+ effectinfotype = type(LLtypeMixin.strequaldescr.get_extra_info())
+ for value in LLtypeMixin.__dict__.values():
+ if isinstance(value, calldescrtype):
+ extra = value.get_extra_info()
+ if (extra and isinstance(extra, effectinfotype) and
+ extra.oopspecindex == oopspecindex):
+ # returns 0 for 'func' in this test
+ return value, 0
+ raise AssertionError("not found: oopspecindex=%d" %
+ oopspecindex)
+
+ calldescr_udiv = LLtypeMixin.int_udiv_descr
+ #calldescr_umod = LLtypeMixin.int_umod_descr
+
+LLtypeMixin.callinfocollection = FakeCallInfoCollection()
+
+
# ____________________________________________________________
diff --git a/rpython/jit/metainterp/optimizeopt/test/test_vecopt.py
b/rpython/jit/metainterp/optimizeopt/test/test_vecopt.py
--- a/rpython/jit/metainterp/optimizeopt/test/test_vecopt.py
+++ b/rpython/jit/metainterp/optimizeopt/test/test_vecopt.py
@@ -659,6 +659,7 @@
assert mref1.is_adjacent_after(mref5)
def test_array_memory_ref_div(self):
+ py.test.skip("XXX rewrite or kill this test for the new divisions")
ops = """
[p0,i0]
i1 = int_floordiv(i0,2)
@@ -724,7 +725,7 @@
ops = """
[p0,i0]
i1 = int_add(i0,4)
- i2 = int_floordiv(i1,2)
+ i2 = int_sub(i1,3) # XXX used to be "divide by 2", not sure about it
i3 = raw_load_i(p0,i2,descr=chararraydescr)
i4 = int_add(i0,2)
i5 = int_mul(i4,2)
diff --git a/rpython/jit/metainterp/pyjitpl.py
b/rpython/jit/metainterp/pyjitpl.py
--- a/rpython/jit/metainterp/pyjitpl.py
+++ b/rpython/jit/metainterp/pyjitpl.py
@@ -201,11 +201,10 @@
# ------------------------------
- for _opimpl in ['int_add', 'int_sub', 'int_mul', 'int_floordiv', 'int_mod',
+ for _opimpl in ['int_add', 'int_sub', 'int_mul',
'int_and', 'int_or', 'int_xor', 'int_signext',
'int_rshift', 'int_lshift', 'uint_rshift',
'uint_lt', 'uint_le', 'uint_gt', 'uint_ge',
- 'uint_floordiv',
'float_add', 'float_sub', 'float_mul', 'float_truediv',
'float_lt', 'float_le', 'float_eq',
'float_ne', 'float_gt', 'float_ge',
diff --git a/rpython/jit/metainterp/resoperation.py
b/rpython/jit/metainterp/resoperation.py
--- a/rpython/jit/metainterp/resoperation.py
+++ b/rpython/jit/metainterp/resoperation.py
@@ -955,9 +955,6 @@
'INT_ADD/2/i',
'INT_SUB/2/i',
'INT_MUL/2/i',
- 'INT_FLOORDIV/2/i',
- 'UINT_FLOORDIV/2/i',
- 'INT_MOD/2/i',
'INT_AND/2/i',
'INT_OR/2/i',
'INT_XOR/2/i',
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
@@ -586,7 +586,7 @@
def internfn(y):
return y * 3
def externfn(y):
- return y % 4
+ return y ^ 4
def f(y):
while y >= 0:
myjitdriver.can_enter_jit(y=y)
@@ -601,7 +601,7 @@
policy = StopAtXPolicy(externfn)
res = self.meta_interp(f, [31], policy=policy)
assert res == 42
- self.check_resops(int_mul=2, int_mod=0)
+ self.check_resops(int_mul=2, int_xor=0)
def test_we_are_jitted(self):
myjitdriver = JitDriver(greens = [], reds = ['y'])
@@ -936,10 +936,11 @@
myjitdriver.can_enter_jit(x=x, y=y, n=n)
myjitdriver.jit_merge_point(x=x, y=y, n=n)
n -= ovfcheck(x % y)
+ x += 1
return n
res = self.meta_interp(f, [20, 1, 2])
assert res == 0
- self.check_resops(call_i=0, call_r=0)
+ self.check_resops(call_i=2, int_eq=3, int_and=2)
def test_abs(self):
myjitdriver = JitDriver(greens = [], reds = ['i', 't'])
@@ -1133,7 +1134,7 @@
while n > 0:
mydriver.can_enter_jit(n=n, x=x)
mydriver.jit_merge_point(n=n, x=x)
- if n % 2 == 0:
+ if n & 1 == 0:
cls = A
else:
cls = B
@@ -1173,7 +1174,6 @@
def test_div_overflow(self):
import sys
- from rpython.rtyper.lltypesystem.lloperation import llop
myjitdriver = JitDriver(greens = [], reds = ['x', 'y', 'res'])
def f(x, y):
res = 0
@@ -1181,15 +1181,13 @@
myjitdriver.can_enter_jit(x=x, y=y, res=res)
myjitdriver.jit_merge_point(x=x, y=y, res=res)
try:
- res += llop.int_floordiv_ovf(lltype.Signed,
- -sys.maxint-1, x)
+ res += ovfcheck((-sys.maxint-1) // x)
x += 5
except OverflowError:
res += 100
y -= 1
return res
- res = self.meta_interp(f, [-41, 16])
- assert res == ((-sys.maxint-1) // (-41) +
+ expected = ((-sys.maxint-1) // (-41) +
(-sys.maxint-1) // (-36) +
(-sys.maxint-1) // (-31) +
(-sys.maxint-1) // (-26) +
@@ -1198,10 +1196,12 @@
(-sys.maxint-1) // (-11) +
(-sys.maxint-1) // (-6) +
100 * 8)
+ assert f(-41, 16) == expected
+ res = self.meta_interp(f, [-41, 16])
+ assert res == expected
def test_overflow_fold_if_divisor_constant(self):
import sys
- from rpython.rtyper.lltypesystem.lloperation import llop
myjitdriver = JitDriver(greens = [], reds = ['x', 'y', 'res'])
def f(x, y):
res = 0
@@ -1209,10 +1209,8 @@
myjitdriver.can_enter_jit(x=x, y=y, res=res)
myjitdriver.jit_merge_point(x=x, y=y, res=res)
try:
- res += llop.int_floordiv_ovf(lltype.Signed,
- x, 2)
- res += llop.int_mod_ovf(lltype.Signed,
- x, 2)
+ res += ovfcheck(x // 2)
+ res += ovfcheck(x % 2)
x += 5
except OverflowError:
res += 100
@@ -1312,7 +1310,6 @@
def test_free_object(self):
import weakref
- from rpython.rtyper.lltypesystem.lloperation import llop
myjitdriver = JitDriver(greens = [], reds = ['n', 'x'])
class X(object):
pass
@@ -3824,7 +3821,6 @@
self.check_operations_history(guard_class=0, record_exact_class=1)
def test_give_class_knowledge_to_tracer_explicitly(self):
- from rpython.rtyper.lltypesystem.lloperation import llop
class Base(object):
def f(self):
raise NotImplementedError
diff --git a/rpython/jit/metainterp/test/test_dict.py
b/rpython/jit/metainterp/test/test_dict.py
--- a/rpython/jit/metainterp/test/test_dict.py
+++ b/rpython/jit/metainterp/test/test_dict.py
@@ -99,9 +99,9 @@
py.test.skip("this is an r_dict test")
myjitdriver = JitDriver(greens = [], reds = ['total', 'dct'])
def key(x):
- return x % 2
+ return x & 1
def eq(x, y):
- return (x % 2) == (y % 2)
+ return (x & 1) == (y & 1)
def f(n):
dct = objectmodel.r_dict(eq, key)
@@ -117,7 +117,7 @@
res1 = f(100)
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit