Commit ca91ec9b authored by Mark Florisson's avatar Mark Florisson

slice assignment broadcasting & fix some bugs

parent 017b73ae
......@@ -1694,7 +1694,7 @@ class NameNode(AtomicExprNode):
code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result())
elif entry.is_local or entry.in_closure or entry.from_closure:
elif entry.is_local or entry.in_closure or entry.from_closure or entry.type.is_memoryviewslice:
# Raise UnboundLocalError for objects and memoryviewslices
raise_unbound = (
(self.cf_maybe_null or self.cf_is_null) and not self.allow_null)
......
......@@ -431,57 +431,20 @@ def verify_direct_dimensions(node):
for access, packing in node.type.axes:
if access != 'direct':
error(self.pos, "All dimensions must be direct")
return False
return True
def broadcast(src, dst, src_temp, dst_temp, code):
"Perform an in-place broadcast of slices src and dst"
if src.type.ndim != dst.type.ndim:
code.putln("__pyx_memoryview_broadcast_inplace(&%s, &%s, %d, %d);" % (
src_temp, dst_temp, src.type.ndim, dst.type.ndim))
return max(src.type.ndim, dst.type.ndim)
return src.type.ndim
def copy_broadcast_memview_src_to_dst_inplace(src, dst, src_temp, dst_temp, code):
def copy_broadcast_memview_src_to_dst(src, dst, code):
"""
It is hard to check for overlapping memory with indirect slices,
so we currently don't support them.
Copy the contents of slice src to slice dst. Does not support indirect
slices.
"""
if not verify_direct_dimensions(src): return
if not verify_direct_dimensions(dst): return
ndim = broadcast(src, dst, src_temp, dst_temp, code)
call = "%s(&%s, &%s, %d)" % (copy_src_to_dst_cname(),
src_temp, dst_temp, ndim)
code.putln(code.error_goto_if_neg(call, dst.pos))
def copy_broadcast_memview_src_to_dst(src, dst, code):
# Note: do not use code.funcstate.allocate_temp to allocate temps, as
# temps will be acquisition counted (so we would need new
# references, as any sudden exception would cause a jump leading to
# a decref before we can nullify our slice)
src_tmp = None
dst_tmp = None
code.begin_block()
if src.type.ndim < dst.type.ndim and not src.result_in_temp():
src_tmp = '__pyx_slice_tmp1'
code.putln("%s %s = %s;" % (memviewslice_cname, src_tmp, src.result()))
if dst.type.ndim < src.type.ndim and not dst.result_in_temp():
dst_tmp = '__pyx+_slice_tmp2'
code.putln("%s %s = %s;" % (memviewslice_cname, dst_tmp, dst.result()))
copy_broadcast_memview_src_to_dst_inplace(src, dst,
src_tmp or src.result(),
dst_tmp or dst.result(),
code)
verify_direct_dimensions(src)
verify_direct_dimensions(dst)
code.end_block()
code.putln(code.error_goto_if_neg(
"%s(%s, %s, %d, %d)" % (copy_src_to_dst_cname(),
src.result(), dst.result(),
src.type.ndim, dst.type.ndim),
dst.pos))
def copy_c_or_fortran_cname(memview):
if memview.is_c_contig:
......@@ -791,7 +754,8 @@ def load_memview_c_utility(util_code_name, context=None, **kwargs):
context=context, **kwargs)
def use_cython_array_utility_code(env):
env.global_scope().context.cython_scope.lookup('array_cwrapper').used = True
scope = env.global_scope().context.cython_scope
scope.lookup('array_cwrapper').used = True
env.use_utility_code(cython_array_utility_code)
context = {
......
This diff is collapsed.
......@@ -18,12 +18,12 @@ typedef struct {
#define CYTHON_ATOMICS 1
#endif
#define __pyx_atomic_int_type int
/* todo: Portland pgcc, maybe OS X's OSAtomicIncrement32,
libatomic + autotools-like distutils support? Such a pain... */
#if CYTHON_ATOMICS && __GNUC__ >= 4 && (__GNUC_MINOR__ > 1 || \
(__GNUC_MINOR__ == 1 && __GNUC_PATHLEVEL >= 2))
/* gcc >= 4.1.2 */
typedef volatile int __pyx_atomic_int;
#define __pyx_atomic_incr_aligned(value, lock) __sync_fetch_and_add(value, 1)
#define __pyx_atomic_decr_aligned(value, lock) __sync_fetch_and_sub(value, 1)
......@@ -33,7 +33,7 @@ typedef struct {
#elif CYTHON_ATOMICS && MSC_VER
/* msvc */
#include <Windows.h>
typedef volatile LONG __pyx_atomic_int;
#define __pyx_atomic_int_type LONG
#define __pyx_atomic_incr_aligned(value, lock) InterlockedIncrement(value)
#define __pyx_atomic_decr_aligned(value, lock) InterlockedDecrement(value)
......@@ -41,7 +41,6 @@ typedef struct {
#warning "Using MSVC atomics"
#endif
#elif CYTHON_ATOMICS && (defined(__ICC) || defined(__INTEL_COMPILER))
typedef volatile int __pyx_atomic_int;
#define __pyx_atomic_incr_aligned(value, lock) _InterlockedIncrement(value)
#define __pyx_atomic_decr_aligned(value, lock) _InterlockedDecrement(value)
......@@ -49,20 +48,20 @@ typedef struct {
#warning "Using Intel atomics"
#endif
#else
typedef volatile int __pyx_atomic_int;
#define CYTHON_ATOMICS 0
#ifdef __PYX_DEBUG_ATOMICS
#warning "Not using atomics"
#endif
#endif
typedef volatile __pyx_atomic_int_type __pyx_atomic_int;
#if CYTHON_ATOMICS
__pyx_atomic_int CYTHON_INLINE
static CYTHON_INLINE __pyx_atomic_int_type
__pyx_atomic_incr_maybealigned(__pyx_atomic_int *value, PyThread_type_lock lock);
__pyx_atomic_int CYTHON_INLINE
static CYTHON_INLINE __pyx_atomic_int_type
__pyx_atomic_decr_maybealigned(__pyx_atomic_int *value, PyThread_type_lock lock);
#define __pyx_add_acquisition_count(memview) \
......@@ -82,7 +81,7 @@ typedef struct {
#define __pyx_check_unaligned(type, pointer) \
(((type) pointer) & (sizeof(pointer) - 1))
int CYTHON_INLINE
static CYTHON_INLINE int
__pyx_atomic_unaligned(__pyx_atomic_int *p)
{
/* uintptr_t is optional in C99, try other stuff */
......@@ -99,7 +98,8 @@ __pyx_atomic_unaligned(__pyx_atomic_int *p)
return 1;
}
__pyx_atomic_int CYTHON_INLINE
static CYTHON_INLINE __pyx_atomic_int_type
__pyx_atomic_incr_maybealigned(__pyx_atomic_int *value, PyThread_type_lock lock)
{
if (unlikely(__pyx_atomic_unaligned(value)))
......@@ -108,7 +108,7 @@ __pyx_atomic_incr_maybealigned(__pyx_atomic_int *value, PyThread_type_lock lock)
return __pyx_atomic_incr_aligned(value, lock);
}
__pyx_atomic_int CYTHON_INLINE
static CYTHON_INLINE __pyx_atomic_int_type
__pyx_atomic_decr_maybealigned(__pyx_atomic_int *value, PyThread_type_lock lock)
{
if (unlikely(__pyx_atomic_unaligned(value)))
......@@ -522,8 +522,7 @@ __pyx_memoryview_copy_new_contig(const __Pyx_memviewslice *from_mvs,
if (unlikely(__Pyx_init_memviewslice(memview_obj, ndim, &new_mvs) < 0))
goto fail;
if (unlikely(__pyx_memoryview_copy_contents(
({{memviewslice_name}} *) from_mvs, &new_mvs, ndim) < 0))
if (unlikely(__pyx_memoryview_copy_contents(*from_mvs, new_mvs, ndim, ndim) < 0))
goto fail;
goto no_fail;
......
......@@ -171,10 +171,10 @@ def test_copy_mismatch():
>>> test_copy_mismatch()
Traceback (most recent call last):
...
ValueError: memoryview shapes are not the same in dimension 0 (got 2 and 1)
ValueError: got differing extents in dimension 0 (got 2 and 3)
'''
cdef int[:,:,::1] mv1 = array((2,2,3), sizeof(int), 'i')
cdef int[:,:,::1] mv2 = array((1,2,3), sizeof(int), 'i')
cdef int[:,:,::1] mv2 = array((3,2,3), sizeof(int), 'i')
mv1[...] = mv2
......
......@@ -1747,7 +1747,7 @@ def test_slice_assignment():
for i in range(10):
for j in range(100):
carray[i][j] = i * 10 + j
carray[i][j] = i * 100 + j
cdef int[:, :] m = carray
cdef int[:, :] copy = m[-6:-1, 60:65].copy()
......@@ -1758,12 +1758,12 @@ def test_slice_assignment():
for i in range(5):
for j in range(5):
assert copy[i, j] == m[-5 + i, -5 + j]
assert copy[i, j] == m[-5 + i, -5 + j], (copy[i, j], m[-5 + i, -5 + j])
@testcase
def test_slice_assignment_broadcast_leading_dimensions():
def test_slice_assignment_broadcast_leading():
"""
>>> test_slice_assignment_broadcast_leading_dimensions()
>>> test_slice_assignment_broadcast_leading()
"""
cdef int array1[1][10]
cdef int array2[10]
......@@ -1780,4 +1780,36 @@ def test_slice_assignment_broadcast_leading_dimensions():
a[:, :] = b[:]
for i in range(10):
assert a[0, i] == b[i] == 10 - 1 - i
assert a[0, i] == b[i] == 10 - 1 - i, (b[i], a[0, i])
@testcase
def test_slice_assignment_broadcast_strides():
"""
>>> test_slice_assignment_broadcast_strides()
"""
cdef int src_array[10]
cdef int dst_array[10][5]
cdef int i, j
for i in range(10):
src_array[i] = 10 - 1 - i
cdef int[:] src = src_array
cdef int[:, :] dst = dst_array
cdef int[:, :] dst_f = dst.copy_fortran()
dst[1:] = src[-1:-6:-1]
dst_f[1:] = src[-1:-6:-1]
for i in range(1, 10):
for j in range(1, 5):
assert dst[i, j] == dst_f[i, j] == j, (dst[i, j], dst_f[i, j], j)
# test overlapping memory with broadcasting
dst[:, 1:4] = dst[1, :3]
dst_f[:, 1:4] = dst[1, 1:4]
for i in range(10):
for j in range(1, 3):
assert dst[i, j] == dst_f[i, j] == j - 1, (dst[i, j], dst_f[i, j], j - 1)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment