From 600b2c8d96836ec3719fe9242ae9171f5067b182 Mon Sep 17 00:00:00 2001 From: swayaminsync Date: Sat, 21 Sep 2024 03:06:36 +0530 Subject: [PATCH] fixed inter-backend cast segment fault --- quaddtype/numpy_quaddtype/src/casts.cpp | 77 +++++++++++++++----- quaddtype/numpy_quaddtype/src/scalar_ops.cpp | 8 +- quaddtype/numpy_quaddtype/src/umath.cpp | 38 ++++------ 3 files changed, 77 insertions(+), 46 deletions(-) diff --git a/quaddtype/numpy_quaddtype/src/casts.cpp b/quaddtype/numpy_quaddtype/src/casts.cpp index ed2f447..c662b4d 100644 --- a/quaddtype/numpy_quaddtype/src/casts.cpp +++ b/quaddtype/numpy_quaddtype/src/casts.cpp @@ -28,9 +28,10 @@ quad_to_quad_resolve_descriptors(PyObject *NPY_UNUSED(self), QuadPrecDTypeObject *given_descrs[2], QuadPrecDTypeObject *loop_descrs[2], npy_intp *view_offset) { - if (given_descrs[0]->backend != given_descrs[1]->backend) { - return NPY_UNSAFE_CASTING; - } + NPY_CASTING casting = NPY_NO_CASTING; + + if (given_descrs[0]->backend != given_descrs[1]->backend) + casting = NPY_UNSAFE_CASTING; Py_INCREF(given_descrs[0]); loop_descrs[0] = given_descrs[0]; @@ -45,7 +46,7 @@ quad_to_quad_resolve_descriptors(PyObject *NPY_UNUSED(self), } *view_offset = 0; - return NPY_NO_CASTING; + return casting; } static int @@ -62,10 +63,26 @@ quad_to_quad_strided_loop_unaligned(PyArrayMethod_Context *context, char *const QuadPrecDTypeObject *descr_in = (QuadPrecDTypeObject *)context->descriptors[0]; QuadPrecDTypeObject *descr_out = (QuadPrecDTypeObject *)context->descriptors[1]; + // inter-backend casting if (descr_in->backend != descr_out->backend) { - PyErr_SetString(PyExc_TypeError, - "Cannot convert between different quad-precision backends"); - return -1; + while (N--) { + quad_value in_val, out_val; + if (descr_in->backend == BACKEND_SLEEF) { + memcpy(&in_val.sleef_value, in_ptr, sizeof(Sleef_quad)); + out_val.longdouble_value = Sleef_cast_to_doubleq1(in_val.sleef_value); + } + else { + memcpy(&in_val.longdouble_value, in_ptr, sizeof(long double)); + out_val.sleef_value = Sleef_cast_from_doubleq1(in_val.longdouble_value); + } + memcpy(out_ptr, &out_val, + (descr_out->backend == BACKEND_SLEEF) ? sizeof(Sleef_quad) + : sizeof(long double)); + in_ptr += in_stride; + out_ptr += out_stride; + } + + return 0; } size_t elem_size = @@ -93,10 +110,26 @@ quad_to_quad_strided_loop_aligned(PyArrayMethod_Context *context, char *const da QuadPrecDTypeObject *descr_in = (QuadPrecDTypeObject *)context->descriptors[0]; QuadPrecDTypeObject *descr_out = (QuadPrecDTypeObject *)context->descriptors[1]; + // inter-backend casting if (descr_in->backend != descr_out->backend) { - PyErr_SetString(PyExc_TypeError, - "Cannot convert between different quad-precision backends"); - return -1; + if (descr_in->backend == BACKEND_SLEEF) { + while (N--) { + Sleef_quad in_val = *(Sleef_quad *)in_ptr; + *(long double *)out_ptr = Sleef_cast_to_doubleq1(in_val); + in_ptr += in_stride; + out_ptr += out_stride; + } + } + else { + while (N--) { + long double in_val = *(long double *)in_ptr; + *(Sleef_quad *)out_ptr = Sleef_cast_from_doubleq1(in_val); + in_ptr += in_stride; + out_ptr += out_stride; + } + } + + return 0; } if (descr_in->backend == BACKEND_SLEEF) { @@ -627,6 +660,11 @@ add_spec(PyArrayMethod_Spec *spec) if (spec_count < NUM_CASTS) { specs[spec_count++] = spec; } + else { + delete[] spec->dtypes; + delete[] spec->slots; + delete spec; + } } // functions to add casts @@ -682,9 +720,8 @@ add_cast_to(PyArray_DTypeMeta *from) PyArrayMethod_Spec ** init_casts_internal(void) { - PyArray_DTypeMeta **quad2quad_dtypes = - new PyArray_DTypeMeta *[2]{&QuadPrecDType, &QuadPrecDType}; - PyType_Slot *quad2quad_slots = new PyType_Slot[]{ + PyArray_DTypeMeta **quad2quad_dtypes = new PyArray_DTypeMeta *[2]{nullptr, nullptr}; + PyType_Slot *quad2quad_slots = new PyType_Slot[4]{ {NPY_METH_resolve_descriptors, (void *)&quad_to_quad_resolve_descriptors}, {NPY_METH_strided_loop, (void *)&quad_to_quad_strided_loop_aligned}, {NPY_METH_unaligned_strided_loop, (void *)&quad_to_quad_strided_loop_unaligned}, @@ -694,7 +731,7 @@ init_casts_internal(void) .name = "cast_QuadPrec_to_QuadPrec", .nin = 1, .nout = 1, - .casting = NPY_NO_CASTING, + .casting = NPY_UNSAFE_CASTING, // since SLEEF -> ld might lose precision .flags = NPY_METH_SUPPORTS_UNALIGNED, .dtypes = quad2quad_dtypes, .slots = quad2quad_slots, @@ -749,13 +786,13 @@ init_casts(void) void free_casts(void) { - for (auto cast : specs) { - if (cast == nullptr) { - continue; + for (size_t i = 0; i < spec_count; i++) { + if (specs[i]) { + delete[] specs[i]->dtypes; + delete[] specs[i]->slots; + delete specs[i]; + specs[i] = nullptr; } - delete[] cast->dtypes; - delete[] cast->slots; - delete cast; } spec_count = 0; } \ No newline at end of file diff --git a/quaddtype/numpy_quaddtype/src/scalar_ops.cpp b/quaddtype/numpy_quaddtype/src/scalar_ops.cpp index 2faf810..98261fe 100644 --- a/quaddtype/numpy_quaddtype/src/scalar_ops.cpp +++ b/quaddtype/numpy_quaddtype/src/scalar_ops.cpp @@ -124,7 +124,6 @@ quad_binary_func(PyObject *op1, PyObject *op2) return (PyObject *)res; } -// todo: add support with float and int PyObject * quad_richcompare(QuadPrecisionObject *self, PyObject *other, int cmp_op) { @@ -212,7 +211,8 @@ QuadPrecision_float(QuadPrecisionObject *self) { if (self->backend == BACKEND_SLEEF) { return PyFloat_FromDouble(Sleef_cast_to_doubleq1(self->value.sleef_value)); - } else { + } + else { return PyFloat_FromDouble((double)self->value.longdouble_value); } } @@ -222,12 +222,12 @@ QuadPrecision_int(QuadPrecisionObject *self) { if (self->backend == BACKEND_SLEEF) { return PyLong_FromLongLong(Sleef_cast_to_int64q1(self->value.sleef_value)); - } else { + } + else { return PyLong_FromLongLong((long long)self->value.longdouble_value); } } - PyNumberMethods quad_as_scalar = { .nb_add = (binaryfunc)quad_binary_func, .nb_subtract = (binaryfunc)quad_binary_func, diff --git a/quaddtype/numpy_quaddtype/src/umath.cpp b/quaddtype/numpy_quaddtype/src/umath.cpp index 7271443..f566545 100644 --- a/quaddtype/numpy_quaddtype/src/umath.cpp +++ b/quaddtype/numpy_quaddtype/src/umath.cpp @@ -282,7 +282,6 @@ quad_binary_op_resolve_descriptors(PyObject *self, PyArray_DTypeMeta *const dtyp // Determine target backend and if casting is needed NPY_CASTING casting = NPY_NO_CASTING; if (descr_in1->backend != descr_in2->backend) { - target_backend = BACKEND_LONGDOUBLE; casting = NPY_SAFE_CASTING; } @@ -398,12 +397,11 @@ static int quad_ufunc_promoter(PyUFuncObject *ufunc, PyArray_DTypeMeta *op_dtypes[], PyArray_DTypeMeta *signature[], PyArray_DTypeMeta *new_op_dtypes[]) { - int nin = ufunc->nin; int nargs = ufunc->nargs; PyArray_DTypeMeta *common = NULL; bool has_quad = false; - + // Handle the special case for reductions if (op_dtypes[0] == NULL) { assert(nin == 2 && ufunc->nout == 1); /* must be reduction */ @@ -417,7 +415,6 @@ quad_ufunc_promoter(PyUFuncObject *ufunc, PyArray_DTypeMeta *op_dtypes[], // Check if any input or signature is QuadPrecision for (int i = 0; i < nin; i++) { if (op_dtypes[i] == &QuadPrecDType) { - has_quad = true; } } @@ -461,7 +458,7 @@ quad_ufunc_promoter(PyUFuncObject *ufunc, PyArray_DTypeMeta *op_dtypes[], else { // Otherwise, use the common dtype Py_INCREF(common); - + new_op_dtypes[i] = common; } } @@ -563,13 +560,14 @@ init_quad_binary_ops(PyObject *numpy) static NPY_CASTING quad_comparison_op_resolve_descriptors(PyObject *self, PyArray_DTypeMeta *const dtypes[], - PyArray_Descr *const given_descrs[], - PyArray_Descr *loop_descrs[], npy_intp *NPY_UNUSED(view_offset)) + PyArray_Descr *const given_descrs[], + PyArray_Descr *loop_descrs[], + npy_intp *NPY_UNUSED(view_offset)) { QuadPrecDTypeObject *descr_in1 = (QuadPrecDTypeObject *)given_descrs[0]; QuadPrecDTypeObject *descr_in2 = (QuadPrecDTypeObject *)given_descrs[1]; QuadBackendType target_backend; - + // As dealing with different backends then cast to boolean NPY_CASTING casting = NPY_NO_CASTING; if (descr_in1->backend != descr_in2->backend) { @@ -599,7 +597,7 @@ quad_comparison_op_resolve_descriptors(PyObject *self, PyArray_DTypeMeta *const if (!loop_descrs[2]) { return (NPY_CASTING)-1; } - return casting; + return casting; } template @@ -626,10 +624,9 @@ quad_generic_comp_strided_loop(PyArrayMethod_Context *context, char *const data[ npy_bool result; if (backend == BACKEND_SLEEF) { - result = sleef_comp(&in1.sleef_value, &in2.sleef_value); + result = sleef_comp(&in1.sleef_value, &in2.sleef_value); } else { - result = ld_comp(&in1.longdouble_value, &in2.longdouble_value); } @@ -642,12 +639,11 @@ quad_generic_comp_strided_loop(PyArrayMethod_Context *context, char *const data[ return 0; } - template int quad_generic_comp_strided_loop_aligned(PyArrayMethod_Context *context, char *const data[], - npy_intp const dimensions[], npy_intp const strides[], - NpyAuxData *auxdata) + npy_intp const dimensions[], npy_intp const strides[], + NpyAuxData *auxdata) { npy_intp N = dimensions[0]; char *in1_ptr = data[0], *in2_ptr = data[1]; @@ -658,19 +654,16 @@ quad_generic_comp_strided_loop_aligned(PyArrayMethod_Context *context, char *con QuadPrecDTypeObject *descr = (QuadPrecDTypeObject *)context->descriptors[0]; QuadBackendType backend = descr->backend; - while (N--) - { + while (N--) { quad_value in1 = *(quad_value *)in1_ptr; quad_value in2 = *(quad_value *)in2_ptr; npy_bool result; - if (backend == BACKEND_SLEEF) - { + if (backend == BACKEND_SLEEF) { result = sleef_comp(&in1.sleef_value, &in2.sleef_value); - } - else - { + } + else { result = ld_comp(&in1.longdouble_value, &in2.longdouble_value); } @@ -711,7 +704,8 @@ create_quad_comparison_ufunc(PyObject *numpy, const char *ufunc_name) PyType_Slot slots[] = { {NPY_METH_resolve_descriptors, (void *)&quad_comparison_op_resolve_descriptors}, - {NPY_METH_strided_loop, (void *)&quad_generic_comp_strided_loop_aligned}, + {NPY_METH_strided_loop, + (void *)&quad_generic_comp_strided_loop_aligned}, {NPY_METH_unaligned_strided_loop, (void *)&quad_generic_comp_strided_loop}, {0, NULL}};