summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCharles Harris <charlesr.harris@gmail.com>2019-01-08 11:35:44 -0700
committerGitHub <noreply@github.com>2019-01-08 11:35:44 -0700
commit4d0732220ee56fd251665c43b6d43272ad5edef6 (patch)
treef0e889824068203e3ead18dbb0ae5241ae7e9758
parente8918143bce960e4f1220a2a210edc2c0d7799d7 (diff)
parentf54f39f8db70b902b2d91512aee6af19625159a4 (diff)
downloadnumpy-4d0732220ee56fd251665c43b6d43272ad5edef6.tar.gz
Merge pull request #12677 from ahaldane/fix_more_uint_aln
MAINT: Further fixups to uint alignment checks
-rw-r--r--doc/source/reference/alignment.rst2
-rw-r--r--numpy/core/src/multiarray/array_assign_array.c56
-rw-r--r--numpy/core/src/multiarray/nditer_constr.c2
-rw-r--r--numpy/core/src/umath/ufunc_object.c2
-rw-r--r--numpy/core/tests/test_multiarray.py33
5 files changed, 74 insertions, 21 deletions
diff --git a/doc/source/reference/alignment.rst b/doc/source/reference/alignment.rst
index b182a1e7b..ebc8f353c 100644
--- a/doc/source/reference/alignment.rst
+++ b/doc/source/reference/alignment.rst
@@ -97,7 +97,7 @@ Here is how the variables above are used:
Note that the strided-copy and strided-cast code are deeply intertwined and so
any arrays being processed by them must be both uint and true aligned, even
-though te copy-code only needs uint alignment and the cast code only true
+though the copy-code only needs uint alignment and the cast code only true
alignment. If there is ever a big rewrite of this code it would be good to
allow them to use different alignments.
diff --git a/numpy/core/src/multiarray/array_assign_array.c b/numpy/core/src/multiarray/array_assign_array.c
index 69a527dfa..b9c1e1be7 100644
--- a/numpy/core/src/multiarray/array_assign_array.c
+++ b/numpy/core/src/multiarray/array_assign_array.c
@@ -24,6 +24,38 @@
#include "array_assign.h"
+/* Check both uint and true alignment */
+NPY_NO_EXPORT int
+copycast_isaligned(int ndim, npy_intp *shape,
+ PyArray_Descr *dtype, char *data, npy_intp *strides)
+{
+ int aligned;
+ int big_aln, small_aln;
+
+ int uint_aln = npy_uint_alignment(dtype->elsize);
+ int true_aln = dtype->alignment;
+
+ /* uint alignment can be 0, meaning not uint alignable */
+ if (uint_aln == 0) {
+ return 0;
+ }
+
+ if (true_aln >= uint_aln) {
+ big_aln = true_aln;
+ small_aln = uint_aln;
+ }
+ else {
+ big_aln = uint_aln;
+ small_aln = true_aln;
+ }
+
+ aligned = raw_array_is_aligned(ndim, shape, data, strides, big_aln);
+ if (aligned && big_aln % small_aln != 0) {
+ aligned = raw_array_is_aligned(ndim, shape, data, strides, small_aln);
+ }
+ return aligned;
+}
+
/*
* Assigns the array from 'src' to 'dst'. The strides must already have
* been broadcast.
@@ -48,15 +80,9 @@ raw_array_assign_array(int ndim, npy_intp *shape,
NPY_BEGIN_THREADS_DEF;
- /* Check both uint and true alignment */
- aligned = raw_array_is_aligned(ndim, shape, dst_data, dst_strides,
- npy_uint_alignment(dst_dtype->elsize)) &&
- raw_array_is_aligned(ndim, shape, dst_data, dst_strides,
- dst_dtype->alignment) &&
- raw_array_is_aligned(ndim, shape, src_data, src_strides,
- npy_uint_alignment(src_dtype->elsize));
- raw_array_is_aligned(ndim, shape, src_data, src_strides,
- src_dtype->alignment);
+ aligned =
+ copycast_isaligned(ndim, shape, dst_dtype, dst_data, dst_strides) &&
+ copycast_isaligned(ndim, shape, src_dtype, src_data, src_strides);
/* Use raw iteration with no heap allocation */
if (PyArray_PrepareTwoRawArrayIter(
@@ -137,15 +163,9 @@ raw_array_wheremasked_assign_array(int ndim, npy_intp *shape,
NPY_BEGIN_THREADS_DEF;
- /* Check both uint and true alignment */
- aligned = raw_array_is_aligned(ndim, shape, dst_data, dst_strides,
- npy_uint_alignment(dst_dtype->elsize)) &&
- raw_array_is_aligned(ndim, shape, dst_data, dst_strides,
- dst_dtype->alignment) &&
- raw_array_is_aligned(ndim, shape, src_data, src_strides,
- npy_uint_alignment(src_dtype->elsize));
- raw_array_is_aligned(ndim, shape, src_data, src_strides,
- src_dtype->alignment);
+ aligned =
+ copycast_isaligned(ndim, shape, dst_dtype, dst_data, dst_strides) &&
+ copycast_isaligned(ndim, shape, src_dtype, src_data, src_strides);
/* Use raw iteration with no heap allocation */
if (PyArray_PrepareThreeRawArrayIter(
diff --git a/numpy/core/src/multiarray/nditer_constr.c b/numpy/core/src/multiarray/nditer_constr.c
index ba7041f32..18a2cc84f 100644
--- a/numpy/core/src/multiarray/nditer_constr.c
+++ b/numpy/core/src/multiarray/nditer_constr.c
@@ -1132,7 +1132,7 @@ npyiter_prepare_one_operand(PyArrayObject **op,
/* Check if the operand is aligned */
if (op_flags & NPY_ITER_ALIGNED) {
/* Check alignment */
- if (!(IsUintAligned(*op) && IsAligned(*op))) {
+ if (!IsAligned(*op)) {
NPY_IT_DBG_PRINT("Iterator: Setting NPY_OP_ITFLAG_CAST "
"because of NPY_ITER_ALIGNED\n");
*op_itflags |= NPY_OP_ITFLAG_CAST;
diff --git a/numpy/core/src/umath/ufunc_object.c b/numpy/core/src/umath/ufunc_object.c
index f950915f5..ac641c610 100644
--- a/numpy/core/src/umath/ufunc_object.c
+++ b/numpy/core/src/umath/ufunc_object.c
@@ -3066,7 +3066,7 @@ PyUFunc_GeneralizedFunction(PyUFuncObject *ufunc,
PyArray_free(remap_axis_memory);
PyArray_free(remap_axis);
- NPY_UF_DBG_PRINT1("Returning code %d\n", reval);
+ NPY_UF_DBG_PRINT1("Returning code %d\n", retval);
return retval;
diff --git a/numpy/core/tests/test_multiarray.py b/numpy/core/tests/test_multiarray.py
index 70cf74c4a..06cabe2cb 100644
--- a/numpy/core/tests/test_multiarray.py
+++ b/numpy/core/tests/test_multiarray.py
@@ -8020,6 +8020,39 @@ class TestAlignment(object):
for shape in [n, (1, 2, 3, n)]:
self.check(shape, np.dtype(dtype), order, align)
+ def test_strided_loop_alignments(self):
+ # particularly test that complex64 and float128 use right alignment
+ # code-paths, since these are particularly problematic. It is useful to
+ # turn on USE_DEBUG for this test, so lowlevel-loop asserts are run.
+ for align in [1, 2, 4, 8, 12, 16, None]:
+ xf64 = _aligned_zeros(3, np.float64)
+
+ xc64 = _aligned_zeros(3, np.complex64, align=align)
+ xf128 = _aligned_zeros(3, np.longdouble, align=align)
+
+ # test casting, both to and from misaligned
+ with suppress_warnings() as sup:
+ sup.filter(np.ComplexWarning, "Casting complex values")
+ xc64.astype('f8')
+ xf64.astype(np.complex64)
+ test = xc64 + xf64
+
+ xf128.astype('f8')
+ xf64.astype(np.longdouble)
+ test = xf128 + xf64
+
+ test = xf128 + xc64
+
+ # test copy, both to and from misaligned
+ # contig copy
+ xf64[:] = xf64.copy()
+ xc64[:] = xc64.copy()
+ xf128[:] = xf128.copy()
+ # strided copy
+ xf64[::2] = xf64[::2].copy()
+ xc64[::2] = xc64[::2].copy()
+ xf128[::2] = xf128[::2].copy()
+
def test_getfield():
a = np.arange(32, dtype='uint16')
if sys.byteorder == 'little':