/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */ /* * (C) 2001 by Argonne National Laboratory. * See COPYRIGHT in top-level directory. */ #include #include #include /* PAIRTYPE_SIZE_EXTENT - calculates size, extent, etc. for pairtype by * defining the appropriate C type. */ #define PAIRTYPE_SIZE_EXTENT(mt1_,ut1_,mt2_,ut2_, type_size_, type_extent_, \ el_size_, true_ub_, alignsize_) \ { \ struct { ut1_ a; ut2_ b; } foo; \ type_size_ = sizeof(foo.a) + sizeof(foo.b); \ type_extent_ = (MPI_Aint) sizeof(foo); \ el_size_ = (sizeof(foo.a) == sizeof(foo.b)) ? (int) sizeof(foo.a) : -1; \ true_ub_ = (MPIR_VOID_PTR_CAST_TO_MPI_AINT ((char *) &foo.b - \ (char *) &foo.a)) + \ (MPI_Aint) sizeof(foo.b); \ alignsize_ = MPL_MAX(MPIR_Datatype_get_basic_size(mt1_), \ MPIR_Datatype_get_basic_size(mt2_)); \ } /*@ MPIR_Type_create_pairtype - create necessary data structures for certain pair types (all but MPI_2INT etc., which never have the size != extent issue). This function is different from the other MPIR_Type_create functions in that it fills in an already- allocated MPIR_Datatype. This is important for allowing configure-time determination of the MPI type values (these types are stored in the "direct" space, for those familiar with how MPICH deals with type allocation). Input Parameters: + type - name of pair type (e.g. MPI_FLOAT_INT) - new_dtp - pointer to previously allocated datatype structure, which is filled in by this function Return Value: MPI_SUCCESS on success, MPI errno on failure. Note: Section 4.9.3 (MINLOC and MAXLOC) of the MPI-1 standard specifies that these types should be built as if by the following (e.g. MPI_FLOAT_INT): type[0] = MPI_FLOAT type[1] = MPI_INT disp[0] = 0 disp[1] = sizeof(float) <---- questionable displacement! block[0] = 1 block[1] = 1 MPI_TYPE_STRUCT(2, block, disp, type, MPI_FLOAT_INT) However, this is a relatively naive approach that does not take struct padding into account when setting the displacement of the second element. Thus in our implementation we have chosen to instead use the actual difference in starting locations of the two types in an actual struct. @*/ int MPIR_Type_create_pairtype(MPI_Datatype type, MPIR_Datatype * new_dtp) { int err, mpi_errno = MPI_SUCCESS; int type_size, alignsize; MPI_Aint type_extent, true_ub, el_size; /* handle is filled in by MPIR_Handle_obj_alloc() */ MPIR_Object_set_ref(new_dtp, 1); new_dtp->is_permanent = 1; new_dtp->is_committed = 1; /* predefined types are pre-committed */ new_dtp->attributes = NULL; new_dtp->cache_id = 0; new_dtp->name[0] = 0; new_dtp->contents = NULL; new_dtp->dataloop = NULL; new_dtp->dataloop_size = -1; new_dtp->dataloop_depth = -1; switch (type) { case MPI_FLOAT_INT: PAIRTYPE_SIZE_EXTENT(MPI_FLOAT, float, MPI_INT, int, type_size, type_extent, el_size, true_ub, alignsize); break; case MPI_DOUBLE_INT: PAIRTYPE_SIZE_EXTENT(MPI_DOUBLE, double, MPI_INT, int, type_size, type_extent, el_size, true_ub, alignsize); break; case MPI_LONG_INT: PAIRTYPE_SIZE_EXTENT(MPI_LONG, long, MPI_INT, int, type_size, type_extent, el_size, true_ub, alignsize); break; case MPI_SHORT_INT: PAIRTYPE_SIZE_EXTENT(MPI_SHORT, short, MPI_INT, int, type_size, type_extent, el_size, true_ub, alignsize); break; case MPI_LONG_DOUBLE_INT: PAIRTYPE_SIZE_EXTENT(MPI_LONG_DOUBLE, long double, MPI_INT, int, type_size, type_extent, el_size, true_ub, alignsize); break; default: /* --BEGIN ERROR HANDLING-- */ mpi_errno = MPIR_Err_create_code(MPI_SUCCESS, MPIR_ERR_RECOVERABLE, "MPIR_Type_create_pairtype", __LINE__, MPI_ERR_OTHER, "**dtype", 0); return mpi_errno; /* --END ERROR HANDLING-- */ } new_dtp->n_builtin_elements = 2; new_dtp->builtin_element_size = el_size; new_dtp->basic_type = type; new_dtp->has_sticky_lb = 0; new_dtp->true_lb = 0; new_dtp->lb = 0; new_dtp->has_sticky_ub = 0; new_dtp->true_ub = true_ub; new_dtp->size = type_size; new_dtp->ub = type_extent; /* possible padding */ new_dtp->extent = type_extent; new_dtp->alignsize = alignsize; /* place maximum on alignment based on padding rules */ /* There are some really wierd rules for structure alignment; * these capture the ones of which we are aware. */ switch (type) { case MPI_SHORT_INT: case MPI_LONG_INT: #ifdef HAVE_MAX_INTEGER_ALIGNMENT new_dtp->alignsize = MPL_MIN(new_dtp->alignsize, HAVE_MAX_INTEGER_ALIGNMENT); #endif break; case MPI_FLOAT_INT: #ifdef HAVE_MAX_FP_ALIGNMENT new_dtp->alignsize = MPL_MIN(new_dtp->alignsize, HAVE_MAX_FP_ALIGNMENT); #endif break; case MPI_DOUBLE_INT: #ifdef HAVE_MAX_DOUBLE_FP_ALIGNMENT new_dtp->alignsize = MPL_MIN(new_dtp->alignsize, HAVE_MAX_DOUBLE_FP_ALIGNMENT); #elif defined(HAVE_MAX_FP_ALIGNMENT) new_dtp->alignsize = MPL_MIN(new_dtp->alignsize, HAVE_MAX_FP_ALIGNMENT); #endif break; case MPI_LONG_DOUBLE_INT: #ifdef HAVE_MAX_LONG_DOUBLE_FP_ALIGNMENT new_dtp->alignsize = MPL_MIN(new_dtp->alignsize, HAVE_MAX_LONG_DOUBLE_FP_ALIGNMENT); #elif defined(HAVE_MAX_FP_ALIGNMENT) new_dtp->alignsize = MPL_MIN(new_dtp->alignsize, HAVE_MAX_FP_ALIGNMENT); #endif break; } new_dtp->is_contig = (((MPI_Aint) type_size) == type_extent) ? 1 : 0; new_dtp->max_contig_blocks = (((MPI_Aint) type_size) == type_extent) ? 1 : 2; /* fill in dataloops -- only case where we precreate dataloops * * this is necessary because these types aren't committed by the * user, which is the other place where we create dataloops. so * if the user uses one of these w/out building some more complex * type and then committing it, then the dataloop will be missing. */ #ifdef MPID_NEEDS_DLOOP_ALL_BYTES /* If MPID implementation needs use to reduce everything to * a byte stream, do that. */ err = MPIR_Dataloop_create_pairtype(type, &(new_dtp->dataloop), &(new_dtp->dataloop_size), &(new_dtp->dataloop_depth), MPIDU_DATALOOP_ALL_BYTES); #else err = MPIR_Dataloop_create_pairtype(type, &(new_dtp->dataloop), &(new_dtp->dataloop_size), &(new_dtp->dataloop_depth), MPIR_DATALOOP_DEFAULT); #endif #ifdef MPID_Type_commit_hook if (!err) { err = MPID_Type_commit_hook(new_dtp); } #endif /* MPID_Type_commit_hook */ /* --BEGIN ERROR HANDLING-- */ if (err) { mpi_errno = MPIR_Err_create_code(MPI_SUCCESS, MPIR_ERR_RECOVERABLE, "MPIR_Dataloop_create_pairtype", __LINE__, MPI_ERR_OTHER, "**nomem", 0); return mpi_errno; } /* --END ERROR HANDLING-- */ return mpi_errno; }