Author: Armin Rigo <ar...@tunes.org> Branch: Changeset: r69211:6a81e7b47559 Date: 2014-02-19 19:38 +0100 http://bitbucket.org/pypy/pypy/changeset/6a81e7b47559/
Log: merge heads diff --git a/lib-python/2.7/test/test_audioop.py b/lib-python/2.7/test/test_audioop.py --- a/lib-python/2.7/test/test_audioop.py +++ b/lib-python/2.7/test/test_audioop.py @@ -1,6 +1,6 @@ import audioop import unittest -from test.test_support import run_unittest +from test.test_support import run_unittest, impl_detail endian = 'big' if audioop.getsample('\0\1', 2, 0) == 1 else 'little' @@ -93,21 +93,25 @@ wtd = len(d2)//3 self.assertEqual(len(audioop.lin2lin(d1, got, wtd)), len(d2)) + @impl_detail(pypy=False) def test_adpcm2lin(self): # Very cursory test self.assertEqual(audioop.adpcm2lin(b'\0\0', 1, None), (b'\0' * 4, (0,0))) self.assertEqual(audioop.adpcm2lin(b'\0\0', 2, None), (b'\0' * 8, (0,0))) self.assertEqual(audioop.adpcm2lin(b'\0\0', 4, None), (b'\0' * 16, (0,0))) + @impl_detail(pypy=False) def test_lin2adpcm(self): # Very cursory test self.assertEqual(audioop.lin2adpcm('\0\0\0\0', 1, None), ('\0\0', (0,0))) + @impl_detail(pypy=False) def test_lin2alaw(self): self.assertEqual(audioop.lin2alaw(data[0], 1), '\xd5\xc5\xf5') self.assertEqual(audioop.lin2alaw(data[1], 2), '\xd5\xd5\xd5') self.assertEqual(audioop.lin2alaw(data[2], 4), '\xd5\xd5\xd5') + @impl_detail(pypy=False) def test_alaw2lin(self): # Cursory d = audioop.lin2alaw(data[0], 1) @@ -123,11 +127,13 @@ self.assertEqual(audioop.alaw2lin(d, 4), b'\x00\x00\x08\x00\x00\x00\x08\x01\x00\x00\x10\x02') + @impl_detail(pypy=False) def test_lin2ulaw(self): self.assertEqual(audioop.lin2ulaw(data[0], 1), '\xff\xe7\xdb') self.assertEqual(audioop.lin2ulaw(data[1], 2), '\xff\xff\xff') self.assertEqual(audioop.lin2ulaw(data[2], 4), '\xff\xff\xff') + @impl_detail(pypy=False) def test_ulaw2lin(self): # Cursory d = audioop.lin2ulaw(data[0], 1) @@ -195,6 +201,7 @@ self.assertRaises(audioop.error, audioop.findmax, ''.join( chr(x) for x in xrange(256)), -2392392) + @impl_detail(pypy=False) def test_issue7673(self): state = None for data, size in INVALID_DATA: @@ -219,6 +226,7 @@ self.assertRaises(audioop.error, audioop.lin2alaw, data, size) self.assertRaises(audioop.error, audioop.lin2adpcm, data, size, state) + @impl_detail(pypy=False) def test_wrongsize(self): data = b'abc' state = None diff --git a/lib-python/conftest.py b/lib-python/conftest.py --- a/lib-python/conftest.py +++ b/lib-python/conftest.py @@ -109,7 +109,7 @@ RegrTest('test_asynchat.py', usemodules='select fcntl'), RegrTest('test_asyncore.py', usemodules='select fcntl'), RegrTest('test_atexit.py', core=True), - RegrTest('test_audioop.py', skip="incomplete module"), + RegrTest('test_audioop.py'), RegrTest('test_augassign.py', core=True), RegrTest('test_base64.py', usemodules='struct'), RegrTest('test_bastion.py'), diff --git a/lib_pypy/audioop.py b/lib_pypy/audioop.py --- a/lib_pypy/audioop.py +++ b/lib_pypy/audioop.py @@ -1,5 +1,8 @@ - +import __builtin__ +import math import struct +from fractions import gcd +from ctypes import create_string_buffer class error(Exception): @@ -8,7 +11,7 @@ def _check_size(size): if size != 1 and size != 2 and size != 4: - raise error("Size should be 1, 2 or 4") + raise error("Size should be 1, 2 or 4") def _check_params(length, size): @@ -17,13 +20,526 @@ raise error("not a whole number of frames") +def _sample_count(cp, size): + return len(cp) / size + + +def _get_samples(cp, size, signed=True): + for i in range(_sample_count(cp, size)): + yield _get_sample(cp, size, i, signed) + + +def _struct_format(size, signed): + if size == 1: + return "b" if signed else "B" + elif size == 2: + return "h" if signed else "H" + elif size == 4: + return "i" if signed else "I" + + +def _get_sample(cp, size, i, signed=True): + fmt = _struct_format(size, signed) + start = i * size + end = start + size + return struct.unpack_from(fmt, buffer(cp)[start:end])[0] + + +def _put_sample(cp, size, i, val, signed=True): + fmt = _struct_format(size, signed) + struct.pack_into(fmt, cp, i * size, val) + + +def _get_maxval(size, signed=True): + if signed and size == 1: + return 0x7f + elif size == 1: + return 0xff + elif signed and size == 2: + return 0x7fff + elif size == 2: + return 0xffff + elif signed and size == 4: + return 0x7fffffff + elif size == 4: + return 0xffffffff + + +def _get_minval(size, signed=True): + if not signed: + return 0 + elif size == 1: + return -0x80 + elif size == 2: + return -0x8000 + elif size == 4: + return -0x80000000 + + +def _get_clipfn(size, signed=True): + maxval = _get_maxval(size, signed) + minval = _get_minval(size, signed) + return lambda val: __builtin__.max(min(val, maxval), minval) + + +def _overflow(val, size, signed=True): + minval = _get_minval(size, signed) + maxval = _get_maxval(size, signed) + if minval <= val <= maxval: + return val + + bits = size * 8 + if signed: + offset = 2**(bits-1) + return ((val + offset) % (2**bits)) - offset + else: + return val % (2**bits) + + def getsample(cp, size, i): _check_params(len(cp), size) if not (0 <= i < len(cp) / size): raise error("Index out of range") - if size == 1: - return struct.unpack_from("B", buffer(cp)[i:])[0] - elif size == 2: - return struct.unpack_from("H", buffer(cp)[i * 2:])[0] - elif size == 4: - return struct.unpack_from("I", buffer(cp)[i * 4:])[0] + return _get_sample(cp, size, i) + + +def max(cp, size): + _check_params(len(cp), size) + + if len(cp) == 0: + return 0 + + return __builtin__.max(abs(sample) for sample in _get_samples(cp, size)) + + +def minmax(cp, size): + _check_params(len(cp), size) + + max_sample, min_sample = 0, 0 + for sample in _get_samples(cp, size): + max_sample = __builtin__.max(sample, max_sample) + min_sample = __builtin__.min(sample, min_sample) + + return min_sample, max_sample + + +def avg(cp, size): + _check_params(len(cp), size) + sample_count = _sample_count(cp, size) + if sample_count == 0: + return 0 + return sum(_get_samples(cp, size)) / sample_count + + +def rms(cp, size): + _check_params(len(cp), size) + + sample_count = _sample_count(cp, size) + if sample_count == 0: + return 0 + + sum_squares = sum(sample**2 for sample in _get_samples(cp, size)) + return int(math.sqrt(sum_squares / sample_count)) + + +def _sum2(cp1, cp2, length): + size = 2 + total = 0 + for i in range(length): + total += getsample(cp1, size, i) * getsample(cp2, size, i) + return total + + +def findfit(cp1, cp2): + size = 2 + + if len(cp1) % 2 != 0 or len(cp2) % 2 != 0: + raise error("Strings should be even-sized") + + if len(cp1) < len(cp2): + raise error("First sample should be longer") + + len1 = _sample_count(cp1, size) + len2 = _sample_count(cp2, size) + + sum_ri_2 = _sum2(cp2, cp2, len2) + sum_aij_2 = _sum2(cp1, cp1, len2) + sum_aij_ri = _sum2(cp1, cp2, len2) + + result = (sum_ri_2 * sum_aij_2 - sum_aij_ri * sum_aij_ri) / sum_aij_2 + + best_result = result + best_i = 0 + + for i in range(1, len1 - len2 + 1): + aj_m1 = _get_sample(cp1, size, i - 1) + aj_lm1 = _get_sample(cp1, size, i + len2 - 1) + + sum_aij_2 += aj_lm1**2 - aj_m1**2 + sum_aij_ri = _sum2(buffer(cp1)[i*size:], cp2, len2) + + result = (sum_ri_2 * sum_aij_2 - sum_aij_ri * sum_aij_ri) / sum_aij_2 + + if result < best_result: + best_result = result + best_i = i + + factor = _sum2(buffer(cp1)[best_i*size:], cp2, len2) / sum_ri_2 + + return best_i, factor + + +def findfactor(cp1, cp2): + size = 2 + + if len(cp1) % 2 != 0: + raise error("Strings should be even-sized") + + if len(cp1) != len(cp2): + raise error("Samples should be same size") + + sample_count = _sample_count(cp1, size) + + sum_ri_2 = _sum2(cp2, cp2, sample_count) + sum_aij_ri = _sum2(cp1, cp2, sample_count) + + return sum_aij_ri / sum_ri_2 + + +def findmax(cp, len2): + size = 2 + sample_count = _sample_count(cp, size) + + if len(cp) % 2 != 0: + raise error("Strings should be even-sized") + + if len2 < 0 or sample_count < len2: + raise error("Input sample should be longer") + + if sample_count == 0: + return 0 + + result = _sum2(cp, cp, len2) + best_result = result + best_i = 0 + + for i in range(1, sample_count - len2 + 1): + sample_leaving_window = getsample(cp, size, i - 1) + sample_entering_window = getsample(cp, size, i + len2 - 1) + + result -= sample_leaving_window**2 + result += sample_entering_window**2 + + if result > best_result: + best_result = result + best_i = i + + return best_i + + +def avgpp(cp, size): + _check_params(len(cp), size) + sample_count = _sample_count(cp, size) + + prevextremevalid = False + prevextreme = None + avg = 0 + nextreme = 0 + + prevval = getsample(cp, size, 0) + val = getsample(cp, size, 1) + + prevdiff = val - prevval + + for i in range(1, sample_count): + val = getsample(cp, size, i) + diff = val - prevval + + if diff * prevdiff < 0: + if prevextremevalid: + avg += abs(prevval - prevextreme) + nextreme += 1 + + prevextremevalid = True + prevextreme = prevval + + prevval = val + if diff != 0: + prevdiff = diff + + if nextreme == 0: + return 0 + + return avg / nextreme + + +def maxpp(cp, size): + _check_params(len(cp), size) + sample_count = _sample_count(cp, size) + + prevextremevalid = False + prevextreme = None + max = 0 + + prevval = getsample(cp, size, 0) + val = getsample(cp, size, 1) + + prevdiff = val - prevval + + for i in range(1, sample_count): + val = getsample(cp, size, i) + diff = val - prevval + + if diff * prevdiff < 0: + if prevextremevalid: + extremediff = abs(prevval - prevextreme) + if extremediff > max: + max = extremediff + prevextremevalid = True + prevextreme = prevval + + prevval = val + if diff != 0: + prevdiff = diff + + return max + + +def cross(cp, size): + _check_params(len(cp), size) + + crossings = 0 + last_sample = 0 + for sample in _get_samples(cp, size): + if sample <= 0 < last_sample or sample >= 0 > last_sample: + crossings += 1 + last_sample = sample + + return crossings + + +def mul(cp, size, factor): + _check_params(len(cp), size) + clip = _get_clipfn(size) + + result = create_string_buffer(len(cp)) + + for i, sample in enumerate(_get_samples(cp, size)): + sample = clip(int(sample * factor)) + _put_sample(result, size, i, sample) + + return result.raw + + +def tomono(cp, size, fac1, fac2): + _check_params(len(cp), size) + clip = _get_clipfn(size) + + sample_count = _sample_count(cp, size) + + result = create_string_buffer(len(cp) / 2) + + for i in range(0, sample_count, 2): + l_sample = getsample(cp, size, i) + r_sample = getsample(cp, size, i + 1) + + sample = (l_sample * fac1) + (r_sample * fac2) + sample = clip(sample) + + _put_sample(result, size, i / 2, sample) + + return result.raw + + +def tostereo(cp, size, fac1, fac2): + _check_params(len(cp), size) + + sample_count = _sample_count(cp, size) + + result = create_string_buffer(len(cp) * 2) + clip = _get_clipfn(size) + + for i in range(sample_count): + sample = _get_sample(cp, size, i) + + l_sample = clip(sample * fac1) + r_sample = clip(sample * fac2) + + _put_sample(result, size, i * 2, l_sample) + _put_sample(result, size, i * 2 + 1, r_sample) + + return result.raw + + +def add(cp1, cp2, size): + _check_params(len(cp1), size) + + if len(cp1) != len(cp2): + raise error("Lengths should be the same") + + clip = _get_clipfn(size) + sample_count = _sample_count(cp1, size) + result = create_string_buffer(len(cp1)) + + for i in range(sample_count): + sample1 = getsample(cp1, size, i) + sample2 = getsample(cp2, size, i) + + sample = clip(sample1 + sample2) + + _put_sample(result, size, i, sample) + + return result.raw + + +def bias(cp, size, bias): + _check_params(len(cp), size) + + result = create_string_buffer(len(cp)) + + for i, sample in enumerate(_get_samples(cp, size)): + sample = _overflow(sample + bias, size) + _put_sample(result, size, i, sample) + + return result.raw + + +def reverse(cp, size): + _check_params(len(cp), size) + sample_count = _sample_count(cp, size) + + result = create_string_buffer(len(cp)) + for i, sample in enumerate(_get_samples(cp, size)): + _put_sample(result, size, sample_count - i - 1, sample) + + return result.raw + + +def lin2lin(cp, size, size2): + _check_params(len(cp), size) + _check_size(size2) + + if size == size2: + return cp + + new_len = (len(cp) / size) * size2 + + result = create_string_buffer(new_len) + + for i in range(_sample_count(cp, size)): + sample = _get_sample(cp, size, i) + if size < size2: + sample = sample << (4 * size2 / size) + elif size > size2: + sample = sample >> (4 * size / size2) + + sample = _overflow(sample, size2) + + _put_sample(result, size2, i, sample) + + return result.raw + + +def ratecv(cp, size, nchannels, inrate, outrate, state, weightA=1, weightB=0): + _check_params(len(cp), size) + if nchannels < 1: + raise error("# of channels should be >= 1") + + bytes_per_frame = size * nchannels + frame_count = len(cp) / bytes_per_frame + + if bytes_per_frame / nchannels != size: + raise OverflowError("width * nchannels too big for a C int") + + if weightA < 1 or weightB < 0: + raise error("weightA should be >= 1, weightB should be >= 0") + + if len(cp) % bytes_per_frame != 0: + raise error("not a whole number of frames") + + if inrate <= 0 or outrate <= 0: + raise error("sampling rate not > 0") + + d = gcd(inrate, outrate) + inrate /= d + outrate /= d + + prev_i = [0] * nchannels + cur_i = [0] * nchannels + + if state is None: + d = -outrate + else: + d, samps = state + + if len(samps) != nchannels: + raise error("illegal state argument") + + prev_i, cur_i = zip(*samps) + prev_i, cur_i = list(prev_i), list(cur_i) + + q = frame_count / inrate + ceiling = (q + 1) * outrate + nbytes = ceiling * bytes_per_frame + + result = create_string_buffer(nbytes) + + samples = _get_samples(cp, size) + out_i = 0 + while True: + while d < 0: + if frame_count == 0: + samps = zip(prev_i, cur_i) + retval = result.raw + + # slice off extra bytes + trim_index = (out_i * bytes_per_frame) - len(retval) + retval = buffer(retval)[:trim_index] + + return (retval, (d, tuple(samps))) + + for chan in range(nchannels): + prev_i[chan] = cur_i[chan] + cur_i[chan] = samples.next() + + cur_i[chan] = ( + (weightA * cur_i[chan] + weightB * prev_i[chan]) + / (weightA + weightB) + ) + + frame_count -= 1 + d += outrate + + while d >= 0: + for chan in range(nchannels): + cur_o = ( + (prev_i[chan] * d + cur_i[chan] * (outrate - d)) + / outrate + ) + _put_sample(result, size, out_i, _overflow(cur_o, size)) + out_i += 1 + d -= inrate + + +def lin2ulaw(cp, size): + raise NotImplementedError() + + +def ulaw2lin(cp, size): + raise NotImplementedError() + + +def lin2alaw(cp, size): + raise NotImplementedError() + + +def alaw2lin(cp, size): + raise NotImplementedError() + + +def lin2adpcm(cp, size, state): + raise NotImplementedError() + + +def adpcm2lin(cp, size, state): + raise NotImplementedError() diff --git a/pypy/doc/whatsnew-head.rst b/pypy/doc/whatsnew-head.rst --- a/pypy/doc/whatsnew-head.rst +++ b/pypy/doc/whatsnew-head.rst @@ -78,3 +78,7 @@ .. branch: optimize-int-and Optimize away INT_AND with constant mask of 1s that fully cover the bitrange of other operand. + +.. branch: bounds-int-add-or +Propagate appropriate bounds through INT_(OR|XOR|AND) operations if the +operands are positive to kill some guards diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -964,8 +964,7 @@ # ----------------------- reduce ------------------------------- - def _reduce_ufunc_impl(ufunc_name, promote_to_largest=False, - cumulative=False): + def _reduce_ufunc_impl(ufunc_name, cumulative=False): @unwrap_spec(keepdims=bool) def impl(self, space, w_axis=None, w_dtype=None, w_out=None, keepdims=False): if space.is_none(w_out): @@ -976,13 +975,11 @@ else: out = w_out return getattr(interp_ufuncs.get(space), ufunc_name).reduce( - space, self, promote_to_largest, w_axis, - keepdims, out, w_dtype, cumulative=cumulative) - return func_with_new_name(impl, "reduce_%s_impl_%d_%d" % (ufunc_name, - promote_to_largest, cumulative)) + space, self, w_axis, keepdims, out, w_dtype, cumulative=cumulative) + return func_with_new_name(impl, "reduce_%s_impl_%d" % (ufunc_name, cumulative)) - descr_sum = _reduce_ufunc_impl("add", True) - descr_prod = _reduce_ufunc_impl("multiply", True) + descr_sum = _reduce_ufunc_impl("add") + descr_prod = _reduce_ufunc_impl("multiply") descr_max = _reduce_ufunc_impl("maximum") descr_min = _reduce_ufunc_impl("minimum") descr_all = _reduce_ufunc_impl('logical_and') diff --git a/pypy/module/micronumpy/interp_ufuncs.py b/pypy/module/micronumpy/interp_ufuncs.py --- a/pypy/module/micronumpy/interp_ufuncs.py +++ b/pypy/module/micronumpy/interp_ufuncs.py @@ -19,12 +19,15 @@ class W_Ufunc(W_Root): - _immutable_fields_ = ["name", "promote_to_float", "promote_bools", "identity", - "int_only", "allow_bool", "allow_complex", "complex_to_float"] + _immutable_fields_ = [ + "name", "promote_to_largest", "promote_to_float", "promote_bools", + "identity", "int_only", "allow_bool", "allow_complex", "complex_to_float" + ] - def __init__(self, name, promote_to_float, promote_bools, identity, - int_only, allow_bool, allow_complex, complex_to_float): + def __init__(self, name, promote_to_largest, promote_to_float, promote_bools, + identity, int_only, allow_bool, allow_complex, complex_to_float): self.name = name + self.promote_to_largest = promote_to_largest self.promote_to_float = promote_to_float self.promote_bools = promote_bools self.identity = identity @@ -88,9 +91,8 @@ 'output must be an array')) else: out = w_out - return self.reduce(space, w_obj, False, #do not promote_to_largest - w_axis, True, #keepdims must be true - out, w_dtype, cumulative=True) + return self.reduce(space, w_obj, w_axis, True, #keepdims must be true + out, w_dtype, cumulative=True) @unwrap_spec(skipna=bool, keepdims=bool) def descr_reduce(self, space, w_obj, w_axis=None, w_dtype=None, @@ -154,15 +156,13 @@ out = None elif not isinstance(w_out, W_NDimArray): raise OperationError(space.w_TypeError, space.wrap( - 'output must be an array')) + 'output must be an array')) else: out = w_out - promote_to_largest = False - return self.reduce(space, w_obj, promote_to_largest, w_axis, keepdims, out, - w_dtype) + return self.reduce(space, w_obj, w_axis, keepdims, out, w_dtype) - def reduce(self, space, w_obj, promote_to_largest, w_axis, - keepdims=False, out=None, dtype=None, cumulative=False): + def reduce(self, space, w_obj, w_axis, keepdims=False, out=None, dtype=None, + cumulative=False): if self.argcount != 2: raise OperationError(space.w_ValueError, space.wrap("reduce only " "supported for binary functions")) @@ -185,8 +185,8 @@ dtype = find_unaryop_result_dtype( space, obj.get_dtype(), promote_to_float=self.promote_to_float, - promote_to_largest=promote_to_largest, - promote_bools=True + promote_to_largest=self.promote_to_largest, + promote_bools=self.promote_bools, ) if self.identity is None: for i in range(shapelen): @@ -263,18 +263,18 @@ return self._outer(space, __args__) def _outer(self, space, __args__): - raise OperationError(space.w_ValueError, - space.wrap("outer product only supported for binary functions")) + raise OperationError(space.w_ValueError, space.wrap( + "outer product only supported for binary functions")) class W_Ufunc1(W_Ufunc): _immutable_fields_ = ["func", "bool_result"] argcount = 1 - def __init__(self, func, name, promote_to_float=False, promote_bools=False, - identity=None, bool_result=False, int_only=False, + def __init__(self, func, name, promote_to_largest=False, promote_to_float=False, + promote_bools=False, identity=None, bool_result=False, int_only=False, allow_bool=True, allow_complex=True, complex_to_float=False): - W_Ufunc.__init__(self, name, promote_to_float, promote_bools, identity, - int_only, allow_bool, allow_complex, complex_to_float) + W_Ufunc.__init__(self, name, promote_to_largest, promote_to_float, promote_bools, + identity, int_only, allow_bool, allow_complex, complex_to_float) self.func = func self.bool_result = bool_result @@ -336,11 +336,11 @@ _immutable_fields_ = ["func", "comparison_func", "done_func"] argcount = 2 - def __init__(self, func, name, promote_to_float=False, promote_bools=False, - identity=None, comparison_func=False, int_only=False, + def __init__(self, func, name, promote_to_largest=False, promote_to_float=False, + promote_bools=False, identity=None, comparison_func=False, int_only=False, allow_bool=True, allow_complex=True, complex_to_float=False): - W_Ufunc.__init__(self, name, promote_to_float, promote_bools, identity, - int_only, allow_bool, allow_complex, complex_to_float) + W_Ufunc.__init__(self, name, promote_to_largest, promote_to_float, promote_bools, + identity, int_only, allow_bool, allow_complex, complex_to_float) self.func = func self.comparison_func = comparison_func if name == 'logical_and': @@ -606,9 +606,9 @@ def __init__(self, space): "NOT_RPYTHON" for ufunc_def in [ - ("add", "add", 2, {"identity": 0}), + ("add", "add", 2, {"identity": 0, "promote_to_largest": True}), ("subtract", "sub", 2), - ("multiply", "mul", 2, {"identity": 1}), + ("multiply", "mul", 2, {"identity": 1, "promote_to_largest": True}), ("bitwise_and", "bitwise_and", 2, {"identity": 1, "int_only": True}), ("bitwise_or", "bitwise_or", 2, {"identity": 0, diff --git a/pypy/module/micronumpy/test/test_ufuncs.py b/pypy/module/micronumpy/test/test_ufuncs.py --- a/pypy/module/micronumpy/test/test_ufuncs.py +++ b/pypy/module/micronumpy/test/test_ufuncs.py @@ -756,7 +756,7 @@ raises(ValueError, maximum.reduce, zeros((2, 0)), axis=1) def test_reduce_1d(self): - from numpypy import add, maximum, less + from numpypy import array, add, maximum, less, float16, complex64 assert less.reduce([5, 4, 3, 2, 1]) assert add.reduce([1, 2, 3]) == 6 @@ -764,6 +764,12 @@ assert maximum.reduce([1, 2, 3]) == 3 raises(ValueError, maximum.reduce, []) + assert add.reduce(array([True, False] * 200)) == 200 + assert add.reduce(array([True, False] * 200, dtype='int8')) == 200 + assert add.reduce(array([True, False] * 200), dtype='int8') == -56 + assert type(add.reduce(array([True, False] * 200, dtype='float16'))) is float16 + assert type(add.reduce(array([True, False] * 200, dtype='complex64'))) is complex64 + def test_reduceND(self): from numpypy import add, arange a = arange(12).reshape(3, 4) @@ -1025,7 +1031,7 @@ assert logaddexp2(float('inf'), float('inf')) == float('inf') def test_accumulate(self): - from numpypy import add, multiply, arange + from numpypy import add, subtract, multiply, divide, arange, dtype assert (add.accumulate([2, 3, 5]) == [2, 5, 10]).all() assert (multiply.accumulate([2, 3, 5]) == [2, 6, 30]).all() a = arange(4).reshape(2,2) @@ -1041,6 +1047,10 @@ print b assert (b == [[0, 0, 1], [1, 3, 5]]).all() assert b.dtype == int + assert add.accumulate([True]*200)[-1] == 200 + assert add.accumulate([True]*200).dtype == dtype('int') + assert subtract.accumulate([True]*200).dtype == dtype('bool') + assert divide.accumulate([True]*200).dtype == dtype('int8') def test_noncommutative_reduce_accumulate(self): import numpypy as np diff --git a/rpython/jit/metainterp/optimizeopt/intbounds.py b/rpython/jit/metainterp/optimizeopt/intbounds.py --- a/rpython/jit/metainterp/optimizeopt/intbounds.py +++ b/rpython/jit/metainterp/optimizeopt/intbounds.py @@ -7,6 +7,7 @@ CONST_0, MODE_ARRAY, MODE_STR, MODE_UNICODE) from rpython.jit.metainterp.optimizeopt.util import make_dispatcher_method from rpython.jit.metainterp.resoperation import rop +from rpython.jit.backend.llsupport import symbolic def get_integer_min(is_unsigned, byte_size): @@ -23,6 +24,17 @@ return (1 << ((byte_size << 3) - 1)) - 1 +def next_pow2_m1(n): + """Calculate next power of 2 greater than n minus one.""" + n |= n >> 1 + n |= n >> 2 + n |= n >> 4 + n |= n >> 8 + n |= n >> 16 + n |= n >> 32 + return n + + class OptIntBounds(Optimization): """Keeps track of the bounds placed on integers by guards and remove redundant guards""" @@ -56,17 +68,24 @@ optimize_GUARD_FALSE = optimize_GUARD_TRUE optimize_GUARD_VALUE = optimize_GUARD_TRUE - def optimize_INT_XOR(self, op): + def optimize_INT_OR_or_XOR(self, op): v1 = self.getvalue(op.getarg(0)) v2 = self.getvalue(op.getarg(1)) if v1 is v2: - self.make_constant_int(op.result, 0) + if op.getopnum() == rop.INT_OR: + self.make_equal_to(op.result, v1) + else: + self.make_constant_int(op.result, 0) return self.emit_operation(op) if v1.intbound.known_ge(IntBound(0, 0)) and \ v2.intbound.known_ge(IntBound(0, 0)): r = self.getvalue(op.result) - r.intbound.make_ge(IntLowerBound(0)) + mostsignificant = v1.intbound.upper | v2.intbound.upper + r.intbound.intersect(IntBound(0, next_pow2_m1(mostsignificant))) + + optimize_INT_OR = optimize_INT_OR_or_XOR + optimize_INT_XOR = optimize_INT_OR_or_XOR def optimize_INT_AND(self, op): v1 = self.getvalue(op.getarg(0)) @@ -82,6 +101,10 @@ val = v1.box.getint() if val >= 0: r.intbound.intersect(IntBound(0, val)) + elif v1.intbound.known_ge(IntBound(0, 0)) and \ + v2.intbound.known_ge(IntBound(0, 0)): + lesser = min(v1.intbound.upper, v2.intbound.upper) + r.intbound.intersect(IntBound(0, next_pow2_m1(lesser))) def optimize_INT_SUB(self, op): v1 = self.getvalue(op.getarg(0)) diff --git a/rpython/jit/metainterp/optimizeopt/test/test_intbounds.py b/rpython/jit/metainterp/optimizeopt/test/test_intbounds.py new file mode 100644 --- /dev/null +++ b/rpython/jit/metainterp/optimizeopt/test/test_intbounds.py @@ -0,0 +1,12 @@ +from rpython.jit.metainterp.optimizeopt.intbounds import next_pow2_m1 + + +def test_next_pow2_m1(): + assert next_pow2_m1(0) == 0 + assert next_pow2_m1(1) == 1 + assert next_pow2_m1(7) == 7 + assert next_pow2_m1(256) == 511 + assert next_pow2_m1(255) == 255 + assert next_pow2_m1(80) == 127 + assert next_pow2_m1((1 << 32) - 5) == (1 << 32) - 1 + assert next_pow2_m1((1 << 64) - 1) == (1 << 64) - 1 diff --git a/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py b/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py --- a/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py +++ b/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py @@ -5326,6 +5326,114 @@ """ self.optimize_loop(ops, ops) + def test_int_and_cmp_above_bounds(self): + ops = """ + [p0,p1] + i0 = getarrayitem_gc(p0, 0, descr=chararraydescr) + i1 = getarrayitem_gc(p1, 0, descr=u2arraydescr) + i2 = int_and(i0, i1) + i3 = int_le(i2, 255) + guard_true(i3) [] + jump(i2) + """ + + expected = """ + [p0,p1] + i0 = getarrayitem_gc(p0, 0, descr=chararraydescr) + i1 = getarrayitem_gc(p1, 0, descr=u2arraydescr) + i2 = int_and(i0, i1) + jump(i2) + """ + self.optimize_loop(ops, expected) + + def test_int_and_cmp_below_bounds(self): + ops = """ + [p0,p1] + i0 = getarrayitem_gc(p0, 0, descr=chararraydescr) + i1 = getarrayitem_gc(p1, 0, descr=u2arraydescr) + i2 = int_and(i0, i1) + i3 = int_lt(i2, 255) + guard_true(i3) [] + jump(i2) + """ + self.optimize_loop(ops, ops) + + def test_int_or_cmp_above_bounds(self): + ops = """ + [p0,p1] + i0 = getarrayitem_gc(p0, 0, descr=chararraydescr) + i1 = getarrayitem_gc(p1, 0, descr=u2arraydescr) + i2 = int_or(i0, i1) + i3 = int_le(i2, 65535) + guard_true(i3) [] + jump(i2) + """ + + expected = """ + [p0,p1] + i0 = getarrayitem_gc(p0, 0, descr=chararraydescr) + i1 = getarrayitem_gc(p1, 0, descr=u2arraydescr) + i2 = int_or(i0, i1) + jump(i2) + """ + self.optimize_loop(ops, expected) + + def test_int_or_cmp_below_bounds(self): + ops = """ + [p0,p1] + i0 = getarrayitem_gc(p0, 0, descr=chararraydescr) + i1 = getarrayitem_gc(p1, 0, descr=u2arraydescr) + i2 = int_or(i0, i1) + i3 = int_lt(i2, 65535) + guard_true(i3) [] + jump(i2) + """ + self.optimize_loop(ops, ops) + + def test_int_xor_cmp_above_bounds(self): + ops = """ + [p0,p1] + i0 = getarrayitem_gc(p0, 0, descr=chararraydescr) + i1 = getarrayitem_gc(p1, 0, descr=u2arraydescr) + i2 = int_xor(i0, i1) + i3 = int_le(i2, 65535) + guard_true(i3) [] + jump(i2) + """ + + expected = """ + [p0,p1] + i0 = getarrayitem_gc(p0, 0, descr=chararraydescr) + i1 = getarrayitem_gc(p1, 0, descr=u2arraydescr) + i2 = int_xor(i0, i1) + jump(i2) + """ + self.optimize_loop(ops, expected) + + def test_int_xor_cmp_below_bounds(self): + ops = """ + [p0,p1] + i0 = getarrayitem_gc(p0, 0, descr=chararraydescr) + i1 = getarrayitem_gc(p1, 0, descr=u2arraydescr) + i2 = int_xor(i0, i1) + i3 = int_lt(i2, 65535) + guard_true(i3) [] + jump(i2) + """ + self.optimize_loop(ops, ops) + + def test_int_or_same_arg(self): + ops = """ + [i0] + i1 = int_or(i0, i0) + jump(i1) + """ + expected = """ + [i0] + jump(i0) + """ + self.optimize_loop(ops, expected) + class TestLLtype(BaseTestOptimizeBasic, LLtypeMixin): pass diff --git a/rpython/jit/metainterp/optimizeopt/test/test_util.py b/rpython/jit/metainterp/optimizeopt/test/test_util.py --- a/rpython/jit/metainterp/optimizeopt/test/test_util.py +++ b/rpython/jit/metainterp/optimizeopt/test/test_util.py @@ -1,6 +1,6 @@ import py, random -from rpython.rtyper.lltypesystem import lltype, llmemory, rclass, rstr +from rpython.rtyper.lltypesystem import lltype, llmemory, rclass, rstr, rffi from rpython.rtyper.lltypesystem.rclass import OBJECT, OBJECT_VTABLE from rpython.rtyper.rclass import FieldListAccessor, IR_QUASIIMMUTABLE @@ -208,6 +208,8 @@ chararray = lltype.GcArray(lltype.Char) chararraydescr = cpu.arraydescrof(chararray) + u2array = lltype.GcArray(rffi.USHORT) + u2arraydescr = cpu.arraydescrof(u2array) # array of structs (complex data) complexarray = lltype.GcArray( _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit