Skip to content

Commit 9642f47

Browse files
committed
Pull request #13: Migrate NpyIter implementation
Merge in ~STEPAN.SINDELAR_ORACLE.COM/numpy-hpy from fa/nditer2 to labs-hpy-port * commit 'b06d48d5f27887fe147801235142468758ab648b': (46 commits) Revert "Temporarily add missing scalarapi.h" Do appropriate include for alloca Introduce HNPY_cast_info, use HPyField in PyArrayMethodObject, migrate function signature 'resolve_descriptors_function' to HPy. Convert PyArrayMethod_Type to legacy HPy type Migrate define_cast_for_descrs, init_cast_info, PyArray_GetCastingImpl Use HPyArray_AdaptDescriptorToArray in hnpyiter_prepare_one_operand Do minimal migration of find_descriptor_from_array Migrate HPyArray_ExtractDTypeAndDescriptor to use HPyGlobal Migrate nditer_constr to use HPyGlobal Include hpy_utils.h in common.h Add HPyGlobal_Is to hpy_utils.c Migrate PyArray_ExtractDTypeAndDescriptor Introduce HPyGlobal HPyArrayDTypeMeta_Type Migrate PyArray_FailUnlessWriteable Introduce legacy accessors NIT_PY_OPERANDS and NIT_PY_DTYPES Finish minimal migration of HNpyIter_AdvancedNew Migrate PyArray_GetMaskedDTypeTransferFunction and PyArray_GetDTypeTransferFunction Temporarily add missing scalarapi.h Use HPyArray_NewFromDescr Add HPyArray_NewFromDescr to ctors.h ...
2 parents 2c00744 + b06d48d commit 9642f47

40 files changed

+2556
-798
lines changed

numpy/core/code_generators/numpy_api.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@
7474
'PyDatetimeArrType_Type': (215, None, '&PyDatetimeArrType_Type'),
7575
'PyTimedeltaArrType_Type': (216, None, '&PyTimedeltaArrType_Type'),
7676
'PyHalfArrType_Type': (217, None, '&PyHalfArrType_Type'),
77-
'NpyIter_Type': (218,),
77+
'NpyIter_Type': (218, None, "_NpyIter_Type_p"),
7878
# End 1.6 API
7979
}
8080

numpy/core/include/numpy/experimental_dtype_api.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,8 @@ typedef struct {
168168
void *reserved[3];
169169
} PyArray_DTypeMeta;
170170

171+
HPyType_LEGACY_HELPERS(PyArray_DTypeMeta)
172+
171173

172174
/*
173175
* ******************************************************

numpy/core/include/numpy/ndarrayobject.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,26 @@ PyArray_DiscardWritebackIfCopy(PyArrayObject *arr)
203203
}
204204
}
205205

206+
static NPY_INLINE void
207+
HPyArray_DiscardWritebackIfCopy(HPyContext *ctx, HPy h_arr)
208+
{
209+
if (!HPy_IsNull(h_arr)) {
210+
HPy h_base = HPyArray_GetBase(ctx, h_arr);
211+
if (HPy_IsNull(h_base)) {
212+
HPy_Close(ctx, h_arr);
213+
return;
214+
}
215+
int flags = HPyArray_FLAGS(ctx, h_arr);
216+
if (flags & NPY_ARRAY_WRITEBACKIFCOPY) {
217+
HPyArray_ENABLEFLAGS(ctx, h_base, NPY_ARRAY_WRITEABLE);
218+
HPyArray_SetBase(ctx, h_arr, HPy_NULL);
219+
HPyArray_CLEARFLAGS(ctx, h_arr, NPY_ARRAY_WRITEBACKIFCOPY);
220+
}
221+
HPy_Close(ctx, h_base);
222+
HPy_Close(ctx, h_arr);
223+
}
224+
}
225+
206226
#define PyArray_DESCR_REPLACE(descr) do { \
207227
PyArray_Descr *_new_; \
208228
_new_ = PyArray_DescrNew(descr); \
@@ -251,6 +271,10 @@ PyArray_DiscardWritebackIfCopy(PyArrayObject *arr)
251271
PyArray_FromDimsAndDataAndDescr(nd, d, PyArray_DescrFromType(type), \
252272
data)
253273

274+
/* Numpy HPy API */
275+
276+
NPY_NO_EXPORT int
277+
HPyArray_ResolveWritebackIfCopy(HPyContext *ctx, HPy self);
254278

255279
/*
256280
Check to see if this key in the dictionary is the "title"

numpy/core/include/numpy/ndarraytypes.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,13 @@ static NPY_INLINE
2424
void capi_warn(const char *where) {
2525
printf("DEBUG WARNING: leaving to CPython API in %s\n", where);
2626
}
27+
28+
static NPY_INLINE
29+
void capi_warn0(const char *caller_name, const char *file, int lineno) {
30+
printf("DEBUG WARNING: (%s:%d) leaving to CPython API in %s\n", file, lineno, caller_name);
31+
}
32+
33+
#define CAPI_WARN(_x) capi_warn0(_x, __FILE__, __LINE__)
2734
static __attribute__ ((noreturn)) NPY_INLINE
2835
void hpy_abort_not_implemented(const char *where) {
2936
printf("FATAL ERROR: not implemented in HPY: %s\n", where);

numpy/core/setup.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -927,6 +927,7 @@ def gl_if_msvc(build_cmd):
927927
join('src', 'multiarray', 'flagsobject.c'),
928928
join('src', 'multiarray', 'getset.c'),
929929
join('src', 'multiarray', 'hashdescr.c'),
930+
join('src', 'multiarray', 'hpy_utils.c'),
930931
join('src', 'multiarray', 'item_selection.c'),
931932
join('src', 'multiarray', 'iterators.c'),
932933
join('src', 'multiarray', 'legacy_dtype_implementation.c'),

numpy/core/src/common/array_assign.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,16 @@ IsUintAligned(PyArrayObject *ap)
152152
npy_uint_alignment(PyArray_DESCR(ap)->elsize));
153153
}
154154

155+
NPY_NO_EXPORT int
156+
HIsUintAligned(HPyContext *ctx, HPy arr, PyArrayObject *arr_data)
157+
{
158+
HPy descr = HPyArray_DESCR(ctx, arr, arr_data);
159+
int res = raw_array_is_aligned(PyArray_NDIM(arr_data), PyArray_DIMS(arr_data),
160+
PyArray_DATA(arr_data), PyArray_STRIDES(arr_data),
161+
npy_uint_alignment(PyArray_Descr_AsStruct(ctx, descr)->elsize));
162+
HPy_Close(ctx, descr);
163+
return res;
164+
}
155165

156166

157167
/* Returns 1 if the arrays have overlapping data, 0 otherwise */

numpy/core/src/common/array_assign.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,9 @@ IsAligned(PyArrayObject *ap);
116116
NPY_NO_EXPORT int
117117
IsUintAligned(PyArrayObject *ap);
118118

119+
NPY_NO_EXPORT int
120+
HIsUintAligned(HPyContext *ctx, HPy arr, PyArrayObject *arr_data);
121+
119122
/* Returns 1 if the arrays have overlapping data, 0 otherwise */
120123
NPY_NO_EXPORT int
121124
arrays_overlap(PyArrayObject *arr1, PyArrayObject *arr2);

numpy/core/src/common/lowlevel_strided_loops.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,13 @@ PyArray_GetDTypeTransferFunction(int aligned,
199199
int *out_needs_api);
200200

