Blame src/mpi/datatype/type_create_subarray.c

Packit Service c5cf8c
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */
Packit Service c5cf8c
/*
Packit Service c5cf8c
 *
Packit Service c5cf8c
 *  (C) 2001 by Argonne National Laboratory.
Packit Service c5cf8c
 *      See COPYRIGHT in top-level directory.
Packit Service c5cf8c
 */
Packit Service c5cf8c
#include "mpiimpl.h"
Packit Service c5cf8c
Packit Service c5cf8c
/* -- Begin Profiling Symbol Block for routine MPI_Type_create_subarray */
Packit Service c5cf8c
#if defined(HAVE_PRAGMA_WEAK)
Packit Service c5cf8c
#pragma weak MPI_Type_create_subarray = PMPI_Type_create_subarray
Packit Service c5cf8c
#elif defined(HAVE_PRAGMA_HP_SEC_DEF)
Packit Service c5cf8c
#pragma _HP_SECONDARY_DEF PMPI_Type_create_subarray  MPI_Type_create_subarray
Packit Service c5cf8c
#elif defined(HAVE_PRAGMA_CRI_DUP)
Packit Service c5cf8c
#pragma _CRI duplicate MPI_Type_create_subarray as PMPI_Type_create_subarray
Packit Service c5cf8c
#elif defined(HAVE_WEAK_ATTRIBUTE)
Packit Service c5cf8c
int MPI_Type_create_subarray(int ndims, const int array_of_sizes[],
Packit Service c5cf8c
                             const int array_of_subsizes[], const int array_of_starts[],
Packit Service c5cf8c
                             int order, MPI_Datatype oldtype, MPI_Datatype * newtype)
Packit Service c5cf8c
    __attribute__ ((weak, alias("PMPI_Type_create_subarray")));
Packit Service c5cf8c
#endif
Packit Service c5cf8c
/* -- End Profiling Symbol Block */
Packit Service c5cf8c
Packit Service c5cf8c
/* Define MPICH_MPI_FROM_PMPI if weak symbols are not supported to build
Packit Service c5cf8c
   the MPI routines */
Packit Service c5cf8c
#ifndef MPICH_MPI_FROM_PMPI
Packit Service c5cf8c
#undef MPI_Type_create_subarray
Packit Service c5cf8c
#define MPI_Type_create_subarray PMPI_Type_create_subarray
Packit Service c5cf8c
Packit Service c5cf8c
#endif
Packit Service c5cf8c
Packit Service c5cf8c
#undef FUNCNAME
Packit Service c5cf8c
#define FUNCNAME MPI_Type_create_subarray
Packit Service c5cf8c
#undef FCNAME
Packit Service c5cf8c
#define FCNAME MPL_QUOTE(FUNCNAME)
Packit Service c5cf8c
/*@
Packit Service c5cf8c
   MPI_Type_create_subarray - Create a datatype for a subarray of a regular,
Packit Service c5cf8c
    multidimensional array
Packit Service c5cf8c
Packit Service c5cf8c
Input Parameters:
Packit Service c5cf8c
+ ndims - number of array dimensions (positive integer)
Packit Service c5cf8c
. array_of_sizes - number of elements of type oldtype in each dimension of the
Packit Service c5cf8c
  full array (array of positive integers)
Packit Service c5cf8c
. array_of_subsizes - number of elements of type oldtype in each dimension of
Packit Service c5cf8c
  the subarray (array of positive integers)
Packit Service c5cf8c
. array_of_starts - starting coordinates of the subarray in each dimension
Packit Service c5cf8c
  (array of nonnegative integers)
Packit Service c5cf8c
. order - array storage order flag (state)
Packit Service c5cf8c
- oldtype - array element datatype (handle)
Packit Service c5cf8c
Packit Service c5cf8c
Output Parameters:
Packit Service c5cf8c
. newtype - new datatype (handle)
Packit Service c5cf8c
Packit Service c5cf8c
.N ThreadSafe
Packit Service c5cf8c
Packit Service c5cf8c
.N Fortran
Packit Service c5cf8c
Packit Service c5cf8c
.N Errors
Packit Service c5cf8c
.N MPI_SUCCESS
Packit Service c5cf8c
.N MPI_ERR_TYPE
Packit Service c5cf8c
.N MPI_ERR_ARG
Packit Service c5cf8c
@*/
Packit Service c5cf8c
int MPI_Type_create_subarray(int ndims,
Packit Service c5cf8c
                             const int array_of_sizes[],
Packit Service c5cf8c
                             const int array_of_subsizes[],
Packit Service c5cf8c
                             const int array_of_starts[],
Packit Service c5cf8c
                             int order, MPI_Datatype oldtype, MPI_Datatype * newtype)
Packit Service c5cf8c
{
Packit Service c5cf8c
    int mpi_errno = MPI_SUCCESS, i;
Packit Service c5cf8c
    MPI_Datatype new_handle;
Packit Service c5cf8c
Packit Service c5cf8c
    /* these variables are from the original version in ROMIO */
Packit Service c5cf8c
    MPI_Aint size, extent, disps[3];
Packit Service c5cf8c
    MPI_Datatype tmp1, tmp2;
Packit Service c5cf8c
Packit Service c5cf8c
#ifdef HAVE_ERROR_CHECKING
Packit Service c5cf8c
    MPI_Aint size_with_aint;
Packit Service c5cf8c
    MPI_Offset size_with_offset;
Packit Service c5cf8c
#endif
Packit Service c5cf8c
Packit Service c5cf8c
    /* for saving contents */
Packit Service c5cf8c
    int *ints;
Packit Service c5cf8c
    MPIR_Datatype *new_dtp;
Packit Service c5cf8c
Packit Service c5cf8c
    MPIR_CHKLMEM_DECL(1);
Packit Service c5cf8c
    MPIR_FUNC_TERSE_STATE_DECL(MPID_STATE_MPI_TYPE_CREATE_SUBARRAY);
Packit Service c5cf8c
Packit Service c5cf8c
    MPIR_ERRTEST_INITIALIZED_ORDIE();
Packit Service c5cf8c
Packit Service c5cf8c
    MPID_THREAD_CS_ENTER(GLOBAL, MPIR_THREAD_GLOBAL_ALLFUNC_MUTEX);
Packit Service c5cf8c
    MPIR_FUNC_TERSE_ENTER(MPID_STATE_MPI_TYPE_CREATE_SUBARRAY);
Packit Service c5cf8c
Packit Service c5cf8c
#ifdef HAVE_ERROR_CHECKING
Packit Service c5cf8c
    {
Packit Service c5cf8c
        MPID_BEGIN_ERROR_CHECKS;
Packit Service c5cf8c
        {
Packit Service c5cf8c
            MPIR_Datatype *datatype_ptr = NULL;
Packit Service c5cf8c
Packit Service c5cf8c
            /* Check parameters */
Packit Service c5cf8c
            MPIR_ERRTEST_ARGNONPOS(ndims, "ndims", mpi_errno, MPI_ERR_DIMS);
Packit Service c5cf8c
            MPIR_ERRTEST_ARGNULL(array_of_sizes, "array_of_sizes", mpi_errno);
Packit Service c5cf8c
            MPIR_ERRTEST_ARGNULL(array_of_subsizes, "array_of_subsizes", mpi_errno);
Packit Service c5cf8c
            MPIR_ERRTEST_ARGNULL(array_of_starts, "array_of_starts", mpi_errno);
Packit Service c5cf8c
            for (i = 0; mpi_errno == MPI_SUCCESS && i < ndims; i++) {
Packit Service c5cf8c
                MPIR_ERRTEST_ARGNONPOS(array_of_sizes[i], "size", mpi_errno, MPI_ERR_ARG);
Packit Service c5cf8c
                MPIR_ERRTEST_ARGNONPOS(array_of_subsizes[i], "subsize", mpi_errno, MPI_ERR_ARG);
Packit Service c5cf8c
                MPIR_ERRTEST_ARGNEG(array_of_starts[i], "start", mpi_errno);
Packit Service c5cf8c
                if (array_of_subsizes[i] > array_of_sizes[i]) {
Packit Service c5cf8c
                    mpi_errno = MPIR_Err_create_code(MPI_SUCCESS,
Packit Service c5cf8c
                                                     MPIR_ERR_RECOVERABLE,
Packit Service c5cf8c
                                                     FCNAME,
Packit Service c5cf8c
                                                     __LINE__,
Packit Service c5cf8c
                                                     MPI_ERR_ARG,
Packit Service c5cf8c
                                                     "**argrange",
Packit Service c5cf8c
                                                     "**argrange %s %d %d",
Packit Service c5cf8c
                                                     "array_of_subsizes",
Packit Service c5cf8c
                                                     array_of_subsizes[i], array_of_sizes[i]);
Packit Service c5cf8c
                    goto fn_fail;
Packit Service c5cf8c
                }
Packit Service c5cf8c
                if (array_of_starts[i] > (array_of_sizes[i] - array_of_subsizes[i])) {
Packit Service c5cf8c
                    mpi_errno = MPIR_Err_create_code(MPI_SUCCESS,
Packit Service c5cf8c
                                                     MPIR_ERR_RECOVERABLE,
Packit Service c5cf8c
                                                     FCNAME,
Packit Service c5cf8c
                                                     __LINE__,
Packit Service c5cf8c
                                                     MPI_ERR_ARG,
Packit Service c5cf8c
                                                     "**argrange",
Packit Service c5cf8c
                                                     "**argrange %s %d %d",
Packit Service c5cf8c
                                                     "array_of_starts",
Packit Service c5cf8c
                                                     array_of_starts[i],
Packit Service c5cf8c
                                                     array_of_sizes[i] - array_of_subsizes[i]);
Packit Service c5cf8c
                    goto fn_fail;
Packit Service c5cf8c
                }
Packit Service c5cf8c
            }
Packit Service c5cf8c
            if (order != MPI_ORDER_FORTRAN && order != MPI_ORDER_C) {
Packit Service c5cf8c
                mpi_errno = MPIR_Err_create_code(MPI_SUCCESS,
Packit Service c5cf8c
                                                 MPIR_ERR_RECOVERABLE,
Packit Service c5cf8c
                                                 FCNAME,
Packit Service c5cf8c
                                                 __LINE__,
Packit Service c5cf8c
                                                 MPI_ERR_ARG, "**arg", "**arg %s", "order");
Packit Service c5cf8c
                goto fn_fail;
Packit Service c5cf8c
            }
Packit Service c5cf8c
Packit Service c5cf8c
            MPIR_Datatype_get_extent_macro(oldtype, extent);
Packit Service c5cf8c
Packit Service c5cf8c
            /* check if MPI_Aint is large enough for size of global array.
Packit Service c5cf8c
             * if not, complain. */
Packit Service c5cf8c
Packit Service c5cf8c
            size_with_aint = extent;
Packit Service c5cf8c
            for (i = 0; i < ndims; i++)
Packit Service c5cf8c
                size_with_aint *= array_of_sizes[i];
Packit Service c5cf8c
            size_with_offset = extent;
Packit Service c5cf8c
            for (i = 0; i < ndims; i++)
Packit Service c5cf8c
                size_with_offset *= array_of_sizes[i];
Packit Service c5cf8c
            if (size_with_aint != size_with_offset) {
Packit Service c5cf8c
                mpi_errno = MPIR_Err_create_code(MPI_SUCCESS,
Packit Service c5cf8c
                                                 MPIR_ERR_FATAL,
Packit Service c5cf8c
                                                 FCNAME,
Packit Service c5cf8c
                                                 __LINE__,
Packit Service c5cf8c
                                                 MPI_ERR_ARG,
Packit Service c5cf8c
                                                 "**subarrayoflow",
Packit Service c5cf8c
                                                 "**subarrayoflow %L", size_with_offset);
Packit Service c5cf8c
                goto fn_fail;
Packit Service c5cf8c
            }
Packit Service c5cf8c
Packit Service c5cf8c
            /* Get handles to MPI objects. */
Packit Service c5cf8c
            MPIR_Datatype_get_ptr(oldtype, datatype_ptr);
Packit Service c5cf8c
Packit Service c5cf8c
            /* Validate datatype_ptr */
Packit Service c5cf8c
            MPIR_Datatype_valid_ptr(datatype_ptr, mpi_errno);
Packit Service c5cf8c
            /* If datatype_ptr is not valid, it will be reset to null */
Packit Service c5cf8c
            if (mpi_errno != MPI_SUCCESS)
Packit Service c5cf8c
                goto fn_fail;
Packit Service c5cf8c
        }
Packit Service c5cf8c
        MPID_END_ERROR_CHECKS;
Packit Service c5cf8c
    }
Packit Service c5cf8c
#endif /* HAVE_ERROR_CHECKING */
Packit Service c5cf8c
Packit Service c5cf8c
    /* ... body of routine ... */
Packit Service c5cf8c
Packit Service c5cf8c
    /* TODO: CHECK THE ERROR RETURNS FROM ALL THESE!!! */
Packit Service c5cf8c
Packit Service c5cf8c
    /* TODO: GRAB EXTENT WITH A MACRO OR SOMETHING FASTER */
Packit Service c5cf8c
    MPIR_Datatype_get_extent_macro(oldtype, extent);
Packit Service c5cf8c
Packit Service c5cf8c
    if (order == MPI_ORDER_FORTRAN) {
Packit Service c5cf8c
        if (ndims == 1)
Packit Service c5cf8c
            mpi_errno = MPIR_Type_contiguous(array_of_subsizes[0], oldtype, &tmp1);
Packit Service c5cf8c
        else {
Packit Service c5cf8c
            mpi_errno = MPIR_Type_vector(array_of_subsizes[1], array_of_subsizes[0], (MPI_Aint) (array_of_sizes[0]), 0, /* stride in types */
Packit Service c5cf8c
                                         oldtype, &tmp1);
Packit Service c5cf8c
            if (mpi_errno)
Packit Service c5cf8c
                MPIR_ERR_POP(mpi_errno);
Packit Service c5cf8c
Packit Service c5cf8c
            size = ((MPI_Aint) (array_of_sizes[0])) * extent;
Packit Service c5cf8c
            for (i = 2; i < ndims; i++) {
Packit Service c5cf8c
                size *= (MPI_Aint) (array_of_sizes[i - 1]);
Packit Service c5cf8c
                mpi_errno = MPIR_Type_vector(array_of_subsizes[i], 1, size, 1,  /* stride in bytes */
Packit Service c5cf8c
                                             tmp1, &tmp2);
Packit Service c5cf8c
                if (mpi_errno)
Packit Service c5cf8c
                    MPIR_ERR_POP(mpi_errno);
Packit Service c5cf8c
                MPIR_Type_free_impl(&tmp1);
Packit Service c5cf8c
                tmp1 = tmp2;
Packit Service c5cf8c
            }
Packit Service c5cf8c
        }
Packit Service c5cf8c
        if (mpi_errno)
Packit Service c5cf8c
            MPIR_ERR_POP(mpi_errno);
Packit Service c5cf8c
Packit Service c5cf8c
        /* add displacement and UB */
Packit Service c5cf8c
Packit Service c5cf8c
        disps[1] = (MPI_Aint) (array_of_starts[0]);
Packit Service c5cf8c
        size = 1;
Packit Service c5cf8c
        for (i = 1; i < ndims; i++) {
Packit Service c5cf8c
            size *= (MPI_Aint) (array_of_sizes[i - 1]);
Packit Service c5cf8c
            disps[1] += size * (MPI_Aint) (array_of_starts[i]);
Packit Service c5cf8c
        }
Packit Service c5cf8c
        /* rest done below for both Fortran and C order */
Packit Service c5cf8c
    } else {    /* MPI_ORDER_C */
Packit Service c5cf8c
Packit Service c5cf8c
        /* dimension ndims-1 changes fastest */
Packit Service c5cf8c
        if (ndims == 1) {
Packit Service c5cf8c
            mpi_errno = MPIR_Type_contiguous(array_of_subsizes[0], oldtype, &tmp1);
Packit Service c5cf8c
            if (mpi_errno)
Packit Service c5cf8c
                MPIR_ERR_POP(mpi_errno);
Packit Service c5cf8c
Packit Service c5cf8c
        } else {
Packit Service c5cf8c
            mpi_errno = MPIR_Type_vector(array_of_subsizes[ndims - 2], array_of_subsizes[ndims - 1], (MPI_Aint) (array_of_sizes[ndims - 1]), 0, /* stride in types */
Packit Service c5cf8c
                                         oldtype, &tmp1);
Packit Service c5cf8c
            if (mpi_errno)
Packit Service c5cf8c
                MPIR_ERR_POP(mpi_errno);
Packit Service c5cf8c
Packit Service c5cf8c
            size = (MPI_Aint) (array_of_sizes[ndims - 1]) * extent;
Packit Service c5cf8c
            for (i = ndims - 3; i >= 0; i--) {
Packit Service c5cf8c
                size *= (MPI_Aint) (array_of_sizes[i + 1]);
Packit Service c5cf8c
                mpi_errno = MPIR_Type_vector(array_of_subsizes[i], 1,   /* blocklen */
Packit Service c5cf8c
                                             size,      /* stride */
Packit Service c5cf8c
                                             1, /* stride in bytes */
Packit Service c5cf8c
                                             tmp1,      /* old type */
Packit Service c5cf8c
                                             &tmp2);
Packit Service c5cf8c
                if (mpi_errno)
Packit Service c5cf8c
                    MPIR_ERR_POP(mpi_errno);
Packit Service c5cf8c
Packit Service c5cf8c
                MPIR_Type_free_impl(&tmp1);
Packit Service c5cf8c
                tmp1 = tmp2;
Packit Service c5cf8c
            }
Packit Service c5cf8c
        }
Packit Service c5cf8c
Packit Service c5cf8c
        /* add displacement and UB */
Packit Service c5cf8c
Packit Service c5cf8c
        disps[1] = (MPI_Aint) (array_of_starts[ndims - 1]);
Packit Service c5cf8c
        size = 1;
Packit Service c5cf8c
        for (i = ndims - 2; i >= 0; i--) {
Packit Service c5cf8c
            size *= (MPI_Aint) (array_of_sizes[i + 1]);
Packit Service c5cf8c
            disps[1] += size * (MPI_Aint) (array_of_starts[i]);
Packit Service c5cf8c
        }
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    disps[1] *= extent;
Packit Service c5cf8c
Packit Service c5cf8c
    disps[2] = extent;
Packit Service c5cf8c
    for (i = 0; i < ndims; i++)
Packit Service c5cf8c
        disps[2] *= (MPI_Aint) (array_of_sizes[i]);
Packit Service c5cf8c
Packit Service c5cf8c
    disps[0] = 0;
Packit Service c5cf8c
Packit Service c5cf8c
/* Instead of using MPI_LB/MPI_UB, which have been removed from MPI in MPI-3,
Packit Service c5cf8c
   use MPI_Type_create_resized. Use hindexed_block to set the starting displacement
Packit Service c5cf8c
   of the datatype (disps[1]) and type_create_resized to set lb to 0 (disps[0])
Packit Service c5cf8c
   and extent to disps[2], which makes ub = disps[2].
Packit Service c5cf8c
 */
Packit Service c5cf8c
Packit Service c5cf8c
    mpi_errno = MPIR_Type_blockindexed(1, 1, &disps[1], 1,      /* 1 means disp is in bytes */
Packit Service c5cf8c
                                       tmp1, &tmp2);
Packit Service c5cf8c
    if (mpi_errno)
Packit Service c5cf8c
        MPIR_ERR_POP(mpi_errno);
Packit Service c5cf8c
Packit Service c5cf8c
    mpi_errno = MPIR_Type_create_resized(tmp2, 0, disps[2], &new_handle);
Packit Service c5cf8c
    if (mpi_errno)
Packit Service c5cf8c
        MPIR_ERR_POP(mpi_errno);
Packit Service c5cf8c
Packit Service c5cf8c
    MPIR_Type_free_impl(&tmp1);
Packit Service c5cf8c
    MPIR_Type_free_impl(&tmp2);
Packit Service c5cf8c
Packit Service c5cf8c
    /* at this point we have the new type, and we've cleaned up any
Packit Service c5cf8c
     * intermediate types created in the process.  we just need to save
Packit Service c5cf8c
     * all our contents/envelope information.
Packit Service c5cf8c
     */
Packit Service c5cf8c
Packit Service c5cf8c
    /* Save contents */
Packit Service c5cf8c
    MPIR_CHKLMEM_MALLOC_ORJUMP(ints, int *, (3 * ndims + 2) * sizeof(int), mpi_errno,
Packit Service c5cf8c
                               "content description", MPL_MEM_BUFFER);
Packit Service c5cf8c
Packit Service c5cf8c
    ints[0] = ndims;
Packit Service c5cf8c
    for (i = 0; i < ndims; i++) {
Packit Service c5cf8c
        ints[i + 1] = array_of_sizes[i];
Packit Service c5cf8c
    }
Packit Service c5cf8c
    for (i = 0; i < ndims; i++) {
Packit Service c5cf8c
        ints[i + ndims + 1] = array_of_subsizes[i];
Packit Service c5cf8c
    }
Packit Service c5cf8c
    for (i = 0; i < ndims; i++) {
Packit Service c5cf8c
        ints[i + 2 * ndims + 1] = array_of_starts[i];
Packit Service c5cf8c
    }
Packit Service c5cf8c
    ints[3 * ndims + 1] = order;
Packit Service c5cf8c
Packit Service c5cf8c
    MPIR_Datatype_get_ptr(new_handle, new_dtp);
Packit Service c5cf8c
    mpi_errno = MPIR_Datatype_set_contents(new_dtp, MPI_COMBINER_SUBARRAY, 3 * ndims + 2,       /* ints */
Packit Service c5cf8c
                                           0,   /* aints */
Packit Service c5cf8c
                                           1,   /* types */
Packit Service c5cf8c
                                           ints, NULL, &oldtype);
Packit Service c5cf8c
    if (mpi_errno)
Packit Service c5cf8c
        MPIR_ERR_POP(mpi_errno);
Packit Service c5cf8c
Packit Service c5cf8c
Packit Service c5cf8c
    MPIR_OBJ_PUBLISH_HANDLE(*newtype, new_handle);
Packit Service c5cf8c
    /* ... end of body of routine ... */
Packit Service c5cf8c
Packit Service c5cf8c
  fn_exit:
Packit Service c5cf8c
    MPIR_CHKLMEM_FREEALL();
Packit Service c5cf8c
    MPIR_FUNC_TERSE_EXIT(MPID_STATE_MPI_TYPE_CREATE_SUBARRAY);
Packit Service c5cf8c
    MPID_THREAD_CS_EXIT(GLOBAL, MPIR_THREAD_GLOBAL_ALLFUNC_MUTEX);
Packit Service c5cf8c
    return mpi_errno;
Packit Service c5cf8c
Packit Service c5cf8c
  fn_fail:
Packit Service c5cf8c
    /* --BEGIN ERROR HANDLING-- */
Packit Service c5cf8c
#ifdef HAVE_ERROR_CHECKING
Packit Service c5cf8c
    {
Packit Service c5cf8c
        mpi_errno =
Packit Service c5cf8c
            MPIR_Err_create_code(mpi_errno, MPIR_ERR_RECOVERABLE, FCNAME, __LINE__, MPI_ERR_OTHER,
Packit Service c5cf8c
                                 "**mpi_type_create_subarray",
Packit Service c5cf8c
                                 "**mpi_type_create_subarray %d %p %p %p %d %D %p", ndims,
Packit Service c5cf8c
                                 array_of_sizes, array_of_subsizes, array_of_starts, order, oldtype,
Packit Service c5cf8c
                                 newtype);
Packit Service c5cf8c
    }
Packit Service c5cf8c
#endif
Packit Service c5cf8c
    mpi_errno = MPIR_Err_return_comm(NULL, FCNAME, mpi_errno);
Packit Service c5cf8c
    goto fn_exit;
Packit Service c5cf8c
    /* --END ERROR HANDLING-- */
Packit Service c5cf8c
}