Author: Armin Rigo <[email protected]>
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 ----------
+
[email protected]("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
+
[email protected]("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
+
[email protected]("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
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit