Author: stian Branch: improve-rbigint Changeset: r56365:3ac65815b0d4 Date: 2012-07-13 23:34 +0200 http://bitbucket.org/pypy/pypy/changeset/3ac65815b0d4/
Log: Fixes. And reintroduce the jit stuff diff --git a/pypy/rlib/rbigint.py b/pypy/rlib/rbigint.py --- a/pypy/rlib/rbigint.py +++ b/pypy/rlib/rbigint.py @@ -141,11 +141,11 @@ class rbigint(object): """This is a reimplementation of longs using a list of digits.""" - def __init__(self, digits=[NULLDIGIT], sign=0): + def __init__(self, digits=[NULLDIGIT], sign=0, size=0): _check_digits(digits) make_sure_not_resized(digits) self._digits = digits - self.size = len(digits) + self.size = size or len(digits) self.sign = sign def digit(self, x): @@ -165,7 +165,7 @@ udigit._always_inline_ = True udigit._annonforceargs_ = [None, r_uint] def setdigit(self, x, val): - val = _mask_digit(val) + val = val & MASK assert val >= 0 self._digits[x] = _store_digit(val) setdigit._annspecialcase_ = 'specialize:argtype(2)' @@ -199,10 +199,10 @@ if SHIFT >= 63: carry = ival >> SHIFT if carry: - return rbigint([_store_digit(_mask_digit(ival)), - _store_digit(_mask_digit(carry))], sign) + return rbigint([_store_digit(ival & MASK), + _store_digit(carry & MASK)], sign) else: - return rbigint([_store_digit(_mask_digit(ival))], sign) + return rbigint([_store_digit(ival & MASK)], sign) t = ival ndigits = 0 @@ -220,7 +220,6 @@ return v @staticmethod - #@jit.elidable def frombool(b): # This function is marked as pure, so you must not call it and # then modify the result. @@ -296,6 +295,7 @@ raise OverflowError return intmask(intmask(x) * sign) + @jit.elidable def tolonglong(self): return _AsLongLong(self) @@ -307,6 +307,7 @@ raise ValueError("cannot convert negative integer to unsigned int") return self._touint_helper() + @jit.elidable def _touint_helper(self): x = r_uint(0) i = self.numdigits() - 1 @@ -319,14 +320,17 @@ i -= 1 return x + @jit.elidable def toulonglong(self): if self.sign == -1: raise ValueError("cannot convert negative integer to unsigned int") return _AsULonglong_ignore_sign(self) + @jit.elidable def uintmask(self): return _AsUInt_mask(self) + @jit.elidable def ulonglongmask(self): """Return r_ulonglong(self), truncating.""" return _AsULonglong_mask(self) @@ -335,21 +339,21 @@ def tofloat(self): return _AsDouble(self) - #@jit.elidable + @jit.elidable def format(self, digits, prefix='', suffix=''): # 'digits' is a string whose length is the base to use, # and where each character is the corresponding digit. return _format(self, digits, prefix, suffix) - #@jit.elidable + @jit.elidable def repr(self): return _format(self, BASE10, '', 'L') - #@jit.elidable + @jit.elidable def str(self): return _format(self, BASE10) - #@jit.elidable + @jit.elidable def eq(self, other): if (self.sign != other.sign or self.numdigits() != other.numdigits()): @@ -365,7 +369,7 @@ def ne(self, other): return not self.eq(other) - #@jit.elidable + @jit.elidable def lt(self, other): if self.sign > other.sign: return False @@ -413,7 +417,7 @@ def hash(self): return _hash(self) - #@jit.elidable + @jit.elidable def add(self, other): if self.sign == 0: return other @@ -426,12 +430,12 @@ result.sign *= other.sign return result - #@jit.elidable + @jit.elidable def sub(self, other): if other.sign == 0: return self if self.sign == 0: - return rbigint(other._digits, -other.sign) + return rbigint(other._digits[:], -other.sign, other.size) if self.sign == other.sign: result = _x_sub(self, other) else: @@ -439,7 +443,7 @@ result.sign *= self.sign return result - #@jit.elidable + @jit.elidable def mul(self, b): asize = self.numdigits() bsize = b.numdigits() @@ -456,7 +460,7 @@ if a._digits[0] == NULLDIGIT: return rbigint() elif a._digits[0] == ONEDIGIT: - return rbigint(b._digits, a.sign * b.sign) + return rbigint(b._digits[:], a.sign * b.sign, b.size) elif bsize == 1: result = rbigint([NULLDIGIT] * 2, a.sign * b.sign) carry = b.widedigit(0) * a.widedigit(0) @@ -464,6 +468,7 @@ carry >>= SHIFT if carry: result.setdigit(1, carry) + result._normalize() return result result = _x_mul(a, b, a.digit(0)) @@ -487,12 +492,12 @@ result.sign = a.sign * b.sign return result - #@jit.elidable + @jit.elidable def truediv(self, other): div = _bigint_true_divide(self, other) return div - #@jit.elidable + @jit.elidable def floordiv(self, other): if other.numdigits() == 1 and other.sign == 1: digit = other.digit(0) @@ -506,11 +511,10 @@ div = div.sub(ONERBIGINT) return div - #@jit.elidable def div(self, other): return self.floordiv(other) - #@jit.elidable + @jit.elidable def mod(self, other): if self.sign == 0: return NULLRBIGINT @@ -549,7 +553,7 @@ mod = mod.add(other) return mod - #@jit.elidable + @jit.elidable def divmod(v, w): """ The / and % operators are now defined in terms of divmod(). @@ -573,7 +577,7 @@ div = div.sub(ONERBIGINT) return div, mod - #@jit.elidable + @jit.elidable def pow(a, b, c=None): negativeOutput = False # if x<0 return negative output @@ -711,12 +715,12 @@ return z def neg(self): - return rbigint(self._digits, -self.sign) + return rbigint(self._digits[:], -self.sign, self.size) def abs(self): if self.sign != -1: return self - return rbigint(self._digits, abs(self.sign)) + return rbigint(self._digits[:], abs(self.sign), self.size) def invert(self): #Implement ~x as -(x + 1) if self.sign == 0: @@ -726,7 +730,17 @@ ret.sign = -ret.sign return ret - #@jit.elidable + def inplace_invert(self): # Used by rshift and bitwise to prevent a double allocation. + if self.sign == 0: + return ONENEGATIVERBIGINT + if self.sign == 1: + _v_iadd(self, 0, self.numdigits(), ONERBIGINT, 1) + else: + _v_isub(self, 0, self.numdigits(), ONERBIGINT, 1) + self.sign = -self.sign + return self + + @jit.elidable def lshift(self, int_other): if int_other < 0: raise ValueError("negative shift count") @@ -738,7 +752,9 @@ remshift = int_other - wordshift * SHIFT if not remshift: - return rbigint([NULLDIGIT] * wordshift + self._digits, self.sign) + ret = rbigint([NULLDIGIT] * wordshift + self._digits, self.sign) + ret._normalize() + return ret oldsize = self.numdigits() newsize = oldsize + wordshift + 1 @@ -760,7 +776,7 @@ return z lshift._always_inline_ = True # It's so fast that it's always benefitial. - #@jit.elidable + @jit.elidable def lqshift(self, int_other): " A quicker one with much less checks, int_other is valid and for the most part constant." assert int_other > 0 @@ -780,7 +796,7 @@ return z lqshift._always_inline_ = True # It's so fast that it's always benefitial. - #@jit.elidable + @jit.elidable def rshift(self, int_other, dont_invert=False): if int_other < 0: raise ValueError("negative shift count") @@ -789,7 +805,7 @@ if self.sign == -1 and not dont_invert: a1 = self.invert() a2 = a1.rshift(int_other) - return a2.invert() + return a2.inplace_invert() wordshift = int_other // SHIFT newsize = self.numdigits() - wordshift @@ -807,7 +823,7 @@ while i < newsize: newdigit = (self.udigit(wordshift) >> loshift) #& lomask if i+1 < newsize: - newdigit |= (self.udigit(wordshift+1) << hishift) #& himask + newdigit += (self.udigit(wordshift+1) << hishift) #& himask z.setdigit(i, newdigit) i += 1 wordshift += 1 @@ -815,15 +831,15 @@ return z rshift._always_inline_ = True # It's so fast that it's always benefitial. - #@jit.elidable + @jit.elidable def and_(self, other): return _bitwise(self, '&', other) - #@jit.elidable + @jit.elidable def xor(self, other): return _bitwise(self, '^', other) - #@jit.elidable + @jit.elidable def or_(self, other): return _bitwise(self, '|', other) @@ -836,7 +852,7 @@ def hex(self): return _format(self, BASE16, '0x', 'L') - #@jit.elidable + @jit.elidable def log(self, base): # base is supposed to be positive or 0.0, which means we use e if base == 10.0: @@ -875,6 +891,7 @@ _normalize._always_inline_ = True + @jit.elidable def bit_length(self): i = self.numdigits() if i == 1 and self._digits[0] == NULLDIGIT: @@ -1044,6 +1061,7 @@ borrow >>= SHIFT borrow &= 1 i += 1 + assert borrow == 0 z._normalize() return z @@ -1091,7 +1109,11 @@ z.setdigit(pz, carry) pz += 1 carry >>= SHIFT - #assert carry <= (_widen_digit(MASK) << 1) + if carry: + carry += z.widedigit(pz) + z.setdigit(pz, carry) + pz += 1 + carry >>= SHIFT if carry: z.setdigit(pz, z.widedigit(pz) + carry) assert (carry >> SHIFT) == 0 @@ -1442,7 +1464,7 @@ pout.setdigit(size, hi) rem -= hi * n size -= 1 - return _mask_digit(rem) + return rem & MASK def _divrem1(a, n): """ @@ -1649,6 +1671,7 @@ a._normalize() _inplace_divrem1(v, v, d, size_v) + v._normalize() return a, v """ @@ -2221,6 +2244,7 @@ digb = b.digit(i) ^ maskb else: digb = maskb + if op == '&': z.setdigit(i, diga & digb) elif op == '|': @@ -2231,7 +2255,8 @@ z._normalize() if negz == 0: return z - return z.invert() + + return z.inplace_invert() _bitwise._annspecialcase_ = "specialize:arg(1)" diff --git a/pypy/rlib/test/test_rbigint.py b/pypy/rlib/test/test_rbigint.py --- a/pypy/rlib/test/test_rbigint.py +++ b/pypy/rlib/test/test_rbigint.py @@ -407,7 +407,7 @@ def test_normalize(self): f1 = bigint([1, 0], 1) f1._normalize() - assert len(f1._digits) == 1 + assert f1.size == 1 f0 = bigint([0], 0) assert f1.sub(f1).eq(f0) diff --git a/pypy/rpython/lltypesystem/ll2ctypes.py b/pypy/rpython/lltypesystem/ll2ctypes.py --- a/pypy/rpython/lltypesystem/ll2ctypes.py +++ b/pypy/rpython/lltypesystem/ll2ctypes.py @@ -133,6 +133,7 @@ rffi.LONGLONG: ctypes.c_longlong, rffi.ULONGLONG: ctypes.c_ulonglong, rffi.SIZE_T: ctypes.c_size_t, + rffi.__INT128: ctypes.c_longlong, # XXX: Not right at all. But for some reason, It started by while doing JIT compile after a merge with default. Can't extend ctypes, because thats a python standard, right? lltype.Bool: getattr(ctypes, "c_bool", ctypes.c_byte), llmemory.Address: ctypes.c_void_p, llmemory.GCREF: ctypes.c_void_p, diff --git a/pypy/translator/goal/targetbigintbenchmark.py b/pypy/translator/goal/targetbigintbenchmark.py --- a/pypy/translator/goal/targetbigintbenchmark.py +++ b/pypy/translator/goal/targetbigintbenchmark.py @@ -35,24 +35,24 @@ Sum: 142.686547 Pypy with improvements: - mod by 2: 0.005516 - mod by 10000: 3.650751 - mod by 1024 (power of two): 0.011492 - Div huge number by 2**128: 2.148300 - rshift: 2.333236 - lshift: 1.355453 - Floordiv by 2: 1.604574 - Floordiv by 3 (not power of two): 4.155219 - 2**500000: 0.033960 - (2**N)**5000000 (power of two): 0.046241 - 10000 ** BIGNUM % 100 1.963261 - i = i * i: 3.906100 - n**10000 (not power of two): 5.994802 - Power of two ** power of two: 0.013270 - v = v * power of two 3.481778 - v = v * v 6.348381 - v = v + v 2.782792 - Sum: 39.835126 + mod by 2: 0.007256 + mod by 10000: 3.175842 + mod by 1024 (power of two): 0.011571 + Div huge number by 2**128: 2.187273 + rshift: 2.319537 + lshift: 1.488359 + Floordiv by 2: 1.513284 + Floordiv by 3 (not power of two): 4.210322 + 2**500000: 0.033903 + (2**N)**5000000 (power of two): 0.052366 + 10000 ** BIGNUM % 100 2.032749 + i = i * i: 4.609749 + n**10000 (not power of two): 6.266791 + Power of two ** power of two: 0.013294 + v = v * power of two 4.107085 + v = v * v 6.384141 + v = v + v 2.820538 + Sum: 41.234060 A pure python form of those tests where also run Improved pypy | Pypy | CPython 2.7.3 _______________________________________________ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit