xref: /netbsd-src/external/gpl3/gcc.old/dist/libgfortran/m4/pack.m4 (revision 4c3eb207d36f67d31994830c0a694161fc1ca39b)
1627f7eb2Smrg`/* Specific implementation of the PACK intrinsic
2*4c3eb207Smrg   Copyright (C) 2002-2020 Free Software Foundation, Inc.
3627f7eb2Smrg   Contributed by Paul Brook <paul@nowt.org>
4627f7eb2Smrg
5627f7eb2SmrgThis file is part of the GNU Fortran runtime library (libgfortran).
6627f7eb2Smrg
7627f7eb2SmrgLibgfortran is free software; you can redistribute it and/or
8627f7eb2Smrgmodify it under the terms of the GNU General Public
9627f7eb2SmrgLicense as published by the Free Software Foundation; either
10627f7eb2Smrgversion 3 of the License, or (at your option) any later version.
11627f7eb2Smrg
12627f7eb2SmrgLigbfortran is distributed in the hope that it will be useful,
13627f7eb2Smrgbut WITHOUT ANY WARRANTY; without even the implied warranty of
14627f7eb2SmrgMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15627f7eb2SmrgGNU General Public License for more details.
16627f7eb2Smrg
17627f7eb2SmrgUnder Section 7 of GPL version 3, you are granted additional
18627f7eb2Smrgpermissions described in the GCC Runtime Library Exception, version
19627f7eb2Smrg3.1, as published by the Free Software Foundation.
20627f7eb2Smrg
21627f7eb2SmrgYou should have received a copy of the GNU General Public License and
22627f7eb2Smrga copy of the GCC Runtime Library Exception along with this program;
23627f7eb2Smrgsee the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
24627f7eb2Smrg<http://www.gnu.org/licenses/>.  */
25627f7eb2Smrg
26627f7eb2Smrg#include "libgfortran.h"
27627f7eb2Smrg#include <string.h>'
28627f7eb2Smrg
29627f7eb2Smrginclude(iparm.m4)dnl
30627f7eb2Smrg
31627f7eb2Smrg`#if defined (HAVE_'rtype_name`)
32627f7eb2Smrg
33627f7eb2Smrg/* PACK is specified as follows:
34627f7eb2Smrg
35627f7eb2Smrg   13.14.80 PACK (ARRAY, MASK, [VECTOR])
36627f7eb2Smrg
37627f7eb2Smrg   Description: Pack an array into an array of rank one under the
38627f7eb2Smrg   control of a mask.
39627f7eb2Smrg
40627f7eb2Smrg   Class: Transformational function.
41627f7eb2Smrg
42627f7eb2Smrg   Arguments:
43627f7eb2Smrg      ARRAY   may be of any type. It shall not be scalar.
44627f7eb2Smrg      MASK    shall be of type LOGICAL. It shall be conformable with ARRAY.
45627f7eb2Smrg      VECTOR  (optional) shall be of the same type and type parameters
46627f7eb2Smrg              as ARRAY. VECTOR shall have at least as many elements as
47627f7eb2Smrg              there are true elements in MASK. If MASK is a scalar
48627f7eb2Smrg              with the value true, VECTOR shall have at least as many
49627f7eb2Smrg              elements as there are in ARRAY.
50627f7eb2Smrg
51627f7eb2Smrg   Result Characteristics: The result is an array of rank one with the
52627f7eb2Smrg   same type and type parameters as ARRAY. If VECTOR is present, the
53627f7eb2Smrg   result size is that of VECTOR; otherwise, the result size is the
54627f7eb2Smrg   number /t/ of true elements in MASK unless MASK is scalar with the
55627f7eb2Smrg   value true, in which case the result size is the size of ARRAY.
56627f7eb2Smrg
57627f7eb2Smrg   Result Value: Element /i/ of the result is the element of ARRAY
58627f7eb2Smrg   that corresponds to the /i/th true element of MASK, taking elements
59627f7eb2Smrg   in array element order, for /i/ = 1, 2, ..., /t/. If VECTOR is
60627f7eb2Smrg   present and has size /n/ > /t/, element /i/ of the result has the
61627f7eb2Smrg   value VECTOR(/i/), for /i/ = /t/ + 1, ..., /n/.
62627f7eb2Smrg
63627f7eb2Smrg   Examples: The nonzero elements of an array M with the value
64627f7eb2Smrg   | 0 0 0 |
65627f7eb2Smrg   | 9 0 0 | may be "gathered" by the function PACK. The result of
66627f7eb2Smrg   | 0 0 7 |
67627f7eb2Smrg   PACK (M, MASK = M.NE.0) is [9,7] and the result of PACK (M, M.NE.0,
68627f7eb2Smrg   VECTOR = (/ 2,4,6,8,10,12 /)) is [9,7,6,8,10,12].
69627f7eb2Smrg
70627f7eb2SmrgThere are two variants of the PACK intrinsic: one, where MASK is
71627f7eb2Smrgarray valued, and the other one where MASK is scalar.  */
72627f7eb2Smrg
73627f7eb2Smrgvoid
74627f7eb2Smrgpack_'rtype_code` ('rtype` *ret, const 'rtype` *array,
75627f7eb2Smrg	       const gfc_array_l1 *mask, const 'rtype` *vector)
76627f7eb2Smrg{
77627f7eb2Smrg  /* r.* indicates the return array.  */
78627f7eb2Smrg  index_type rstride0;
79627f7eb2Smrg  'rtype_name` * restrict rptr;
80627f7eb2Smrg  /* s.* indicates the source array.  */
81627f7eb2Smrg  index_type sstride[GFC_MAX_DIMENSIONS];
82627f7eb2Smrg  index_type sstride0;
83627f7eb2Smrg  const 'rtype_name` *sptr;
84627f7eb2Smrg  /* m.* indicates the mask array.  */
85627f7eb2Smrg  index_type mstride[GFC_MAX_DIMENSIONS];
86627f7eb2Smrg  index_type mstride0;
87627f7eb2Smrg  const GFC_LOGICAL_1 *mptr;
88627f7eb2Smrg
89627f7eb2Smrg  index_type count[GFC_MAX_DIMENSIONS];
90627f7eb2Smrg  index_type extent[GFC_MAX_DIMENSIONS];
91627f7eb2Smrg  int zero_sized;
92627f7eb2Smrg  index_type n;
93627f7eb2Smrg  index_type dim;
94627f7eb2Smrg  index_type nelem;
95627f7eb2Smrg  index_type total;
96627f7eb2Smrg  int mask_kind;
97627f7eb2Smrg
98627f7eb2Smrg  dim = GFC_DESCRIPTOR_RANK (array);
99627f7eb2Smrg
100627f7eb2Smrg  mptr = mask->base_addr;
101627f7eb2Smrg
102627f7eb2Smrg  /* Use the same loop for all logical types, by using GFC_LOGICAL_1
103627f7eb2Smrg     and using shifting to address size and endian issues.  */
104627f7eb2Smrg
105627f7eb2Smrg  mask_kind = GFC_DESCRIPTOR_SIZE (mask);
106627f7eb2Smrg
107627f7eb2Smrg  if (mask_kind == 1 || mask_kind == 2 || mask_kind == 4 || mask_kind == 8
108627f7eb2Smrg#ifdef HAVE_GFC_LOGICAL_16
109627f7eb2Smrg      || mask_kind == 16
110627f7eb2Smrg#endif
111627f7eb2Smrg      )
112627f7eb2Smrg    {
113627f7eb2Smrg      /*  Do not convert a NULL pointer as we use test for NULL below.  */
114627f7eb2Smrg      if (mptr)
115627f7eb2Smrg	mptr = GFOR_POINTER_TO_L1 (mptr, mask_kind);
116627f7eb2Smrg    }
117627f7eb2Smrg  else
118627f7eb2Smrg    runtime_error ("Funny sized logical array");
119627f7eb2Smrg
120627f7eb2Smrg  zero_sized = 0;
121627f7eb2Smrg  for (n = 0; n < dim; n++)
122627f7eb2Smrg    {
123627f7eb2Smrg      count[n] = 0;
124627f7eb2Smrg      extent[n] = GFC_DESCRIPTOR_EXTENT(array,n);
125627f7eb2Smrg      if (extent[n] <= 0)
126627f7eb2Smrg       zero_sized = 1;
127627f7eb2Smrg      sstride[n] = GFC_DESCRIPTOR_STRIDE(array,n);
128627f7eb2Smrg      mstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(mask,n);
129627f7eb2Smrg    }
130627f7eb2Smrg  if (sstride[0] == 0)
131627f7eb2Smrg    sstride[0] = 1;
132627f7eb2Smrg  if (mstride[0] == 0)
133627f7eb2Smrg    mstride[0] = mask_kind;
134627f7eb2Smrg
135627f7eb2Smrg  if (zero_sized)
136627f7eb2Smrg    sptr = NULL;
137627f7eb2Smrg  else
138627f7eb2Smrg    sptr = array->base_addr;
139627f7eb2Smrg
140627f7eb2Smrg  if (ret->base_addr == NULL || unlikely (compile_options.bounds_check))
141627f7eb2Smrg    {
142627f7eb2Smrg      /* Count the elements, either for allocating memory or
143627f7eb2Smrg	 for bounds checking.  */
144627f7eb2Smrg
145627f7eb2Smrg      if (vector != NULL)
146627f7eb2Smrg	{
147627f7eb2Smrg	  /* The return array will have as many
148627f7eb2Smrg	     elements as there are in VECTOR.  */
149627f7eb2Smrg	  total = GFC_DESCRIPTOR_EXTENT(vector,0);
150627f7eb2Smrg	  if (total < 0)
151627f7eb2Smrg	    {
152627f7eb2Smrg	      total = 0;
153627f7eb2Smrg	      vector = NULL;
154627f7eb2Smrg	    }
155627f7eb2Smrg	}
156627f7eb2Smrg      else
157627f7eb2Smrg        {
158627f7eb2Smrg      	  /* We have to count the true elements in MASK.  */
159627f7eb2Smrg	  total = count_0 (mask);
160627f7eb2Smrg        }
161627f7eb2Smrg
162627f7eb2Smrg      if (ret->base_addr == NULL)
163627f7eb2Smrg	{
164627f7eb2Smrg	  /* Setup the array descriptor.  */
165627f7eb2Smrg	  GFC_DIMENSION_SET(ret->dim[0], 0, total-1, 1);
166627f7eb2Smrg
167627f7eb2Smrg	  ret->offset = 0;
168627f7eb2Smrg
169627f7eb2Smrg	  /* xmallocarray allocates a single byte for zero size.  */
170627f7eb2Smrg	  ret->base_addr = xmallocarray (total, sizeof ('rtype_name`));
171627f7eb2Smrg
172627f7eb2Smrg	  if (total == 0)
173627f7eb2Smrg	    return;
174627f7eb2Smrg	}
175627f7eb2Smrg      else
176627f7eb2Smrg	{
177627f7eb2Smrg	  /* We come here because of range checking.  */
178627f7eb2Smrg	  index_type ret_extent;
179627f7eb2Smrg
180627f7eb2Smrg	  ret_extent = GFC_DESCRIPTOR_EXTENT(ret,0);
181627f7eb2Smrg	  if (total != ret_extent)
182627f7eb2Smrg	    runtime_error ("Incorrect extent in return value of PACK intrinsic;"
183627f7eb2Smrg			   " is %ld, should be %ld", (long int) total,
184627f7eb2Smrg			   (long int) ret_extent);
185627f7eb2Smrg	}
186627f7eb2Smrg    }
187627f7eb2Smrg
188627f7eb2Smrg  rstride0 = GFC_DESCRIPTOR_STRIDE(ret,0);
189627f7eb2Smrg  if (rstride0 == 0)
190627f7eb2Smrg    rstride0 = 1;
191627f7eb2Smrg  sstride0 = sstride[0];
192627f7eb2Smrg  mstride0 = mstride[0];
193627f7eb2Smrg  rptr = ret->base_addr;
194627f7eb2Smrg
195627f7eb2Smrg  while (sptr && mptr)
196627f7eb2Smrg    {
197627f7eb2Smrg      /* Test this element.  */
198627f7eb2Smrg      if (*mptr)
199627f7eb2Smrg        {
200627f7eb2Smrg          /* Add it.  */
201627f7eb2Smrg	  *rptr = *sptr;
202627f7eb2Smrg          rptr += rstride0;
203627f7eb2Smrg        }
204627f7eb2Smrg      /* Advance to the next element.  */
205627f7eb2Smrg      sptr += sstride0;
206627f7eb2Smrg      mptr += mstride0;
207627f7eb2Smrg      count[0]++;
208627f7eb2Smrg      n = 0;
209627f7eb2Smrg      while (count[n] == extent[n])
210627f7eb2Smrg        {
211627f7eb2Smrg          /* When we get to the end of a dimension, reset it and increment
212627f7eb2Smrg             the next dimension.  */
213627f7eb2Smrg          count[n] = 0;
214627f7eb2Smrg          /* We could precalculate these products, but this is a less
215627f7eb2Smrg             frequently used path so probably not worth it.  */
216627f7eb2Smrg          sptr -= sstride[n] * extent[n];
217627f7eb2Smrg          mptr -= mstride[n] * extent[n];
218627f7eb2Smrg          n++;
219627f7eb2Smrg          if (n >= dim)
220627f7eb2Smrg            {
221627f7eb2Smrg              /* Break out of the loop.  */
222627f7eb2Smrg              sptr = NULL;
223627f7eb2Smrg              break;
224627f7eb2Smrg            }
225627f7eb2Smrg          else
226627f7eb2Smrg            {
227627f7eb2Smrg              count[n]++;
228627f7eb2Smrg              sptr += sstride[n];
229627f7eb2Smrg              mptr += mstride[n];
230627f7eb2Smrg            }
231627f7eb2Smrg        }
232627f7eb2Smrg    }
233627f7eb2Smrg
234627f7eb2Smrg  /* Add any remaining elements from VECTOR.  */
235627f7eb2Smrg  if (vector)
236627f7eb2Smrg    {
237627f7eb2Smrg      n = GFC_DESCRIPTOR_EXTENT(vector,0);
238627f7eb2Smrg      nelem = ((rptr - ret->base_addr) / rstride0);
239627f7eb2Smrg      if (n > nelem)
240627f7eb2Smrg        {
241627f7eb2Smrg          sstride0 = GFC_DESCRIPTOR_STRIDE(vector,0);
242627f7eb2Smrg          if (sstride0 == 0)
243627f7eb2Smrg            sstride0 = 1;
244627f7eb2Smrg
245627f7eb2Smrg          sptr = vector->base_addr + sstride0 * nelem;
246627f7eb2Smrg          n -= nelem;
247627f7eb2Smrg          while (n--)
248627f7eb2Smrg            {
249627f7eb2Smrg	      *rptr = *sptr;
250627f7eb2Smrg              rptr += rstride0;
251627f7eb2Smrg              sptr += sstride0;
252627f7eb2Smrg            }
253627f7eb2Smrg        }
254627f7eb2Smrg    }
255627f7eb2Smrg}
256627f7eb2Smrg
257627f7eb2Smrg#endif
258627f7eb2Smrg'
259