Author: Armin Rigo <[email protected]>
Branch: 
Changeset: r84740:6a21d9bbc8ad
Date: 2016-05-27 22:51 +0200
http://bitbucket.org/pypy/pypy/changeset/6a21d9bbc8ad/

Log:    hg merge remove-raisingops (again)

        optimize in the JIT divisions by constants

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
@@ -49,7 +49,8 @@
             while a < 300:
                 res1 = a/b     # ID: div
                 res2 = a/2     # ID: shift
-                res += res1 + res2
+                res3 = a/11    # ID: mul
+                res += res1 + res2 + res3
                 a += 1
             return res
         #
@@ -65,6 +66,17 @@
         assert loop.match_by_id('shift', """
             i1 = int_rshift(i2, 1)
         """)
+        if sys.maxint > 2**32:
+            args = (63, -5030930201920786804, 3)
+        else:
+            args = (31, -1171354717, 3)
+        assert loop.match_by_id('mul', """
+            i2 = int_rshift(i1, %d)
+            i3 = int_xor(i1, i2)
+            i4 = uint_mul_high(i3, %d)
+            i5 = uint_rshift(i4, %d)
+            i6 = int_xor(i5, i2)
+        """ % args)
 
     def test_division_to_rshift_allcases(self):
         """
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
@@ -92,6 +92,11 @@
         self.mc.MUL(res.value, reg1.value, reg2.value)
         return fcond
 
+    def emit_op_uint_mul_high(self, op, arglocs, regalloc, fcond):
+        reg1, reg2, res = arglocs
+        self.mc.UMULL(r.ip.value, res.value, reg1.value, reg2.value)
+        return fcond
+
     def emit_op_int_force_ge_zero(self, op, arglocs, regalloc, fcond):
         arg, res = arglocs
         self.mc.CMP_ri(arg.value, 0)
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
@@ -467,6 +467,8 @@
         self.possibly_free_var(op)
         return [reg1, reg2, res]
 
+    prepare_op_uint_mul_high = prepare_op_int_mul
+
     def prepare_op_int_force_ge_zero(self, op, fcond):
         argloc = self.make_sure_var_in_reg(op.getarg(0))
         resloc = self.force_allocate_reg(op, [op.getarg(0)])
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
@@ -62,6 +62,12 @@
         else:
             self.mc.mulld(res.value, l0.value, l1.value)
 
+    def emit_uint_mul_high(self, op, arglocs, regalloc):
+        l0, l1, res = arglocs
+        assert not l0.is_imm()
+        assert not l1.is_imm()
+        self.mc.mulhdu(res.value, l0.value, l1.value)
+
     def do_emit_int_binary_ovf(self, op, arglocs):
         l0, l1, res = arglocs[0], arglocs[1], arglocs[2]
         self.mc.load_imm(r.SCRATCH, 0)
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
@@ -438,6 +438,7 @@
     prepare_int_lshift = helper.prepare_binary_op
     prepare_int_rshift = helper.prepare_binary_op
     prepare_uint_rshift = helper.prepare_binary_op
+    prepare_uint_mul_high = 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
@@ -532,6 +532,7 @@
             rop.INT_AND,
             rop.INT_OR,
             rop.INT_XOR,
+            rop.UINT_MUL_HIGH,
             ]:
     OPERATIONS.append(BinaryOperation(_op))
 
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
@@ -1289,6 +1289,9 @@
     genop_float_mul = _binaryop('MULSD')
     genop_float_truediv = _binaryop('DIVSD')
 
+    def genop_uint_mul_high(self, op, arglocs, result_loc):
+        self.mc.MUL(arglocs[0])
+
     def genop_int_and(self, op, arglocs, result_loc):
         arg1 = arglocs[1]
         if IS_X86_64 and (isinstance(arg1, ImmedLoc) and
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
@@ -561,6 +561,27 @@
     consider_int_sub_ovf = _consider_binop
     consider_int_add_ovf = _consider_binop_symm
 
+    def consider_uint_mul_high(self, op):
+        arg1, arg2 = op.getarglist()
+        # should support all cases, but is optimized for (box, const)
+        if isinstance(arg1, Const):
+            arg1, arg2 = arg2, arg1
+        self.rm.make_sure_var_in_reg(arg2, selected_reg=eax)
+        l1 = self.loc(arg1)
+        # l1 is a register != eax, or stack_bp; or, just possibly, it
+        # can be == eax if arg1 is arg2
+        assert not isinstance(l1, ImmedLoc)
+        assert l1 is not eax or arg1 is arg2
+        #
+        # eax will be trash after the operation
+        self.rm.possibly_free_var(arg2)
+        tmpvar = TempVar()
+        self.rm.force_allocate_reg(tmpvar, selected_reg=eax)
+        self.rm.possibly_free_var(tmpvar)
+        #
+        self.rm.force_allocate_reg(op, selected_reg=edx)
+        self.perform(op, [l1], edx)
+
     def consider_int_neg(self, op):
         res = self.rm.force_result_in_reg(op, op.getarg(0))
         self.perform(op, [res], res)
diff --git a/rpython/jit/backend/x86/regloc.py 
b/rpython/jit/backend/x86/regloc.py
--- a/rpython/jit/backend/x86/regloc.py
+++ b/rpython/jit/backend/x86/regloc.py
@@ -641,6 +641,7 @@
     SUB = _binaryop('SUB')
     IMUL = _binaryop('IMUL')
     NEG = _unaryop('NEG')
+    MUL = _unaryop('MUL')
 
     CMP = _binaryop('CMP')
     CMP16 = _binaryop('CMP16')
diff --git a/rpython/jit/backend/x86/rx86.py b/rpython/jit/backend/x86/rx86.py
--- a/rpython/jit/backend/x86/rx86.py
+++ b/rpython/jit/backend/x86/rx86.py
@@ -558,6 +558,9 @@
     DIV_r = insn(rex_w, '\xF7', register(1), '\xF0')
     IDIV_r = insn(rex_w, '\xF7', register(1), '\xF8')
 
+    MUL_r = insn(rex_w, '\xF7', orbyte(4<<3), register(1), '\xC0')
+    MUL_b = insn(rex_w, '\xF7', orbyte(4<<3), stack_bp(1))
+
     IMUL_rr = insn(rex_w, '\x0F\xAF', register(1, 8), register(2), '\xC0')
     IMUL_rb = insn(rex_w, '\x0F\xAF', register(1, 8), stack_bp(2))
 
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
@@ -408,6 +408,14 @@
     def bhimpl_int_mul(a, b):
         return intmask(a * b)
 
+    @arguments("i", "i", returns="i")
+    def bhimpl_uint_mul_high(a, b):
+        from rpython.jit.metainterp.optimizeopt import intdiv
+        a = r_uint(a)
+        b = r_uint(b)
+        c = intdiv.unsigned_mul_high(a, b)
+        return intmask(c)
+
     @arguments("L", "i", "i", returns="iL")
     def bhimpl_int_add_jump_if_ovf(label, a, b):
         try:
diff --git a/rpython/jit/metainterp/optimizeopt/intdiv.py 
b/rpython/jit/metainterp/optimizeopt/intdiv.py
new file mode 100644
--- /dev/null
+++ b/rpython/jit/metainterp/optimizeopt/intdiv.py
@@ -0,0 +1,115 @@
+from rpython.rlib.rarithmetic import LONG_BIT, intmask, r_uint
+from rpython.rlib.rbigint import rbigint, ONERBIGINT
+
+from rpython.jit.metainterp.history import ConstInt
+from rpython.jit.metainterp.resoperation import ResOperation, rop
+
+
+# Logic to replace the signed integer division by a constant
+# by a few operations involving a UINT_MUL_HIGH.
+
+
+def magic_numbers(m):
+    assert m == intmask(m)
+    assert m & (m-1) != 0    # not a power of two
+    assert m >= 3
+    i = 1
+    while (r_uint(1) << (i+1)) < r_uint(m):
+        i += 1
+
+    # k = 2**(64+i) // m + 1, computed manually using rbigint
+    #                         because that's the easiest
+    k1 = ONERBIGINT.lshift(LONG_BIT + i).floordiv(rbigint.fromint(m))
+    k = k1.touint() + r_uint(1)
+
+    assert k != r_uint(0)
+    # Proof that k < 2**64 holds in all cases, even with the "+1":
+    #
+    # starting point: 2**i < m < 2**(i+1)  with i <= 63
+    # 2**i < m
+    # 2**i <= m - (2.0**(i-63))  as real number, because (2.0**(i-63))<=1.0
+    # 2**(64+i) <= 2**64 * m - 2**(i+1)   as integers again
+    # 2**(64+i) < 2**64 * m - m
+    # 2**(64+i) / float(m) < 2**64-1    real numbers division
+    # 2**(64+i) // m < 2**64-1    with the integer division
+    #       k        < 2**64
+
+    assert k > (r_uint(1) << (LONG_BIT-1))
+
+    return (k, i)
+
+
+def division_operations(n_box, m, known_nonneg=False):
+    kk, ii = magic_numbers(m)
+
+    # Turn the division into:
+    #     t = n >> 63            # t == 0 or t == -1
+    #     return (((n^t) * k) >> (64 + i)) ^ t
+
+    # Proof that this gives exactly a = n // m = floor(q), where q
+    # is the real number quotient:
+    #
+    # case t == 0, i.e. 0 <= n < 2**63
+    #
+    #     a <= q <= a + (m-1)/m     (we use '/' for the real quotient here)
+    #    
+    #     n * k == n * (2**(64+i) // m + 1)
+    #           == n * ceil(2**(64+i) / m)
+    #           == n * (2**(64+i) / m + ferr)         for 0 < ferr < 1
+    #           == q * 2**(64+i) + err                for 0 < err < n
+    #           <  q * 2**(64+i) + n
+    #           <= (a + (m-1)/m) * 2**(64+i) + n
+    #           == 2**(64+i) * (a + extra)            for 0 <= extra < ?
+    #    
+    #     extra == (m-1)/m + (n / 2**(64+i))
+    #    
+    #     but  n < 2**63 < 2**(64+i)/m  because  m < 2**(i+1)
+    #    
+    #     extra < (m-1)/m + 1/m
+    #     extra < 1.
+    #
+    # case t == -1, i.e. -2**63 <= n <= -1
+    #
+    #     (note that n^(-1) == ~n)
+    #     0 <= ~n < 2**63
+    #     by the previous case we get an answer a == (~n) // m
+    #     ~a == n // m    because it's a division truncating towards -inf.
+
+    if not known_nonneg:
+        t_box = ResOperation(rop.INT_RSHIFT, [n_box, ConstInt(LONG_BIT - 1)])
+        nt_box = ResOperation(rop.INT_XOR, [n_box, t_box])
+    else:
+        t_box = None
+        nt_box = n_box
+    mul_box = ResOperation(rop.UINT_MUL_HIGH, [nt_box, ConstInt(intmask(kk))])
+    sh_box = ResOperation(rop.UINT_RSHIFT, [mul_box, ConstInt(ii)])
+    if not known_nonneg:
+        final_box = ResOperation(rop.INT_XOR, [sh_box, t_box])
+        return [t_box, nt_box, mul_box, sh_box, final_box]
+    else:
+        return [mul_box, sh_box]
+
+
+def unsigned_mul_high(a, b):
+    DIGIT = LONG_BIT / 2
+    MASK = (1 << DIGIT) - 1
+
+    ah = a >> DIGIT
+    al = a & MASK
+    bh = b >> DIGIT
+    bl = b & MASK
+
+    rll = al * bl; assert rll == r_uint(rll)
+    rlh = al * bh; assert rlh == r_uint(rlh)
+    rhl = ah * bl; assert rhl == r_uint(rhl)
+    rhh = ah * bh; assert rhh == r_uint(rhh)
+
+    r1 = (rll >> DIGIT) + rhl
+    assert r1 == r_uint(r1)
+
+    r1 = r_uint(r1)
+    r2 = r_uint(r1 + rlh)
+    borrow = r_uint(r2 < r1) << DIGIT
+
+    r3 = (r2 >> DIGIT) + borrow + r_uint(rhh)
+    return r3
diff --git a/rpython/jit/metainterp/optimizeopt/optimizer.py 
b/rpython/jit/metainterp/optimizeopt/optimizer.py
--- a/rpython/jit/metainterp/optimizeopt/optimizer.py
+++ b/rpython/jit/metainterp/optimizeopt/optimizer.py
@@ -5,7 +5,7 @@
      ConstIntBound, MININT, MAXINT, IntUnbounded
 from rpython.jit.metainterp.optimizeopt.util import make_dispatcher_method
 from rpython.jit.metainterp.resoperation import rop, AbstractResOp, 
GuardResOp,\
-     OpHelpers, ResOperation
+     OpHelpers
 from rpython.jit.metainterp.optimizeopt import info
 from rpython.jit.metainterp.optimize import InvalidLoop
 from rpython.jit.metainterp.typesystem import llhelper
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
@@ -700,19 +700,31 @@
             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 == 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=[arg1, ConstInt(highest_bit(val))],
-                            descr=DONT_CHANGE)  # <- xxx rename? means "kill"
-        self.emit_operation(op)
-        return True
+        if not b2.is_constant():
+            return False
+        val = b2.getint()
+        if val <= 0:
+            return False
+        if val == 1:
+            self.make_equal_to(op, arg1)
+            self.last_emitted_operation = REMOVED
+            return True
+        elif 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=[arg1, ConstInt(highest_bit(val))],
+                        descr=DONT_CHANGE)  # <- xxx rename? means "kill"
+            self.optimizer.send_extra_operation(op)
+            return True
+        else:
+            from rpython.jit.metainterp.optimizeopt import intdiv
+            known_nonneg = b1.known_ge(IntBound(0, 0))
+            operations = intdiv.division_operations(arg1, val, known_nonneg)
+            newop = None
+            for newop in operations:
+                self.optimizer.send_extra_operation(newop)
+            self.make_equal_to(op, newop)
+            return True
 
     def optimize_CAST_PTR_TO_INT(self, op):
         self.optimizer.pure_reverse(op)
diff --git a/rpython/jit/metainterp/optimizeopt/test/test_intdiv.py 
b/rpython/jit/metainterp/optimizeopt/test/test_intdiv.py
new file mode 100644
--- /dev/null
+++ b/rpython/jit/metainterp/optimizeopt/test/test_intdiv.py
@@ -0,0 +1,48 @@
+import sys
+import py
+from hypothesis import given, strategies
+
+from rpython.jit.metainterp.optimizeopt.intdiv import magic_numbers, LONG_BIT
+from rpython.jit.metainterp.optimizeopt.intdiv import division_operations
+from rpython.jit.metainterp.optimizeopt.intdiv import unsigned_mul_high
+from rpython.jit.metainterp.history import ConstInt
+from rpython.jit.metainterp.resoperation import InputArgInt
+from rpython.jit.metainterp.executor import execute
+
+not_power_of_two = (strategies.integers(min_value=3, max_value=sys.maxint)
+                    .filter(lambda m: (m & (m - 1)) != 0))
+
+
+@given(strategies.integers(min_value=0, max_value=sys.maxint),
+       not_power_of_two)
+def test_magic_numbers(n, m):
+    k, i = magic_numbers(m)
+    k = int(k)    # and no longer r_uint, with wrap-around semantics
+    a = (n * k) >> (LONG_BIT + i)
+    assert a == n // m
+
+
+@given(strategies.integers(min_value=0, max_value=2*sys.maxint+1),
+       strategies.integers(min_value=0, max_value=2*sys.maxint+1))
+def test_unsigned_mul_high(a, b):
+    c = unsigned_mul_high(a, b)
+    assert c == ((a * b) >> LONG_BIT)
+
+
+@given(strategies.integers(min_value=-sys.maxint-1, max_value=sys.maxint),
+       not_power_of_two,
+       strategies.booleans())
+def test_division_operations(n, m, known_nonneg):
+    if n < 0:
+        known_nonneg = False
+    n_box = InputArgInt()
+    ops = division_operations(n_box, m, known_nonneg)
+
+    constants = {n_box: ConstInt(n)}
+    for op in ops:
+        argboxes = op.getarglist()
+        constantboxes = [constants.get(box, box) for box in argboxes]
+        res = execute(None, None, op.getopnum(), None, *constantboxes)
+        constants[op] = ConstInt(res)
+
+    assert constants[op].getint() == n // m
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
@@ -4640,17 +4640,21 @@
 
     def test_intdiv_bounds(self):
         ops = """
-        [i0]
-        i2 = call_pure_i(321, i0, 3, descr=int_py_div_descr)
+        [i0, i1]
+        i4 = int_ge(i1, 3)
+        guard_true(i4) []
+        i2 = call_pure_i(321, i0, i1, 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)
+        jump(i3, i1)
+        """
+        expected = """
+        [i0, i1]
+        i4 = int_ge(i1, 3)
+        guard_true(i4) []
+        i2 = call_i(321, i0, i1, descr=int_py_div_descr)
         i3 = int_add(i2, 50)
-        jump(i3)
+        jump(i3, i1)
         """
         self.optimize_loop(ops, expected)
 
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
@@ -1,5 +1,6 @@
 import py, sys
 from rpython.rlib.objectmodel import instantiate
+from rpython.rlib.rarithmetic import intmask
 from rpython.rtyper.lltypesystem import lltype
 from rpython.jit.metainterp import compile, resume
 from rpython.jit.metainterp.history import AbstractDescr, ConstInt, TreeLoop
@@ -5327,9 +5328,7 @@
         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 = """
@@ -5343,13 +5342,50 @@
         i10 = call_i(327, i1, 0, descr=int_py_div_descr)
         # i11 = i1
         i5 = int_rshift(i1, 1)
-        i7 = call_i(330, i1, 3, descr=int_py_div_descr)
         i9 = int_rshift(i1, 2)
