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 
16 /* NOTE: bufp values are unused, ripe for removal */
17 
18 int PREPEND_PREFIX(Segment_contig_m2m)(DLOOP_Offset *blocks_p,
19 				       DLOOP_Type el_type,
20 				       DLOOP_Offset rel_off,
21 				       void *bufp,
22 				       void *v_paramp);
23 int PREPEND_PREFIX(Segment_vector_m2m)(DLOOP_Offset *blocks_p,
24 				       DLOOP_Count count,
25 				       DLOOP_Count blksz,
26 				       DLOOP_Offset stride,
27 				       DLOOP_Type el_type,
28 				       DLOOP_Offset rel_off,
29 				       void *bufp,
30 				       void *v_paramp);
31 int PREPEND_PREFIX(Segment_blkidx_m2m)(DLOOP_Offset *blocks_p,
32 				       DLOOP_Count count,
33 				       DLOOP_Count blocklen,
34 				       DLOOP_Offset *offsetarray,
35 				       DLOOP_Type el_type,
36 				       DLOOP_Offset rel_off,
37 				       void *bufp,
38 				       void *v_paramp);
39 int PREPEND_PREFIX(Segment_index_m2m)(DLOOP_Offset *blocks_p,
40 				      DLOOP_Count count,
41 				      DLOOP_Count *blockarray,
42 				      DLOOP_Offset *offsetarray,
43 				      DLOOP_Type el_type,
44 				      DLOOP_Offset rel_off,
45 				      void *bufp,
46 				      void *v_paramp);
47 
PREPEND_PREFIX(Segment_pack)48 void PREPEND_PREFIX(Segment_pack)(DLOOP_Segment *segp,
49 				  DLOOP_Offset   first,
50 				  DLOOP_Offset  *lastp,
51 				  void *streambuf)
52 {
53     struct PREPEND_PREFIX(m2m_params) params; /* defined in dataloop_parts.h */
54 
55     /* experimenting with discarding buf value in the segment, keeping in
56      * per-use structure instead. would require moving the parameters around a
57      * bit.
58      */
59     params.userbuf   = segp->ptr;
60     params.streambuf = streambuf;
61     params.direction = DLOOP_M2M_FROM_USERBUF;
62 
63     PREPEND_PREFIX(Segment_manipulate)(segp, first, lastp,
64 				       PREPEND_PREFIX(Segment_contig_m2m),
65 				       PREPEND_PREFIX(Segment_vector_m2m),
66 				       PREPEND_PREFIX(Segment_blkidx_m2m),
67 				       PREPEND_PREFIX(Segment_index_m2m),
68 				       NULL, /* size fn */
69 				       &params);
70     return;
71 }
72 
PREPEND_PREFIX(Segment_unpack)73 void PREPEND_PREFIX(Segment_unpack)(DLOOP_Segment *segp,
74 				    DLOOP_Offset   first,
75 				    DLOOP_Offset  *lastp,
76 				    void *streambuf)
77 {
78     struct PREPEND_PREFIX(m2m_params) params;
79 
80     /* experimenting with discarding buf value in the segment, keeping in
81      * per-use structure instead. would require moving the parameters around a
82      * bit.
83      */
84     params.userbuf   = segp->ptr;
85     params.streambuf = streambuf;
86     params.direction = DLOOP_M2M_TO_USERBUF;
87 
88     PREPEND_PREFIX(Segment_manipulate)(segp, first, lastp,
89 				       PREPEND_PREFIX(Segment_contig_m2m),
90 				       PREPEND_PREFIX(Segment_vector_m2m),
91 				       PREPEND_PREFIX(Segment_blkidx_m2m),
92 				       PREPEND_PREFIX(Segment_index_m2m),
93 				       NULL, /* size fn */
94 				       &params);
95     return;
96 }
97 
98 /* PIECE FUNCTIONS BELOW */
99 
PREPEND_PREFIX(Segment_contig_m2m)100 int PREPEND_PREFIX(Segment_contig_m2m)(DLOOP_Offset *blocks_p,
101 				       DLOOP_Type el_type,
102 				       DLOOP_Offset rel_off,
103 				       void *bufp ATTRIBUTE((unused)),
104 				       void *v_paramp)
105 {
106     DLOOP_Offset el_size; /* DLOOP_Count? */
107     DLOOP_Offset size;
108     struct PREPEND_PREFIX(m2m_params) *paramp = v_paramp;
109 
110     DLOOP_Handle_get_size_macro(el_type, el_size);
111     size = *blocks_p * el_size;
112 
113 #ifdef MPID_SU_VERBOSE
114     dbg_printf("\t[contig unpack: do=" DLOOP_OFFSET_FMT_DEC_SPEC ", dp=%x, bp=%x, sz=" DLOOP_OFFSET_FMT_DEC_SPEC ", blksz=" DLOOP_OFFSET_FMT_DEC_SPEC "]\n",
115 	       rel_off,
116 	       (unsigned) bufp,
117 	       (unsigned) paramp->u.unpack.unpack_buffer,
118 	       el_size,
119 	       *blocks_p);
120 #endif
121 
122     if (paramp->direction == DLOOP_M2M_TO_USERBUF) {
123 	/* Ensure that pointer increment fits in a pointer */
124 	/* userbuf is a pointer (not a displacement) since it is being
125 	 * used on a memcpy */
126 	DLOOP_Ensure_Offset_fits_in_pointer((DLOOP_VOID_PTR_CAST_TO_OFFSET (paramp->userbuf)) + rel_off);
127 	DLOOP_Memcpy((char *) paramp->userbuf + rel_off, paramp->streambuf, size);
128     }
129     else {
130 	/* Ensure that pointer increment fits in a pointer */
131 	/* userbuf is a pointer (not a displacement) since it is being used on a memcpy */
132 	DLOOP_Ensure_Offset_fits_in_pointer((DLOOP_VOID_PTR_CAST_TO_OFFSET (paramp->userbuf)) + rel_off);
133 	DLOOP_Memcpy(paramp->streambuf, (char *) paramp->userbuf + rel_off, size);
134     }
135     /* Ensure that pointer increment fits in a pointer */
136     /* streambuf is a pointer (not a displacement) since it was used on a memcpy */
137     DLOOP_Ensure_Offset_fits_in_pointer((DLOOP_VOID_PTR_CAST_TO_OFFSET (paramp->streambuf)) + size);
138     paramp->streambuf += size;
139     return 0;
140 }
141 
142 /* Segment_vector_m2m
143  *
144  * Note: this combines both packing and unpacking functionality.
145  *
146  * Note: this is only called when the starting position is at the beginning
147  * of a whole block in a vector type.
148  */
PREPEND_PREFIX(Segment_vector_m2m)149 int PREPEND_PREFIX(Segment_vector_m2m)(DLOOP_Offset *blocks_p,
150 				       DLOOP_Count count ATTRIBUTE((unused)),
151 				       DLOOP_Count blksz,
152 				       DLOOP_Offset stride,
153 				       DLOOP_Type el_type,
154 				       DLOOP_Offset rel_off, /* offset into buffer */
155 				       void *bufp ATTRIBUTE((unused)),
156 				       void *v_paramp)
157 {
158     DLOOP_Count i, blocks_left, whole_count;
159     DLOOP_Offset el_size;
160     struct PREPEND_PREFIX(m2m_params) *paramp = v_paramp;
161     char *cbufp;
162 
163     /* Ensure that pointer increment fits in a pointer */
164     /* userbuf is a pointer (not a displacement) since it is being used for a memory copy */
165     DLOOP_Ensure_Offset_fits_in_pointer((DLOOP_VOID_PTR_CAST_TO_OFFSET (paramp->userbuf)) + rel_off);
166     cbufp = (char*) paramp->userbuf + rel_off;
167     DLOOP_Handle_get_size_macro(el_type, el_size);
168 
169     whole_count = (blksz > 0) ? (*blocks_p / (DLOOP_Offset) blksz) : 0;
170     blocks_left = (blksz > 0) ? (*blocks_p % (DLOOP_Offset) blksz) : 0;
171 
172     if (paramp->direction == DLOOP_M2M_TO_USERBUF) {
173 	if (el_size == 8
174 	    MPIR_ALIGN8_TEST(paramp->streambuf,cbufp))
175 	{
176 	    MPIDI_COPY_TO_VEC(paramp->streambuf, cbufp, stride,
177 			      int64_t, blksz, whole_count);
178 	    MPIDI_COPY_TO_VEC(paramp->streambuf, cbufp, 0,
179 			      int64_t, blocks_left, 1);
180 	}
181 	else if (el_size == 4
182 		 MPIR_ALIGN4_TEST(paramp->streambuf,cbufp))
183 	{
184 	    MPIDI_COPY_TO_VEC((paramp->streambuf), cbufp, stride,
185 			      int32_t, blksz, whole_count);
186 	    MPIDI_COPY_TO_VEC(paramp->streambuf, cbufp, 0,
187 			      int32_t, blocks_left, 1);
188 	}
189 	else if (el_size == 2) {
190 	    MPIDI_COPY_TO_VEC(paramp->streambuf, cbufp, stride,
191 			      int16_t, blksz, whole_count);
192 	    MPIDI_COPY_TO_VEC(paramp->streambuf, cbufp, 0,
193 			      int16_t, blocks_left, 1);
194 	}
195 	else {
196 	    for (i=0; i < whole_count; i++) {
197 		DLOOP_Memcpy(cbufp, paramp->streambuf, ((DLOOP_Offset) blksz) * el_size);
198 		/* Ensure that pointer increment fits in a pointer */
199 		/* streambuf is a pointer (not a displacement) since it is being used for a memory copy */
200 		DLOOP_Ensure_Offset_fits_in_pointer((DLOOP_VOID_PTR_CAST_TO_OFFSET (paramp->streambuf)) +
201 						 ((DLOOP_Offset) blksz) * el_size);
202 		paramp->streambuf += ((DLOOP_Offset) blksz) * el_size;
203 
204 		DLOOP_Ensure_Offset_fits_in_pointer((DLOOP_VOID_PTR_CAST_TO_OFFSET (cbufp)) + stride);
205 		cbufp += stride;
206 	    }
207 	    if (blocks_left) {
208 		DLOOP_Memcpy(cbufp, paramp->streambuf, ((DLOOP_Offset) blocks_left) * el_size);
209 		/* Ensure that pointer increment fits in a pointer */
210 		/* streambuf is a pointer (not a displacement) since
211 		 * it is being used for a memory copy */
212 		DLOOP_Ensure_Offset_fits_in_pointer((DLOOP_VOID_PTR_CAST_TO_OFFSET (paramp->streambuf)) +
213 						 ((DLOOP_Offset) blocks_left) * el_size);
214 		paramp->streambuf += ((DLOOP_Offset) blocks_left) * el_size;
215 	    }
216 	}
217     }
218     else /* M2M_FROM_USERBUF */ {
219 	if (el_size == 8
220 	    MPIR_ALIGN8_TEST(cbufp,paramp->streambuf))
221 	{
222 	    MPIDI_COPY_FROM_VEC(cbufp, paramp->streambuf, stride,
223 				int64_t, blksz, whole_count);
224 	    MPIDI_COPY_FROM_VEC(cbufp, paramp->streambuf, 0,
225 				int64_t, blocks_left, 1);
226 	}
227 	else if (el_size == 4
228 		 MPIR_ALIGN4_TEST(cbufp,paramp->streambuf))
229 	{
230 	    MPIDI_COPY_FROM_VEC(cbufp, paramp->streambuf, stride,
231 				int32_t, blksz, whole_count);
232 	    MPIDI_COPY_FROM_VEC(cbufp, paramp->streambuf, 0,
233 				int32_t, blocks_left, 1);
234 	}
235 	else if (el_size == 2) {
236 	    MPIDI_COPY_FROM_VEC(cbufp, paramp->streambuf, stride,
237 				int16_t, blksz, whole_count);
238 	    MPIDI_COPY_FROM_VEC(cbufp, paramp->streambuf, 0,
239 				int16_t, blocks_left, 1);
240 	}
241 	else {
242 	    for (i=0; i < whole_count; i++) {
243 		DLOOP_Memcpy(paramp->streambuf, cbufp, (DLOOP_Offset) blksz * el_size);
244 		/* Ensure that pointer increment fits in a pointer */
245 		/* streambuf is a pointer (not a displacement) since
246 		 * it is being used for a memory copy */
247 		DLOOP_Ensure_Offset_fits_in_pointer((DLOOP_VOID_PTR_CAST_TO_OFFSET (paramp->streambuf)) +
248 						 (DLOOP_Offset) blksz * el_size);
249 		paramp->streambuf += (DLOOP_Offset) blksz * el_size;
250 		cbufp += stride;
251 	    }
252 	    if (blocks_left) {
253 		DLOOP_Memcpy(paramp->streambuf, cbufp, (DLOOP_Offset) blocks_left * el_size);
254 		/* Ensure that pointer increment fits in a pointer */
255 		/* streambuf is a pointer (not a displacement) since
256 		 * it is being used for a memory copy */
257 		DLOOP_Ensure_Offset_fits_in_pointer((DLOOP_VOID_PTR_CAST_TO_OFFSET (paramp->streambuf)) +
258 						 (DLOOP_Offset) blocks_left * el_size);
259 		paramp->streambuf += (DLOOP_Offset) blocks_left * el_size;
260 	    }
261 	}
262     }
263 
264     return 0;
265 }
266 
267 /* MPID_Segment_blkidx_m2m
268  */
PREPEND_PREFIX(Segment_blkidx_m2m)269 int PREPEND_PREFIX(Segment_blkidx_m2m)(DLOOP_Offset *blocks_p,
270 				       DLOOP_Count count,
271 				       DLOOP_Count blocklen,
272 				       DLOOP_Offset *offsetarray,
273 				       DLOOP_Type el_type,
274 				       DLOOP_Offset rel_off,
275 				       void *bufp ATTRIBUTE((unused)),
276 				       void *v_paramp)
277 {
278     DLOOP_Count curblock = 0;
279     DLOOP_Offset el_size;
280     DLOOP_Offset blocks_left = *blocks_p;
281     char *cbufp;
282     struct PREPEND_PREFIX(m2m_params) *paramp = v_paramp;
283 
284     DLOOP_Handle_get_size_macro(el_type, el_size);
285 
286     while (blocks_left) {
287 	char *src, *dest;
288 
289 	DLOOP_Assert(curblock < count);
290 
291 	/* Ensure that pointer increment fits in a pointer */
292 	/* userbuf is a pointer (not a displacement) since it is being
293 	 * used for a memory copy */
294 	DLOOP_Ensure_Offset_fits_in_pointer((DLOOP_VOID_PTR_CAST_TO_OFFSET (paramp->userbuf)) +
295 					 rel_off + offsetarray[curblock]);
296 	cbufp = (char*) paramp->userbuf + rel_off + offsetarray[curblock];
297 
298 	if (blocklen > blocks_left) blocklen = blocks_left;
299 
300 	if (paramp->direction == DLOOP_M2M_TO_USERBUF) {
301 	    src  = paramp->streambuf;
302 	    dest = cbufp;
303 	}
304 	else {
305 	    src  = cbufp;
306 	    dest = paramp->streambuf;
307 	}
308 
309 	/* note: macro modifies dest buffer ptr, so we must reset */
310 	if (el_size == 8
311 	    MPIR_ALIGN8_TEST(src, dest))
312 	{
313 	    MPIDI_COPY_FROM_VEC(src, dest, 0, int64_t, blocklen, 1);
314 	}
315 	else if (el_size == 4
316 		 MPIR_ALIGN4_TEST(src,dest))
317 	{
318 	    MPIDI_COPY_FROM_VEC(src, dest, 0, int32_t, blocklen, 1);
319 	}
320 	else if (el_size == 2) {
321 	    MPIDI_COPY_FROM_VEC(src, dest, 0, int16_t, blocklen, 1);
322 	}
323 	else {
324 	    DLOOP_Memcpy(dest, src, (DLOOP_Offset) blocklen * el_size);
325 	}
326 
327 	/* Ensure that pointer increment fits in a pointer */
328 	/* streambuf is a pointer (not a displacement) since it is
329 	 * being used for a memory copy */
330 	DLOOP_Ensure_Offset_fits_in_pointer((DLOOP_VOID_PTR_CAST_TO_OFFSET (paramp->streambuf)) +
331 					 (DLOOP_Offset) blocklen * el_size);
332 	paramp->streambuf += (DLOOP_Offset) blocklen * el_size;
333 	blocks_left -= blocklen;
334 	curblock++;
335     }
336 
337     return 0;
338 }
339 
340 /* MPID_Segment_index_m2m
341  */
PREPEND_PREFIX(Segment_index_m2m)342 int PREPEND_PREFIX(Segment_index_m2m)(DLOOP_Offset *blocks_p,
343 				      DLOOP_Count count,
344 				      DLOOP_Count *blockarray,
345 				      DLOOP_Offset *offsetarray,
346 				      DLOOP_Type el_type,
347 				      DLOOP_Offset rel_off,
348 				      void *bufp ATTRIBUTE((unused)),
349 				      void *v_paramp)
350 {
351     int curblock = 0;
352     DLOOP_Offset el_size;
353     DLOOP_Offset cur_block_sz, blocks_left = *blocks_p;
354     char *cbufp;
355     struct PREPEND_PREFIX(m2m_params) *paramp = v_paramp;
356 
357     DLOOP_Handle_get_size_macro(el_type, el_size);
358 
359     while (blocks_left) {
360 	char *src, *dest;
361 
362 	DLOOP_Assert(curblock < count);
363 	cur_block_sz = blockarray[curblock];
364 
365 	/* Ensure that pointer increment fits in a pointer */
366 	/* userbuf is a pointer (not a displacement) since it is being
367 	 * used for a memory copy */
368 	DLOOP_Ensure_Offset_fits_in_pointer((DLOOP_VOID_PTR_CAST_TO_OFFSET (paramp->userbuf)) +
369 					 rel_off + offsetarray[curblock]);
370 	cbufp = (char*) paramp->userbuf + rel_off + offsetarray[curblock];
371 
372 	if (cur_block_sz > blocks_left) cur_block_sz = blocks_left;
373 
374 	if (paramp->direction == DLOOP_M2M_TO_USERBUF) {
375 	    src  = paramp->streambuf;
376 	    dest = cbufp;
377 	}
378 	else {
379 	    src  = cbufp;
380 	    dest = paramp->streambuf;
381 	}
382 
383 	/* note: macro modifies dest buffer ptr, so we must reset */
384 	if (el_size == 8
385 	    MPIR_ALIGN8_TEST(src, dest))
386 	{
387 	    MPIDI_COPY_FROM_VEC(src, dest, 0, int64_t, cur_block_sz, 1);
388 	}
389 	else if (el_size == 4
390 		 MPIR_ALIGN4_TEST(src,dest))
391 	{
392 	    MPIDI_COPY_FROM_VEC(src, dest, 0, int32_t, cur_block_sz, 1);
393 	}
394 	else if (el_size == 2) {
395 	    MPIDI_COPY_FROM_VEC(src, dest, 0, int16_t, cur_block_sz, 1);
396 	}
397 	else {
398 	    DLOOP_Memcpy(dest, src, cur_block_sz * el_size);
399 	}
400 
401 	/* Ensure that pointer increment fits in a pointer */
402 	/* streambuf is a pointer (not a displacement) since it is
403 	 * being used for a memory copy */
404 	DLOOP_Ensure_Offset_fits_in_pointer((DLOOP_VOID_PTR_CAST_TO_OFFSET (paramp->streambuf)) +
405 					 cur_block_sz * el_size);
406 	paramp->streambuf += cur_block_sz * el_size;
407 	blocks_left -= cur_block_sz;
408 	curblock++;
409     }
410 
411     return 0;
412 }
413 
414 /*
415  * Local variables:
416  * c-indent-tabs-mode: nil
417  * End:
418  */
419