[pypy-commit] pypy remove-raisingops: Remove divisions and modulos from regular JIT operations, uses oopspec

arigo pypy.commits at gmail.com
Tue May 10 12:31:37 EDT 2016


Author: Armin Rigo <arigo at tunes.org>
Branch: remove-raisingops
Changeset: r84351:1ad01ba1173b
Date: 2016-05-10 18:31 +0200
http://bitbucket.org/pypy/pypy/changeset/1ad01ba1173b/

Log:	Remove divisions and modulos from regular JIT operations, uses
	oopspec calls

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
@@ -26,6 +26,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
@@ -1903,15 +1903,19 @@
         self.callcontrol.callinfocollection.add(oopspecindex, calldescr, func)
 
     def _handle_int_ovf(self, op, oopspec_name, args):
-        assert oopspec_name in ('int.add_ovf', 'int.sub_ovf', 'int.mul_ovf',
-                                'int.py_div', 'int.py_mod')
-        op0 = SpaceOperation(oopspec_name.replace('.', '_'), args, op.result)
-        if oopspec_name in ('int.add_ovf', 'int.mul_ovf'):
-            op0 = self._rewrite_symmetric(op0)
-        oplist = [op0]
-        if oopspec_name.endswith('_ovf'):
-            oplist.insert(0, SpaceOperation('-live-', [], None))
-        return oplist
+        opname = oopspec_name.replace('.', '_')
+        if oopspec_name in ('int.add_ovf', 'int.sub_ovf', 'int.mul_ovf'):
+            op0 = SpaceOperation(opname, args, op.result)
+            if oopspec_name in ('int.add_ovf', 'int.mul_ovf'):
+                op0 = self._rewrite_symmetric(op0)
+            oplist = [op0]
+            if oopspec_name.endswith('_ovf'):
+                oplist.insert(0, SpaceOperation('-live-', [], None))
+            return oplist
+        else:
+            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)
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:]]
@@ -273,7 +277,7 @@
     v3 = varoftype(lltype.Signed)
     for v1 in [varoftype(lltype.Signed), const(42)]:
         for v2 in [varoftype(lltype.Signed), const(43)]:
-            op = SpaceOperation('foobar', [v1, v2], v3)
+            op = SpaceOperation('direct_call', [Constant(opname), v1, v2], v3)
             oplist = Transformer(FakeCPU())._handle_int_ovf(op, 'int.'+opname,
                                                             [v1, v2])
             op1, op0 = oplist
@@ -293,7 +297,7 @@
     v3 = varoftype(lltype.Signed)
     for v1 in [varoftype(lltype.Signed), const(42)]:
         for v2 in [varoftype(lltype.Signed), const(43)]:
-            op = SpaceOperation('foobar', [v1, v2], v3)
+            op = SpaceOperation('direct_call', [Constant(opname), v1, v2], v3)
             oplist = Transformer(FakeCPU())._handle_int_ovf(op, 'int.'+opname,
                                                             [v1, v2])
             op1, op0 = oplist
@@ -304,18 +308,19 @@
             assert op1.args == []
             assert op1.result is None
 
- at py.test.mark.parametrize('opname', ['py_div', 'py_mod'])
-def test_asymmetric_op_nonovf(opname):
+ at py.test.mark.parametrize('opname', ['py_div', 'udiv', 'py_mod', 'umod'])
+def test_asymmetric_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('foobar', [v1, v2], v3)
-            oplist = Transformer(FakeCPU())._handle_int_ovf(op, 'int.'+opname,
-                                                            [v1, v2])
-            [op0] = oplist
-            assert op0.opname == 'int_'+opname
-            assert op0.args == [v1, v2]
-            assert op0.result == v3
+            op = SpaceOperation('direct_call', [Constant(opname), v1, v2], v3)
+            op0 = tr._handle_int_ovf(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(
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,11 +955,6 @@
     'INT_ADD/2/i',
     'INT_SUB/2/i',
     'INT_MUL/2/i',
-    'INT_C_DIV/2/i',      # C-style handling of negatives (backend only)
-    'INT_PY_DIV/2/i',     # Python-style handling of negatives (frontend)
-    'UINT_FLOORDIV/2/i',
-    'INT_C_MOD/2/i',      # C-style handling of negatives (backend only)
-    'INT_PY_MOD/2/i',     # Python-style handling of negatives (frontend)
     'INT_AND/2/i',
     'INT_OR/2/i',
     'INT_XOR/2/i',
diff --git a/rpython/rtyper/rint.py b/rpython/rtyper/rint.py
--- a/rpython/rtyper/rint.py
+++ b/rpython/rtyper/rint.py
@@ -307,8 +307,7 @@
     """Write a simple operation implementing the given 'func'.
     It must be an operation that cannot raise.
     """
-    if '_ovf' in func or (func.startswith(('mod', 'floordiv'))
-                              and not hop.s_result.unsigned):
+    if '_ovf' in func or func.startswith(('mod', 'floordiv')):
         raise TyperError("%r should not be used here any more" % (func,))
 
     r_result = hop.r_result
@@ -351,8 +350,6 @@
     if not any_implicit_exception:
         if not func.startswith(('mod', 'floordiv')):
             return _rtype_template(hop, func)
-        if hop.s_result.unsigned:
-            return _rtype_template(hop, func)
 
     repr = hop.r_result
     assert repr.lowleveltype != Bool
@@ -399,11 +396,6 @@
         raise ZeroDivisionError("integer division")
     return ll_int_floordiv(x, y)
 
-def ll_uint_floordiv_zer(x, y):
-    if y == 0:
-        raise ZeroDivisionError("unsigned integer division")
-    return llop.uint_floordiv(Unsigned, x, y)
-
 def ll_int_floordiv_ovf(x, y):
     # JIT: intentionally not short-circuited to produce only one guard
     # and to remove the check fully if one of the arguments is known
@@ -416,23 +408,44 @@
         raise ZeroDivisionError("integer division")
     return ll_int_floordiv_ovf(x, y)
 
-def ll_llong_floordiv(x, y):
-    r = llop.llong_floordiv(SignedLongLong, x, y)  # <= truncates like in C
-    p = r * y
-    if y < 0: u = p - x
-    else:     u = x - p
-    return r + (u >> LLONG_BITS_1)
+ at jit.oopspec("int.udiv(x, y)")
+def ll_uint_floordiv(x, y):
+    return llop.uint_floordiv(Unsigned, x, y)
 
-def ll_llong_floordiv_zer(x, y):
+def ll_uint_floordiv_zer(x, y):
     if y == 0:
-        raise ZeroDivisionError("longlong division")
-    return ll_llong_floordiv(x, y)
+        raise ZeroDivisionError("unsigned integer division")
+    return ll_uint_floordiv(x, y)
 
-def ll_ullong_floordiv_zer(x, y):
-    if y == 0:
-        raise ZeroDivisionError("unsigned longlong division")
-    return llop.ullong_floordiv(UnsignedLongLong, x, y)
+if SignedLongLong == Signed:
+    ll_llong_floordiv      = ll_int_floordiv
+    ll_llong_floordiv_zer  = ll_int_floordiv_zer
+    ll_ullong_floordiv     = ll_uint_floordiv
+    ll_ullong_floordiv_zer = ll_uint_floordiv_zer
+else:
+    @jit.dont_look_inside
+    def ll_llong_floordiv(x, y):
+        r = llop.llong_floordiv(SignedLongLong, x, y)  # <= truncates like in C
+        p = r * y
+        if y < 0: u = p - x
+        else:     u = x - p
+        return r + (u >> LLONG_BITS_1)
 
+    def ll_llong_floordiv_zer(x, y):
+        if y == 0:
+            raise ZeroDivisionError("longlong division")
+        return ll_llong_floordiv(x, y)
+
+    @jit.dont_look_inside
+    def ll_ullong_floordiv(x, y):
+        return llop.ullong_floordiv(UnsignedLongLong, x, y)
+
+    def ll_ullong_floordiv_zer(x, y):
+        if y == 0:
+            raise ZeroDivisionError("unsigned longlong division")
+        return ll_ullong_floordiv(x, y)
+
+ at jit.dont_look_inside
 def ll_lllong_floordiv(x, y):
     r = llop.lllong_floordiv(SignedLongLongLong, x, y) # <= truncates like in C
     p = r * y
@@ -460,11 +473,6 @@
         raise ZeroDivisionError
     return ll_int_mod(x, y)
 
-def ll_uint_mod_zer(x, y):
-    if y == 0:
-        raise ZeroDivisionError
-    return llop.uint_mod(Unsigned, x, y)
-
 def ll_int_mod_ovf(x, y):
     # see comment in ll_int_floordiv_ovf
     if (x == -sys.maxint - 1) & (y == -1):
@@ -476,22 +484,43 @@
         raise ZeroDivisionError
     return ll_int_mod_ovf(x, y)
 
-def ll_llong_mod(x, y):
-    r = llop.llong_mod(SignedLongLong, x, y)       # <= truncates like in C
-    if y < 0: u = -r
-    else:     u = r
-    return r + (y & (u >> LLONG_BITS_1))
+ at jit.oopspec("int.umod(x, y)")
+def ll_uint_mod(x, y):
+    return llop.uint_mod(Unsigned, x, y)
 
-def ll_llong_mod_zer(x, y):
+def ll_uint_mod_zer(x, y):
     if y == 0:
         raise ZeroDivisionError
-    return ll_llong_mod(x, y)
+    return ll_uint_mod(x, y)
 
-def ll_ullong_mod_zer(x, y):
-    if y == 0:
-        raise ZeroDivisionError
-    return llop.ullong_mod(UnsignedLongLong, x, y)
+if SignedLongLong == Signed:
+    ll_llong_mod      = ll_int_mod
+    ll_llong_mod_zer  = ll_int_mod_zer
+    ll_ullong_mod     = ll_uint_mod
+    ll_ullong_mod_zer = ll_uint_mod_zer
+else:
+    @jit.dont_look_inside
+    def ll_llong_mod(x, y):
+        r = llop.llong_mod(SignedLongLong, x, y)    # <= truncates like in C
+        if y < 0: u = -r
+        else:     u = r
+        return r + (y & (u >> LLONG_BITS_1))
 
+    def ll_llong_mod_zer(x, y):
+        if y == 0:
+            raise ZeroDivisionError
+        return ll_llong_mod(x, y)
+
+    @jit.dont_look_inside
+    def ll_ullong_mod(x, y):
+        return llop.ullong_mod(UnsignedLongLong, x, y)
+
+    def ll_ullong_mod_zer(x, y):
+        if y == 0:
+            raise ZeroDivisionError
+        return llop.ullong_mod(UnsignedLongLong, x, y)
+
+ at jit.dont_look_inside
 def ll_lllong_mod(x, y):
     r = llop.lllong_mod(SignedLongLongLong, x, y)  # <= truncates like in C
     if y < 0: u = -r


More information about the pypy-commit mailing list