1/* Generic implementation of the PACK intrinsic
2   Copyright (C) 2002-2022 Free Software Foundation, Inc.
3   Contributed by Paul Brook <paul@nowt.org>
4
5This file is part of the GNU Fortran runtime library (libgfortran).
6
7Libgfortran is free software; you can redistribute it and/or
8modify it under the terms of the GNU General Public
9License as published by the Free Software Foundation; either
10version 3 of the License, or (at your option) any later version.
11
12Ligbfortran is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15GNU General Public License for more details.
16
17Under Section 7 of GPL version 3, you are granted additional
18permissions described in the GCC Runtime Library Exception, version
193.1, as published by the Free Software Foundation.
20
21You should have received a copy of the GNU General Public License and
22a copy of the GCC Runtime Library Exception along with this program;
23see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
24<http://www.gnu.org/licenses/>.  */
25
26#include "libgfortran.h"
27#include <string.h>
28
29/* PACK is specified as follows:
30
31   13.14.80 PACK (ARRAY, MASK, [VECTOR])
32
33   Description: Pack an array into an array of rank one under the
34   control of a mask.
35
36   Class: Transformational function.
37
38   Arguments:
39      ARRAY   may be of any type. It shall not be scalar.
40      MASK    shall be of type LOGICAL. It shall be conformable with ARRAY.
41      VECTOR  (optional) shall be of the same type and type parameters
42              as ARRAY. VECTOR shall have at least as many elements as
43              there are true elements in MASK. If MASK is a scalar
44              with the value true, VECTOR shall have at least as many
45              elements as there are in ARRAY.
46
47   Result Characteristics: The result is an array of rank one with the
48   same type and type parameters as ARRAY. If VECTOR is present, the
49   result size is that of VECTOR; otherwise, the result size is the
50   number /t/ of true elements in MASK unless MASK is scalar with the
51   value true, in which case the result size is the size of ARRAY.
52
53   Result Value: Element /i/ of the result is the element of ARRAY
54   that corresponds to the /i/th true element of MASK, taking elements
55   in array element order, for /i/ = 1, 2, ..., /t/. If VECTOR is
56   present and has size /n/ > /t/, element /i/ of the result has the
57   value VECTOR(/i/), for /i/ = /t/ + 1, ..., /n/.
58
59   Examples: The nonzero elements of an array M with the value
60   | 0 0 0 |
61   | 9 0 0 | may be "gathered" by the function PACK. The result of
62   | 0 0 7 |
63   PACK (M, MASK = M.NE.0) is [9,7] and the result of PACK (M, M.NE.0,
64   VECTOR = (/ 2,4,6,8,10,12 /)) is [9,7,6,8,10,12].
65
66There are two variants of the PACK intrinsic: one, where MASK is
67array valued, and the other one where MASK is scalar.  */
68
69static void
70pack_internal (gfc_array_char *ret, const gfc_array_char *array,
71	       const gfc_array_l1 *mask, const gfc_array_char *vector,
72	       index_type size)
73{
74  /* r.* indicates the return array.  */
75  index_type rstride0;
76  char * restrict rptr;
77  /* s.* indicates the source array.  */
78  index_type sstride[GFC_MAX_DIMENSIONS];
79  index_type sstride0;
80  const char *sptr;
81  /* m.* indicates the mask array.  */
82  index_type mstride[GFC_MAX_DIMENSIONS];
83  index_type mstride0;
84  const GFC_LOGICAL_1 *mptr;
85
86  index_type count[GFC_MAX_DIMENSIONS];
87  index_type extent[GFC_MAX_DIMENSIONS];
88  bool zero_sized;
89  index_type n;
90  index_type dim;
91  index_type nelem;
92  index_type total;
93  int mask_kind;
94
95  dim = GFC_DESCRIPTOR_RANK (array);
96
97  sptr = array->base_addr;
98  mptr = mask->base_addr;
99
100  /* Use the same loop for all logical types, by using GFC_LOGICAL_1
101     and using shifting to address size and endian issues.  */
102
103  mask_kind = GFC_DESCRIPTOR_SIZE (mask);
104
105  if (mask_kind == 1 || mask_kind == 2 || mask_kind == 4 || mask_kind == 8
106#ifdef HAVE_GFC_LOGICAL_16
107      || mask_kind == 16
108#endif
109      )
110    {
111      /*  Don't convert a NULL pointer as we use test for NULL below.  */
112      if (mptr)
113	mptr = GFOR_POINTER_TO_L1 (mptr, mask_kind);
114    }
115  else
116    runtime_error ("Funny sized logical array");
117
118  zero_sized = false;
119  for (n = 0; n < dim; n++)
120    {
121      count[n] = 0;
122      extent[n] = GFC_DESCRIPTOR_EXTENT(array,n);
123      if (extent[n] <= 0)
124	zero_sized = true;
125      sstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(array,n);
126      mstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(mask,n);
127    }
128  if (sstride[0] == 0)
129    sstride[0] = size;
130  if (mstride[0] == 0)
131    mstride[0] = mask_kind;
132
133  if (zero_sized)
134    sptr = NULL;
135  else
136    sptr = array->base_addr;
137
138  if (ret->base_addr == NULL || unlikely (compile_options.bounds_check))
139    {
140      /* Count the elements, either for allocating memory or
141	 for bounds checking.  */
142
143      if (vector != NULL)
144	{
145	  /* The return array will have as many
146	     elements as there are in VECTOR.  */
147	  total = GFC_DESCRIPTOR_EXTENT(vector,0);
148	}
149      else
150	{
151	  /* We have to count the true elements in MASK.  */
152
153	  total = count_0 (mask);
154	}
155
156      if (ret->base_addr == NULL)
157	{
158	  /* Setup the array descriptor.  */
159	  GFC_DIMENSION_SET(ret->dim[0], 0, total-1, 1);
160
161	  ret->offset = 0;
162	  /* xmallocarray allocates a single byte for zero size.  */
163	  ret->base_addr = xmallocarray (total, size);
164
165	  if (total == 0)
166	    return;      /* In this case, nothing remains to be done.  */
167	}
168      else
169	{
170	  /* We come here because of range checking.  */
171	  index_type ret_extent;
172
173	  ret_extent = GFC_DESCRIPTOR_EXTENT(ret,0);
174	  if (total != ret_extent)
175	    runtime_error ("Incorrect extent in return value of PACK intrinsic;"
176			   " is %ld, should be %ld", (long int) total,
177			   (long int) ret_extent);
178	}
179    }
180
181  rstride0 = GFC_DESCRIPTOR_STRIDE_BYTES(ret,0);
182  if (rstride0 == 0)
183    rstride0 = size;
184  sstride0 = sstride[0];
185  mstride0 = mstride[0];
186  rptr = ret->base_addr;
187
188  while (sptr && mptr)
189    {
190      /* Test this element.  */
191      if (*mptr)
192        {
193          /* Add it.  */
194          memcpy (rptr, sptr, size);
195          rptr += rstride0;
196        }
197      /* Advance to the next element.  */
198      sptr += sstride0;
199      mptr += mstride0;
200      count[0]++;
201      n = 0;
202      while (count[n] == extent[n])
203        {
204          /* When we get to the end of a dimension, reset it and increment
205             the next dimension.  */
206          count[n] = 0;
207          /* We could precalculate these products, but this is a less
208             frequently used path so probably not worth it.  */
209          sptr -= sstride[n] * extent[n];
210          mptr -= mstride[n] * extent[n];
211          n++;
212          if (n >= dim)
213            {
214              /* Break out of the loop.  */
215              sptr = NULL;
216              break;
217            }
218          else
219            {
220              count[n]++;
221              sptr += sstride[n];
222              mptr += mstride[n];
223            }
224        }
225    }
226
227  /* Add any remaining elements from VECTOR.  */
228  if (vector)
229    {
230      n = GFC_DESCRIPTOR_EXTENT(vector,0);
231      nelem = ((rptr - ret->base_addr) / rstride0);
232      if (n > nelem)
233        {
234          sstride0 = GFC_DESCRIPTOR_STRIDE_BYTES(vector,0);
235          if (sstride0 == 0)
236            sstride0 = size;
237
238          sptr = vector->base_addr + sstride0 * nelem;
239          n -= nelem;
240          while (n--)
241            {
242              memcpy (rptr, sptr, size);
243              rptr += rstride0;
244              sptr += sstride0;
245            }
246        }
247    }
248}
249
250extern void pack (gfc_array_char *, const gfc_array_char *,
251		  const gfc_array_l1 *, const gfc_array_char *);
252export_proto(pack);
253
254void
255pack (gfc_array_char *ret, const gfc_array_char *array,
256      const gfc_array_l1 *mask, const gfc_array_char *vector)
257{
258  index_type type_size;
259  index_type size;
260
261  type_size = GFC_DTYPE_TYPE_SIZE(array);
262
263  switch(type_size)
264    {
265    case GFC_DTYPE_LOGICAL_1:
266    case GFC_DTYPE_INTEGER_1:
267      pack_i1 ((gfc_array_i1 *) ret, (gfc_array_i1 *) array,
268	       (gfc_array_l1 *) mask, (gfc_array_i1 *) vector);
269      return;
270
271    case GFC_DTYPE_LOGICAL_2:
272    case GFC_DTYPE_INTEGER_2:
273      pack_i2 ((gfc_array_i2 *) ret, (gfc_array_i2 *) array,
274	       (gfc_array_l1 *) mask, (gfc_array_i2 *) vector);
275      return;
276
277    case GFC_DTYPE_LOGICAL_4:
278    case GFC_DTYPE_INTEGER_4:
279      pack_i4 ((gfc_array_i4 *) ret, (gfc_array_i4 *) array,
280	       (gfc_array_l1 *) mask, (gfc_array_i4 *) vector);
281      return;
282
283    case GFC_DTYPE_LOGICAL_8:
284    case GFC_DTYPE_INTEGER_8:
285      pack_i8 ((gfc_array_i8 *) ret, (gfc_array_i8 *) array,
286	       (gfc_array_l1 *) mask, (gfc_array_i8 *) vector);
287      return;
288
289#ifdef HAVE_GFC_INTEGER_16
290    case GFC_DTYPE_LOGICAL_16:
291    case GFC_DTYPE_INTEGER_16:
292      pack_i16 ((gfc_array_i16 *) ret, (gfc_array_i16 *) array,
293		(gfc_array_l1 *) mask, (gfc_array_i16 *) vector);
294      return;
295#endif
296
297    case GFC_DTYPE_REAL_4:
298      pack_r4 ((gfc_array_r4 *) ret, (gfc_array_r4 *) array,
299	       (gfc_array_l1 *) mask, (gfc_array_r4 *) vector);
300      return;
301
302    case GFC_DTYPE_REAL_8:
303      pack_r8 ((gfc_array_r8 *) ret, (gfc_array_r8 *) array,
304	       (gfc_array_l1 *) mask, (gfc_array_r8 *) vector);
305      return;
306
307/* FIXME: This here is a hack, which will have to be removed when
308   the array descriptor is reworked.  Currently, we don't store the
309   kind value for the type, but only the size.  Because on targets with
310   __float128, we have sizeof(logn double) == sizeof(__float128),
311   we cannot discriminate here and have to fall back to the generic
312   handling (which is suboptimal).  */
313#if !defined(GFC_REAL_16_IS_FLOAT128)
314# ifdef HAVE_GFC_REAL_10
315    case GFC_DTYPE_REAL_10:
316      pack_r10 ((gfc_array_r10 *) ret, (gfc_array_r10 *) array,
317		(gfc_array_l1 *) mask, (gfc_array_r10 *) vector);
318      return;
319# endif
320
321# ifdef HAVE_GFC_REAL_16
322    case GFC_DTYPE_REAL_16:
323      pack_r16 ((gfc_array_r16 *) ret, (gfc_array_r16 *) array,
324		(gfc_array_l1 *) mask, (gfc_array_r16 *) vector);
325      return;
326# endif
327#endif
328
329    case GFC_DTYPE_COMPLEX_4:
330      pack_c4 ((gfc_array_c4 *) ret, (gfc_array_c4 *) array,
331	       (gfc_array_l1 *) mask, (gfc_array_c4 *) vector);
332      return;
333
334    case GFC_DTYPE_COMPLEX_8:
335      pack_c8 ((gfc_array_c8 *) ret, (gfc_array_c8 *) array,
336	       (gfc_array_l1 *) mask, (gfc_array_c8 *) vector);
337      return;
338
339/* FIXME: This here is a hack, which will have to be removed when
340   the array descriptor is reworked.  Currently, we don't store the
341   kind value for the type, but only the size.  Because on targets with
342   __float128, we have sizeof(logn double) == sizeof(__float128),
343   we cannot discriminate here and have to fall back to the generic
344   handling (which is suboptimal).  */
345#if !defined(GFC_REAL_16_IS_FLOAT128)
346# ifdef HAVE_GFC_COMPLEX_10
347    case GFC_DTYPE_COMPLEX_10:
348      pack_c10 ((gfc_array_c10 *) ret, (gfc_array_c10 *) array,
349		(gfc_array_l1 *) mask, (gfc_array_c10 *) vector);
350      return;
351# endif
352
353# ifdef HAVE_GFC_COMPLEX_16
354    case GFC_DTYPE_COMPLEX_16:
355      pack_c16 ((gfc_array_c16 *) ret, (gfc_array_c16 *) array,
356		(gfc_array_l1 *) mask, (gfc_array_c16 *) vector);
357      return;
358# endif
359#endif
360    }
361
362  /* For other types, let's check the actual alignment of the data pointers.
363     If they are aligned, we can safely call the unpack functions.  */
364
365  switch (GFC_DESCRIPTOR_SIZE (array))
366    {
367    case 1:
368      pack_i1 ((gfc_array_i1 *) ret, (gfc_array_i1 *) array,
369	       (gfc_array_l1 *) mask, (gfc_array_i1 *) vector);
370      return;
371
372    case 2:
373      if (GFC_UNALIGNED_2(ret->base_addr) || GFC_UNALIGNED_2(array->base_addr)
374	  || (vector && GFC_UNALIGNED_2(vector->base_addr)))
375	break;
376      else
377	{
378	  pack_i2 ((gfc_array_i2 *) ret, (gfc_array_i2 *) array,
379		   (gfc_array_l1 *) mask, (gfc_array_i2 *) vector);
380	  return;
381	}
382
383    case 4:
384      if (GFC_UNALIGNED_4(ret->base_addr) || GFC_UNALIGNED_4(array->base_addr)
385	  || (vector && GFC_UNALIGNED_4(vector->base_addr)))
386	break;
387      else
388	{
389	  pack_i4 ((gfc_array_i4 *) ret, (gfc_array_i4 *) array,
390		   (gfc_array_l1 *) mask, (gfc_array_i4 *) vector);
391	  return;
392	}
393
394    case 8:
395      if (GFC_UNALIGNED_8(ret->base_addr) || GFC_UNALIGNED_8(array->base_addr)
396	  || (vector && GFC_UNALIGNED_8(vector->base_addr)))
397	break;
398      else
399	{
400	  pack_i8 ((gfc_array_i8 *) ret, (gfc_array_i8 *) array,
401		   (gfc_array_l1 *) mask, (gfc_array_i8 *) vector);
402	  return;
403	}
404
405#ifdef HAVE_GFC_INTEGER_16
406    case 16:
407      if (GFC_UNALIGNED_16(ret->base_addr) || GFC_UNALIGNED_16(array->base_addr)
408	  || (vector && GFC_UNALIGNED_16(vector->base_addr)))
409	break;
410      else
411	{
412	  pack_i16 ((gfc_array_i16 *) ret, (gfc_array_i16 *) array,
413		    (gfc_array_l1 *) mask, (gfc_array_i16 *) vector);
414	  return;
415	}
416#endif
417    default:
418      break;
419    }
420
421  size = GFC_DESCRIPTOR_SIZE (array);
422  pack_internal (ret, array, mask, vector, size);
423}
424
425
426extern void pack_char (gfc_array_char *, GFC_INTEGER_4, const gfc_array_char *,
427		       const gfc_array_l1 *, const gfc_array_char *,
428		       GFC_INTEGER_4, GFC_INTEGER_4);
429export_proto(pack_char);
430
431void
432pack_char (gfc_array_char *ret,
433	   GFC_INTEGER_4 ret_length __attribute__((unused)),
434	   const gfc_array_char *array, const gfc_array_l1 *mask,
435	   const gfc_array_char *vector, GFC_INTEGER_4 array_length,
436	   GFC_INTEGER_4 vector_length __attribute__((unused)))
437{
438  pack_internal (ret, array, mask, vector, array_length);
439}
440
441
442extern void pack_char4 (gfc_array_char *, GFC_INTEGER_4, const gfc_array_char *,
443			const gfc_array_l1 *, const gfc_array_char *,
444			GFC_INTEGER_4, GFC_INTEGER_4);
445export_proto(pack_char4);
446
447void
448pack_char4 (gfc_array_char *ret,
449	    GFC_INTEGER_4 ret_length __attribute__((unused)),
450	    const gfc_array_char *array, const gfc_array_l1 *mask,
451	    const gfc_array_char *vector, GFC_INTEGER_4 array_length,
452	    GFC_INTEGER_4 vector_length __attribute__((unused)))
453{
454  pack_internal (ret, array, mask, vector, array_length * sizeof (gfc_char4_t));
455}
456
457
458static void
459pack_s_internal (gfc_array_char *ret, const gfc_array_char *array,
460		 const GFC_LOGICAL_4 *mask, const gfc_array_char *vector,
461		 index_type size)
462{
463  /* r.* indicates the return array.  */
464  index_type rstride0;
465  char *rptr;
466  /* s.* indicates the source array.  */
467  index_type sstride[GFC_MAX_DIMENSIONS];
468  index_type sstride0;
469  const char *sptr;
470
471  index_type count[GFC_MAX_DIMENSIONS];
472  index_type extent[GFC_MAX_DIMENSIONS];
473  index_type n;
474  index_type dim;
475  index_type ssize;
476  index_type nelem;
477  index_type total;
478
479  dim = GFC_DESCRIPTOR_RANK (array);
480  /* Initialize sstride[0] to avoid -Wmaybe-uninitialized
481     complaints.  */
482  sstride[0] = size;
483  ssize = 1;
484  for (n = 0; n < dim; n++)
485    {
486      count[n] = 0;
487      extent[n] = GFC_DESCRIPTOR_EXTENT(array,n);
488      if (extent[n] < 0)
489	extent[n] = 0;
490
491      sstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(array,n);
492      ssize *= extent[n];
493    }
494  if (sstride[0] == 0)
495    sstride[0] = size;
496
497  sstride0 = sstride[0];
498
499  if (ssize != 0)
500    sptr = array->base_addr;
501  else
502    sptr = NULL;
503
504  if (ret->base_addr == NULL)
505    {
506      /* Allocate the memory for the result.  */
507
508      if (vector != NULL)
509	{
510	  /* The return array will have as many elements as there are
511	     in vector.  */
512	  total = GFC_DESCRIPTOR_EXTENT(vector,0);
513	  if (total <= 0)
514	    {
515	      total = 0;
516	      vector = NULL;
517	    }
518	}
519      else
520	{
521	  if (*mask)
522	    {
523	      /* The result array will have as many elements as the input
524		 array.  */
525	      total = extent[0];
526	      for (n = 1; n < dim; n++)
527		total *= extent[n];
528	    }
529	  else
530	    /* The result array will be empty.  */
531	    total = 0;
532	}
533
534      /* Setup the array descriptor.  */
535      GFC_DIMENSION_SET(ret->dim[0],0,total-1,1);
536
537      ret->offset = 0;
538
539      ret->base_addr = xmallocarray (total, size);
540
541      if (total == 0)
542	return;
543    }
544
545  rstride0 = GFC_DESCRIPTOR_STRIDE_BYTES(ret,0);
546  if (rstride0 == 0)
547    rstride0 = size;
548  rptr = ret->base_addr;
549
550  /* The remaining possibilities are now:
551       If MASK is .TRUE., we have to copy the source array into the
552     result array. We then have to fill it up with elements from VECTOR.
553       If MASK is .FALSE., we have to copy VECTOR into the result
554     array. If VECTOR were not present we would have already returned.  */
555
556  if (*mask && ssize != 0)
557    {
558      while (sptr)
559	{
560	  /* Add this element.  */
561	  memcpy (rptr, sptr, size);
562	  rptr += rstride0;
563
564	  /* Advance to the next element.  */
565	  sptr += sstride0;
566	  count[0]++;
567	  n = 0;
568	  while (count[n] == extent[n])
569	    {
570	      /* When we get to the end of a dimension, reset it and
571		 increment the next dimension.  */
572	      count[n] = 0;
573	      /* We could precalculate these products, but this is a
574		 less frequently used path so probably not worth it.  */
575	      sptr -= sstride[n] * extent[n];
576	      n++;
577	      if (n >= dim)
578		{
579		  /* Break out of the loop.  */
580		  sptr = NULL;
581		  break;
582		}
583	      else
584		{
585		  count[n]++;
586		  sptr += sstride[n];
587		}
588	    }
589	}
590    }
591
592  /* Add any remaining elements from VECTOR.  */
593  if (vector)
594    {
595      n = GFC_DESCRIPTOR_EXTENT(vector,0);
596      nelem = ((rptr - ret->base_addr) / rstride0);
597      if (n > nelem)
598        {
599          sstride0 = GFC_DESCRIPTOR_STRIDE_BYTES(vector,0);
600          if (sstride0 == 0)
601            sstride0 = size;
602
603          sptr = vector->base_addr + sstride0 * nelem;
604          n -= nelem;
605          while (n--)
606            {
607              memcpy (rptr, sptr, size);
608              rptr += rstride0;
609              sptr += sstride0;
610            }
611        }
612    }
613}
614
615extern void pack_s (gfc_array_char *ret, const gfc_array_char *array,
616		    const GFC_LOGICAL_4 *, const gfc_array_char *);
617export_proto(pack_s);
618
619void
620pack_s (gfc_array_char *ret, const gfc_array_char *array,
621	const GFC_LOGICAL_4 *mask, const gfc_array_char *vector)
622{
623  pack_s_internal (ret, array, mask, vector, GFC_DESCRIPTOR_SIZE (array));
624}
625
626
627extern void pack_s_char (gfc_array_char *ret, GFC_INTEGER_4,
628			 const gfc_array_char *array, const GFC_LOGICAL_4 *,
629			 const gfc_array_char *, GFC_INTEGER_4,
630			 GFC_INTEGER_4);
631export_proto(pack_s_char);
632
633void
634pack_s_char (gfc_array_char *ret,
635	     GFC_INTEGER_4 ret_length __attribute__((unused)),
636	     const gfc_array_char *array, const GFC_LOGICAL_4 *mask,
637	     const gfc_array_char *vector, GFC_INTEGER_4 array_length,
638	     GFC_INTEGER_4 vector_length __attribute__((unused)))
639{
640  pack_s_internal (ret, array, mask, vector, array_length);
641}
642
643
644extern void pack_s_char4 (gfc_array_char *ret, GFC_INTEGER_4,
645			  const gfc_array_char *array, const GFC_LOGICAL_4 *,
646			  const gfc_array_char *, GFC_INTEGER_4,
647			  GFC_INTEGER_4);
648export_proto(pack_s_char4);
649
650void
651pack_s_char4 (gfc_array_char *ret,
652	      GFC_INTEGER_4 ret_length __attribute__((unused)),
653	      const gfc_array_char *array, const GFC_LOGICAL_4 *mask,
654	      const gfc_array_char *vector, GFC_INTEGER_4 array_length,
655	      GFC_INTEGER_4 vector_length __attribute__((unused)))
656{
657  pack_s_internal (ret, array, mask, vector,
658		   array_length * sizeof (gfc_char4_t));
659}
660