Author: Armin Rigo <ar...@tunes.org>
Branch: remove-raisingops
Changeset: r83916:90b064ce2c83
Date: 2016-04-26 18:49 +0200
http://bitbucket.org/pypy/pypy/changeset/90b064ce2c83/

Log:    Port the logic to rint.py

diff --git a/rpython/rtyper/raisingops.py b/rpython/rtyper/raisingops.py
deleted file mode 100644
--- a/rpython/rtyper/raisingops.py
+++ /dev/null
@@ -1,295 +0,0 @@
-import sys
-from rpython.rlib.rarithmetic import r_longlong, r_uint, intmask
-from rpython.rtyper.lltypesystem.lloperation import llop
-from rpython.rtyper.lltypesystem.lltype import Signed, SignedLongLong, \
-                                        UnsignedLongLong
-
-#XXX original SIGNED_RIGHT_SHIFT_ZERO_FILLS not taken into account
-#XXX assuming HAVE_LONG_LONG (int_mul_ovf)
-#XXX should int_mod and int_floordiv return an intmask(...) instead?
-
-LONG_MAX = sys.maxint
-LONG_MIN = -sys.maxint-1
-
-LLONG_MAX = r_longlong(2 ** (r_longlong.BITS-1) - 1)
-LLONG_MIN = -LLONG_MAX-1
-
-def int_floordiv_zer(x, y):
-    '''#define OP_INT_FLOORDIV_ZER(x,y,r,err) \
-        if ((y)) { OP_INT_FLOORDIV(x,y,r,err); } \
-        else FAIL_ZER(err, "integer division")
-    '''
-    if y:
-        return llop.int_floordiv(Signed, x, y)
-    else:
-        raise ZeroDivisionError("integer division")
-
-def uint_floordiv_zer(x, y):
-    '''#define OP_UINT_FLOORDIV_ZER(x,y,r,err) \
-        if ((y)) { OP_UINT_FLOORDIV(x,y,r,err); } \
-        else FAIL_ZER(err, "unsigned integer division")
-    '''
-    if y:
-        return x / y
-    else:
-        raise ZeroDivisionError("unsigned integer division")
-
-def llong_floordiv_zer(x, y):
-    '''#define OP_LLONG_FLOORDIV_ZER(x,y,r) \
-      if ((y)) { OP_LLONG_FLOORDIV(x,y,r); } \
-      else FAIL_ZER("integer division")
-    '''
-    if y:
-        return llop.llong_floordiv(SignedLongLong, x, y)
-    else:
-        raise ZeroDivisionError("integer division")
-
-def ullong_floordiv_zer(x, y):
-    '''#define OP_ULLONG_FLOORDIV_ZER(x,y,r) \
-      if ((y)) { OP_ULLONG_FLOORDIV(x,y,r); } \
-      else FAIL_ZER("unsigned integer division")
-    '''
-    if y:
-        return llop.llong_floordiv(UnsignedLongLong, x, y)
-    else:
-        raise ZeroDivisionError("unsigned integer division")
-
-
-def int_neg_ovf(x):
-    if x == LONG_MIN:
-        raise OverflowError("integer negate")
-    return -x
-
-def llong_neg_ovf(x):
-    if x == LLONG_MIN:
-        raise OverflowError("integer negate")
-    return -x
-
-def int_abs_ovf(x):
-    if x == LONG_MIN:
-        raise OverflowError("integer absolute")
-    if x < 0:
-        return -x
-    else:
-        return x
-
-def llong_abs_ovf(x):
-    if x == LLONG_MIN:
-        raise OverflowError("integer absolute")
-    if x < 0:
-        return -x
-    else:
-        return x
-
-def int_add_ovf(x, y):
-    '''#define OP_INT_ADD_OVF(x,y,r,err) \
-        OP_INT_ADD(x,y,r,err); \
-        if ((r^(x)) >= 0 || (r^(y)) >= 0); \
-        else FAIL_OVF(err, "integer addition")
-    '''
-    r = intmask(r_uint(x) + r_uint(y))
-    if r^x >= 0 or r^y >= 0:
-        return r
-    else:
-        raise OverflowError("integer addition")
-
-def int_add_nonneg_ovf(x, y):
-    '''
-    OP_INT_ADD(x,y,r); \
-    if (r >= (x)); \
-    else FAIL_OVF("integer addition")
-    '''
-    r = intmask(r_uint(x) + r_uint(y))
-    if r >= x:
-        return r
-    else:
-        raise OverflowError("integer addition")
-
-def int_sub_ovf(x, y):
-    '''#define OP_INT_SUB_OVF(x,y,r,err) \
-        OP_INT_SUB(x,y,r,err); \
-        if ((r^(x)) >= 0 || (r^~(y)) >= 0); \
-        else FAIL_OVF(err, "integer subtraction")
-    '''
-    r = intmask(r_uint(x) - r_uint(y))
-    if r^x >= 0 or r^~y >= 0:
-        return r
-    else:
-        raise OverflowError("integer subtraction")
-
-def int_lshift_ovf(x, y):
-    '''#define OP_INT_LSHIFT_OVF(x,y,r,err) \
-        OP_INT_LSHIFT(x,y,r,err); \
-        if ((x) != Py_ARITHMETIC_RIGHT_SHIFT(long, r, (y))) \
-                FAIL_OVF(err, "x<<y losing bits or changing sign")
-    '''
-    r = x << y
-    if x != _Py_ARITHMETIC_RIGHT_SHIFT(r, y):
-        raise OverflowError("x<<y losing bits or changing sign")
-    else:
-        return r
-
-def int_rshift_val(x, y):
-    '''#define OP_INT_RSHIFT_VAL(x,y,r,err) \
-        if ((y) >= 0) { OP_INT_RSHIFT(x,y,r,err); } \
-        else FAIL_VAL(err, "negative shift count")
-    '''
-    if y >= 0:
-        return _Py_ARITHMETIC_RIGHT_SHIFT(x, y)
-    else:
-        raise ValueError("negative shift count")
-
-def int_lshift_val(x, y):
-    '''#define OP_INT_LSHIFT_VAL(x,y,r,err) \
-        if ((y) >= 0) { OP_INT_LSHIFT(x,y,r,err); } \
-        else FAIL_VAL(err, "negative shift count")
-    '''
-    if y >= 0:
-        return x << y
-    else:
-        raise ValueError("negative shift count")
-
-def int_lshift_ovf_val(x, y):
-    '''#define OP_INT_LSHIFT_OVF_VAL(x,y,r,err) \
-        if ((y) >= 0) { OP_INT_LSHIFT_OVF(x,y,r,err); } \
-        else FAIL_VAL(err, "negative shift count")
-    '''
-    if y >= 0:
-        return int_lshift_ovf(x, y)
-    else:
-        raise ValueError("negative shift count")
-
-def int_floordiv_ovf(x, y):
-    '''#define OP_INT_FLOORDIV_OVF(x,y,r,err) \
-        if ((y) == -1 && (x) < 0 && ((unsigned long)(x) << 1) == 0) \
-                FAIL_OVF(err, "integer division"); \
-        OP_INT_FLOORDIV(x,y,r,err)
-    '''
-    if y == -1 and x < 0 and (r_uint(x) << 1) == 0:
-        raise OverflowError("integer division")
-    else:
-        return llop.int_floordiv(Signed, x, y)
-
-def int_floordiv_ovf_zer(x, y):
-    '''#define OP_INT_FLOORDIV_OVF_ZER(x,y,r,err) \
-        if ((y)) { OP_INT_FLOORDIV_OVF(x,y,r,err); } \
-        else FAIL_ZER(err, "integer division")
-    '''
-    if y:
-        return int_floordiv_ovf(x, y)
-    else:
-        raise ZeroDivisionError("integer division")
-
-def int_mod_ovf(x, y):
-    '''#define OP_INT_MOD_OVF(x,y,r,err) \
-        if ((y) == -1 && (x) < 0 && ((unsigned long)(x) << 1) == 0) \
-                FAIL_OVF(err, "integer modulo"); \
-        OP_INT_MOD(x,y,r,err)
-    '''
-    if y == -1 and x < 0 and (r_uint(x) << 1) == 0:
-        raise OverflowError("integer modulo")
-    else:
-        return llop.int_mod(Signed, x, y)
-
-def int_mod_zer(x, y):
-    '''#define OP_INT_MOD_ZER(x,y,r,err) \
-        if ((y)) { OP_INT_MOD(x,y,r,err); } \
-        else FAIL_ZER(err, "integer modulo")
-    '''
-    if y:
-        return llop.int_mod(Signed, x, y)
-    else:
-        raise ZeroDivisionError("integer modulo")
-
-def uint_mod_zer(x, y):
-    '''#define OP_UINT_MOD_ZER(x,y,r,err) \
-        if ((y)) { OP_UINT_MOD(x,y,r,err); } \
-        else FAIL_ZER(err, "unsigned integer modulo")
-    '''
-    if y:
-        return x % y
-    else:
-        raise ZeroDivisionError("unsigned integer modulo")
-
-def int_mod_ovf_zer(x, y):
-    '''#define OP_INT_MOD_OVF_ZER(x,y,r,err) \
-        if ((y)) { OP_INT_MOD_OVF(x,y,r,err); } \
-        else FAIL_ZER(err, "integer modulo")
-    '''
-    if y:
-        return int_mod_ovf(x, y)
-    else:
-        raise ZeroDivisionError("integer modulo")
-
-def llong_mod_zer(x, y):
-    '''#define OP_LLONG_MOD_ZER(x,y,r) \
-      if ((y)) { OP_LLONG_MOD(x,y,r); } \
-      else FAIL_ZER("integer modulo")
-    '''
-    if y:
-        return llop.int_mod(SignedLongLong, x, y)
-    else:
-        raise ZeroDivisionError("integer modulo")
-
-# Helpers...
-
-def _Py_ARITHMETIC_RIGHT_SHIFT(i, j):
-    '''
-// Py_ARITHMETIC_RIGHT_SHIFT
-// C doesn't define whether a right-shift of a signed integer sign-extends
-// or zero-fills.  Here a macro to force sign extension:
-// Py_ARITHMETIC_RIGHT_SHIFT(TYPE, I, J)
-//    Return I >> J, forcing sign extension.
-// Requirements:
-//    I is of basic signed type TYPE (char, short, int, long, or long long).
-//    TYPE is one of char, short, int, long, or long long, although long long
-//    must not be used except on platforms that support it.
-//    J is an integer >= 0 and strictly less than the number of bits in TYPE
-//    (because C doesn't define what happens for J outside that range either).
-// Caution:
-//    I may be evaluated more than once.
-
-#ifdef SIGNED_RIGHT_SHIFT_ZERO_FILLS
-    #define Py_ARITHMETIC_RIGHT_SHIFT(TYPE, I, J) \
-            ((I) < 0 ? ~((~(unsigned TYPE)(I)) >> (J)) : (I) >> (J))
-#else
-    #define Py_ARITHMETIC_RIGHT_SHIFT(TYPE, I, J) ((I) >> (J))
-#endif
-    '''
-    return i >> j
-
-#XXX some code from src/int.h seems missing
-#def int_mul_ovf(x, y): #HAVE_LONG_LONG version
-#    '''{ \
-#        PY_LONG_LONG lr = (PY_LONG_LONG)(x) * (PY_LONG_LONG)(y); \
-#        r = (long)lr; \
-#        if ((PY_LONG_LONG)r == lr); \
-#        else FAIL_OVF(err, "integer multiplication"); \
-#    }
-#    '''
-#    lr = r_longlong(x) * r_longlong(y);
-#    r  = intmask(lr)
-#    if r_longlong(r) == lr:
-#        return r
-#    else:
-#        raise OverflowError("integer multiplication")
-
-#not HAVE_LONG_LONG version
-def int_mul_ovf(a, b):          #long a, long b, long *longprod):
-    longprod = a * b
-    doubleprod = float(a) * float(b)
-    doubled_longprod = float(longprod)
-
-    # Fast path for normal case:  small multiplicands, and no info is lost in 
either method.
-    if doubled_longprod == doubleprod:
-        return longprod
-
-    # Somebody somewhere lost info.  Close enough, or way off?  Note
-    # that a != 0 and b != 0 (else doubled_longprod == doubleprod == 0).
-    # The difference either is or isn't significant compared to the
-    # true value (of which doubleprod is a good approximation).
-    # absdiff/absprod <= 1/32 iff 32 * absdiff <= absprod -- 5 good bits is 
"close enough"
-    if 32.0 * abs(doubled_longprod - doubleprod) <= abs(doubleprod):
-        return longprod
-
-    raise OverflowError("integer multiplication")
diff --git a/rpython/rtyper/rint.py b/rpython/rtyper/rint.py
--- a/rpython/rtyper/rint.py
+++ b/rpython/rtyper/rint.py
@@ -4,7 +4,7 @@
 from rpython.flowspace.operation import op_appendices
 from rpython.rlib import objectmodel, jit
 from rpython.rlib.rarithmetic import intmask, longlongmask, r_int, r_longlong
-from rpython.rlib.rarithmetic import r_uint, r_ulonglong
+from rpython.rlib.rarithmetic import r_uint, r_ulonglong, r_longlonglong
 from rpython.rtyper.error import TyperError
 from rpython.rtyper.lltypesystem.lltype import (Signed, Unsigned, Bool, Float,
     Char, UniChar, UnsignedLongLong, SignedLongLong, build_number, Number,
@@ -12,6 +12,8 @@
 from rpython.rtyper.rfloat import FloatRepr
 from rpython.rtyper.rmodel import inputconst, log
 from rpython.tool.pairtype import pairtype
+from rpython.rtyper.lltypesystem.lloperation import llop
+
 
 class IntegerRepr(FloatRepr):
     def __init__(self, lowleveltype, opprefix):
@@ -100,11 +102,7 @@
         if hop.s_result.unsigned:
             raise TyperError("forbidden uint_abs_ovf")
         else:
-            [v_arg] = hop.inputargs(self)
-            hop.has_implicit_exception(OverflowError) # record we know about it
-            hop.exception_is_here()
-            llfunc = globals()['ll_' + self.opprefix + 'abs_ovf']
-            return hop.gendirectcall(llfunc, v_arg)
+            return _rtype_call_helper(hop, 'abs_ovf')
 
     def rtype_invert(self, hop):
         self = self.as_int
@@ -129,12 +127,7 @@
             hop.exception_cannot_occur()
             return self.rtype_neg(hop)
         else:
-            [v_arg] = hop.inputargs(self)
-            hop.has_implicit_exception(OverflowError) # record we know about it
-            hop.exception_is_here()
-            llfunc = globals()['ll_' + self.opprefix + 'sub_ovf']
-            c_zero = hop.inputconst(self.lowleveltype, 0)
-            return hop.gendirectcall(llfunc, c_zero, v_arg)
+            return _rtype_call_helper(hop, 'neg_ovf')
 
     def rtype_pos(self, hop):
         self = self.as_int
@@ -226,28 +219,28 @@
                 hop = hop.copy()
                 hop.swap_fst_snd_args()
                 func = 'add_nonneg_ovf'
-        return _rtype_template(hop, func)
+        return _rtype_call_helper(hop, func)
 
     def rtype_sub(_, hop):
         return _rtype_template(hop, 'sub')
     rtype_inplace_sub = rtype_sub
 
     def rtype_sub_ovf(_, hop):
-        return _rtype_template(hop, 'sub_ovf')
+        return _rtype_call_helper(hop, 'sub_ovf')
 
     def rtype_mul(_, hop):
         return _rtype_template(hop, 'mul')
     rtype_inplace_mul = rtype_mul
 
     def rtype_mul_ovf(_, hop):
-        return _rtype_template(hop, 'mul_ovf')
+        return _rtype_call_helper(hop, 'mul_ovf')
 
     def rtype_floordiv(_, hop):
-        return _rtype_template(hop, 'floordiv', [ZeroDivisionError])
+        return _rtype_call_helper(hop, 'floordiv', [ZeroDivisionError])
     rtype_inplace_floordiv = rtype_floordiv
 
     def rtype_floordiv_ovf(_, hop):
-        return _rtype_template(hop, 'floordiv_ovf', [ZeroDivisionError])
+        return _rtype_call_helper(hop, 'floordiv_ovf', [ZeroDivisionError])
 
     # turn 'div' on integers into 'floordiv'
     rtype_div         = rtype_floordiv
@@ -257,11 +250,11 @@
     # 'def rtype_truediv' is delegated to the superclass FloatRepr
 
     def rtype_mod(_, hop):
-        return _rtype_template(hop, 'mod', [ZeroDivisionError])
+        return _rtype_call_helper(hop, 'mod', [ZeroDivisionError])
     rtype_inplace_mod = rtype_mod
 
     def rtype_mod_ovf(_, hop):
-        return _rtype_template(hop, 'mod_ovf', [ZeroDivisionError])
+        return _rtype_call_helper(hop, 'mod_ovf', [ZeroDivisionError])
 
     def rtype_xor(_, hop):
         return _rtype_template(hop, 'xor')
@@ -280,7 +273,7 @@
     rtype_inplace_lshift = rtype_lshift
 
     def rtype_lshift_ovf(_, hop):
-        return _rtype_template(hop, 'lshift_ovf')
+        return _rtype_call_helper(hop, 'lshift_ovf')
 
     def rtype_rshift(_, hop):
         return _rtype_template(hop, 'rshift')
@@ -310,17 +303,13 @@
 
 #Helper functions
 
-def _rtype_template(hop, func, implicit_excs=[]):
-    if func.endswith('_ovf'):
-        if hop.s_result.unsigned:
-            raise TyperError("forbidden unsigned " + func)
-        else:
-            hop.has_implicit_exception(OverflowError)
-
-    for implicit_exc in implicit_excs:
-        if hop.has_implicit_exception(implicit_exc):
-            appendix = op_appendices[implicit_exc]
-            func += '_' + appendix
+def _rtype_template(hop, func):
+    """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):
+        raise TyperError("%r should not be used here any more" % (func,))
 
     r_result = hop.r_result
     if r_result.lowleveltype == Bool:
@@ -332,74 +321,269 @@
     else:
         repr2 = repr
     vlist = hop.inputargs(repr, repr2)
-    hop.exception_is_here()
+    hop.exception_cannot_occur()
 
     prefix = repr.opprefix
-
     v_res = hop.genop(prefix+func, vlist, resulttype=repr)
-    bothnonneg = hop.args_s[0].nonneg and hop.args_s[1].nonneg
-    if prefix in ('int_', 'llong_') and not bothnonneg:
-
-        # cpython, and rpython, assumed that integer division truncates
-        # towards -infinity.  however, in C99 and most (all?) other
-        # backends, integer division truncates towards 0.  so assuming
-        # that, we call a helper function that applies the necessary
-        # correction in the right cases.
-
-        op = func.split('_', 1)[0]
-
-        if op == 'floordiv':
-            llfunc = globals()['ll_correct_' + prefix + 'floordiv']
-            v_res = hop.gendirectcall(llfunc, vlist[0], vlist[1], v_res)
-        elif op == 'mod':
-            llfunc = globals()['ll_correct_' + prefix + 'mod']
-            v_res = hop.gendirectcall(llfunc, vlist[1], v_res)
-
     v_res = hop.llops.convertvar(v_res, repr, r_result)
     return v_res
 
 
+def _rtype_call_helper(hop, func, implicit_excs=[]):
+    """Write a call to a helper implementing the given 'func'.
+    It can raise OverflowError if 'func' ends with '_ovf'.
+    Other possible exceptions can be specified in 'implicit_excs'.
+    """
+    any_implicit_exception = False
+    if func.endswith('_ovf'):
+        if hop.s_result.unsigned:
+            raise TyperError("forbidden unsigned " + func)
+        else:
+            hop.has_implicit_exception(OverflowError)
+            any_implicit_exception = True
+
+    for implicit_exc in implicit_excs:
+        if hop.has_implicit_exception(implicit_exc):
+            appendix = op_appendices[implicit_exc]
+            func += '_' + appendix
+            any_implicit_exception = True
+
+    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
+    if func in ('abs_ovf', 'neg_ovf'):
+        vlist = hop.inputargs(repr)
+    else:
+        if func.startswith(('lshift', 'rshift')):
+            vlist = hop.inputargs(repr, signed_repr)
+        else:
+            vlist = hop.inputargs(repr, repr)
+    if any_implicit_exception:
+        hop.exception_is_here()
+    else:
+        hop.exception_cannot_occur()
+
+    llfunc = globals()['ll_' + repr.opprefix + func]
+    v_result = hop.gendirectcall(llfunc, *vlist)
+    assert v_result.concretetype == repr.lowleveltype
+    return v_result
+
+
 INT_BITS_1 = r_int.BITS - 1
 LLONG_BITS_1 = r_longlong.BITS - 1
+LLLONG_BITS_1 = r_longlonglong.BITS - 1
 INT_MIN = int(-(1 << INT_BITS_1))
 LLONG_MIN = r_longlong(-(1 << LLONG_BITS_1))
 
-def ll_correct_int_floordiv(x, y, r):
+
+# ---------- floordiv ----------
+
+def ll_int_floordiv(x, y):
+    # Python, and RPython, assume that integer division truncates
+    # towards -infinity.  However, in C, integer division truncates
+    # towards 0.  So assuming that, we need to apply a correction
+    # in the right cases.
+    r = llop.int_floordiv(Signed, x, y)            # <= truncates like in C
     p = r * y
     if y < 0: u = p - x
     else:     u = x - p
     return r + (u >> INT_BITS_1)
 
-def ll_correct_llong_floordiv(x, y, r):
+def ll_int_floordiv_zer(x, y):
+    if y == 0:
+        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
+    if (x == -sys.maxint - 1) & (y == -1):
+        raise OverflowError("integer division")
+    return ll_int_floordiv(x, y)
+
+def ll_int_floordiv_ovf_zer(x, y):
+    if y == 0:
+        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)
 
-def ll_correct_int_mod(y, r):
+def ll_llong_floordiv_zer(x, y):
+    if y == 0:
+        raise ZeroDivisionError("longlong division")
+    return ll_llong_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)
+
+def ll_lllong_floordiv(x, y):
+    r = llop.lllong_floordiv(SignedLongLongLong, x, y) # <= truncates like in C
+    p = r * y
+    if y < 0: u = p - x
+    else:     u = x - p
+    return r + (u >> LLLONG_BITS_1)
+
+def ll_lllong_floordiv_zer(x, y):
+    if y == 0:
+        raise ZeroDivisionError("longlonglong division")
+    return ll_lllong_floordiv(x, y)
+
+
+# ---------- mod ----------
+
+def ll_int_mod(x, y):
+    r = llop.int_mod(Signed, x, y)                 # <= truncates like in C
     if y < 0: u = -r
     else:     u = r
     return r + (y & (u >> INT_BITS_1))
 
-def ll_correct_llong_mod(y, r):
+def ll_int_mod_zer(x, y):
+    if y == 0:
+        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):
+        raise OverflowError
+    return ll_int_mod(x, y)
+
+def ll_int_mod_ovf_zer(x, y):
+    if y == 0:
+        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))
 
+def ll_llong_mod_zer(x, y):
+    if y == 0:
+        raise ZeroDivisionError
+    return ll_llong_mod(x, y)
+
+def ll_ullong_mod_zer(x, y):
+    if y == 0:
+        raise ZeroDivisionError
+    return llop.ullong_mod(UnsignedLongLong, x, y)
+
+def ll_lllong_mod(x, y):
+    r = llop.lllong_mod(SignedLongLongLong, x, y)  # <= truncates like in C
+    if y < 0: u = -r
+    else:     u = r
+    return r + (y & (u >> LLLONG_BITS_1))
+
+def ll_lllong_mod_zer(x, y):
+    if y == 0:
+        raise ZeroDivisionError
+    return ll_lllong_mod(x, y)
+
+
+# ---------- add, sub, mul ----------
+
+@jit.oopspec("add_ovf")
+def ll_int_add_ovf(x, y):
+    r = intmask(r_uint(x) + r_uint(y))
+    if r^x < 0 and r^y < 0:
+        raise OverflowError("integer addition")
+    return r
+
+@jit.oopspec("add_ovf")
+def ll_int_add_nonneg_ovf(x, y):     # y can be assumed >= 0
+    r = intmask(r_uint(x) + r_uint(y))
+    if r < x:
+        raise OverflowError("integer addition")
+    return r
 
 @jit.oopspec("sub_ovf")
 def ll_int_sub_ovf(x, y):
     r = intmask(r_uint(x) - r_uint(y))
-    if r^x >= 0 or r^~y >= 0:
-        return r
-    raise OverflowError("integer subtraction")
+    if r^x < 0 and r^~y < 0:
+        raise OverflowError("integer subtraction")
+    return r
 
 @jit.oopspec("sub_ovf")
 def ll_llong_sub_ovf(x, y):
     r = longlongmask(r_ulonglong(x) - r_ulonglong(y))
-    if r^x >= 0 or r^~y >= 0:
+    if r^x < 0 and r^~y < 0:
+        raise OverflowError("longlong subtraction")
+    return r
+
+@jit.oopspec("mul_ovf")
+def ll_int_mul_ovf(a, b):
+    if INT_BITS_1 < LLONG_BITS_1:
+        rr = r_longlong(a) * r_longlong(b)
+        r = intmask(rr)
+        if r_longlong(r) != rr:
+            raise OverflowError("integer multiplication")
         return r
-    raise OverflowError("longlong subtraction")
+    else:
+        longprod = intmask(a * b)
+        doubleprod = float(a) * float(b)
+        doubled_longprod = float(longprod)
+
+        # Fast path for normal case:  small multiplicands, and no info
+        # is lost in either method.
+        if doubled_longprod == doubleprod:
+            return longprod
+
+        # Somebody somewhere lost info.  Close enough, or way off?  Note
+        # that a != 0 and b != 0 (else doubled_longprod == doubleprod == 0).
+        # The difference either is or isn't significant compared to the
+        # true value (of which doubleprod is a good approximation).
+        # absdiff/absprod <= 1/32 iff 32 * absdiff <= absprod -- 5 good
+        # bits is "close enough"
+        if 32.0 * abs(doubled_longprod - doubleprod) <= abs(doubleprod):
+            return longprod
+
+        raise OverflowError("integer multiplication")
+
+
+# ---------- lshift, neg, abs ----------
+
+def ll_int_lshift_ovf(x, y):
+    result = x << y
+    if (result >> y) != x:
+        raise OverflowError("x<<y loosing bits or changing sign")
+    return result
+
+def ll_int_neg_ovf(x):
+    if jit.we_are_jitted():
+        return ll_int_sub_ovf(0, x)
+    if x == INT_MIN:
+        raise OverflowError
+    return -x
+
+def ll_llong_neg_ovf(x):
+    if jit.we_are_jitted():
+        return ll_llong_sub_ovf(0, x)
+    if x == LLONG_MIN:
+        raise OverflowError
+    return -x
 
 def ll_int_abs_ovf(x):
     if x == INT_MIN:
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to