-:    0:Source:/home/MPI/testing/mpich2/mpich2/src/mpid/common/datatype/mpid_type_struct.c
        -:    0:Graph:mpid_type_struct.gcno
        -:    0:Data:mpid_type_struct.gcda
        -:    0:Runs:4382
        -:    0:Programs:1376
        -:    1:/* -*- Mode: C; c-basic-offset:4 ; -*- */
        -:    2:
        -:    3:/*
        -:    4: *  (C) 2001 by Argonne National Laboratory.
        -:    5: *      See COPYRIGHT in top-level directory.
        -:    6: */
        -:    7:
        -:    8:#include <mpiimpl.h>
        -:    9:#include <mpid_dataloop.h>
        -:   10:#include <stdlib.h>
        -:   11:#include <limits.h>
        -:   12:
        -:   13:#undef MPID_STRUCT_FLATTEN_DEBUG
        -:   14:#undef MPID_STRUCT_DEBUG
        -:   15:
        -:   16:static int MPID_Type_struct_alignsize(int count,
        -:   17:				      MPI_Datatype *oldtype_array,
        -:   18:				      MPI_Aint *displacement_array);
        -:   19:
        -:   20:/* MPID_Type_struct_alignsize
        -:   21: *
        -:   22: * This function guesses at how the C compiler would align a structure
        -:   23: * with the given components.
        -:   24: *
        -:   25: * It uses these configure-time defines to do its magic:
        -:   26: * - HAVE_MAX_INTEGER_ALIGNMENT - maximum byte alignment of integers
        -:   27: * - HAVE_MAX_FP_ALIGNMENT      - maximum byte alignment of floating points
        -:   28: * - HAVE_MAX_LONG_DOUBLE_FP_ALIGNMENT - maximum byte alignment with long
        -:   29: *                                   doubles (if different from FP_ALIGNMENT)
        -:   30: * - HAVE_MAX_DOUBLE_FP_ALIGNMENT - maximum byte alignment with doubles (if
        -:   31: *                                  long double is different from FP_ALIGNMENT)
        -:   32: * - HAVE_DOUBLE_POS_ALIGNMENT  - indicates that structures with doubles
        -:   33: *                                are aligned differently if double isn't
        -:   34: *                                at displacement 0 (e.g. PPC32/64).
        -:   35: * - HAVE_LLINT_POS_ALIGNMENT   - same as above, for MPI_LONG_LONG_INT
        -:   36: *
        -:   37: * The different FP, DOUBLE, LONG_DOUBLE alignment case are necessary for
        -:   38: * Cygwin on X86 (because long_double is 12 bytes, so double and long double
        -:   39: * have different natural alignments).  Linux on X86, however, does not have
        -:   40: * different rules for this case.
        -:   41: */
        -:   42:static int MPID_Type_struct_alignsize(int count,
        -:   43:				      MPI_Datatype *oldtype_array,
        -:   44:				      MPI_Aint *displacement_array)
    29483:   45:{
    29483:   46:    int i, max_alignsize = 0, tmp_alignsize, derived_alignsize = 0;
        -:   47:
  5400627:   48:    for (i=0; i < count; i++)
        -:   49:    {
        -:   50:	/* shouldn't be called with an LB or UB, but we'll handle it nicely */
  5371144:   51:	if (oldtype_array[i] == MPI_LB || oldtype_array[i] == MPI_UB) continue;
  5348067:   52:	else if (HANDLE_GET_KIND(oldtype_array[i]) == HANDLE_KIND_BUILTIN)
        -:   53:	{
  5338788:   54:	    tmp_alignsize = MPID_Datatype_get_basic_size(oldtype_array[i]);
        -:   55:
        -:   56:#ifdef HAVE_DOUBLE_ALIGNMENT_EXCEPTION
        -:   57:	    if (oldtype_array[i] == MPI_DOUBLE) {
        -:   58:		tmp_alignsize = HAVE_DOUBLE_ALIGNMENT_EXCEPTION;
        -:   59:	    }
        -:   60:#endif
        -:   61:
  5338788:   62:	    switch(oldtype_array[i])
        -:   63:	    {
        -:   64:		case MPI_FLOAT:
        -:   65:		case MPI_DOUBLE:
        -:   66:		case MPI_LONG_DOUBLE:
        -:   67:#if defined(HAVE_MAX_LONG_DOUBLE_FP_ALIGNMENT) && \
        -:   68:    defined(HAVE_MAX_DOUBLE_FP_ALIGNMENT)
        -:   69:		    if (oldtype_array[i] == MPI_LONG_DOUBLE) {
        -:   70:			if (tmp_alignsize > HAVE_MAX_LONG_DOUBLE_FP_ALIGNMENT)
        -:   71:			    tmp_alignsize = HAVE_MAX_LONG_DOUBLE_FP_ALIGNMENT;
        -:   72:		    }
        -:   73:		    else if (oldtype_array[i] == MPI_DOUBLE) {
        -:   74:			if (tmp_alignsize > HAVE_MAX_DOUBLE_FP_ALIGNMENT)
        -:   75:			    tmp_alignsize = HAVE_MAX_DOUBLE_FP_ALIGNMENT;
        -:   76:		    }
        -:   77:		    else {
        -:   78:			/* HAVE_MAX_FP_ALIGNMENT may not be defined, hence commented */
        -:   79:				/*
        -:   80:			if (tmp_alignsize > HAVE_MAX_FP_ALIGNMENT)
        -:   81:			    tmp_alignsize = HAVE_MAX_FP_ALIGNMENT;
        -:   82:				*/
        -:   83:		    }
        -:   84:#elif defined(HAVE_MAX_FP_ALIGNMENT)
   463245:   85:		    if (tmp_alignsize > HAVE_MAX_FP_ALIGNMENT)
   216033:   86:			tmp_alignsize = HAVE_MAX_FP_ALIGNMENT;
        -:   87:#endif
        -:   88:#ifdef HAVE_DOUBLE_POS_ALIGNMENT
        -:   89:		    /* sort of a hack, but so is this rule */
        -:   90:		    if (oldtype_array[i] == MPI_DOUBLE &&
        -:   91:			displacement_array[i] != (MPI_Aint) 0)
        -:   92:		    {
        -:   93:			tmp_alignsize = 4;
        -:   94:		    }
        -:   95:#endif
        -:   96:		    break;
        -:   97:		default:
        -:   98:#ifdef HAVE_MAX_INTEGER_ALIGNMENT
  4875543:   99:		    if (tmp_alignsize > HAVE_MAX_INTEGER_ALIGNMENT)
        6:  100:			tmp_alignsize = HAVE_MAX_INTEGER_ALIGNMENT;
        -:  101:#endif
        -:  102:		    break;
        -:  103:#ifdef HAVE_LLINT_POS_ALIGNMENT
        -:  104:		    if (oldtype_array[i] == MPI_LONG_LONG_INT &&
        -:  105:			displacement_array[i] != (MPI_Aint) 0)
        -:  106:		    {
        -:  107:			tmp_alignsize = 4;
        -:  108:		    }
        -:  109:#endif
        -:  110:	    }
        -:  111:	}
        -:  112:	else
        -:  113:	{
        -:  114:	    MPID_Datatype *dtp;
        -:  115:
     9279:  116:	    MPID_Datatype_get_ptr(oldtype_array[i], dtp);
     9279:  117:	    tmp_alignsize = dtp->alignsize;
     9279:  118:	    if (derived_alignsize < tmp_alignsize)
     6391:  119:		derived_alignsize = tmp_alignsize;
        -:  120:	}
  5348067:  121:	if (max_alignsize < tmp_alignsize) max_alignsize = tmp_alignsize;
        -:  122:
        -:  123:    }
        -:  124:
    29483:  125:    return max_alignsize;
        -:  126:}
        -:  127:
        -:  128:
        -:  129:/*@
        -:  130:  MPID_Type_struct - create a struct datatype
        -:  131:
        -:  132:  Input Parameters:
        -:  133:+ count - number of blocks in vector
        -:  134:. blocklength_array - number of elements in each block
        -:  135:. displacement_array - offsets of blocks from start of type in bytes
        -:  136:- oldtype_array - types (using handle) of datatypes on which vector is based
        -:  137:
        -:  138:  Output Parameters:
        -:  139:. newtype - handle of new struct datatype
        -:  140:
        -:  141:  Return Value:
        -:  142:  MPI_SUCCESS on success, MPI errno on failure.
        -:  143:@*/
        -:  144:int MPID_Type_struct(int count,
        -:  145:		     int *blocklength_array,
        -:  146:		     MPI_Aint *displacement_array,
        -:  147:		     MPI_Datatype *oldtype_array,
        -:  148:		     MPI_Datatype *newtype)
    29484:  149:{
    29484:  150:    int mpi_errno = MPI_SUCCESS;
    29484:  151:    int i, old_are_contig = 1, definitely_not_contig = 0;
    29484:  152:    int found_sticky_lb = 0, found_sticky_ub = 0, found_true_lb = 0,
    29484:  153:	found_true_ub = 0, found_el_type = 0;
    29484:  154:    MPI_Aint el_sz = 0;
    29484:  155:    int size = 0;
    29484:  156:    MPI_Datatype el_type = MPI_DATATYPE_NULL;
    29484:  157:    MPI_Aint true_lb_disp = 0, true_ub_disp = 0, sticky_lb_disp = 0,
    29484:  158:	sticky_ub_disp = 0;
        -:  159:
        -:  160:    MPID_Datatype *new_dtp;
        -:  161:
    29484:  162:    if (count == 0) return MPID_Type_zerolen(newtype);
        -:  163:
        -:  164:#ifdef MPID_STRUCT_DEBUG
        -:  165:    MPIDI_Datatype_printf(oldtype_array[0], 1, displacement_array[0],
        -:  166:			  blocklength_array[0], 1);
        -:  167:    for (i=1; i < count; i++)
        -:  168:    {
        -:  169:	MPIDI_Datatype_printf(oldtype_array[i], 1, displacement_array[i],
        -:  170:			      blocklength_array[i], 0);
        -:  171:    }
        -:  172:#endif
        -:  173:
        -:  174:    /* allocate new datatype object and handle */
    29483:  175:    new_dtp = (MPID_Datatype *) MPIU_Handle_obj_alloc(&MPID_Datatype_mem);
        -:  176:    /* --BEGIN ERROR HANDLING-- */
    29483:  177:    if (!new_dtp)
        -:  178:    {
    #####:  179:	mpi_errno = MPIR_Err_create_code(MPI_SUCCESS, MPIR_ERR_RECOVERABLE,
        -:  180:					 "MPID_Type_struct",
        -:  181:					 __LINE__, MPI_ERR_OTHER,
        -:  182:					 "**nomem", 0);
    #####:  183:	return mpi_errno;
        -:  184:    }
        -:  185:    /* --END ERROR HANDLING-- */
        -:  186:
        -:  187:    /* handle is filled in by MPIU_Handle_obj_alloc() */
    29483:  188:    MPIU_Object_set_ref(new_dtp, 1);
    29483:  189:    new_dtp->is_permanent = 0;
    29483:  190:    new_dtp->is_committed = 0;
    29483:  191:    new_dtp->attributes   = NULL;
    29483:  192:    new_dtp->cache_id     = 0;
    29483:  193:    new_dtp->name[0]      = 0;
    29483:  194:    new_dtp->contents     = NULL;
        -:  195:
    29483:  196:    new_dtp->dataloop       = NULL;
    29483:  197:    new_dtp->dataloop_size  = -1;
    29483:  198:    new_dtp->dataloop_depth = -1;
    29483:  199:    new_dtp->hetero_dloop       = NULL;
    29483:  200:    new_dtp->hetero_dloop_size  = -1;
    29483:  201:    new_dtp->hetero_dloop_depth = -1;
        -:  202:
        -:  203:    /* check for junk struct with all zero blocks */
    29483:  204:    for (i=0; i < count; i++) if (blocklength_array[i] != 0) break;
        -:  205:
    29483:  206:    if (i == count)
        -:  207:    {
    #####:  208:	MPIU_Handle_obj_free(&MPID_Datatype_mem, new_dtp);
    #####:  209:	return MPID_Type_zerolen(newtype);
        -:  210:    }
        -:  211:
    29483:  212:    new_dtp->max_contig_blocks = 0;
  5400627:  213:    for (i=0; i < count; i++)
        -:  214:    {
        -:  215:	int is_builtin =
  5371144:  216:	    (HANDLE_GET_KIND(oldtype_array[i]) == HANDLE_KIND_BUILTIN);
        -:  217:	MPI_Aint tmp_lb, tmp_ub, tmp_true_lb, tmp_true_ub;
        -:  218:	MPI_Aint tmp_el_sz;
        -:  219:	MPI_Datatype tmp_el_type;
  5371144:  220:	MPID_Datatype *old_dtp = NULL;
        -:  221:
        -:  222:	/* Interpreting typemap to not include 0 blklen things, including
        -:  223:	 * MPI_LB and MPI_UB. -- Rob Ross, 10/31/2005
        -:  224:	 */
  5371144:  225:	if (blocklength_array[i] == 0) continue;
        -:  226:
  5371143:  227:	if (is_builtin)
        -:  228:	{
  5361864:  229:	    tmp_el_sz   = MPID_Datatype_get_basic_size(oldtype_array[i]);
  5361864:  230:	    tmp_el_type = oldtype_array[i];
        -:  231:
  5361864:  232:	    MPID_DATATYPE_BLOCK_LB_UB((MPI_Aint)(blocklength_array[i]),
        -:  233:				      displacement_array[i],
        -:  234:				      0,
        -:  235:				      tmp_el_sz,
        -:  236:				      tmp_el_sz,
        -:  237:				      tmp_lb,
        -:  238:				      tmp_ub);
  5361864:  239:	    tmp_true_lb = tmp_lb;
  5361864:  240:	    tmp_true_ub = tmp_ub;
        -:  241:
  5361864:  242:	    size += tmp_el_sz * blocklength_array[i];
        -:  243:
  5361864:  244:	    new_dtp->max_contig_blocks++;
        -:  245:	}
        -:  246:	else
        -:  247:	{
     9279:  248:	    MPID_Datatype_get_ptr(oldtype_array[i], old_dtp);
        -:  249:
        -:  250:	    /* Ensure that "element_size" fits into an int datatype. */
        -:  251:	    MPID_Ensure_Aint_fits_in_int(old_dtp->element_size);
        -:  252:
     9279:  253:	    tmp_el_sz   = old_dtp->element_size;
     9279:  254:	    tmp_el_type = old_dtp->eltype;
        -:  255:
     9279:  256:	    MPID_DATATYPE_BLOCK_LB_UB((MPI_Aint) blocklength_array[i],
        -:  257:				      displacement_array[i],
        -:  258:				      old_dtp->lb,
        -:  259:				      old_dtp->ub,
        -:  260:				      old_dtp->extent,
        -:  261:				      tmp_lb,
        -:  262:				      tmp_ub);
     9279:  263:	    tmp_true_lb = tmp_lb + (old_dtp->true_lb - old_dtp->lb);
     9279:  264:	    tmp_true_ub = tmp_ub + (old_dtp->true_ub - old_dtp->ub);
        -:  265:
     9279:  266:	    size += old_dtp->size * blocklength_array[i];
        -:  267:
     9279:  268:	    new_dtp->max_contig_blocks += old_dtp->max_contig_blocks;
        -:  269:	}
        -:  270:
        -:  271:	/* element size and type */
  5371143:  272:	if (oldtype_array[i] != MPI_LB && oldtype_array[i] != MPI_UB)
        -:  273:	{
  5348066:  274:	    if (found_el_type == 0)
        -:  275:	    {
    29482:  276:		el_sz         = tmp_el_sz;
    29482:  277:		el_type       = tmp_el_type;
    29482:  278:		found_el_type = 1;
        -:  279:	    }
  5318584:  280:	    else if (el_sz != tmp_el_sz)
        -:  281:	    {
    65918:  282:		el_sz = -1;
    65918:  283:		el_type = MPI_DATATYPE_NULL;
        -:  284:	    }
  5252666:  285:	    else if (el_type != tmp_el_type)
        -:  286:	    {
        -:  287:		/* Q: should we set el_sz = -1 even though the same? */
       34:  288:		el_type = MPI_DATATYPE_NULL;
        -:  289:	    }
        -:  290:	}
        -:  291:
        -:  292:	/* keep lowest sticky lb */
  5371143:  293:	if ((oldtype_array[i] == MPI_LB) ||
        -:  294:	    (!is_builtin && old_dtp->has_sticky_lb))
        -:  295:	{
    23776:  296:	    if (!found_sticky_lb)
        -:  297:	    {
    19066:  298:		found_sticky_lb = 1;
    19066:  299:		sticky_lb_disp  = tmp_lb;
        -:  300:	    }
     4710:  301:	    else if (sticky_lb_disp > tmp_lb)
        -:  302:	    {
     2310:  303:		sticky_lb_disp = tmp_lb;
        -:  304:	    }
        -:  305:	}
        -:  306:
        -:  307:	/* keep highest sticky ub */
  5371143:  308:	if ((oldtype_array[i] == MPI_UB) ||
        -:  309:	    (!is_builtin && old_dtp->has_sticky_ub))
        -:  310:	{
    11356:  311:	    if (!found_sticky_ub)
        -:  312:	    {
     8624:  313:		found_sticky_ub = 1;
     8624:  314:		sticky_ub_disp  = tmp_ub;
        -:  315:	    }
     2732:  316:	    else if (sticky_ub_disp < tmp_ub)
        -:  317:	    {
     2534:  318:		sticky_ub_disp = tmp_ub;
        -:  319:	    }
        -:  320:	}
        -:  321:
        -:  322:	/* keep lowest true lb and highest true ub
        -:  323:	 *
        -:  324:	 * note: checking for contiguity at the same time, to avoid
        -:  325:	 *       yet another pass over the arrays
        -:  326:	 */
  5371143:  327:	if (oldtype_array[i] != MPI_UB && oldtype_array[i] != MPI_LB)
        -:  328:	{
  5348066:  329:	    if (!found_true_lb)
        -:  330:	    {
    29482:  331:		found_true_lb = 1;
    29482:  332:		true_lb_disp  = tmp_true_lb;
        -:  333:	    }
  5318584:  334:	    else if (true_lb_disp > tmp_true_lb)
        -:  335:	    {
        -:  336:		/* element starts before previous */
      955:  337:		true_lb_disp = tmp_true_lb;
      955:  338:		definitely_not_contig = 1;
        -:  339:	    }
        -:  340:
  5348066:  341:	    if (!found_true_ub)
        -:  342:	    {
    29482:  343:		found_true_ub = 1;
    29482:  344:		true_ub_disp  = tmp_true_ub;
        -:  345:	    }
  5318584:  346:	    else if (true_ub_disp < tmp_true_ub)
        -:  347:	    {
  5317361:  348:		true_ub_disp = tmp_true_ub;
        -:  349:	    }
        -:  350:	    else {
        -:  351:		/* element ends before previous ended */
     1223:  352:		definitely_not_contig = 1;
        -:  353:	    }
        -:  354:	}
        -:  355:
  5371143:  356:	if (!is_builtin && !old_dtp->is_contig)
        -:  357:	{
     8382:  358:	    old_are_contig = 0;
        -:  359:	}
        -:  360:    }
        -:  361:
    29483:  362:    new_dtp->n_elements = -1; /* TODO */
    29483:  363:    new_dtp->element_size = el_sz;
    29483:  364:    new_dtp->eltype = el_type;
        -:  365:
    29483:  366:    new_dtp->has_sticky_lb = found_sticky_lb;
    29483:  367:    new_dtp->true_lb       = true_lb_disp;
    29483:  368:    new_dtp->lb = (found_sticky_lb) ? sticky_lb_disp : true_lb_disp;
        -:  369:
    29483:  370:    new_dtp->has_sticky_ub = found_sticky_ub;
    29483:  371:    new_dtp->true_ub       = true_ub_disp;
    29483:  372:    new_dtp->ub = (found_sticky_ub) ? sticky_ub_disp : true_ub_disp;
        -:  373:
    29483:  374:    new_dtp->alignsize = MPID_Type_struct_alignsize(count,
        -:  375:						    oldtype_array,
        -:  376:						    displacement_array);
        -:  377:
    29483:  378:    new_dtp->extent = new_dtp->ub - new_dtp->lb;
    29483:  379:    if ((!found_sticky_lb) && (!found_sticky_ub))
        -:  380:    {
        -:  381:	/* account for padding */
        -:  382:	MPI_Aint epsilon = (new_dtp->alignsize > 0) ?
    10058:  383:	    new_dtp->extent % ((MPI_Aint)(new_dtp->alignsize)) : 0;
        -:  384:
    10058:  385:	if (epsilon)
        -:  386:	{
     1360:  387:	    new_dtp->ub    += ((MPI_Aint)(new_dtp->alignsize) - epsilon);
     1360:  388:	    new_dtp->extent = new_dtp->ub - new_dtp->lb;
        -:  389:	}
        -:  390:    }
        -:  391:
    29483:  392:    new_dtp->size = size;
        -:  393:
        -:  394:    /* new type is contig for N types if its size and extent are the
        -:  395:     * same, and the old type was also contiguous, and we didn't see
        -:  396:     * something noncontiguous based on true ub/ub.
        -:  397:     */
    32337:  398:    if (((MPI_Aint)(new_dtp->size) == new_dtp->extent) &&
        -:  399:	old_are_contig && (! definitely_not_contig))
        -:  400:    {
     2854:  401:	new_dtp->is_contig = 1;
        -:  402:    }
        -:  403:    else
        -:  404:    {
    26629:  405:	new_dtp->is_contig = 0;
        -:  406:    }
        -:  407:
    29483:  408:    *newtype = new_dtp->handle;
    29483:  409:    return mpi_errno;
        -:  410:}
        -:  411:
        -:  412: