Author: Armin Rigo <ar...@tunes.org> 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 +@jit.dont_look_inside +def _int_floordiv(n, m): + return llop.int_floordiv(lltype.Signed, n, m) + +@jit.dont_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(): +@py.test.mark.parametrize('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 + +@py.test.mark.parametrize('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 pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit