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