* testsuite/26_numerics/headers/cmath/hypot.cc: XFAIL on AIX.
[official-gcc.git] / libgfortran / intrinsics / pack_generic.c
blob5aea3d0e1f6447331e1b7afa8bce799290b84d36
1 /* Generic implementation of the PACK intrinsic
2 Copyright (C) 2002-2016 Free Software Foundation, Inc.
3 Contributed by Paul Brook <paul@nowt.org>
5 This file is part of the GNU Fortran 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"
27 #include <stdlib.h>
28 #include <assert.h>
29 #include <string.h>
31 /* PACK is specified as follows:
33 13.14.80 PACK (ARRAY, MASK, [VECTOR])
35 Description: Pack an array into an array of rank one under the
36 control of a mask.
38 Class: Transformational function.
40 Arguments:
41 ARRAY may be of any type. It shall not be scalar.
42 MASK shall be of type LOGICAL. It shall be conformable with ARRAY.
43 VECTOR (optional) shall be of the same type and type parameters
44 as ARRAY. VECTOR shall have at least as many elements as
45 there are true elements in MASK. If MASK is a scalar
46 with the value true, VECTOR shall have at least as many
47 elements as there are in ARRAY.
49 Result Characteristics: The result is an array of rank one with the
50 same type and type parameters as ARRAY. If VECTOR is present, the
51 result size is that of VECTOR; otherwise, the result size is the
52 number /t/ of true elements in MASK unless MASK is scalar with the
53 value true, in which case the result size is the size of ARRAY.
55 Result Value: Element /i/ of the result is the element of ARRAY
56 that corresponds to the /i/th true element of MASK, taking elements
57 in array element order, for /i/ = 1, 2, ..., /t/. If VECTOR is
58 present and has size /n/ > /t/, element /i/ of the result has the
59 value VECTOR(/i/), for /i/ = /t/ + 1, ..., /n/.
61 Examples: The nonzero elements of an array M with the value
62 | 0 0 0 |
63 | 9 0 0 | may be "gathered" by the function PACK. The result of
64 | 0 0 7 |
65 PACK (M, MASK = M.NE.0) is [9,7] and the result of PACK (M, M.NE.0,
66 VECTOR = (/ 2,4,6,8,10,12 /)) is [9,7,6,8,10,12].
68 There are two variants of the PACK intrinsic: one, where MASK is
69 array valued, and the other one where MASK is scalar. */
71 static void
72 pack_internal (gfc_array_char *ret, const gfc_array_char *array,
73 const gfc_array_l1 *mask, const gfc_array_char *vector,
74 index_type size)
76 /* r.* indicates the return array. */
77 index_type rstride0;
78 char * restrict rptr;
79 /* s.* indicates the source array. */
80 index_type sstride[GFC_MAX_DIMENSIONS];
81 index_type sstride0;
82 const char *sptr;
83 /* m.* indicates the mask array. */
84 index_type mstride[GFC_MAX_DIMENSIONS];
85 index_type mstride0;
86 const GFC_LOGICAL_1 *mptr;
88 index_type count[GFC_MAX_DIMENSIONS];
89 index_type extent[GFC_MAX_DIMENSIONS];
90 index_type n;
91 index_type dim;
92 index_type nelem;
93 index_type total;
94 int mask_kind;
96 dim = GFC_DESCRIPTOR_RANK (array);
98 sptr = array->base_addr;
99 mptr = mask->base_addr;
101 /* Use the same loop for all logical types, by using GFC_LOGICAL_1
102 and using shifting to address size and endian issues. */
104 mask_kind = GFC_DESCRIPTOR_SIZE (mask);
106 if (mask_kind == 1 || mask_kind == 2 || mask_kind == 4 || mask_kind == 8
107 #ifdef HAVE_GFC_LOGICAL_16
108 || mask_kind == 16
109 #endif
112 /* Don't convert a NULL pointer as we use test for NULL below. */
113 if (mptr)
114 mptr = GFOR_POINTER_TO_L1 (mptr, mask_kind);
116 else
117 runtime_error ("Funny sized logical array");
119 for (n = 0; n < dim; n++)
121 count[n] = 0;
122 extent[n] = GFC_DESCRIPTOR_EXTENT(array,n);
123 sstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(array,n);
124 mstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(mask,n);
126 if (sstride[0] == 0)
127 sstride[0] = size;
128 if (mstride[0] == 0)
129 mstride[0] = mask_kind;
131 if (ret->base_addr == NULL || unlikely (compile_options.bounds_check))
133 /* Count the elements, either for allocating memory or
134 for bounds checking. */
136 if (vector != NULL)
138 /* The return array will have as many
139 elements as there are in VECTOR. */
140 total = GFC_DESCRIPTOR_EXTENT(vector,0);
142 else
144 /* We have to count the true elements in MASK. */
146 total = count_0 (mask);
149 if (ret->base_addr == NULL)
151 /* Setup the array descriptor. */
152 GFC_DIMENSION_SET(ret->dim[0], 0, total-1, 1);
154 ret->offset = 0;
155 /* xmallocarray allocates a single byte for zero size. */
156 ret->base_addr = xmallocarray (total, size);
158 if (total == 0)
159 return; /* In this case, nothing remains to be done. */
161 else
163 /* We come here because of range checking. */
164 index_type ret_extent;
166 ret_extent = GFC_DESCRIPTOR_EXTENT(ret,0);
167 if (total != ret_extent)
168 runtime_error ("Incorrect extent in return value of PACK intrinsic;"
169 " is %ld, should be %ld", (long int) total,
170 (long int) ret_extent);
174 rstride0 = GFC_DESCRIPTOR_STRIDE_BYTES(ret,0);
175 if (rstride0 == 0)
176 rstride0 = size;
177 sstride0 = sstride[0];
178 mstride0 = mstride[0];
179 rptr = ret->base_addr;
181 while (sptr && mptr)
183 /* Test this element. */
184 if (*mptr)
186 /* Add it. */
187 memcpy (rptr, sptr, size);
188 rptr += rstride0;
190 /* Advance to the next element. */
191 sptr += sstride0;
192 mptr += mstride0;
193 count[0]++;
194 n = 0;
195 while (count[n] == extent[n])
197 /* When we get to the end of a dimension, reset it and increment
198 the next dimension. */
199 count[n] = 0;
200 /* We could precalculate these products, but this is a less
201 frequently used path so probably not worth it. */
202 sptr -= sstride[n] * extent[n];
203 mptr -= mstride[n] * extent[n];
204 n++;
205 if (n >= dim)
207 /* Break out of the loop. */
208 sptr = NULL;
209 break;
211 else
213 count[n]++;
214 sptr += sstride[n];
215 mptr += mstride[n];
220 /* Add any remaining elements from VECTOR. */
221 if (vector)
223 n = GFC_DESCRIPTOR_EXTENT(vector,0);
224 nelem = ((rptr - ret->base_addr) / rstride0);
225 if (n > nelem)
227 sstride0 = GFC_DESCRIPTOR_STRIDE_BYTES(vector,0);
228 if (sstride0 == 0)
229 sstride0 = size;
231 sptr = vector->base_addr + sstride0 * nelem;
232 n -= nelem;
233 while (n--)
235 memcpy (rptr, sptr, size);
236 rptr += rstride0;
237 sptr += sstride0;
243 extern void pack (gfc_array_char *, const gfc_array_char *,
244 const gfc_array_l1 *, const gfc_array_char *);
245 export_proto(pack);
247 void
248 pack (gfc_array_char *ret, const gfc_array_char *array,
249 const gfc_array_l1 *mask, const gfc_array_char *vector)
251 index_type type_size;
252 index_type size;
254 type_size = GFC_DTYPE_TYPE_SIZE(array);
256 switch(type_size)
258 case GFC_DTYPE_LOGICAL_1:
259 case GFC_DTYPE_INTEGER_1:
260 case GFC_DTYPE_DERIVED_1:
261 pack_i1 ((gfc_array_i1 *) ret, (gfc_array_i1 *) array,
262 (gfc_array_l1 *) mask, (gfc_array_i1 *) vector);
263 return;
265 case GFC_DTYPE_LOGICAL_2:
266 case GFC_DTYPE_INTEGER_2:
267 pack_i2 ((gfc_array_i2 *) ret, (gfc_array_i2 *) array,
268 (gfc_array_l1 *) mask, (gfc_array_i2 *) vector);
269 return;
271 case GFC_DTYPE_LOGICAL_4:
272 case GFC_DTYPE_INTEGER_4:
273 pack_i4 ((gfc_array_i4 *) ret, (gfc_array_i4 *) array,
274 (gfc_array_l1 *) mask, (gfc_array_i4 *) vector);
275 return;
277 case GFC_DTYPE_LOGICAL_8:
278 case GFC_DTYPE_INTEGER_8:
279 pack_i8 ((gfc_array_i8 *) ret, (gfc_array_i8 *) array,
280 (gfc_array_l1 *) mask, (gfc_array_i8 *) vector);
281 return;
283 #ifdef HAVE_GFC_INTEGER_16
284 case GFC_DTYPE_LOGICAL_16:
285 case GFC_DTYPE_INTEGER_16:
286 pack_i16 ((gfc_array_i16 *) ret, (gfc_array_i16 *) array,
287 (gfc_array_l1 *) mask, (gfc_array_i16 *) vector);
288 return;
289 #endif
291 case GFC_DTYPE_REAL_4:
292 pack_r4 ((gfc_array_r4 *) ret, (gfc_array_r4 *) array,
293 (gfc_array_l1 *) mask, (gfc_array_r4 *) vector);
294 return;
296 case GFC_DTYPE_REAL_8:
297 pack_r8 ((gfc_array_r8 *) ret, (gfc_array_r8 *) array,
298 (gfc_array_l1 *) mask, (gfc_array_r8 *) vector);
299 return;
301 /* FIXME: This here is a hack, which will have to be removed when
302 the array descriptor is reworked. Currently, we don't store the
303 kind value for the type, but only the size. Because on targets with
304 __float128, we have sizeof(logn double) == sizeof(__float128),
305 we cannot discriminate here and have to fall back to the generic
306 handling (which is suboptimal). */
307 #if !defined(GFC_REAL_16_IS_FLOAT128)
308 # ifdef HAVE_GFC_REAL_10
309 case GFC_DTYPE_REAL_10:
310 pack_r10 ((gfc_array_r10 *) ret, (gfc_array_r10 *) array,
311 (gfc_array_l1 *) mask, (gfc_array_r10 *) vector);
312 return;
313 # endif
315 # ifdef HAVE_GFC_REAL_16
316 case GFC_DTYPE_REAL_16:
317 pack_r16 ((gfc_array_r16 *) ret, (gfc_array_r16 *) array,
318 (gfc_array_l1 *) mask, (gfc_array_r16 *) vector);
319 return;
320 # endif
321 #endif
323 case GFC_DTYPE_COMPLEX_4:
324 pack_c4 ((gfc_array_c4 *) ret, (gfc_array_c4 *) array,
325 (gfc_array_l1 *) mask, (gfc_array_c4 *) vector);
326 return;
328 case GFC_DTYPE_COMPLEX_8:
329 pack_c8 ((gfc_array_c8 *) ret, (gfc_array_c8 *) array,
330 (gfc_array_l1 *) mask, (gfc_array_c8 *) vector);
331 return;
333 /* FIXME: This here is a hack, which will have to be removed when
334 the array descriptor is reworked. Currently, we don't store the
335 kind value for the type, but only the size. Because on targets with
336 __float128, we have sizeof(logn double) == sizeof(__float128),
337 we cannot discriminate here and have to fall back to the generic
338 handling (which is suboptimal). */
339 #if !defined(GFC_REAL_16_IS_FLOAT128)
340 # ifdef HAVE_GFC_COMPLEX_10
341 case GFC_DTYPE_COMPLEX_10:
342 pack_c10 ((gfc_array_c10 *) ret, (gfc_array_c10 *) array,
343 (gfc_array_l1 *) mask, (gfc_array_c10 *) vector);
344 return;
345 # endif
347 # ifdef HAVE_GFC_COMPLEX_16
348 case GFC_DTYPE_COMPLEX_16:
349 pack_c16 ((gfc_array_c16 *) ret, (gfc_array_c16 *) array,
350 (gfc_array_l1 *) mask, (gfc_array_c16 *) vector);
351 return;
352 # endif
353 #endif
355 /* For derived types, let's check the actual alignment of the
356 data pointers. If they are aligned, we can safely call
357 the unpack functions. */
359 case GFC_DTYPE_DERIVED_2:
360 if (GFC_UNALIGNED_2(ret->base_addr) || GFC_UNALIGNED_2(array->base_addr)
361 || (vector && GFC_UNALIGNED_2(vector->base_addr)))
362 break;
363 else
365 pack_i2 ((gfc_array_i2 *) ret, (gfc_array_i2 *) array,
366 (gfc_array_l1 *) mask, (gfc_array_i2 *) vector);
367 return;
370 case GFC_DTYPE_DERIVED_4:
371 if (GFC_UNALIGNED_4(ret->base_addr) || GFC_UNALIGNED_4(array->base_addr)
372 || (vector && GFC_UNALIGNED_4(vector->base_addr)))
373 break;
374 else
376 pack_i4 ((gfc_array_i4 *) ret, (gfc_array_i4 *) array,
377 (gfc_array_l1 *) mask, (gfc_array_i4 *) vector);
378 return;
381 case GFC_DTYPE_DERIVED_8:
382 if (GFC_UNALIGNED_8(ret->base_addr) || GFC_UNALIGNED_8(array->base_addr)
383 || (vector && GFC_UNALIGNED_8(vector->base_addr)))
384 break;
385 else
387 pack_i8 ((gfc_array_i8 *) ret, (gfc_array_i8 *) array,
388 (gfc_array_l1 *) mask, (gfc_array_i8 *) vector);
389 return;
392 #ifdef HAVE_GFC_INTEGER_16
393 case GFC_DTYPE_DERIVED_16:
394 if (GFC_UNALIGNED_16(ret->base_addr) || GFC_UNALIGNED_16(array->base_addr)
395 || (vector && GFC_UNALIGNED_16(vector->base_addr)))
396 break;
397 else
399 pack_i16 ((gfc_array_i16 *) ret, (gfc_array_i16 *) array,
400 (gfc_array_l1 *) mask, (gfc_array_i16 *) vector);
401 return;
403 #endif
407 size = GFC_DESCRIPTOR_SIZE (array);
408 pack_internal (ret, array, mask, vector, size);
412 extern void pack_char (gfc_array_char *, GFC_INTEGER_4, const gfc_array_char *,
413 const gfc_array_l1 *, const gfc_array_char *,
414 GFC_INTEGER_4, GFC_INTEGER_4);
415 export_proto(pack_char);
417 void
418 pack_char (gfc_array_char *ret,
419 GFC_INTEGER_4 ret_length __attribute__((unused)),
420 const gfc_array_char *array, const gfc_array_l1 *mask,
421 const gfc_array_char *vector, GFC_INTEGER_4 array_length,
422 GFC_INTEGER_4 vector_length __attribute__((unused)))
424 pack_internal (ret, array, mask, vector, array_length);
428 extern void pack_char4 (gfc_array_char *, GFC_INTEGER_4, const gfc_array_char *,
429 const gfc_array_l1 *, const gfc_array_char *,
430 GFC_INTEGER_4, GFC_INTEGER_4);
431 export_proto(pack_char4);
433 void
434 pack_char4 (gfc_array_char *ret,
435 GFC_INTEGER_4 ret_length __attribute__((unused)),
436 const gfc_array_char *array, const gfc_array_l1 *mask,
437 const gfc_array_char *vector, GFC_INTEGER_4 array_length,
438 GFC_INTEGER_4 vector_length __attribute__((unused)))
440 pack_internal (ret, array, mask, vector, array_length * sizeof (gfc_char4_t));
444 static void
445 pack_s_internal (gfc_array_char *ret, const gfc_array_char *array,
446 const GFC_LOGICAL_4 *mask, const gfc_array_char *vector,
447 index_type size)
449 /* r.* indicates the return array. */
450 index_type rstride0;
451 char *rptr;
452 /* s.* indicates the source array. */
453 index_type sstride[GFC_MAX_DIMENSIONS];
454 index_type sstride0;
455 const char *sptr;
457 index_type count[GFC_MAX_DIMENSIONS];
458 index_type extent[GFC_MAX_DIMENSIONS];
459 index_type n;
460 index_type dim;
461 index_type ssize;
462 index_type nelem;
463 index_type total;
465 dim = GFC_DESCRIPTOR_RANK (array);
466 /* Initialize sstride[0] to avoid -Wmaybe-uninitialized
467 complaints. */
468 sstride[0] = size;
469 ssize = 1;
470 for (n = 0; n < dim; n++)
472 count[n] = 0;
473 extent[n] = GFC_DESCRIPTOR_EXTENT(array,n);
474 if (extent[n] < 0)
475 extent[n] = 0;
477 sstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(array,n);
478 ssize *= extent[n];
480 if (sstride[0] == 0)
481 sstride[0] = size;
483 sstride0 = sstride[0];
485 if (ssize != 0)
486 sptr = array->base_addr;
487 else
488 sptr = NULL;
490 if (ret->base_addr == NULL)
492 /* Allocate the memory for the result. */
494 if (vector != NULL)
496 /* The return array will have as many elements as there are
497 in vector. */
498 total = GFC_DESCRIPTOR_EXTENT(vector,0);
499 if (total <= 0)
501 total = 0;
502 vector = NULL;
505 else
507 if (*mask)
509 /* The result array will have as many elements as the input
510 array. */
511 total = extent[0];
512 for (n = 1; n < dim; n++)
513 total *= extent[n];
515 else
516 /* The result array will be empty. */
517 total = 0;
520 /* Setup the array descriptor. */
521 GFC_DIMENSION_SET(ret->dim[0],0,total-1,1);
523 ret->offset = 0;
525 ret->base_addr = xmallocarray (total, size);
527 if (total == 0)
528 return;
531 rstride0 = GFC_DESCRIPTOR_STRIDE_BYTES(ret,0);
532 if (rstride0 == 0)
533 rstride0 = size;
534 rptr = ret->base_addr;
536 /* The remaining possibilities are now:
537 If MASK is .TRUE., we have to copy the source array into the
538 result array. We then have to fill it up with elements from VECTOR.
539 If MASK is .FALSE., we have to copy VECTOR into the result
540 array. If VECTOR were not present we would have already returned. */
542 if (*mask && ssize != 0)
544 while (sptr)
546 /* Add this element. */
547 memcpy (rptr, sptr, size);
548 rptr += rstride0;
550 /* Advance to the next element. */
551 sptr += sstride0;
552 count[0]++;
553 n = 0;
554 while (count[n] == extent[n])
556 /* When we get to the end of a dimension, reset it and
557 increment the next dimension. */
558 count[n] = 0;
559 /* We could precalculate these products, but this is a
560 less frequently used path so probably not worth it. */
561 sptr -= sstride[n] * extent[n];
562 n++;
563 if (n >= dim)
565 /* Break out of the loop. */
566 sptr = NULL;
567 break;
569 else
571 count[n]++;
572 sptr += sstride[n];
578 /* Add any remaining elements from VECTOR. */
579 if (vector)
581 n = GFC_DESCRIPTOR_EXTENT(vector,0);
582 nelem = ((rptr - ret->base_addr) / rstride0);
583 if (n > nelem)
585 sstride0 = GFC_DESCRIPTOR_STRIDE_BYTES(vector,0);
586 if (sstride0 == 0)
587 sstride0 = size;
589 sptr = vector->base_addr + sstride0 * nelem;
590 n -= nelem;
591 while (n--)
593 memcpy (rptr, sptr, size);
594 rptr += rstride0;
595 sptr += sstride0;
601 extern void pack_s (gfc_array_char *ret, const gfc_array_char *array,
602 const GFC_LOGICAL_4 *, const gfc_array_char *);
603 export_proto(pack_s);
605 void
606 pack_s (gfc_array_char *ret, const gfc_array_char *array,
607 const GFC_LOGICAL_4 *mask, const gfc_array_char *vector)
609 pack_s_internal (ret, array, mask, vector, GFC_DESCRIPTOR_SIZE (array));
613 extern void pack_s_char (gfc_array_char *ret, GFC_INTEGER_4,
614 const gfc_array_char *array, const GFC_LOGICAL_4 *,
615 const gfc_array_char *, GFC_INTEGER_4,
616 GFC_INTEGER_4);
617 export_proto(pack_s_char);
619 void
620 pack_s_char (gfc_array_char *ret,
621 GFC_INTEGER_4 ret_length __attribute__((unused)),
622 const gfc_array_char *array, const GFC_LOGICAL_4 *mask,
623 const gfc_array_char *vector, GFC_INTEGER_4 array_length,
624 GFC_INTEGER_4 vector_length __attribute__((unused)))
626 pack_s_internal (ret, array, mask, vector, array_length);
630 extern void pack_s_char4 (gfc_array_char *ret, GFC_INTEGER_4,
631 const gfc_array_char *array, const GFC_LOGICAL_4 *,
632 const gfc_array_char *, GFC_INTEGER_4,
633 GFC_INTEGER_4);
634 export_proto(pack_s_char4);
636 void
637 pack_s_char4 (gfc_array_char *ret,
638 GFC_INTEGER_4 ret_length __attribute__((unused)),
639 const gfc_array_char *array, const GFC_LOGICAL_4 *mask,
640 const gfc_array_char *vector, GFC_INTEGER_4 array_length,
641 GFC_INTEGER_4 vector_length __attribute__((unused)))
643 pack_s_internal (ret, array, mask, vector,
644 array_length * sizeof (gfc_char4_t));