Skip to content

Commit

Permalink
fixed inter-backend cast segment fault
Browse files Browse the repository at this point in the history
  • Loading branch information
SwayamInSync committed Sep 20, 2024
1 parent 672be17 commit 600b2c8
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 46 deletions.
77 changes: 57 additions & 20 deletions quaddtype/numpy_quaddtype/src/casts.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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];
Expand All @@ -45,7 +46,7 @@ quad_to_quad_resolve_descriptors(PyObject *NPY_UNUSED(self),
}

*view_offset = 0;
return NPY_NO_CASTING;
return casting;
}

static int
Expand All @@ -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 =
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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},
Expand All @@ -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,
Expand Down Expand Up @@ -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;
}
8 changes: 4 additions & 4 deletions quaddtype/numpy_quaddtype/src/scalar_ops.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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);
}
}
Expand All @@ -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<quad_add, ld_add>,
.nb_subtract = (binaryfunc)quad_binary_func<quad_sub, ld_sub>,
Expand Down
38 changes: 16 additions & 22 deletions quaddtype/numpy_quaddtype/src/umath.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -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 */
Expand All @@ -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;
}
}
Expand Down Expand Up @@ -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;
}
}
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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 <cmp_quad_def sleef_comp, cmp_londouble_def ld_comp>
Expand All @@ -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);
}

Expand All @@ -642,12 +639,11 @@ quad_generic_comp_strided_loop(PyArrayMethod_Context *context, char *const data[
return 0;
}


template <cmp_quad_def sleef_comp, cmp_londouble_def ld_comp>
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];
Expand All @@ -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);
}

Expand Down Expand Up @@ -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<sleef_comp, ld_comp>},
{NPY_METH_strided_loop,
(void *)&quad_generic_comp_strided_loop_aligned<sleef_comp, ld_comp>},
{NPY_METH_unaligned_strided_loop,
(void *)&quad_generic_comp_strided_loop<sleef_comp, ld_comp>},
{0, NULL}};
Expand Down

0 comments on commit 600b2c8

Please sign in to comment.