1 /* Generic implementation of the SPREAD intrinsic
2 Copyright 2002, 2005, 2006, 2007, 2009 Free Software Foundation, Inc.
3 Contributed by Paul Brook <paul@nowt.org>
5 This file is part of the GNU Fortran 95 runtime library (libgfortran).
7 Libgfortran is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public
9 License as published by the Free Software Foundation; either
10 version 3 of the License, or (at your option) any later version.
12 Ligbfortran is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 Under Section 7 of GPL version 3, you are granted additional
18 permissions described in the GCC Runtime Library Exception, version
19 3.1, as published by the Free Software Foundation.
21 You should have received a copy of the GNU General Public License and
22 a copy of the GCC Runtime Library Exception along with this program;
23 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
24 <http://www.gnu.org/licenses/>. */
26 #include "libgfortran.h"
32 spread_internal (gfc_array_char
*ret
, const gfc_array_char
*source
,
33 const index_type
*along
, const index_type
*pncopies
)
35 /* r.* indicates the return array. */
36 index_type rstride
[GFC_MAX_DIMENSIONS
];
38 index_type rdelta
= 0;
43 /* s.* indicates the source array. */
44 index_type sstride
[GFC_MAX_DIMENSIONS
];
49 index_type count
[GFC_MAX_DIMENSIONS
];
50 index_type extent
[GFC_MAX_DIMENSIONS
];
56 size
= GFC_DESCRIPTOR_SIZE(source
);
58 srank
= GFC_DESCRIPTOR_RANK(source
);
61 if (rrank
> GFC_MAX_DIMENSIONS
)
62 runtime_error ("return rank too large in spread()");
65 runtime_error ("dim outside of rank in spread()");
69 if (ret
->data
== NULL
)
71 /* The front end has signalled that we need to populate the
72 return array descriptor. */
76 ret
->dtype
= (source
->dtype
& ~GFC_DTYPE_RANK_MASK
) | rrank
;
79 for (n
= 0; n
< rrank
; n
++)
91 extent
[dim
] = GFC_DESCRIPTOR_EXTENT(source
,dim
);
92 sstride
[dim
] = GFC_DESCRIPTOR_STRIDE_BYTES(source
,dim
);
93 rstride
[dim
] = rs
* size
;
100 GFC_DIMENSION_SET(ret
->dim
[n
], 0, ub
, stride
);
104 ret
->data
= internal_malloc_size (rs
* size
);
107 ret
->data
= internal_malloc_size (1);
118 if (GFC_DESCRIPTOR_RANK(ret
) != rrank
)
119 runtime_error ("rank mismatch in spread()");
121 if (compile_options
.bounds_check
)
123 for (n
= 0; n
< rrank
; n
++)
125 index_type ret_extent
;
127 ret_extent
= GFC_DESCRIPTOR_EXTENT(ret
,n
);
130 rdelta
= GFC_DESCRIPTOR_STRIDE_BYTES(ret
,n
);
132 if (ret_extent
!= ncopies
)
133 runtime_error("Incorrect extent in return value of SPREAD"
134 " intrinsic in dimension %ld: is %ld,"
135 " should be %ld", (long int) n
+1,
136 (long int) ret_extent
, (long int) ncopies
);
141 extent
[dim
] = GFC_DESCRIPTOR_EXTENT(source
,dim
);
142 if (ret_extent
!= extent
[dim
])
143 runtime_error("Incorrect extent in return value of SPREAD"
144 " intrinsic in dimension %ld: is %ld,"
145 " should be %ld", (long int) n
+1,
146 (long int) ret_extent
,
147 (long int) extent
[dim
]);
149 if (extent
[dim
] <= 0)
151 sstride
[dim
] = GFC_DESCRIPTOR_STRIDE_BYTES(source
,dim
);
152 rstride
[dim
] = GFC_DESCRIPTOR_STRIDE_BYTES(ret
,n
);
159 for (n
= 0; n
< rrank
; n
++)
163 rdelta
= GFC_DESCRIPTOR_STRIDE_BYTES(ret
,n
);
168 extent
[dim
] = GFC_DESCRIPTOR_EXTENT(source
,dim
);
169 if (extent
[dim
] <= 0)
171 sstride
[dim
] = GFC_DESCRIPTOR_STRIDE_BYTES(source
,dim
);
172 rstride
[dim
] = GFC_DESCRIPTOR_STRIDE_BYTES(ret
,n
);
184 sstride0
= sstride
[0];
185 rstride0
= rstride
[0];
191 /* Spread this element. */
193 for (n
= 0; n
< ncopies
; n
++)
195 memcpy (dest
, sptr
, size
);
198 /* Advance to the next element. */
203 while (count
[n
] == extent
[n
])
205 /* When we get to the end of a dimension, reset it and increment
206 the next dimension. */
208 /* We could precalculate these products, but this is a less
209 frequently used path so probably not worth it. */
210 sptr
-= sstride
[n
] * extent
[n
];
211 rptr
-= rstride
[n
] * extent
[n
];
215 /* Break out of the loop. */
229 /* This version of spread_internal treats the special case of a scalar
230 source. This is much simpler than the more general case above. */
233 spread_internal_scalar (gfc_array_char
*ret
, const char *source
,
234 const index_type
*along
, const index_type
*pncopies
)
237 int ncopies
= *pncopies
;
241 size
= GFC_DESCRIPTOR_SIZE(ret
);
243 if (GFC_DESCRIPTOR_RANK (ret
) != 1)
244 runtime_error ("incorrect destination rank in spread()");
247 runtime_error ("dim outside of rank in spread()");
249 if (ret
->data
== NULL
)
251 ret
->data
= internal_malloc_size (ncopies
* size
);
253 GFC_DIMENSION_SET(ret
->dim
[0], 0, ncopies
- 1, 1);
257 if (ncopies
- 1 > (GFC_DESCRIPTOR_EXTENT(ret
,0) - 1)
258 / GFC_DESCRIPTOR_STRIDE(ret
,0))
259 runtime_error ("dim too large in spread()");
262 for (n
= 0; n
< ncopies
; n
++)
264 dest
= (char*)(ret
->data
+ n
* GFC_DESCRIPTOR_STRIDE_BYTES(ret
,0));
265 memcpy (dest
, source
, size
);
269 extern void spread (gfc_array_char
*, const gfc_array_char
*,
270 const index_type
*, const index_type
*);
271 export_proto(spread
);
274 spread (gfc_array_char
*ret
, const gfc_array_char
*source
,
275 const index_type
*along
, const index_type
*pncopies
)
277 index_type type_size
;
279 type_size
= GFC_DTYPE_TYPE_SIZE(ret
);
282 case GFC_DTYPE_DERIVED_1
:
283 case GFC_DTYPE_LOGICAL_1
:
284 case GFC_DTYPE_INTEGER_1
:
285 spread_i1 ((gfc_array_i1
*) ret
, (gfc_array_i1
*) source
,
289 case GFC_DTYPE_LOGICAL_2
:
290 case GFC_DTYPE_INTEGER_2
:
291 spread_i2 ((gfc_array_i2
*) ret
, (gfc_array_i2
*) source
,
295 case GFC_DTYPE_LOGICAL_4
:
296 case GFC_DTYPE_INTEGER_4
:
297 spread_i4 ((gfc_array_i4
*) ret
, (gfc_array_i4
*) source
,
301 case GFC_DTYPE_LOGICAL_8
:
302 case GFC_DTYPE_INTEGER_8
:
303 spread_i8 ((gfc_array_i8
*) ret
, (gfc_array_i8
*) source
,
307 #ifdef HAVE_GFC_INTEGER_16
308 case GFC_DTYPE_LOGICAL_16
:
309 case GFC_DTYPE_INTEGER_16
:
310 spread_i16 ((gfc_array_i16
*) ret
, (gfc_array_i16
*) source
,
315 case GFC_DTYPE_REAL_4
:
316 spread_r4 ((gfc_array_r4
*) ret
, (gfc_array_r4
*) source
,
320 case GFC_DTYPE_REAL_8
:
321 spread_r8 ((gfc_array_r8
*) ret
, (gfc_array_r8
*) source
,
325 #ifdef GFC_HAVE_REAL_10
326 case GFC_DTYPE_REAL_10
:
327 spread_r10 ((gfc_array_r10
*) ret
, (gfc_array_r10
*) source
,
332 #ifdef GFC_HAVE_REAL_16
333 case GFC_DTYPE_REAL_16
:
334 spread_r16 ((gfc_array_r16
*) ret
, (gfc_array_r16
*) source
,
339 case GFC_DTYPE_COMPLEX_4
:
340 spread_c4 ((gfc_array_c4
*) ret
, (gfc_array_c4
*) source
,
344 case GFC_DTYPE_COMPLEX_8
:
345 spread_c8 ((gfc_array_c8
*) ret
, (gfc_array_c8
*) source
,
349 #ifdef GFC_HAVE_COMPLEX_10
350 case GFC_DTYPE_COMPLEX_10
:
351 spread_c10 ((gfc_array_c10
*) ret
, (gfc_array_c10
*) source
,
356 #ifdef GFC_HAVE_COMPLEX_16
357 case GFC_DTYPE_COMPLEX_16
:
358 spread_c16 ((gfc_array_c16
*) ret
, (gfc_array_c16
*) source
,
363 case GFC_DTYPE_DERIVED_2
:
364 if (GFC_UNALIGNED_2(ret
->data
) || GFC_UNALIGNED_2(source
->data
))
368 spread_i2 ((gfc_array_i2
*) ret
, (gfc_array_i2
*) source
,
373 case GFC_DTYPE_DERIVED_4
:
374 if (GFC_UNALIGNED_4(ret
->data
) || GFC_UNALIGNED_4(source
->data
))
378 spread_i4 ((gfc_array_i4
*) ret
, (gfc_array_i4
*) source
,
383 case GFC_DTYPE_DERIVED_8
:
384 if (GFC_UNALIGNED_8(ret
->data
) || GFC_UNALIGNED_8(source
->data
))
388 spread_i8 ((gfc_array_i8
*) ret
, (gfc_array_i8
*) source
,
393 #ifdef HAVE_GFC_INTEGER_16
394 case GFC_DTYPE_DERIVED_16
:
395 if (GFC_UNALIGNED_16(ret
->data
) || GFC_UNALIGNED_16(source
->data
))
399 spread_i16 ((gfc_array_i16
*) ret
, (gfc_array_i16
*) source
,
406 spread_internal (ret
, source
, along
, pncopies
);
410 extern void spread_char (gfc_array_char
*, GFC_INTEGER_4
,
411 const gfc_array_char
*, const index_type
*,
412 const index_type
*, GFC_INTEGER_4
);
413 export_proto(spread_char
);
416 spread_char (gfc_array_char
*ret
,
417 GFC_INTEGER_4 ret_length
__attribute__((unused
)),
418 const gfc_array_char
*source
, const index_type
*along
,
419 const index_type
*pncopies
,
420 GFC_INTEGER_4 source_length
__attribute__((unused
)))
422 spread_internal (ret
, source
, along
, pncopies
);
426 extern void spread_char4 (gfc_array_char
*, GFC_INTEGER_4
,
427 const gfc_array_char
*, const index_type
*,
428 const index_type
*, GFC_INTEGER_4
);
429 export_proto(spread_char4
);
432 spread_char4 (gfc_array_char
*ret
,
433 GFC_INTEGER_4 ret_length
__attribute__((unused
)),
434 const gfc_array_char
*source
, const index_type
*along
,
435 const index_type
*pncopies
,
436 GFC_INTEGER_4 source_length
__attribute__((unused
)))
438 spread_internal (ret
, source
, along
, pncopies
);
442 /* The following are the prototypes for the versions of spread with a
445 extern void spread_scalar (gfc_array_char
*, const char *,
446 const index_type
*, const index_type
*);
447 export_proto(spread_scalar
);
450 spread_scalar (gfc_array_char
*ret
, const char *source
,
451 const index_type
*along
, const index_type
*pncopies
)
453 index_type type_size
;
456 runtime_error ("return array missing descriptor in spread()");
458 type_size
= GFC_DTYPE_TYPE_SIZE(ret
);
461 case GFC_DTYPE_DERIVED_1
:
462 case GFC_DTYPE_LOGICAL_1
:
463 case GFC_DTYPE_INTEGER_1
:
464 spread_scalar_i1 ((gfc_array_i1
*) ret
, (GFC_INTEGER_1
*) source
,
468 case GFC_DTYPE_LOGICAL_2
:
469 case GFC_DTYPE_INTEGER_2
:
470 spread_scalar_i2 ((gfc_array_i2
*) ret
, (GFC_INTEGER_2
*) source
,
474 case GFC_DTYPE_LOGICAL_4
:
475 case GFC_DTYPE_INTEGER_4
:
476 spread_scalar_i4 ((gfc_array_i4
*) ret
, (GFC_INTEGER_4
*) source
,
480 case GFC_DTYPE_LOGICAL_8
:
481 case GFC_DTYPE_INTEGER_8
:
482 spread_scalar_i8 ((gfc_array_i8
*) ret
, (GFC_INTEGER_8
*) source
,
486 #ifdef HAVE_GFC_INTEGER_16
487 case GFC_DTYPE_LOGICAL_16
:
488 case GFC_DTYPE_INTEGER_16
:
489 spread_scalar_i16 ((gfc_array_i16
*) ret
, (GFC_INTEGER_16
*) source
,
494 case GFC_DTYPE_REAL_4
:
495 spread_scalar_r4 ((gfc_array_r4
*) ret
, (GFC_REAL_4
*) source
,
499 case GFC_DTYPE_REAL_8
:
500 spread_scalar_r8 ((gfc_array_r8
*) ret
, (GFC_REAL_8
*) source
,
504 #ifdef HAVE_GFC_REAL_10
505 case GFC_DTYPE_REAL_10
:
506 spread_scalar_r10 ((gfc_array_r10
*) ret
, (GFC_REAL_10
*) source
,
511 #ifdef HAVE_GFC_REAL_16
512 case GFC_DTYPE_REAL_16
:
513 spread_scalar_r16 ((gfc_array_r16
*) ret
, (GFC_REAL_16
*) source
,
518 case GFC_DTYPE_COMPLEX_4
:
519 spread_scalar_c4 ((gfc_array_c4
*) ret
, (GFC_COMPLEX_4
*) source
,
523 case GFC_DTYPE_COMPLEX_8
:
524 spread_scalar_c8 ((gfc_array_c8
*) ret
, (GFC_COMPLEX_8
*) source
,
528 #ifdef HAVE_GFC_COMPLEX_10
529 case GFC_DTYPE_COMPLEX_10
:
530 spread_scalar_c10 ((gfc_array_c10
*) ret
, (GFC_COMPLEX_10
*) source
,
535 #ifdef HAVE_GFC_COMPLEX_16
536 case GFC_DTYPE_COMPLEX_16
:
537 spread_scalar_c16 ((gfc_array_c16
*) ret
, (GFC_COMPLEX_16
*) source
,
542 case GFC_DTYPE_DERIVED_2
:
543 if (GFC_UNALIGNED_2(ret
->data
) || GFC_UNALIGNED_2(source
))
547 spread_scalar_i2 ((gfc_array_i2
*) ret
, (GFC_INTEGER_2
*) source
,
552 case GFC_DTYPE_DERIVED_4
:
553 if (GFC_UNALIGNED_4(ret
->data
) || GFC_UNALIGNED_4(source
))
557 spread_scalar_i4 ((gfc_array_i4
*) ret
, (GFC_INTEGER_4
*) source
,
562 case GFC_DTYPE_DERIVED_8
:
563 if (GFC_UNALIGNED_8(ret
->data
) || GFC_UNALIGNED_8(source
))
567 spread_scalar_i8 ((gfc_array_i8
*) ret
, (GFC_INTEGER_8
*) source
,
571 #ifdef HAVE_GFC_INTEGER_16
572 case GFC_DTYPE_DERIVED_16
:
573 if (GFC_UNALIGNED_16(ret
->data
) || GFC_UNALIGNED_16(source
))
577 spread_scalar_i16 ((gfc_array_i16
*) ret
, (GFC_INTEGER_16
*) source
,
584 spread_internal_scalar (ret
, source
, along
, pncopies
);
588 extern void spread_char_scalar (gfc_array_char
*, GFC_INTEGER_4
,
589 const char *, const index_type
*,
590 const index_type
*, GFC_INTEGER_4
);
591 export_proto(spread_char_scalar
);
594 spread_char_scalar (gfc_array_char
*ret
,
595 GFC_INTEGER_4 ret_length
__attribute__((unused
)),
596 const char *source
, const index_type
*along
,
597 const index_type
*pncopies
,
598 GFC_INTEGER_4 source_length
__attribute__((unused
)))
601 runtime_error ("return array missing descriptor in spread()");
602 spread_internal_scalar (ret
, source
, along
, pncopies
);
606 extern void spread_char4_scalar (gfc_array_char
*, GFC_INTEGER_4
,
607 const char *, const index_type
*,
608 const index_type
*, GFC_INTEGER_4
);
609 export_proto(spread_char4_scalar
);
612 spread_char4_scalar (gfc_array_char
*ret
,
613 GFC_INTEGER_4 ret_length
__attribute__((unused
)),
614 const char *source
, const index_type
*along
,
615 const index_type
*pncopies
,
616 GFC_INTEGER_4 source_length
__attribute__((unused
)))
619 runtime_error ("return array missing descriptor in spread()");
620 spread_internal_scalar (ret
, source
, along
, pncopies
);