1*b1e83836Smrg /* Specific implementation of the PACK intrinsic
2*b1e83836Smrg Copyright (C) 2002-2022 Free Software Foundation, Inc.
3*b1e83836Smrg Contributed by Paul Brook <paul@nowt.org>
4*b1e83836Smrg
5*b1e83836Smrg This file is part of the GNU Fortran runtime library (libgfortran).
6*b1e83836Smrg
7*b1e83836Smrg Libgfortran is free software; you can redistribute it and/or
8*b1e83836Smrg modify it under the terms of the GNU General Public
9*b1e83836Smrg License as published by the Free Software Foundation; either
10*b1e83836Smrg version 3 of the License, or (at your option) any later version.
11*b1e83836Smrg
12*b1e83836Smrg Ligbfortran is distributed in the hope that it will be useful,
13*b1e83836Smrg but WITHOUT ANY WARRANTY; without even the implied warranty of
14*b1e83836Smrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15*b1e83836Smrg GNU General Public License for more details.
16*b1e83836Smrg
17*b1e83836Smrg Under Section 7 of GPL version 3, you are granted additional
18*b1e83836Smrg permissions described in the GCC Runtime Library Exception, version
19*b1e83836Smrg 3.1, as published by the Free Software Foundation.
20*b1e83836Smrg
21*b1e83836Smrg You should have received a copy of the GNU General Public License and
22*b1e83836Smrg a copy of the GCC Runtime Library Exception along with this program;
23*b1e83836Smrg see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
24*b1e83836Smrg <http://www.gnu.org/licenses/>. */
25*b1e83836Smrg
26*b1e83836Smrg #include "libgfortran.h"
27*b1e83836Smrg #include <string.h>
28*b1e83836Smrg
29*b1e83836Smrg
30*b1e83836Smrg #if defined (HAVE_GFC_COMPLEX_17)
31*b1e83836Smrg
32*b1e83836Smrg /* PACK is specified as follows:
33*b1e83836Smrg
34*b1e83836Smrg 13.14.80 PACK (ARRAY, MASK, [VECTOR])
35*b1e83836Smrg
36*b1e83836Smrg Description: Pack an array into an array of rank one under the
37*b1e83836Smrg control of a mask.
38*b1e83836Smrg
39*b1e83836Smrg Class: Transformational function.
40*b1e83836Smrg
41*b1e83836Smrg Arguments:
42*b1e83836Smrg ARRAY may be of any type. It shall not be scalar.
43*b1e83836Smrg MASK shall be of type LOGICAL. It shall be conformable with ARRAY.
44*b1e83836Smrg VECTOR (optional) shall be of the same type and type parameters
45*b1e83836Smrg as ARRAY. VECTOR shall have at least as many elements as
46*b1e83836Smrg there are true elements in MASK. If MASK is a scalar
47*b1e83836Smrg with the value true, VECTOR shall have at least as many
48*b1e83836Smrg elements as there are in ARRAY.
49*b1e83836Smrg
50*b1e83836Smrg Result Characteristics: The result is an array of rank one with the
51*b1e83836Smrg same type and type parameters as ARRAY. If VECTOR is present, the
52*b1e83836Smrg result size is that of VECTOR; otherwise, the result size is the
53*b1e83836Smrg number /t/ of true elements in MASK unless MASK is scalar with the
54*b1e83836Smrg value true, in which case the result size is the size of ARRAY.
55*b1e83836Smrg
56*b1e83836Smrg Result Value: Element /i/ of the result is the element of ARRAY
57*b1e83836Smrg that corresponds to the /i/th true element of MASK, taking elements
58*b1e83836Smrg in array element order, for /i/ = 1, 2, ..., /t/. If VECTOR is
59*b1e83836Smrg present and has size /n/ > /t/, element /i/ of the result has the
60*b1e83836Smrg value VECTOR(/i/), for /i/ = /t/ + 1, ..., /n/.
61*b1e83836Smrg
62*b1e83836Smrg Examples: The nonzero elements of an array M with the value
63*b1e83836Smrg | 0 0 0 |
64*b1e83836Smrg | 9 0 0 | may be "gathered" by the function PACK. The result of
65*b1e83836Smrg | 0 0 7 |
66*b1e83836Smrg PACK (M, MASK = M.NE.0) is [9,7] and the result of PACK (M, M.NE.0,
67*b1e83836Smrg VECTOR = (/ 2,4,6,8,10,12 /)) is [9,7,6,8,10,12].
68*b1e83836Smrg
69*b1e83836Smrg There are two variants of the PACK intrinsic: one, where MASK is
70*b1e83836Smrg array valued, and the other one where MASK is scalar. */
71*b1e83836Smrg
72*b1e83836Smrg void
pack_c17(gfc_array_c17 * ret,const gfc_array_c17 * array,const gfc_array_l1 * mask,const gfc_array_c17 * vector)73*b1e83836Smrg pack_c17 (gfc_array_c17 *ret, const gfc_array_c17 *array,
74*b1e83836Smrg const gfc_array_l1 *mask, const gfc_array_c17 *vector)
75*b1e83836Smrg {
76*b1e83836Smrg /* r.* indicates the return array. */
77*b1e83836Smrg index_type rstride0;
78*b1e83836Smrg GFC_COMPLEX_17 * restrict rptr;
79*b1e83836Smrg /* s.* indicates the source array. */
80*b1e83836Smrg index_type sstride[GFC_MAX_DIMENSIONS];
81*b1e83836Smrg index_type sstride0;
82*b1e83836Smrg const GFC_COMPLEX_17 *sptr;
83*b1e83836Smrg /* m.* indicates the mask array. */
84*b1e83836Smrg index_type mstride[GFC_MAX_DIMENSIONS];
85*b1e83836Smrg index_type mstride0;
86*b1e83836Smrg const GFC_LOGICAL_1 *mptr;
87*b1e83836Smrg
88*b1e83836Smrg index_type count[GFC_MAX_DIMENSIONS];
89*b1e83836Smrg index_type extent[GFC_MAX_DIMENSIONS];
90*b1e83836Smrg int zero_sized;
91*b1e83836Smrg index_type n;
92*b1e83836Smrg index_type dim;
93*b1e83836Smrg index_type nelem;
94*b1e83836Smrg index_type total;
95*b1e83836Smrg int mask_kind;
96*b1e83836Smrg
97*b1e83836Smrg dim = GFC_DESCRIPTOR_RANK (array);
98*b1e83836Smrg
99*b1e83836Smrg mptr = mask->base_addr;
100*b1e83836Smrg
101*b1e83836Smrg /* Use the same loop for all logical types, by using GFC_LOGICAL_1
102*b1e83836Smrg and using shifting to address size and endian issues. */
103*b1e83836Smrg
104*b1e83836Smrg mask_kind = GFC_DESCRIPTOR_SIZE (mask);
105*b1e83836Smrg
106*b1e83836Smrg if (mask_kind == 1 || mask_kind == 2 || mask_kind == 4 || mask_kind == 8
107*b1e83836Smrg #ifdef HAVE_GFC_LOGICAL_16
108*b1e83836Smrg || mask_kind == 16
109*b1e83836Smrg #endif
110*b1e83836Smrg )
111*b1e83836Smrg {
112*b1e83836Smrg /* Do not convert a NULL pointer as we use test for NULL below. */
113*b1e83836Smrg if (mptr)
114*b1e83836Smrg mptr = GFOR_POINTER_TO_L1 (mptr, mask_kind);
115*b1e83836Smrg }
116*b1e83836Smrg else
117*b1e83836Smrg runtime_error ("Funny sized logical array");
118*b1e83836Smrg
119*b1e83836Smrg zero_sized = 0;
120*b1e83836Smrg for (n = 0; n < dim; n++)
121*b1e83836Smrg {
122*b1e83836Smrg count[n] = 0;
123*b1e83836Smrg extent[n] = GFC_DESCRIPTOR_EXTENT(array,n);
124*b1e83836Smrg if (extent[n] <= 0)
125*b1e83836Smrg zero_sized = 1;
126*b1e83836Smrg sstride[n] = GFC_DESCRIPTOR_STRIDE(array,n);
127*b1e83836Smrg mstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(mask,n);
128*b1e83836Smrg }
129*b1e83836Smrg if (sstride[0] == 0)
130*b1e83836Smrg sstride[0] = 1;
131*b1e83836Smrg if (mstride[0] == 0)
132*b1e83836Smrg mstride[0] = mask_kind;
133*b1e83836Smrg
134*b1e83836Smrg if (zero_sized)
135*b1e83836Smrg sptr = NULL;
136*b1e83836Smrg else
137*b1e83836Smrg sptr = array->base_addr;
138*b1e83836Smrg
139*b1e83836Smrg if (ret->base_addr == NULL || unlikely (compile_options.bounds_check))
140*b1e83836Smrg {
141*b1e83836Smrg /* Count the elements, either for allocating memory or
142*b1e83836Smrg for bounds checking. */
143*b1e83836Smrg
144*b1e83836Smrg if (vector != NULL)
145*b1e83836Smrg {
146*b1e83836Smrg /* The return array will have as many
147*b1e83836Smrg elements as there are in VECTOR. */
148*b1e83836Smrg total = GFC_DESCRIPTOR_EXTENT(vector,0);
149*b1e83836Smrg if (total < 0)
150*b1e83836Smrg {
151*b1e83836Smrg total = 0;
152*b1e83836Smrg vector = NULL;
153*b1e83836Smrg }
154*b1e83836Smrg }
155*b1e83836Smrg else
156*b1e83836Smrg {
157*b1e83836Smrg /* We have to count the true elements in MASK. */
158*b1e83836Smrg total = count_0 (mask);
159*b1e83836Smrg }
160*b1e83836Smrg
161*b1e83836Smrg if (ret->base_addr == NULL)
162*b1e83836Smrg {
163*b1e83836Smrg /* Setup the array descriptor. */
164*b1e83836Smrg GFC_DIMENSION_SET(ret->dim[0], 0, total-1, 1);
165*b1e83836Smrg
166*b1e83836Smrg ret->offset = 0;
167*b1e83836Smrg
168*b1e83836Smrg /* xmallocarray allocates a single byte for zero size. */
169*b1e83836Smrg ret->base_addr = xmallocarray (total, sizeof (GFC_COMPLEX_17));
170*b1e83836Smrg
171*b1e83836Smrg if (total == 0)
172*b1e83836Smrg return;
173*b1e83836Smrg }
174*b1e83836Smrg else
175*b1e83836Smrg {
176*b1e83836Smrg /* We come here because of range checking. */
177*b1e83836Smrg index_type ret_extent;
178*b1e83836Smrg
179*b1e83836Smrg ret_extent = GFC_DESCRIPTOR_EXTENT(ret,0);
180*b1e83836Smrg if (total != ret_extent)
181*b1e83836Smrg runtime_error ("Incorrect extent in return value of PACK intrinsic;"
182*b1e83836Smrg " is %ld, should be %ld", (long int) total,
183*b1e83836Smrg (long int) ret_extent);
184*b1e83836Smrg }
185*b1e83836Smrg }
186*b1e83836Smrg
187*b1e83836Smrg rstride0 = GFC_DESCRIPTOR_STRIDE(ret,0);
188*b1e83836Smrg if (rstride0 == 0)
189*b1e83836Smrg rstride0 = 1;
190*b1e83836Smrg sstride0 = sstride[0];
191*b1e83836Smrg mstride0 = mstride[0];
192*b1e83836Smrg rptr = ret->base_addr;
193*b1e83836Smrg
194*b1e83836Smrg while (sptr && mptr)
195*b1e83836Smrg {
196*b1e83836Smrg /* Test this element. */
197*b1e83836Smrg if (*mptr)
198*b1e83836Smrg {
199*b1e83836Smrg /* Add it. */
200*b1e83836Smrg *rptr = *sptr;
201*b1e83836Smrg rptr += rstride0;
202*b1e83836Smrg }
203*b1e83836Smrg /* Advance to the next element. */
204*b1e83836Smrg sptr += sstride0;
205*b1e83836Smrg mptr += mstride0;
206*b1e83836Smrg count[0]++;
207*b1e83836Smrg n = 0;
208*b1e83836Smrg while (count[n] == extent[n])
209*b1e83836Smrg {
210*b1e83836Smrg /* When we get to the end of a dimension, reset it and increment
211*b1e83836Smrg the next dimension. */
212*b1e83836Smrg count[n] = 0;
213*b1e83836Smrg /* We could precalculate these products, but this is a less
214*b1e83836Smrg frequently used path so probably not worth it. */
215*b1e83836Smrg sptr -= sstride[n] * extent[n];
216*b1e83836Smrg mptr -= mstride[n] * extent[n];
217*b1e83836Smrg n++;
218*b1e83836Smrg if (n >= dim)
219*b1e83836Smrg {
220*b1e83836Smrg /* Break out of the loop. */
221*b1e83836Smrg sptr = NULL;
222*b1e83836Smrg break;
223*b1e83836Smrg }
224*b1e83836Smrg else
225*b1e83836Smrg {
226*b1e83836Smrg count[n]++;
227*b1e83836Smrg sptr += sstride[n];
228*b1e83836Smrg mptr += mstride[n];
229*b1e83836Smrg }
230*b1e83836Smrg }
231*b1e83836Smrg }
232*b1e83836Smrg
233*b1e83836Smrg /* Add any remaining elements from VECTOR. */
234*b1e83836Smrg if (vector)
235*b1e83836Smrg {
236*b1e83836Smrg n = GFC_DESCRIPTOR_EXTENT(vector,0);
237*b1e83836Smrg nelem = ((rptr - ret->base_addr) / rstride0);
238*b1e83836Smrg if (n > nelem)
239*b1e83836Smrg {
240*b1e83836Smrg sstride0 = GFC_DESCRIPTOR_STRIDE(vector,0);
241*b1e83836Smrg if (sstride0 == 0)
242*b1e83836Smrg sstride0 = 1;
243*b1e83836Smrg
244*b1e83836Smrg sptr = vector->base_addr + sstride0 * nelem;
245*b1e83836Smrg n -= nelem;
246*b1e83836Smrg while (n--)
247*b1e83836Smrg {
248*b1e83836Smrg *rptr = *sptr;
249*b1e83836Smrg rptr += rstride0;
250*b1e83836Smrg sptr += sstride0;
251*b1e83836Smrg }
252*b1e83836Smrg }
253*b1e83836Smrg }
254*b1e83836Smrg }
255*b1e83836Smrg
256*b1e83836Smrg #endif
257*b1e83836Smrg
258