-        i9d = call_i(332, i1, 6, descr=int_py_div_descr)
         jump(i5, i9)
         """
         self.optimize_loop(ops, expected)
 
+    def test_division_to_mul_high_nonneg(self):
+        from rpython.jit.metainterp.optimizeopt.intdiv import magic_numbers
+        for divisor in [3, 5, 12]:
+            kk, ii = magic_numbers(divisor)
+            ops = """
+            [i1]
+            i3 = int_ge(i1, 0)
+            guard_true(i3) []
+            i2 = call_pure_i(321, i1, %d, descr=int_py_div_descr)
+            jump(i2)
+            """ % divisor
+            expected = """
+            [i1]
+            i4 = uint_mul_high(i1, %d)
+            i2 = uint_rshift(i4, %d)
+            jump(i2)
+            """ % (intmask(kk), ii)
+            self.optimize_loop(ops, expected)
+
+    def test_division_to_mul_high(self):
+        from rpython.jit.metainterp.optimizeopt.intdiv import magic_numbers
+        for divisor in [3, 5, 12]:
+            kk, ii = magic_numbers(divisor)
+            ops = """
+            [i1]
+            i2 = call_pure_i(321, i1, %d, descr=int_py_div_descr)
+            jump(i2)
+            """ % divisor
+            expected = """
+            [i1]
+            i3 = int_rshift(i1, %d)
+            i4 = int_xor(i1, i3)
+            i5 = uint_mul_high(i4, %d)
+            i6 = uint_rshift(i5, %d)
+            i2 = int_xor(i6, i3)
+            jump(i2)
+            """ % (63 if sys.maxint > 2**32 else 31, intmask(kk), ii)
+            self.optimize_loop(ops, expected)
+
     def test_mul_to_lshift(self):
         ops = """
         [i1, i2]
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,6 +955,7 @@
     'INT_ADD/2/i',
     'INT_SUB/2/i',
     'INT_MUL/2/i',
+    'UINT_MUL_HIGH/2/i',       # a * b as a double-word, keep the high word
     'INT_AND/2/i',
     'INT_OR/2/i',
     'INT_XOR/2/i',
diff --git a/rpython/jit/metainterp/test/test_executor.py 
b/rpython/jit/metainterp/test/test_executor.py
--- a/rpython/jit/metainterp/test/test_executor.py
+++ b/rpython/jit/metainterp/test/test_executor.py
@@ -158,6 +158,10 @@
         (rop.UINT_RSHIFT, [(-1, 4, intmask(r_uint(-1) >> r_uint(4))),
                            ( 1, 4, intmask(r_uint(1) >> r_uint(4))),
                            ( 3, 3, 0)]),
+        (rop.UINT_MUL_HIGH, [(5, 6, 0),
+                             (0xffff, 0xffff, 0),
+                             (-1, -1, -2),
+                             (-1, 123, 122)]),
         ]:
         for x, y, z in testcases:
             yield opnum, [x, y], z
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to