[pypy-commit] pypy default: merge heads

arigo noreply at buildbot.pypy.org
Wed Feb 19 19:38:56 CET 2014


Author: Armin Rigo <arigo at 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(


More information about the pypy-commit mailing list