201201
NPY_NO_EXPORT int
202+
HPyArray_GetDTypeTransferFunction(HPyContext *ctx, int aligned,
203+
npy_intp src_stride, npy_intp dst_stride,
204+
HPy src_dtype, HPy dst_dtype,
205+
int move_references,
206+
HNPY_cast_info *cast_info,
207+
int *out_needs_api);
208+
NPY_NO_EXPORT int
202209
get_fields_transfer_function(int aligned,
203210
npy_intp src_stride, npy_intp dst_stride,
204211
PyArray_Descr *src_dtype, PyArray_Descr *dst_dtype,
@@ -243,6 +250,18 @@ PyArray_GetMaskedDTypeTransferFunction(int aligned,
243250
NPY_cast_info *cast_info,
244251
int *out_needs_api);
245252

253+
NPY_NO_EXPORT int
254+
HPyArray_GetMaskedDTypeTransferFunction(HPyContext *ctx, int aligned,
255+
npy_intp src_stride,
256+
npy_intp dst_stride,
257+
npy_intp mask_stride,
258+
HPy src_dtype,
259+
HPy dst_dtype,
260+
HPy mask_dtype,
261+
int move_references,
262+
NPY_cast_info *cast_info,
263+
int *out_needs_api);
264+
246265
/*
247266
* Casts the specified number of elements from 'src' with data type
248267
* 'src_dtype' to 'dst' with 'dst_dtype'. See

numpy/core/src/common/mem_overlap.c

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -709,6 +709,27 @@ get_array_memory_extents(PyArrayObject *arr,
709709
}
710710
}
711711

712+
static void
713+
hpy_get_array_memory_extents(HPyContext *ctx, HPy arr,
714+
npy_uintp *out_start, npy_uintp *out_end,
715+
npy_uintp *num_bytes)
716+
{
717+
npy_intp low, upper;
718+
int j;
719+
PyArrayObject *arr_data = PyArrayObject_AsStruct(ctx, arr);
720+
npy_intp itemsize = HPyArray_ITEMSIZE(ctx, arr, arr_data);
721+
offset_bounds_from_strides(itemsize, PyArray_NDIM(arr_data),
722+
PyArray_DIMS(arr_data), PyArray_STRIDES(arr_data),
723+
&low, &upper);
724+
*out_start = (npy_uintp)PyArray_DATA(arr_data) + (npy_uintp)low;
725+
*out_end = (npy_uintp)PyArray_DATA(arr_data) + (npy_uintp)upper;
726+
727+
*num_bytes = itemsize;
728+
for (j = 0; j < PyArray_NDIM(arr_data); ++j) {
729+
*num_bytes *= PyArray_DIM(arr_data, j);
730+
}
731+
}
732+
712733

713734
static int
714735
strides_to_terms(PyArrayObject *arr, diophantine_term_t *terms,
@@ -837,6 +858,94 @@ solve_may_share_memory(PyArrayObject *a, PyArrayObject *b,
837858
return solve_diophantine(nterms, terms, rhs, max_work, 0, x);
838859
}
839860

861+
/* PyArrayObject *a, PyArrayObject *b */
862+
NPY_VISIBILITY_HIDDEN mem_overlap_t
863+
hpy_solve_may_share_memory(HPyContext *ctx, HPy a, HPy b,
864+
HPy_ssize_t max_work)
865+
{
866+
npy_int64 rhs;
867+
diophantine_term_t terms[2*NPY_MAXDIMS + 2];
868+
npy_uintp start1 = 0, end1 = 0, size1 = 0;
869+
npy_uintp start2 = 0, end2 = 0, size2 = 0;
870+
npy_uintp uintp_rhs;
871+
npy_int64 x[2*NPY_MAXDIMS + 2];
872+
unsigned int nterms;
873+
874+
hpy_get_array_memory_extents(ctx, a, &start1, &end1, &size1);
875+
hpy_get_array_memory_extents(ctx, b, &start2, &end2, &size2);
876+
877+
if (!(start1 < end2 && start2 < end1 && start1 < end1 && start2 < end2)) {
878+
/* Memory extents don't overlap */
879+
return MEM_OVERLAP_NO;
880+
}
881+
882+
if (max_work == 0) {
883+
/* Too much work required, give up */
884+
return MEM_OVERLAP_TOO_HARD;
885+
}
886+
887+
/* Convert problem to Diophantine equation form with positive coefficients.
888+
The bounds computed by offset_bounds_from_strides correspond to
889+
all-positive strides.
890+
891+
start1 + sum(abs(stride1)*x1)
892+
== start2 + sum(abs(stride2)*x2)
893+
== end1 - 1 - sum(abs(stride1)*x1')
894+
== end2 - 1 - sum(abs(stride2)*x2')
895+
896+
<=>
897+
898+
sum(abs(stride1)*x1) + sum(abs(stride2)*x2')
899+
== end2 - 1 - start1
900+
901+
OR
902+
903+
sum(abs(stride1)*x1') + sum(abs(stride2)*x2)
904+
== end1 - 1 - start2
905+
906+
We pick the problem with the smaller RHS (they are non-negative due to
907+
the extent check above.)
908+
*/
909+
910+
uintp_rhs = MIN(end2 - 1 - start1, end1 - 1 - start2);
911+
if (uintp_rhs > NPY_MAX_INT64) {
912+
/* Integer overflow */
913+
return MEM_OVERLAP_OVERFLOW;
914+
}
915+
rhs = (npy_int64)uintp_rhs;
916+
917+
nterms = 0;
918+
PyArrayObject *a_data = PyArrayObject_AsStruct(ctx, a);
919+
if (strides_to_terms(a_data, terms, &nterms, 1)) {
920+
return MEM_OVERLAP_OVERFLOW;
921+
}
922+
PyArrayObject *b_data = PyArrayObject_AsStruct(ctx, b);
923+
if (strides_to_terms(b_data, terms, &nterms, 1)) {
924+
return MEM_OVERLAP_OVERFLOW;
925+
}
926+
npy_intp a_itemsize = HPyArray_ITEMSIZE(ctx, a, a_data);
927+
if (a_itemsize > 1) {
928+
terms[nterms].a = 1;
929+
terms[nterms].ub = a_itemsize - 1;
930+
++nterms;
931+
}
932+
npy_intp b_itemsize = HPyArray_ITEMSIZE(ctx, b, b_data);
933+
if (b_itemsize > 1) {
934+
terms[nterms].a = 1;
935+
terms[nterms].ub = b_itemsize - 1;
936+
++nterms;
937+
}
938+
939+
/* Simplify, if possible */
940+
if (diophantine_simplify(&nterms, terms, rhs)) {
941+
/* Integer overflow */
942+
return MEM_OVERLAP_OVERFLOW;
943+
}
944+
945+
/* Solve */
946+
return solve_diophantine(nterms, terms, rhs, (Py_ssize_t)max_work, 0, x);
947+
}
948+
840949

841950
/**
842951
* Determine whether an array has internal overlap.

numpy/core/src/multiarray/_datetime.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ create_datetime_dtype_with_unit(int type_num, NPY_DATETIMEUNIT unit);
3838
NPY_NO_EXPORT PyArray_DatetimeMetaData *
3939
get_datetime_metadata_from_dtype(PyArray_Descr *dtype);
4040

41+
NPY_NO_EXPORT PyArray_DatetimeMetaData *
42+
h_get_datetime_metadata_from_dtype(HPyContext *ctx, PyArray_Descr *dtype_data);
43+
4144
NPY_NO_EXPORT int
4245
find_string_array_datetime64_type(PyArrayObject *arr,
4346
PyArray_DatetimeMetaData *meta);

0 commit comments

Comments
 (0)