Author: Carl Friedrich Bolz-Tereick <cfb...@gmx.de> Branch: py3.6 Changeset: r96958:5a7ab6765acf Date: 2019-07-10 13:38 +0200 http://bitbucket.org/pypy/pypy/changeset/5a7ab6765acf/
Log: merge default diff --git a/rpython/jit/backend/arm/assembler.py b/rpython/jit/backend/arm/assembler.py --- a/rpython/jit/backend/arm/assembler.py +++ b/rpython/jit/backend/arm/assembler.py @@ -532,26 +532,22 @@ def gen_shadowstack_header(self, gcrootmap): # lr = shadow stack top addr - # r4 = *lr + # ip = *lr rst = gcrootmap.get_root_stack_top_addr() self.mc.gen_load_int(r.lr.value, rst) - self.load_reg(self.mc, r.r4, r.lr) - # *r4 = 1 - # the '1' is to benefit from the shadowstack 'is_minor' optimization - self.mc.gen_load_int(r.ip.value, 1) - self.store_reg(self.mc, r.ip, r.r4) - # *(r4+WORD) = r.fp - self.store_reg(self.mc, r.fp, r.r4, WORD) + self.load_reg(self.mc, r.ip, r.lr) + # *ip = r.fp + self.store_reg(self.mc, r.fp, r.ip) # - self.mc.ADD_ri(r.r4.value, r.r4.value, 2 * WORD) - # *lr = r4 + 2 * WORD - self.store_reg(self.mc, r.r4, r.lr) + self.mc.ADD_ri(r.ip.value, r.ip.value, WORD) + # *lr = ip + WORD + self.store_reg(self.mc, r.ip, r.lr) def gen_footer_shadowstack(self, gcrootmap, mc): rst = gcrootmap.get_root_stack_top_addr() mc.gen_load_int(r.ip.value, rst) self.load_reg(mc, r.r4, r.ip) - mc.SUB_ri(r.r4.value, r.r4.value, 2 * WORD) + mc.SUB_ri(r.r4.value, r.r4.value, WORD) self.store_reg(mc, r.r4, r.ip) def _dump(self, ops, type='loop'): diff --git a/rpython/jit/backend/arm/regalloc.py b/rpython/jit/backend/arm/regalloc.py --- a/rpython/jit/backend/arm/regalloc.py +++ b/rpython/jit/backend/arm/regalloc.py @@ -373,6 +373,10 @@ if box.type == REF and self.rm.is_still_alive(box): assert not noregs assert loc.is_core_reg() + #val = self.cpu.all_reg_indexes[loc.value] + # ^^^ That is the correct way to write it down, but as a + # special case in the arm backend only, this is equivalent + # to just the line below: val = loc.value gcmap[val // WORD // 8] |= r_uint(1) << (val % (WORD * 8)) for box, loc in self.fm.bindings.iteritems(): diff --git a/rpython/rlib/rbigint.py b/rpython/rlib/rbigint.py --- a/rpython/rlib/rbigint.py +++ b/rpython/rlib/rbigint.py @@ -1423,6 +1423,12 @@ bits = ovfcheck((i-1) * SHIFT) + msd_bits return bits + def gcd(self, other): + """ Compute the (always positive) greatest common divisor of self and + other """ + return gcd_lehmer(self.abs(), other.abs()) + + def __repr__(self): return "<rbigint digits=%s, sign=%s, size=%d, len=%d, %s>" % (self._digits, self.sign, self.numdigits(), len(self._digits), @@ -2960,3 +2966,88 @@ z.setdigit(pdigit, accum) z._normalize() return z + + +def gcd_binary(a, b): + if a == 0: + return b + + if b == 0: + return a + + a, b = abs(a), abs(b) + + shift = 0 + while (a | b) & 1 == 0: + a >>= 1 + b >>= 1 + shift += 1 + + while a & 1 == 0: + a >>= 1 + + while b & 1 == 0: + b >>= 1 + + while a != b: + a, b = abs(a - b), min(a, b) + while a & 1 == 0: + a >>= 1 + + return a << shift + +def lehmer_xgcd(a, b): + s_old, s_new = 1, 0 + t_old, t_new = 0, 1 + while b >> (SHIFT >> 1): + q, r = a // b, a % b + + a, b = b, r + s_old, s_new = s_new, s_old - q * s_new + t_old, t_new = t_new, t_old - q * t_new + + return s_old, t_old, s_new, t_new + +def gcd_lehmer(a, b): + if a.lt(b): + a, b = b, a + + while b.size > 1: + a_ms = a.digit(a.size-1) + + x = 0 + while a_ms & (0xFF << SHIFT-8) == 0: + a_ms <<= 8 + x += 8 + + while a_ms & (1 << SHIFT-1) == 0: + a_ms <<= 1 + x += 1 + + a_ms |= a.digit(a.size-2) >> SHIFT-x + + if a.size == b.size: + b_ms = (b.digit(b.size-1) << x) | (b.digit(b.size-2) >> SHIFT-x) + elif a.size == b.size+1: + b_ms = b.digit(b.size-1) >> SHIFT-x + else: + b_ms = 0 + + if b_ms >> (SHIFT+1 >> 1) == 0: + a, b = b, a.mod(b) + continue + + s_old, t_old, s_new, t_new = lehmer_xgcd(a_ms, b_ms) + + n_a = a.int_mul(s_new).add(b.int_mul(t_new)).abs() + b = a.int_mul(s_old).add(b.int_mul(t_old)).abs() + a = n_a + + if a.lt(b): + a, b = b, a + + if not b.tobool(): + return a + + a = a.mod(b) + return rbigint.fromint(gcd_binary(b.toint(), a.toint())) diff --git a/rpython/rlib/test/test_rbigint.py b/rpython/rlib/test/test_rbigint.py --- a/rpython/rlib/test/test_rbigint.py +++ b/rpython/rlib/test/test_rbigint.py @@ -11,12 +11,13 @@ from rpython.rlib import rbigint as lobj from rpython.rlib.rarithmetic import r_uint, r_longlong, r_ulonglong, intmask from rpython.rlib.rbigint import (rbigint, SHIFT, MASK, KARATSUBA_CUTOFF, - _store_digit, _mask_digit, InvalidEndiannessError, InvalidSignednessError) + _store_digit, _mask_digit, InvalidEndiannessError, InvalidSignednessError, + gcd_lehmer, lehmer_xgcd, gcd_binary) from rpython.rlib.rfloat import NAN from rpython.rtyper.test.test_llinterp import interpret from rpython.translator.c.test.test_standalone import StandaloneTests -from hypothesis import given, strategies, example +from hypothesis import given, strategies, example, settings longs = strategies.builds( long, strategies.integers()) @@ -836,6 +837,27 @@ t = bigint.tobytes(len(s), byteorder=byteorder, signed=signed) assert s == t + def test_gcd(self): + assert gcd_binary(2*3*7**2, 2**2*7) == 2*7 + assert gcd_binary(-2*3*7**2, 2**2*7) == 2*7 + assert gcd_binary(2*3*7**2, -2**2*7) == 2*7 + assert gcd_binary(-2*3*7**2, -2**2*7) == 2*7 + assert gcd_binary(1234, 5678) == 2 + assert gcd_binary(13, 13**6) == 13 + assert gcd_binary(12, 0) == 12 + assert gcd_binary(0, 0) == 0 + + x = rbigint.fromlong(9969216677189303386214405760200) + y = rbigint.fromlong(16130531424904581415797907386349) + g = x.gcd(y) + assert g == rbigint.fromlong(1) + + for x in gen_signs([12843440367927679363613699686751681643652809878241019930204617606850071260822269719878805]): + x = rbigint.fromlong(x) + for y in gen_signs([12372280584571061381380725743231391746505148712246738812788540537514927882776203827701778968535]): + y = rbigint.fromlong(y) + g = x.gcd(y) + assert g.tolong() == 18218089570126697993340888567155155527541105 class TestInternalFunctions(object): @@ -1255,3 +1277,52 @@ assert lx.lt(ly) == (x < y) assert lx.eq(ly) == (x == y) assert lx.le(ly) == (x <= y) + + @given(ints, ints, ints) + def test_gcd_binary(self, x, y, z): + x, y, z = abs(x), abs(y), abs(z) + + def test(a, b, res): + g = gcd_binary(a, b) + + assert g == res + + a, b = x, y + while b: + a, b = b, a % b + + gcd_x_y = a + + test(x, y, gcd_x_y) + test(x, 0, x) + test(0, x, x) + test(x * z, y * z, gcd_x_y * z) + test(x * z, z, z) + test(z, y * z, z) + + @given(biglongs, biglongs, biglongs) + @example(112233445566778899112233445566778899112233445566778899, + 13579246801357924680135792468013579246801, + 99887766554433221113) + @settings(max_examples=10) + def test_gcd(self, x, y, z): + print(x, y, z) + x, y, z = abs(x), abs(y), abs(z) + + def test(a, b, res): + g = rbigint.fromlong(a).gcd(rbigint.fromlong(b)).tolong() + + assert g == res + + a, b = x, y + while b: + a, b = b, a % b + + gcd_x_y = a + + test(x, y, gcd_x_y) + test(x * z, y * z, gcd_x_y * z) + test(x * z, z, z) + test(z, y * z, z) + test(x, 0, x) + test(0, x, x) diff --git a/rpython/translator/goal/targetbigintbenchmark.py b/rpython/translator/goal/targetbigintbenchmark.py --- a/rpython/translator/goal/targetbigintbenchmark.py +++ b/rpython/translator/goal/targetbigintbenchmark.py @@ -251,8 +251,19 @@ sumTime += _time print "v = v + v", _time + x = rbigint.fromstr("13579246801357924680135792468013579246801") + y = rbigint.fromstr("112233445566778899112233445566778899112233445566778899") + t = time() + for i in range(5000): + x.gcd(y) + x = x.int_mul(2).int_add(1) + _time = time() - t + print "gcd", _time + + sumTime += _time + print "Sum: ", sumTime - + return 0 # _____ Define and setup target ___ _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit