root/mpich2/trunk/src/mpid/common/datatype/dataloop/segment_ops.c @ 4872

Revision 4872, 31.9 KB (checked in by rross, 5 months ago)

Got rid of incorrect "unused" attributes on input variables that are used.

Line 
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 <stdio.h>
9#include <stdlib.h>
10#include <string.h>
11#include <sys/types.h>
12
13#include "dataloop.h"
14#include "veccpy.h"
15
16int PREPEND_PREFIX(Segment_contig_m2m)(DLOOP_Offset *blocks_p,
17                                       DLOOP_Type el_type,
18                                       DLOOP_Offset rel_off,
19                                       void *bufp ATTRIBUTE((unused)),
20                                       void *v_paramp)
21{
22    DLOOP_Offset el_size; /* DLOOP_Count? */
23    DLOOP_Offset size;
24    struct PREPEND_PREFIX(m2m_params) *paramp = v_paramp;
25
26    DLOOP_Handle_get_size_macro(el_type, el_size);
27    size = *blocks_p * el_size;
28
29#ifdef MPID_SU_VERBOSE
30    dbg_printf("\t[contig unpack: do=" MPI_AINT_FMT_DEC_SPEC ", dp=%x, bp=%x, sz=" MPI_AINT_FMT_DEC_SPEC ", blksz=" MPI_AINT_FMT_DEC_SPEC "]\n",
31               rel_off,
32               (unsigned) bufp,
33               (unsigned) paramp->u.unpack.unpack_buffer,
34               el_size,
35               *blocks_p);
36#endif
37
38    if (paramp->direction == DLOOP_M2M_TO_USERBUF) {
39        /* Ensure that pointer increment fits in a pointer */
40        /* userbuf is a pointer (not a displacement) since it is being
41         * used on a memcpy */
42        MPID_Ensure_Aint_fits_in_pointer((MPI_VOID_PTR_CAST_TO_MPI_AINT (paramp->userbuf)) + rel_off);
43        DLOOP_Memcpy((char *) paramp->userbuf + rel_off, paramp->streambuf, size);
44    }
45    else {
46        /* Ensure that pointer increment fits in a pointer */
47        /* userbuf is a pointer (not a displacement) since it is being used on a memcpy */
48        MPID_Ensure_Aint_fits_in_pointer((MPI_VOID_PTR_CAST_TO_MPI_AINT (paramp->userbuf)) + rel_off);
49        DLOOP_Memcpy(paramp->streambuf, (char *) paramp->userbuf + rel_off, size);
50    }
51    /* Ensure that pointer increment fits in a pointer */
52    /* streambuf is a pointer (not a displacement) since it was used on a memcpy */
53    MPID_Ensure_Aint_fits_in_pointer((MPI_VOID_PTR_CAST_TO_MPI_AINT (paramp->streambuf)) + size);
54    paramp->streambuf += size;
55    return 0;
56}
57
58/* Segment_vector_m2m
59 *
60 * Note: this combines both packing and unpacking functionality.
61 *
62 * Note: this is only called when the starting position is at the beginning
63 * of a whole block in a vector type.
64 */
65int PREPEND_PREFIX(Segment_vector_m2m)(DLOOP_Offset *blocks_p,
66                                       DLOOP_Count count ATTRIBUTE((unused)),
67                                       DLOOP_Count blksz,
68                                       DLOOP_Offset stride,
69                                       DLOOP_Type el_type,
70                                       DLOOP_Offset rel_off, /* offset into buffer */
71                                       void *bufp ATTRIBUTE((unused)),
72                                       void *v_paramp)
73{
74    DLOOP_Count i, blocks_left, whole_count;
75    DLOOP_Offset el_size;
76    struct PREPEND_PREFIX(m2m_params) *paramp = v_paramp;
77    char *cbufp;
78
79    /* Ensure that pointer increment fits in a pointer */
80    /* userbuf is a pointer (not a displacement) since it is being used for a memory copy */
81    MPID_Ensure_Aint_fits_in_pointer((MPI_VOID_PTR_CAST_TO_MPI_AINT (paramp->userbuf)) + rel_off);
82    cbufp = (char*) paramp->userbuf + rel_off;
83    DLOOP_Handle_get_size_macro(el_type, el_size);
84
85    whole_count = (blksz > 0) ? (*blocks_p / (DLOOP_Offset) blksz) : 0;
86    blocks_left = (blksz > 0) ? (*blocks_p % (DLOOP_Offset) blksz) : 0;
87
88    if (paramp->direction == DLOOP_M2M_TO_USERBUF) {
89        if (el_size == 8
90            MPIR_ALIGN8_TEST(paramp->streambuf,cbufp))
91        {
92            MPIDI_COPY_TO_VEC(paramp->streambuf, cbufp, stride,
93                              int64_t, blksz, whole_count);
94            MPIDI_COPY_TO_VEC(paramp->streambuf, cbufp, 0,
95                              int64_t, blocks_left, 1);
96        }
97        else if (el_size == 4
98                 MPIR_ALIGN4_TEST(paramp->streambuf,cbufp))
99        {
100            MPIDI_COPY_TO_VEC((paramp->streambuf), cbufp, stride,
101                              int32_t, blksz, whole_count);
102            MPIDI_COPY_TO_VEC(paramp->streambuf, cbufp, 0,
103                              int32_t, blocks_left, 1);
104        }
105        else if (el_size == 2) {
106            MPIDI_COPY_TO_VEC(paramp->streambuf, cbufp, stride,
107                              int16_t, blksz, whole_count);
108            MPIDI_COPY_TO_VEC(paramp->streambuf, cbufp, 0,
109                              int16_t, blocks_left, 1);
110        }
111        else {
112            for (i=0; i < whole_count; i++) {
113                DLOOP_Memcpy(cbufp, paramp->streambuf, ((DLOOP_Offset) blksz) * el_size);
114                /* Ensure that pointer increment fits in a pointer */
115                /* streambuf is a pointer (not a displacement) since it is being used for a memory copy */
116                MPID_Ensure_Aint_fits_in_pointer((MPI_VOID_PTR_CAST_TO_MPI_AINT (paramp->streambuf)) +
117                                                 ((DLOOP_Offset) blksz) * el_size);
118                paramp->streambuf += ((DLOOP_Offset) blksz) * el_size;
119
120                MPID_Ensure_Aint_fits_in_pointer((MPI_VOID_PTR_CAST_TO_MPI_AINT (cbufp)) + stride);
121                cbufp += stride;
122            }
123            if (blocks_left) {
124                DLOOP_Memcpy(cbufp, paramp->streambuf, ((DLOOP_Offset) blocks_left) * el_size);
125                /* Ensure that pointer increment fits in a pointer */
126                /* streambuf is a pointer (not a displacement) since
127                 * it is being used for a memory copy */
128                MPID_Ensure_Aint_fits_in_pointer((MPI_VOID_PTR_CAST_TO_MPI_AINT (paramp->streambuf)) +
129                                                 ((DLOOP_Offset) blocks_left) * el_size);
130                paramp->streambuf += ((DLOOP_Offset) blocks_left) * el_size;
131            }
132        }
133    }
134    else /* M2M_FROM_USERBUF */ {
135        if (el_size == 8
136            MPIR_ALIGN8_TEST(cbufp,paramp->streambuf))
137        {
138            MPIDI_COPY_FROM_VEC(cbufp, paramp->streambuf, stride,
139                                int64_t, blksz, whole_count);
140            MPIDI_COPY_FROM_VEC(cbufp, paramp->streambuf, 0,
141                                int64_t, blocks_left, 1);
142        }
143        else if (el_size == 4
144                 MPIR_ALIGN4_TEST(cbufp,paramp->streambuf))
145        {
146            MPIDI_COPY_FROM_VEC(cbufp, paramp->streambuf, stride,
147                                int32_t, blksz, whole_count);
148            MPIDI_COPY_FROM_VEC(cbufp, paramp->streambuf, 0,
149                                int32_t, blocks_left, 1);
150        }
151        else if (el_size == 2) {
152            MPIDI_COPY_FROM_VEC(cbufp, paramp->streambuf, stride,
153                                int16_t, blksz, whole_count);
154            MPIDI_COPY_FROM_VEC(cbufp, paramp->streambuf, 0,
155                                int16_t, blocks_left, 1);
156        }
157        else {
158            for (i=0; i < whole_count; i++) {
159                DLOOP_Memcpy(paramp->streambuf, cbufp, (DLOOP_Offset) blksz * el_size);
160                /* Ensure that pointer increment fits in a pointer */
161                /* streambuf is a pointer (not a displacement) since
162                 * it is being used for a memory copy */
163                MPID_Ensure_Aint_fits_in_pointer((MPI_VOID_PTR_CAST_TO_MPI_AINT (paramp->streambuf)) +
164                                                 (DLOOP_Offset) blksz * el_size);
165                paramp->streambuf += (DLOOP_Offset) blksz * el_size;
166                cbufp += stride;
167            }
168            if (blocks_left) {
169                DLOOP_Memcpy(paramp->streambuf, cbufp, (DLOOP_Offset) blocks_left * el_size);
170                /* Ensure that pointer increment fits in a pointer */
171                /* streambuf is a pointer (not a displacement) since
172                 * it is being used for a memory copy */
173                MPID_Ensure_Aint_fits_in_pointer((MPI_VOID_PTR_CAST_TO_MPI_AINT (paramp->streambuf)) +
174                                                 (DLOOP_Offset) blocks_left * el_size);
175                paramp->streambuf += (DLOOP_Offset) blocks_left * el_size;
176            }
177        }
178    }
179
180    return 0;
181}
182
183/* MPID_Segment_blkidx_m2m
184 */
185int PREPEND_PREFIX(Segment_blkidx_m2m)(DLOOP_Offset *blocks_p,
186                                       DLOOP_Count count,
187                                       DLOOP_Count blocklen,
188                                       DLOOP_Offset *offsetarray,
189                                       DLOOP_Type el_type,
190                                       DLOOP_Offset rel_off,
191                                       void *bufp ATTRIBUTE((unused)),
192                                       void *v_paramp)
193{
194    DLOOP_Count curblock = 0;
195    DLOOP_Offset el_size;
196    DLOOP_Offset blocks_left = *blocks_p;
197    char *cbufp;
198    struct PREPEND_PREFIX(m2m_params) *paramp = v_paramp;
199
200    DLOOP_Handle_get_size_macro(el_type, el_size);
201
202    while (blocks_left) {
203        char *src, *dest;
204
205        DLOOP_Assert(curblock < count);
206
207        /* Ensure that pointer increment fits in a pointer */
208        /* userbuf is a pointer (not a displacement) since it is being
209         * used for a memory copy */
210        MPID_Ensure_Aint_fits_in_pointer((MPI_VOID_PTR_CAST_TO_MPI_AINT (paramp->userbuf)) +
211                                         rel_off + offsetarray[curblock]);
212        cbufp = (char*) paramp->userbuf + rel_off + offsetarray[curblock];
213
214        if (blocklen > blocks_left) blocklen = blocks_left;
215
216        if (paramp->direction == DLOOP_M2M_TO_USERBUF) {
217            src  = paramp->streambuf;
218            dest = cbufp;
219        }
220        else {
221            src  = cbufp;
222            dest = paramp->streambuf;
223        }
224
225        /* note: macro modifies dest buffer ptr, so we must reset */
226        if (el_size == 8
227            MPIR_ALIGN8_TEST(src, dest))
228        {
229            MPIDI_COPY_FROM_VEC(src, dest, 0, int64_t, blocklen, 1);
230        }
231        else if (el_size == 4
232                 MPIR_ALIGN4_TEST(src,dest))
233        {
234            MPIDI_COPY_FROM_VEC(src, dest, 0, int32_t, blocklen, 1);
235        }
236        else if (el_size == 2) {
237            MPIDI_COPY_FROM_VEC(src, dest, 0, int16_t, blocklen, 1);
238        }
239        else {
240            DLOOP_Memcpy(dest, src, (DLOOP_Offset) blocklen * el_size);
241        }
242
243        /* Ensure that pointer increment fits in a pointer */
244        /* streambuf is a pointer (not a displacement) since it is
245         * being used for a memory copy */
246        MPID_Ensure_Aint_fits_in_pointer((MPI_VOID_PTR_CAST_TO_MPI_AINT (paramp->streambuf)) +
247                                         (DLOOP_Offset) blocklen * el_size);
248        paramp->streambuf += (DLOOP_Offset) blocklen * el_size;
249        blocks_left -= blocklen;
250        curblock++;
251    }
252
253    return 0;
254}
255
256/* MPID_Segment_index_m2m
257 */
258int PREPEND_PREFIX(Segment_index_m2m)(DLOOP_Offset *blocks_p,
259                                      DLOOP_Count count,
260                                      DLOOP_Count *blockarray,
261                                      DLOOP_Offset *offsetarray,
262                                      DLOOP_Type el_type,
263                                      DLOOP_Offset rel_off,
264                                      void *bufp ATTRIBUTE((unused)),
265                                      void *v_paramp)
266{
267    int curblock = 0;
268    DLOOP_Offset el_size;
269    DLOOP_Offset cur_block_sz, blocks_left = *blocks_p;
270    char *cbufp;
271    struct PREPEND_PREFIX(m2m_params) *paramp = v_paramp;
272
273    DLOOP_Handle_get_size_macro(el_type, el_size);
274
275    while (blocks_left) {
276        char *src, *dest;
277
278        DLOOP_Assert(curblock < count);
279        cur_block_sz = blockarray[curblock];
280
281        /* Ensure that pointer increment fits in a pointer */
282        /* userbuf is a pointer (not a displacement) since it is being
283         * used for a memory copy */
284        MPID_Ensure_Aint_fits_in_pointer((MPI_VOID_PTR_CAST_TO_MPI_AINT (paramp->userbuf)) +
285                                         rel_off + offsetarray[curblock]);
286        cbufp = (char*) paramp->userbuf + rel_off + offsetarray[curblock];
287
288        if (cur_block_sz > blocks_left) cur_block_sz = blocks_left;
289
290        if (paramp->direction == DLOOP_M2M_TO_USERBUF) {
291            src  = paramp->streambuf;
292            dest = cbufp;
293        }
294        else {
295            src  = cbufp;
296            dest = paramp->streambuf;
297        }
298
299        /* note: macro modifies dest buffer ptr, so we must reset */
300        if (el_size == 8
301            MPIR_ALIGN8_TEST(src, dest))
302        {
303            MPIDI_COPY_FROM_VEC(src, dest, 0, int64_t, cur_block_sz, 1);
304        }
305        else if (el_size == 4
306                 MPIR_ALIGN4_TEST(src,dest))
307        {
308            MPIDI_COPY_FROM_VEC(src, dest, 0, int32_t, cur_block_sz, 1);
309        }
310        else if (el_size == 2) {
311            MPIDI_COPY_FROM_VEC(src, dest, 0, int16_t, cur_block_sz, 1);
312        }
313        else {
314            DLOOP_Memcpy(dest, src, cur_block_sz * el_size);
315        }
316
317        /* Ensure that pointer increment fits in a pointer */
318        /* streambuf is a pointer (not a displacement) since it is
319         * being used for a memory copy */
320        MPID_Ensure_Aint_fits_in_pointer((MPI_VOID_PTR_CAST_TO_MPI_AINT (paramp->streambuf)) +
321                                         cur_block_sz * el_size);
322        paramp->streambuf += cur_block_sz * el_size;
323        blocks_left -= cur_block_sz;
324        curblock++;
325    }
326
327    return 0;
328}
329
330void PREPEND_PREFIX(Segment_pack)(DLOOP_Segment *segp,
331                                  DLOOP_Offset   first,
332                                  DLOOP_Offset  *lastp,
333                                  void *streambuf)
334{
335    struct PREPEND_PREFIX(m2m_params) params;
336
337    /* experimenting with discarding buf value in the segment, keeping in
338     * per-use structure instead. would require moving the parameters around a
339     * bit.
340     */
341    params.userbuf   = segp->ptr;
342    params.streambuf = streambuf;
343    params.direction = DLOOP_M2M_FROM_USERBUF;
344
345    PREPEND_PREFIX(Segment_manipulate)(segp, first, lastp,
346                                       PREPEND_PREFIX(Segment_contig_m2m),
347                                       PREPEND_PREFIX(Segment_vector_m2m),
348                                       PREPEND_PREFIX(Segment_blkidx_m2m),
349                                       PREPEND_PREFIX(Segment_index_m2m),
350                                       NULL, /* size fn */
351                                       &params);
352    return;
353}
354
355void PREPEND_PREFIX(Segment_unpack)(DLOOP_Segment *segp,
356                                    DLOOP_Offset   first,
357                                    DLOOP_Offset  *lastp,
358                                    void *streambuf)
359{
360    struct PREPEND_PREFIX(m2m_params) params;
361
362    /* experimenting with discarding buf value in the segment, keeping in
363     * per-use structure instead. would require moving the parameters around a
364     * bit.
365     */
366    params.userbuf   = segp->ptr;
367    params.streambuf = streambuf;
368    params.direction = DLOOP_M2M_TO_USERBUF;
369
370    PREPEND_PREFIX(Segment_manipulate)(segp, first, lastp,
371                                       PREPEND_PREFIX(Segment_contig_m2m),
372                                       PREPEND_PREFIX(Segment_vector_m2m),
373                                       PREPEND_PREFIX(Segment_blkidx_m2m),
374                                       PREPEND_PREFIX(Segment_index_m2m),
375                                       NULL, /* size fn */
376                                       &params);
377    return;
378}
379
380struct PREPEND_PREFIX(contig_blocks_params) {
381    DLOOP_Count  count;
382    DLOOP_Offset last_loc;
383};
384
385/* MPID_Segment_contig_count_block
386 *
387 * Note: because bufp is just an offset, we can ignore it in our
388 *       calculations of # of contig regions.
389 */
390static int DLOOP_Segment_contig_count_block(DLOOP_Offset *blocks_p,
391                                            DLOOP_Type el_type,
392                                            DLOOP_Offset rel_off,
393                                            DLOOP_Buffer bufp ATTRIBUTE((unused)),
394                                            void *v_paramp)
395{
396    DLOOP_Offset size, el_size;
397    struct PREPEND_PREFIX(contig_blocks_params) *paramp = v_paramp;
398
399    DLOOP_Assert(*blocks_p > 0);
400
401    DLOOP_Handle_get_size_macro(el_type, el_size);
402    size = *blocks_p * el_size;
403
404#ifdef MPID_SP_VERBOSE
405    MPIU_dbg_printf("contig count block: count = %d, buf+off = %d, lastloc = " MPI_AINT_FMT_DEC_SPEC "\n",
406                    (int) paramp->count,
407                    (int) ((char *) bufp + rel_off),
408                    paramp->last_loc);
409#endif
410
411    if (paramp->count > 0 && rel_off == paramp->last_loc)
412    {
413        /* this region is adjacent to the last */
414        paramp->last_loc += size;
415    }
416    else {
417        /* new region */
418        paramp->last_loc = rel_off + size;
419        paramp->count++;
420    }
421    return 0;
422}
423
424/* DLOOP_Segment_vector_count_block
425 *
426 * Input Parameters:
427 * blocks_p - [inout] pointer to a count of blocks (total, for all noncontiguous pieces)
428 * count    - # of noncontiguous regions
429 * blksz    - size of each noncontiguous region
430 * stride   - distance in bytes from start of one region to start of next
431 * el_type - elemental type (e.g. MPI_INT)
432 * ...
433 *
434 * Note: this is only called when the starting position is at the beginning
435 * of a whole block in a vector type.
436 */
437static int DLOOP_Segment_vector_count_block(DLOOP_Offset *blocks_p,
438                                            DLOOP_Count count,
439                                            DLOOP_Count blksz,
440                                            DLOOP_Offset stride,
441                                            DLOOP_Type el_type,
442                                            DLOOP_Offset rel_off, /* offset into buffer */
443                                            void *bufp ATTRIBUTE((unused)),
444                                            void *v_paramp)
445{
446    DLOOP_Count new_blk_count;
447    DLOOP_Offset size, el_size;
448    struct PREPEND_PREFIX(contig_blocks_params) *paramp = v_paramp;
449
450    DLOOP_Assert(count > 0 && blksz > 0 && *blocks_p > 0);
451
452    DLOOP_Handle_get_size_macro(el_type, el_size);
453    size = el_size * blksz;
454    new_blk_count = count;
455
456    /* if size == stride, then blocks are adjacent to one another */
457    if (size == stride) new_blk_count = 1;
458
459    if (paramp->count > 0 && rel_off == paramp->last_loc)
460    {
461        /* first block sits at end of last block */
462        new_blk_count--;
463    }
464
465    paramp->last_loc = rel_off + ((DLOOP_Offset)(count-1)) * stride + size;
466    paramp->count += new_blk_count;
467    return 0;
468}
469
470/* DLOOP_Segment_blkidx_count_block
471 *
472 * Note: this is only called when the starting position is at the
473 * beginning of a whole block in a blockindexed type.
474 */
475static int DLOOP_Segment_blkidx_count_block(DLOOP_Offset *blocks_p,
476                                            DLOOP_Count count,
477                                            DLOOP_Count blksz,
478                                            DLOOP_Offset *offsetarray,
479                                            DLOOP_Type el_type,
480                                            DLOOP_Offset rel_off,
481                                            void *bufp ATTRIBUTE((unused)),
482                                            void *v_paramp)
483{
484    DLOOP_Count i, new_blk_count;
485    DLOOP_Offset size, el_size, last_loc;
486    struct PREPEND_PREFIX(contig_blocks_params) *paramp = v_paramp;
487
488    DLOOP_Assert(count > 0 && blksz > 0 && *blocks_p > 0);
489
490    DLOOP_Handle_get_size_macro(el_type, el_size);
491    size = el_size * (DLOOP_Offset) blksz;
492    new_blk_count = count;
493
494    if (paramp->count > 0 && ((rel_off + offsetarray[0]) == paramp->last_loc))
495    {
496        /* first block sits at end of last block */
497        new_blk_count--;
498    }
499
500    last_loc = rel_off + offsetarray[0] + size;
501    for (i=1; i < count; i++) {
502        if (last_loc == rel_off + offsetarray[i]) new_blk_count--;
503
504        last_loc = rel_off + offsetarray[i] + size;
505    }
506
507    paramp->last_loc = last_loc;
508    paramp->count += new_blk_count;
509    return 0;
510}
511
512/* DLOOP_Segment_index_count_block
513 *
514 * Note: this is only called when the starting position is at the
515 * beginning of a whole block in an indexed type.
516 */
517static int DLOOP_Segment_index_count_block(DLOOP_Offset *blocks_p,
518                                           DLOOP_Count count,
519                                           DLOOP_Count *blockarray,
520                                           DLOOP_Offset *offsetarray,
521                                           DLOOP_Type el_type,
522                                           DLOOP_Offset rel_off,
523                                           void *bufp ATTRIBUTE((unused)),
524                                           void *v_paramp)
525{
526    DLOOP_Count new_blk_count;
527    DLOOP_Offset el_size, last_loc;
528    struct PREPEND_PREFIX(contig_blocks_params) *paramp = v_paramp;
529
530    DLOOP_Assert(count > 0 && *blocks_p > 0);
531
532    DLOOP_Handle_get_size_macro(el_type, el_size);
533    new_blk_count = count;
534
535    if (paramp->count > 0 && ((rel_off + offsetarray[0]) == paramp->last_loc))
536    {
537        /* first block sits at end of last block */
538        new_blk_count--;
539    }
540
541    /* Note: when we build an indexed type we combine adjacent regions,
542     *       so we're not going to go through and check every piece
543     *       separately here. if someone else were building indexed
544     *       dataloops by hand, then the loop here might be necessary.
545     *       DLOOP_Count i and DLOOP_Offset size would need to be
546     *       declared above.
547     */
548#if 0
549    last_loc = rel_off * offsetarray[0] + ((DLOOP_Offset) blockarray[0]) * el_size;
550    for (i=1; i < count; i++) {
551        if (last_loc == rel_off + offsetarray[i]) new_blk_count--;
552
553        last_loc = rel_off + offsetarray[i] + ((DLOOP_Offset) blockarray[i]) * el_size;
554    }
555#else
556    last_loc = rel_off + offsetarray[count-1] + ((DLOOP_Offset) blockarray[count-1]) * el_size;
557#endif
558
559    paramp->last_loc = last_loc;
560    paramp->count += new_blk_count;
561    return 0;
562}
563
564/* DLOOP_Segment_count_contig_blocks()
565 *
566 * Count number of contiguous regions in segment between first and last.
567 */
568void PREPEND_PREFIX(Segment_count_contig_blocks)(DLOOP_Segment *segp,
569                                                 DLOOP_Offset first,
570                                                 DLOOP_Offset *lastp,
571                                                 DLOOP_Count *countp)
572{
573    struct PREPEND_PREFIX(contig_blocks_params) params;
574
575    params.count    = 0;
576    params.last_loc = 0;
577
578    /* FIXME: The blkidx and index functions are not used since they
579     * optimize the count by coalescing contiguous segments, while
580     * functions using the count do not optimize in the same way
581     * (e.g., flatten code) */
582    PREPEND_PREFIX(Segment_manipulate)(segp,
583                                       first,
584                                       lastp,
585                                       DLOOP_Segment_contig_count_block,
586                                       DLOOP_Segment_vector_count_block,
587                                       DLOOP_Segment_blkidx_count_block,
588                                       DLOOP_Segment_index_count_block,
589                                       NULL, /* size fn */
590                                       (void *) &params);
591
592    *countp = params.count;
593    return;
594}
595
596/********** FUNCTIONS FOR FLATTENING INTO MPI OFFSETS AND BLKLENS  **********/
597
598/* Segment_mpi_flatten
599 *
600 * Flattens into a set of blocklengths and displacements, as in an
601 * MPI hindexed type. Note that we use appropriately-sized variables
602 * in the associated params structure for this reason.
603 *
604 * NOTE: blocks will be in units of bytes when returned.
605 *
606 * WARNING: there's potential for overflow here as we convert from
607 *          various types into an index of bytes.
608 */
609struct PREPEND_PREFIX(mpi_flatten_params) {
610    int       index, length;
611    MPI_Aint  last_end;
612    int      *blklens;
613    MPI_Aint *disps;
614};
615
616/* DLOOP_Segment_contig_mpi_flatten
617 *
618 */
619static int DLOOP_Segment_contig_mpi_flatten(DLOOP_Offset *blocks_p,
620                                            DLOOP_Type el_type,
621                                            DLOOP_Offset rel_off,
622                                            void *bufp,
623                                            void *v_paramp)
624{
625    int last_idx, size;
626    DLOOP_Offset el_size;
627    char *last_end = NULL;
628    struct PREPEND_PREFIX(mpi_flatten_params) *paramp = v_paramp;
629
630    DLOOP_Handle_get_size_macro(el_type, el_size);
631    size = *blocks_p * el_size;
632
633    last_idx = paramp->index - 1;
634    if (last_idx >= 0) {
635        /* Since disps can be negative, we cannot use
636         * MPID_Ensure_Aint_fits_in_pointer to verify that disps +
637         * blklens fits in a pointer.  Just let it truncate, if the
638         * sizeof a pointer is less than the sizeof an MPI_Aint.
639         */
640        last_end = (char*) MPI_AINT_CAST_TO_VOID_PTR
641                   (paramp->disps[last_idx] + ((DLOOP_Offset) paramp->blklens[last_idx]));
642    }
643
644    /* Since bufp can be a displacement and can be negative, we cannot
645     * use MPID_Ensure_Aint_fits_in_pointer to ensure the sum fits in
646     * a pointer.  Just let it truncate.
647     */
648    if ((last_idx == paramp->length-1) &&
649        (last_end != ((char *) bufp + rel_off)))
650    {
651        /* we have used up all our entries, and this region doesn't fit on
652         * the end of the last one.  setting blocks to 0 tells manipulation
653         * function that we are done (and that we didn't process any blocks).
654         */
655        *blocks_p = 0;
656        return 1;
657    }
658    else if (last_idx >= 0 && (last_end == ((char *) bufp + rel_off)))
659    {
660        /* add this size to the last vector rather than using up another one */
661        paramp->blklens[last_idx] += size;
662    }
663    else {
664        /* Since bufp can be a displacement and can be negative, we cannot use
665         * MPI_VOID_PTR_CAST_TO_MPI_AINT to cast the sum to a pointer.  Just let it
666         * sign extend.
667         */
668        paramp->disps[last_idx+1]   = MPI_PTR_DISP_CAST_TO_MPI_AINT bufp + rel_off;
669        paramp->blklens[last_idx+1] = size;
670        paramp->index++;
671    }
672    return 0;
673}
674
675/* DLOOP_Segment_vector_mpi_flatten
676 *
677 * Input Parameters:
678 * blocks_p - [inout] pointer to a count of blocks (total, for all noncontiguous pieces)
679 * count    - # of noncontiguous regions
680 * blksz    - size of each noncontiguous region
681 * stride   - distance in bytes from start of one region to start of next
682 * el_type - elemental type (e.g. MPI_INT)
683 * ...
684 *
685 * Note: this is only called when the starting position is at the beginning
686 * of a whole block in a vector type.
687 *
688 * TODO: MAKE THIS CODE SMARTER, USING THE SAME GENERAL APPROACH AS IN THE
689 *       COUNT BLOCK CODE ABOVE.
690 */
691static int DLOOP_Segment_vector_mpi_flatten(DLOOP_Offset *blocks_p,
692                                            DLOOP_Count count,
693                                            DLOOP_Count blksz,
694                                            DLOOP_Offset stride,
695                                            DLOOP_Type el_type,
696                                            DLOOP_Offset rel_off, /* offset into buffer */
697                                            void *bufp, /* start of buffer */
698                                            void *v_paramp)
699{
700    int i, size, blocks_left;
701    DLOOP_Offset el_size;
702    struct PREPEND_PREFIX(mpi_flatten_params) *paramp = v_paramp;
703
704    DLOOP_Handle_get_size_macro(el_type, el_size);
705    blocks_left = (int)*blocks_p;
706
707    for (i=0; i < count && blocks_left > 0; i++) {
708        int last_idx;
709        char *last_end = NULL;
710
711        if (blocks_left > blksz) {
712            size = blksz * (int) el_size;
713            blocks_left -= blksz;
714        }
715        else {
716            /* last pass */
717            size = blocks_left * (int) el_size;
718            blocks_left = 0;
719        }
720
721        last_idx = paramp->index - 1;
722        if (last_idx >= 0) {
723            /* Since disps can be negative, we cannot use
724             * MPID_Ensure_Aint_fits_in_pointer to verify that disps +
725             * blklens fits in a pointer.  Nor can we use
726             * MPI_AINT_CAST_TO_VOID_PTR to cast the sum to a pointer.
727             * Just let it truncate, if the sizeof a pointer is less
728             * than the sizeof an MPI_Aint.
729             */
730            last_end = (char *) MPI_AINT_CAST_TO_VOID_PTR
731                       (paramp->disps[last_idx] +
732                         (MPI_Aint)(paramp->blklens[last_idx]));
733        }
734
735        /* Since bufp can be a displacement and can be negative, we cannot use
736         * MPID_Ensure_Aint_fits_in_pointer to ensure the sum fits in a pointer.
737         * Just let it truncate.
738         */
739        if ((last_idx == paramp->length-1) &&
740            (last_end != ((char *) bufp + rel_off)))
741        {
742            /* we have used up all our entries, and this one doesn't fit on
743             * the end of the last one.
744             */
745            *blocks_p -= (blocks_left + (size / (int) el_size));
746#ifdef MPID_SP_VERBOSE
747            MPIU_dbg_printf("\t[vector to vec exiting (1): next ind = %d, " MPI_AINT_FMT_DEC_SPEC " blocks processed.\n",
748                            paramp->u.pack_vector.index,
749                            *blocks_p);
750#endif
751            return 1;
752        }
753        else if (last_idx >= 0 && (last_end == ((char *) bufp + rel_off)))
754        {
755            /* add this size to the last vector rather than using up new one */
756            paramp->blklens[last_idx] += size;
757        }
758        else {
759            /* Since bufp can be a displacement and can be negative, we cannot use
760             * MPI_VOID_PTR_CAST_TO_MPI_AINT to cast the sum to a pointer.  Just let it
761             * sign extend.
762             */
763            paramp->disps[last_idx+1]   = MPI_PTR_DISP_CAST_TO_MPI_AINT bufp + rel_off;
764            paramp->blklens[last_idx+1] = size;
765            paramp->index++;
766        }
767
768        rel_off += stride;
769    }
770
771#ifdef MPID_SP_VERBOSE
772    MPIU_dbg_printf("\t[vector to vec exiting (2): next ind = %d, " MPI_AINT_FMT_DEC_SPEC " blocks processed.\n",
773                    paramp->u.pack_vector.index,
774                    *blocks_p);
775#endif
776
777    /* if we get here then we processed ALL the blocks; don't need to update
778     * blocks_p
779     */
780
781    DLOOP_Assert(blocks_left == 0);
782    return 0;
783}
784
785static int DLOOP_Segment_blkidx_mpi_flatten(DLOOP_Offset *blocks_p,
786                                            DLOOP_Count count,
787                                            DLOOP_Count blksz,
788                                            DLOOP_Offset *offsetarray,
789                                            DLOOP_Type el_type,
790                                            DLOOP_Offset rel_off,
791                                            void *bufp,
792                                            void *v_paramp)
793{
794    int i, size, blocks_left;
795    DLOOP_Offset el_size;
796    struct PREPEND_PREFIX(mpi_flatten_params) *paramp = v_paramp;
797
798    DLOOP_Handle_get_size_macro(el_type, el_size);
799    blocks_left = *blocks_p;
800
801    for (i=0; i < count && blocks_left > 0; i++) {
802        int last_idx;
803        char *last_end = NULL;
804
805        if (blocks_left > blksz) {
806            size = blksz * (int) el_size;
807            blocks_left -= blksz;
808        }
809        else {
810            /* last pass */
811            size = blocks_left * (int) el_size;
812            blocks_left = 0;
813        }
814
815        last_idx = paramp->index - 1;
816        if (last_idx >= 0) {
817            /* Since disps can be negative, we cannot use
818             * MPID_Ensure_Aint_fits_in_pointer to verify that disps +
819             * blklens fits in a pointer.  Nor can we use
820             * MPI_AINT_CAST_TO_VOID_PTR to cast the sum to a pointer.
821             * Just let it truncate, if the sizeof a pointer is less
822             * than the sizeof an MPI_Aint.
823             */
824            last_end = (char*) MPI_AINT_CAST_TO_VOID_PTR
825                       (paramp->disps[last_idx] + ((DLOOP_Offset) paramp->blklens[last_idx]));
826        }
827
828        /* Since bufp can be a displacement and can be negative, we
829         * cannot use MPID_Ensure_Aint_fits_in_pointer to ensure the
830         * sum fits in a pointer.  Just let it truncate.
831         */
832        if ((last_idx == paramp->length-1) &&
833            (last_end != ((char *) bufp + rel_off)))
834        {
835            /* we have used up all our entries, and this one doesn't fit on
836             * the end of the last one.
837             */
838            *blocks_p -= ((DLOOP_Offset) blocks_left + (((DLOOP_Offset) size) / el_size));
839#ifdef MPID_SP_VERBOSE
840            MPIU_dbg_printf("\t[vector to vec exiting (1): next ind = %d, %d blocks processed.\n",
841                            paramp->u.pack_vector.index,
842                            (int) *blocks_p);
843#endif
844            return 1;
845        }
846        else if (last_idx >= 0 && (last_end == ((char *) bufp + rel_off)))
847        {
848            /* add this size to the last vector rather than using up new one */
849            paramp->blklens[last_idx] += size;
850        }
851        else {
852            /* Since bufp can be a displacement and can be negative, we cannot use
853             * MPI_VOID_PTR_CAST_TO_MPI_AINT to cast the sum to a pointer.  Just let it
854             * sign extend.
855             */
856            paramp->disps[last_idx+1]   = MPI_PTR_DISP_CAST_TO_MPI_AINT bufp + rel_off + offsetarray[last_idx+1];
857            paramp->blklens[last_idx+1] = size;
858            paramp->index++;
859        }
860
861        rel_off += offsetarray[i];
862    }
863
864#ifdef MPID_SP_VERBOSE
865    MPIU_dbg_printf("\t[vector to vec exiting (2): next ind = %d, " MPI_AINT_FMT_DEC_SPEC " blocks processed.\n",
866                    paramp->u.pack_vector.index,
867                    *blocks_p);
868#endif
869
870    /* if we get here then we processed ALL the blocks; don't need to update
871     * blocks_p
872     */
873
874    DLOOP_Assert(blocks_left == 0);
875    return 0;
876}
877
878static int DLOOP_Segment_index_mpi_flatten(DLOOP_Offset *blocks_p,
879                                           DLOOP_Count count,
880                                           DLOOP_Count *blockarray,
881                                           DLOOP_Offset *offsetarray,
882                                           DLOOP_Type el_type,
883                                           DLOOP_Offset rel_off,
884                                           void *bufp,
885                                           void *v_paramp)
886{
887    int i, size, blocks_left;
888    DLOOP_Offset el_size;
889    struct PREPEND_PREFIX(mpi_flatten_params) *paramp = v_paramp;
890
891    DLOOP_Handle_get_size_macro(el_type, el_size);
892    blocks_left = *blocks_p;
893
894    for (i=0; i < count && blocks_left > 0; i++) {
895        int last_idx;
896        char *last_end = NULL;
897
898        if (blocks_left > blockarray[i]) {
899            size = blockarray[i] * (int) el_size;
900            blocks_left -= blockarray[i];
901        }
902        else {
903            /* last pass */
904            size = blocks_left * (int) el_size;
905            blocks_left = 0;
906        }
907
908        last_idx = paramp->index - 1;
909        if (last_idx >= 0) {
910            /* Since disps can be negative, we cannot use
911             * MPID_Ensure_Aint_fits_in_pointer to verify that disps +
912             * blklens fits in a pointer.  Nor can we use
913             * MPI_AINT_CAST_TO_VOID_PTR to cast the sum to a pointer.
914             * Just let it truncate, if the sizeof a pointer is less
915             * than the sizeof an MPI_Aint.
916             */
917            last_end = (char *) MPI_AINT_CAST_TO_VOID_PTR
918                       (paramp->disps[last_idx] +
919                        (MPI_Aint)(paramp->blklens[last_idx]));
920        }
921
922        /* Since bufp can be a displacement and can be negative, we
923         * cannot use MPID_Ensure_Aint_fits_in_pointer to ensure the
924         * sum fits in a pointer.  Just let it truncate.
925         */
926        if ((last_idx == paramp->length-1) &&
927            (last_end != ((char *) bufp + rel_off)))
928        {
929            /* we have used up all our entries, and this one doesn't fit on
930             * the end of the last one.
931             */
932            *blocks_p -= (blocks_left + (size / (int) el_size));
933#ifdef MPID_SP_VERBOSE
934            MPIU_dbg_printf("\t[vector to vec exiting (1): next ind = %d, " MPI_AINT_FMT_DEC_SPEC " blocks processed.\n",
935                            paramp->u.pack_vector.index,
936                            *blocks_p);
937#endif
938            return 1;
939        }
940        else if (last_idx >= 0 && (last_end == ((char *) bufp + rel_off)))
941        {
942            /* add this size to the last vector rather than using up new one */
943            paramp->blklens[last_idx] += size;
944        }
945        else {
946            /* Since bufp can be a displacement and can be negative, we cannot use
947             * MPI_VOID_PTR_CAST_TO_MPI_AINT to cast the sum to a pointer.  Just let it
948             * sign extend.
949             */
950            paramp->disps[last_idx+1]   = MPI_PTR_DISP_CAST_TO_MPI_AINT bufp + rel_off + offsetarray[last_idx+1];
951            paramp->blklens[last_idx+1] = size;
952            paramp->index++;
953        }
954
955        rel_off += offsetarray[i];
956    }
957
958#ifdef MPID_SP_VERBOSE
959    MPIU_dbg_printf("\t[vector to vec exiting (2): next ind = %d, " MPI_AINT_FMT_DEC_SPEC " blocks processed.\n",
960                    paramp->u.pack_vector.index,
961                    *blocks_p);
962#endif
963
964    /* if we get here then we processed ALL the blocks; don't need to update
965     * blocks_p
966     */
967
968    DLOOP_Assert(blocks_left == 0);
969    return 0;
970}
971
972/* MPID_Segment_mpi_flatten - flatten a type into a representation
973 *                            appropriate for passing to hindexed create.
974 *
975 * Parameters:
976 * segp    - pointer to segment structure
977 * first   - first byte in segment to pack
978 * lastp   - in/out parameter describing last byte to pack (and afterwards
979 *           the last byte _actually_ packed)
980 *           NOTE: actually returns index of byte _after_ last one packed
981 * blklens, disps - the usual blocklength and displacement arrays for MPI
982 * lengthp - in/out parameter describing length of array (and afterwards
983 *           the amount of the array that has actual data)
984 */
985void PREPEND_PREFIX(Segment_mpi_flatten)(DLOOP_Segment *segp,
986                                         DLOOP_Offset first,
987                                         DLOOP_Offset *lastp,
988                                         int *blklens,
989                                         MPI_Aint *disps,
990                                         int *lengthp)
991{
992    struct PREPEND_PREFIX(mpi_flatten_params) params;
993
994    DLOOP_Assert(*lengthp > 0);
995
996    params.index   = 0;
997    params.length  = *lengthp;
998    params.blklens = blklens;
999    params.disps   = disps;
1000
1001    PREPEND_PREFIX(Segment_manipulate)(segp,
1002                                       first,
1003                                       lastp,
1004                                       DLOOP_Segment_contig_mpi_flatten,
1005                                       DLOOP_Segment_vector_mpi_flatten,
1006                                       DLOOP_Segment_blkidx_mpi_flatten,
1007                                       DLOOP_Segment_index_mpi_flatten,
1008                                       NULL,
1009                                       &params);
1010
1011    /* last value already handled by MPID_Segment_manipulate */
1012    *lengthp = params.index;
1013    return;
1014}
1015
1016/*
1017 * Local variables:
1018 * c-indent-tabs-mode: nil
1019 * End:
1020 */
Note: See TracBrowser for help on using the browser.