]> git.ipfire.org Git - thirdparty/gcc.git/blame - libgfortran/intrinsics/spread_generic.c
re PR libfortran/32972 (performance of pack/unpack)
[thirdparty/gcc.git] / libgfortran / intrinsics / spread_generic.c
CommitLineData
7f68c75f 1/* Generic implementation of the SPREAD intrinsic
36ae8a61 2 Copyright 2002, 2005, 2006, 2007 Free Software Foundation, Inc.
6de9cd9a
DN
3 Contributed by Paul Brook <paul@nowt.org>
4
57dea9f6 5This file is part of the GNU Fortran 95 runtime library (libgfortran).
6de9cd9a 6
57dea9f6
TM
7Libgfortran is free software; you can redistribute it and/or
8modify it under the terms of the GNU General Public
6de9cd9a 9License as published by the Free Software Foundation; either
57dea9f6 10version 2 of the License, or (at your option) any later version.
6de9cd9a 11
57dea9f6
TM
12In addition to the permissions in the GNU General Public License, the
13Free Software Foundation gives you unlimited permission to link the
14compiled version of this file into combinations with other programs,
15and to distribute those combinations without any restriction coming
16from the use of this file. (The General Public License restrictions
17do apply in other respects; for example, they cover modification of
18the file, and distribution when not linked into a combine
19executable.)
20
21Ligbfortran is distributed in the hope that it will be useful,
6de9cd9a
DN
22but WITHOUT ANY WARRANTY; without even the implied warranty of
23MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
57dea9f6 24GNU General Public License for more details.
6de9cd9a 25
57dea9f6
TM
26You should have received a copy of the GNU General Public
27License along with libgfortran; see the file COPYING. If not,
fe2ae685
KC
28write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
29Boston, MA 02110-1301, USA. */
6de9cd9a 30
36ae8a61 31#include "libgfortran.h"
6de9cd9a
DN
32#include <stdlib.h>
33#include <assert.h>
34#include <string.h>
6de9cd9a 35
7823229b
RS
36static void
37spread_internal (gfc_array_char *ret, const gfc_array_char *source,
38 const index_type *along, const index_type *pncopies,
39 index_type size)
6de9cd9a
DN
40{
41 /* r.* indicates the return array. */
e33e218b 42 index_type rstride[GFC_MAX_DIMENSIONS];
6de9cd9a 43 index_type rstride0;
7672ae20 44 index_type rdelta = 0;
8e6d7b8a
TK
45 index_type rrank;
46 index_type rs;
6de9cd9a
DN
47 char *rptr;
48 char *dest;
49 /* s.* indicates the source array. */
e33e218b 50 index_type sstride[GFC_MAX_DIMENSIONS];
6de9cd9a 51 index_type sstride0;
8e6d7b8a 52 index_type srank;
6de9cd9a
DN
53 const char *sptr;
54
e33e218b
TK
55 index_type count[GFC_MAX_DIMENSIONS];
56 index_type extent[GFC_MAX_DIMENSIONS];
6de9cd9a
DN
57 index_type n;
58 index_type dim;
6de9cd9a
DN
59 index_type ncopies;
60
8e6d7b8a
TK
61 srank = GFC_DESCRIPTOR_RANK(source);
62
63 rrank = srank + 1;
64 if (rrank > GFC_MAX_DIMENSIONS)
65 runtime_error ("return rank too large in spread()");
66
67 if (*along > rrank)
68 runtime_error ("dim outside of rank in spread()");
69
70 ncopies = *pncopies;
71
8e6d7b8a 72 if (ret->data == NULL)
6de9cd9a 73 {
8e6d7b8a
TK
74 /* The front end has signalled that we need to populate the
75 return array descriptor. */
76 ret->dtype = (source->dtype & ~GFC_DTYPE_RANK_MASK) | rrank;
77 dim = 0;
78 rs = 1;
79 for (n = 0; n < rrank; n++)
80 {
81 ret->dim[n].stride = rs;
82 ret->dim[n].lbound = 0;
83 if (n == *along - 1)
84 {
85 ret->dim[n].ubound = ncopies - 1;
86 rdelta = rs * size;
87 rs *= ncopies;
88 }
89 else
90 {
91 count[dim] = 0;
92 extent[dim] = source->dim[dim].ubound + 1
93 - source->dim[dim].lbound;
94 sstride[dim] = source->dim[dim].stride * size;
95 rstride[dim] = rs * size;
96
97 ret->dim[n].ubound = extent[dim]-1;
98 rs *= extent[dim];
99 dim++;
100 }
101 }
efd4dc1a 102 ret->offset = 0;
3d894fc3
FXC
103 if (rs > 0)
104 ret->data = internal_malloc_size (rs * size);
105 else
106 {
107 ret->data = internal_malloc_size (1);
108 return;
109 }
6de9cd9a 110 }
8e6d7b8a
TK
111 else
112 {
3cc50edc
TK
113 int zero_sized;
114
115 zero_sized = 0;
116
8e6d7b8a
TK
117 dim = 0;
118 if (GFC_DESCRIPTOR_RANK(ret) != rrank)
119 runtime_error ("rank mismatch in spread()");
6de9cd9a 120
3cc50edc 121 if (compile_options.bounds_check)
8e6d7b8a 122 {
3cc50edc 123 for (n = 0; n < rrank; n++)
8e6d7b8a 124 {
3cc50edc
TK
125 index_type ret_extent;
126
127 ret_extent = ret->dim[n].ubound + 1 - ret->dim[n].lbound;
128 if (n == *along - 1)
129 {
130 rdelta = ret->dim[n].stride * size;
131
132 if (ret_extent != ncopies)
133 runtime_error("Incorrect extent in return value of SPREAD"
1cc0507d
FXC
134 " intrinsic in dimension %ld: is %ld,"
135 " should be %ld", (long int) n+1,
136 (long int) ret_extent, (long int) ncopies);
3cc50edc
TK
137 }
138 else
139 {
140 count[dim] = 0;
141 extent[dim] = source->dim[dim].ubound + 1
142 - source->dim[dim].lbound;
143 if (ret_extent != extent[dim])
144 runtime_error("Incorrect extent in return value of SPREAD"
1cc0507d
FXC
145 " intrinsic in dimension %ld: is %ld,"
146 " should be %ld", (long int) n+1,
147 (long int) ret_extent,
3cc50edc
TK
148 (long int) extent[dim]);
149
150 if (extent[dim] <= 0)
151 zero_sized = 1;
152 sstride[dim] = source->dim[dim].stride * size;
153 rstride[dim] = ret->dim[n].stride * size;
154 dim++;
155 }
8e6d7b8a 156 }
3cc50edc
TK
157 }
158 else
159 {
160 for (n = 0; n < rrank; n++)
8e6d7b8a 161 {
3cc50edc
TK
162 if (n == *along - 1)
163 {
164 rdelta = ret->dim[n].stride * size;
165 }
166 else
167 {
168 count[dim] = 0;
169 extent[dim] = source->dim[dim].ubound + 1
170 - source->dim[dim].lbound;
171 if (extent[dim] <= 0)
172 zero_sized = 1;
173 sstride[dim] = source->dim[dim].stride * size;
174 rstride[dim] = ret->dim[n].stride * size;
175 dim++;
176 }
8e6d7b8a
TK
177 }
178 }
3cc50edc
TK
179
180 if (zero_sized)
181 return;
182
8e6d7b8a
TK
183 if (sstride[0] == 0)
184 sstride[0] = size;
185 }
6de9cd9a
DN
186 sstride0 = sstride[0];
187 rstride0 = rstride[0];
188 rptr = ret->data;
189 sptr = source->data;
6de9cd9a
DN
190
191 while (sptr)
192 {
193 /* Spread this element. */
194 dest = rptr;
195 for (n = 0; n < ncopies; n++)
196 {
197 memcpy (dest, sptr, size);
198 dest += rdelta;
199 }
200 /* Advance to the next element. */
201 sptr += sstride0;
202 rptr += rstride0;
203 count[0]++;
204 n = 0;
205 while (count[n] == extent[n])
206 {
207 /* When we get to the end of a dimension, reset it and increment
208 the next dimension. */
209 count[n] = 0;
210 /* We could precalculate these products, but this is a less
211 frequently used path so probably not worth it. */
212 sptr -= sstride[n] * extent[n];
213 rptr -= rstride[n] * extent[n];
214 n++;
8e6d7b8a 215 if (n >= srank)
6de9cd9a
DN
216 {
217 /* Break out of the loop. */
218 sptr = NULL;
219 break;
220 }
221 else
222 {
223 count[n]++;
224 sptr += sstride[n];
225 rptr += rstride[n];
226 }
227 }
228 }
229}
7823229b 230
2853e512
PT
231/* This version of spread_internal treats the special case of a scalar
232 source. This is much simpler than the more general case above. */
233
234static void
235spread_internal_scalar (gfc_array_char *ret, const char *source,
236 const index_type *along, const index_type *pncopies,
237 index_type size)
238{
239 int n;
240 int ncopies = *pncopies;
241 char * dest;
242
243 if (GFC_DESCRIPTOR_RANK (ret) != 1)
244 runtime_error ("incorrect destination rank in spread()");
245
246 if (*along > 1)
247 runtime_error ("dim outside of rank in spread()");
248
249 if (ret->data == NULL)
250 {
251 ret->data = internal_malloc_size (ncopies * size);
252 ret->offset = 0;
253 ret->dim[0].stride = 1;
254 ret->dim[0].lbound = 0;
255 ret->dim[0].ubound = ncopies - 1;
256 }
257 else
258 {
2853e512
PT
259 if (ncopies - 1 > (ret->dim[0].ubound - ret->dim[0].lbound)
260 / ret->dim[0].stride)
261 runtime_error ("dim too large in spread()");
262 }
263
264 for (n = 0; n < ncopies; n++)
265 {
266 dest = (char*)(ret->data + n*size*ret->dim[0].stride);
267 memcpy (dest , source, size);
268 }
269}
270
7823229b
RS
271extern void spread (gfc_array_char *, const gfc_array_char *,
272 const index_type *, const index_type *);
273export_proto(spread);
274
275void
276spread (gfc_array_char *ret, const gfc_array_char *source,
277 const index_type *along, const index_type *pncopies)
278{
75f2543f
TK
279 index_type type_size;
280
281 type_size = GFC_DTYPE_TYPE_SIZE(ret);
282 switch(type_size)
283 {
c7d0f4d5 284 case GFC_DTYPE_DERIVED_1:
75f2543f
TK
285 case GFC_DTYPE_LOGICAL_1:
286 case GFC_DTYPE_INTEGER_1:
287 spread_i1 ((gfc_array_i1 *) ret, (gfc_array_i1 *) source,
288 *along, *pncopies);
289 return;
290
291 case GFC_DTYPE_LOGICAL_2:
292 case GFC_DTYPE_INTEGER_2:
293 spread_i2 ((gfc_array_i2 *) ret, (gfc_array_i2 *) source,
294 *along, *pncopies);
295 return;
296
297 case GFC_DTYPE_LOGICAL_4:
298 case GFC_DTYPE_INTEGER_4:
299 spread_i4 ((gfc_array_i4 *) ret, (gfc_array_i4 *) source,
300 *along, *pncopies);
301 return;
302
303 case GFC_DTYPE_LOGICAL_8:
304 case GFC_DTYPE_INTEGER_8:
305 spread_i8 ((gfc_array_i8 *) ret, (gfc_array_i8 *) source,
306 *along, *pncopies);
307 return;
308
309#ifdef HAVE_GFC_INTEGER_16
310 case GFC_DTYPE_LOGICAL_16:
311 case GFC_DTYPE_INTEGER_16:
312 spread_i16 ((gfc_array_i16 *) ret, (gfc_array_i16 *) source,
313 *along, *pncopies);
314 return;
315#endif
316
317 case GFC_DTYPE_REAL_4:
318 spread_r4 ((gfc_array_r4 *) ret, (gfc_array_r4 *) source,
319 *along, *pncopies);
320 return;
321
322 case GFC_DTYPE_REAL_8:
323 spread_r8 ((gfc_array_r8 *) ret, (gfc_array_r8 *) source,
324 *along, *pncopies);
325 return;
326
327#ifdef GFC_HAVE_REAL_10
328 case GFC_DTYPE_REAL_10:
329 spread_r10 ((gfc_array_r10 *) ret, (gfc_array_r10 *) source,
330 *along, *pncopies);
331 return;
332#endif
333
334#ifdef GFC_HAVE_REAL_16
335 case GFC_DTYPE_REAL_16:
336 spread_r16 ((gfc_array_r16 *) ret, (gfc_array_r16 *) source,
337 *along, *pncopies);
338 return;
339#endif
340
341 case GFC_DTYPE_COMPLEX_4:
342 spread_c4 ((gfc_array_c4 *) ret, (gfc_array_c4 *) source,
343 *along, *pncopies);
344 return;
345
346 case GFC_DTYPE_COMPLEX_8:
347 spread_c8 ((gfc_array_c8 *) ret, (gfc_array_c8 *) source,
348 *along, *pncopies);
349 return;
350
351#ifdef GFC_HAVE_COMPLEX_10
352 case GFC_DTYPE_COMPLEX_10:
353 spread_c10 ((gfc_array_c10 *) ret, (gfc_array_c10 *) source,
354 *along, *pncopies);
355 return;
356#endif
357
358#ifdef GFC_HAVE_COMPLEX_16
359 case GFC_DTYPE_COMPLEX_16:
360 spread_c16 ((gfc_array_c16 *) ret, (gfc_array_c16 *) source,
361 *along, *pncopies);
362 return;
363#endif
364
c7d0f4d5
TK
365 case GFC_DTYPE_DERIVED_2:
366 if (GFC_UNALIGNED_2(ret->data) || GFC_UNALIGNED_2(source->data))
367 break;
368 else
369 {
370 spread_i1 ((gfc_array_i1 *) ret, (gfc_array_i1 *) source,
371 *along, *pncopies);
372 return;
373 }
374
375 case GFC_DTYPE_DERIVED_4:
376 if (GFC_UNALIGNED_4(ret->data) || GFC_UNALIGNED_4(source->data))
377 break;
378 else
379 {
380 spread_i4 ((gfc_array_i4 *) ret, (gfc_array_i4 *) source,
381 *along, *pncopies);
382 return;
383 }
384
385 case GFC_DTYPE_DERIVED_8:
386 if (GFC_UNALIGNED_8(ret->data) || GFC_UNALIGNED_8(source->data))
387 break;
388 else
389 {
390 spread_i8 ((gfc_array_i8 *) ret, (gfc_array_i8 *) source,
391 *along, *pncopies);
392 return;
393 }
394
395#ifdef HAVE_GFC_INTEGER_16
396 case GFC_DTYPE_DERIVED_16:
397 if (GFC_UNALIGNED_16(ret->data) || GFC_UNALIGNED_16(source->data))
398 break;
399 else
400 {
401 spread_i16 ((gfc_array_i16 *) ret, (gfc_array_i16 *) source,
402 *along, *pncopies);
403 return;
404 }
405#endif
75f2543f 406 }
c7d0f4d5 407
7823229b
RS
408 spread_internal (ret, source, along, pncopies, GFC_DESCRIPTOR_SIZE (source));
409}
410
411extern void spread_char (gfc_array_char *, GFC_INTEGER_4,
412 const gfc_array_char *, const index_type *,
413 const index_type *, GFC_INTEGER_4);
414export_proto(spread_char);
415
416void
417spread_char (gfc_array_char *ret,
418 GFC_INTEGER_4 ret_length __attribute__((unused)),
419 const gfc_array_char *source, const index_type *along,
420 const index_type *pncopies, GFC_INTEGER_4 source_length)
421{
422 spread_internal (ret, source, along, pncopies, source_length);
423}
2853e512
PT
424
425/* The following are the prototypes for the versions of spread with a
426 scalar source. */
427
428extern void spread_scalar (gfc_array_char *, const char *,
429 const index_type *, const index_type *);
430export_proto(spread_scalar);
431
432void
433spread_scalar (gfc_array_char *ret, const char *source,
434 const index_type *along, const index_type *pncopies)
435{
75f2543f
TK
436 index_type type_size;
437
2853e512
PT
438 if (!ret->dtype)
439 runtime_error ("return array missing descriptor in spread()");
75f2543f
TK
440
441 type_size = GFC_DTYPE_TYPE_SIZE(ret);
442 switch(type_size)
443 {
c7d0f4d5 444 case GFC_DTYPE_DERIVED_1:
75f2543f
TK
445 case GFC_DTYPE_LOGICAL_1:
446 case GFC_DTYPE_INTEGER_1:
447 spread_scalar_i1 ((gfc_array_i1 *) ret, (GFC_INTEGER_1 *) source,
448 *along, *pncopies);
449 return;
450
451 case GFC_DTYPE_LOGICAL_2:
452 case GFC_DTYPE_INTEGER_2:
453 spread_scalar_i2 ((gfc_array_i2 *) ret, (GFC_INTEGER_2 *) source,
454 *along, *pncopies);
455 return;
456
457 case GFC_DTYPE_LOGICAL_4:
458 case GFC_DTYPE_INTEGER_4:
459 spread_scalar_i4 ((gfc_array_i4 *) ret, (GFC_INTEGER_4 *) source,
460 *along, *pncopies);
461 return;
462
463 case GFC_DTYPE_LOGICAL_8:
464 case GFC_DTYPE_INTEGER_8:
465 spread_scalar_i8 ((gfc_array_i8 *) ret, (GFC_INTEGER_8 *) source,
466 *along, *pncopies);
467 return;
468
469#ifdef HAVE_GFC_INTEGER_16
470 case GFC_DTYPE_LOGICAL_16:
471 case GFC_DTYPE_INTEGER_16:
472 spread_scalar_i16 ((gfc_array_i16 *) ret, (GFC_INTEGER_16 *) source,
473 *along, *pncopies);
474 return;
475#endif
476
477 case GFC_DTYPE_REAL_4:
478 spread_scalar_r4 ((gfc_array_r4 *) ret, (GFC_REAL_4 *) source,
479 *along, *pncopies);
480 return;
481
482 case GFC_DTYPE_REAL_8:
483 spread_scalar_r8 ((gfc_array_r8 *) ret, (GFC_REAL_8 *) source,
484 *along, *pncopies);
485 return;
486
487#ifdef HAVE_GFC_REAL_10
488 case GFC_DTYPE_REAL_10:
489 spread_scalar_r10 ((gfc_array_r10 *) ret, (GFC_REAL_10 *) source,
490 *along, *pncopies);
491 return;
492#endif
493
494#ifdef HAVE_GFC_REAL_16
495 case GFC_DTYPE_REAL_16:
496 spread_scalar_r16 ((gfc_array_r16 *) ret, (GFC_REAL_16 *) source,
497 *along, *pncopies);
498 return;
499#endif
500
501 case GFC_DTYPE_COMPLEX_4:
502 spread_scalar_c4 ((gfc_array_c4 *) ret, (GFC_COMPLEX_4 *) source,
503 *along, *pncopies);
504 return;
505
506 case GFC_DTYPE_COMPLEX_8:
507 spread_scalar_c8 ((gfc_array_c8 *) ret, (GFC_COMPLEX_8 *) source,
508 *along, *pncopies);
509 return;
510
511#ifdef HAVE_GFC_COMPLEX_10
512 case GFC_DTYPE_COMPLEX_10:
513 spread_scalar_c10 ((gfc_array_c10 *) ret, (GFC_COMPLEX_10 *) source,
514 *along, *pncopies);
515 return;
516#endif
517
518#ifdef HAVE_GFC_COMPLEX_16
519 case GFC_DTYPE_COMPLEX_16:
520 spread_scalar_c16 ((gfc_array_c16 *) ret, (GFC_COMPLEX_16 *) source,
521 *along, *pncopies);
522 return;
523#endif
524
c7d0f4d5
TK
525 case GFC_DTYPE_DERIVED_2:
526 if (GFC_UNALIGNED_2(ret->data) || GFC_UNALIGNED_2(source))
527 break;
528 else
529 {
530 spread_scalar_i2 ((gfc_array_i2 *) ret, (GFC_INTEGER_2 *) source,
531 *along, *pncopies);
532 return;
533 }
534
535 case GFC_DTYPE_DERIVED_4:
536 if (GFC_UNALIGNED_4(ret->data) || GFC_UNALIGNED_4(source))
537 break;
538 else
539 {
540 spread_scalar_i4 ((gfc_array_i4 *) ret, (GFC_INTEGER_4 *) source,
541 *along, *pncopies);
542 return;
543 }
544
545 case GFC_DTYPE_DERIVED_8:
546 if (GFC_UNALIGNED_8(ret->data) || GFC_UNALIGNED_8(source))
547 break;
548 else
549 {
550 spread_scalar_i8 ((gfc_array_i8 *) ret, (GFC_INTEGER_8 *) source,
551 *along, *pncopies);
552 return;
553 }
554#ifdef HAVE_GFC_INTEGER_16
555 case GFC_DTYPE_DERIVED_16:
556 if (GFC_UNALIGNED_16(ret->data) || GFC_UNALIGNED_16(source))
557 break;
558 else
559 {
560 spread_scalar_i16 ((gfc_array_i16 *) ret, (GFC_INTEGER_16 *) source,
561 *along, *pncopies);
562 return;
563 }
564#endif
75f2543f
TK
565 }
566
2853e512
PT
567 spread_internal_scalar (ret, source, along, pncopies, GFC_DESCRIPTOR_SIZE (ret));
568}
569
570
571extern void spread_char_scalar (gfc_array_char *, GFC_INTEGER_4,
572 const char *, const index_type *,
573 const index_type *, GFC_INTEGER_4);
574export_proto(spread_char_scalar);
575
576void
577spread_char_scalar (gfc_array_char *ret,
578 GFC_INTEGER_4 ret_length __attribute__((unused)),
579 const char *source, const index_type *along,
580 const index_type *pncopies, GFC_INTEGER_4 source_length)
581{
582 if (!ret->dtype)
583 runtime_error ("return array missing descriptor in spread()");
584 spread_internal_scalar (ret, source, along, pncopies, source_length);
585}
586