1*b1e83836Smrg /* Specific implementation of the UNPACK intrinsic
2*b1e83836Smrg Copyright (C) 2008-2022 Free Software Foundation, Inc.
3*b1e83836Smrg Contributed by Thomas Koenig <tkoenig@gcc.gnu.org>, based on
4*b1e83836Smrg unpack_generic.c by Paul Brook <paul@nowt.org>.
5*b1e83836Smrg
6*b1e83836Smrg This file is part of the GNU Fortran runtime library (libgfortran).
7*b1e83836Smrg
8*b1e83836Smrg Libgfortran is free software; you can redistribute it and/or
9*b1e83836Smrg modify it under the terms of the GNU General Public
10*b1e83836Smrg License as published by the Free Software Foundation; either
11*b1e83836Smrg version 3 of the License, or (at your option) any later version.
12*b1e83836Smrg
13*b1e83836Smrg Ligbfortran is distributed in the hope that it will be useful,
14*b1e83836Smrg but WITHOUT ANY WARRANTY; without even the implied warranty of
15*b1e83836Smrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16*b1e83836Smrg GNU General Public License for more details.
17*b1e83836Smrg
18*b1e83836Smrg Under Section 7 of GPL version 3, you are granted additional
19*b1e83836Smrg permissions described in the GCC Runtime Library Exception, version
20*b1e83836Smrg 3.1, as published by the Free Software Foundation.
21*b1e83836Smrg
22*b1e83836Smrg You should have received a copy of the GNU General Public License and
23*b1e83836Smrg a copy of the GCC Runtime Library Exception along with this program;
24*b1e83836Smrg see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
25*b1e83836Smrg <http://www.gnu.org/licenses/>. */
26*b1e83836Smrg
27*b1e83836Smrg #include "libgfortran.h"
28*b1e83836Smrg #include <string.h>
29*b1e83836Smrg
30*b1e83836Smrg
31*b1e83836Smrg #if defined (HAVE_GFC_COMPLEX_17)
32*b1e83836Smrg
33*b1e83836Smrg void
unpack0_c17(gfc_array_c17 * ret,const gfc_array_c17 * vector,const gfc_array_l1 * mask,const GFC_COMPLEX_17 * fptr)34*b1e83836Smrg unpack0_c17 (gfc_array_c17 *ret, const gfc_array_c17 *vector,
35*b1e83836Smrg const gfc_array_l1 *mask, const GFC_COMPLEX_17 *fptr)
36*b1e83836Smrg {
37*b1e83836Smrg /* r.* indicates the return array. */
38*b1e83836Smrg index_type rstride[GFC_MAX_DIMENSIONS];
39*b1e83836Smrg index_type rstride0;
40*b1e83836Smrg index_type rs;
41*b1e83836Smrg GFC_COMPLEX_17 * restrict rptr;
42*b1e83836Smrg /* v.* indicates the vector array. */
43*b1e83836Smrg index_type vstride0;
44*b1e83836Smrg GFC_COMPLEX_17 *vptr;
45*b1e83836Smrg /* Value for field, this is constant. */
46*b1e83836Smrg const GFC_COMPLEX_17 fval = *fptr;
47*b1e83836Smrg /* m.* indicates the mask array. */
48*b1e83836Smrg index_type mstride[GFC_MAX_DIMENSIONS];
49*b1e83836Smrg index_type mstride0;
50*b1e83836Smrg const GFC_LOGICAL_1 *mptr;
51*b1e83836Smrg
52*b1e83836Smrg index_type count[GFC_MAX_DIMENSIONS];
53*b1e83836Smrg index_type extent[GFC_MAX_DIMENSIONS];
54*b1e83836Smrg index_type n;
55*b1e83836Smrg index_type dim;
56*b1e83836Smrg
57*b1e83836Smrg int empty;
58*b1e83836Smrg int mask_kind;
59*b1e83836Smrg
60*b1e83836Smrg empty = 0;
61*b1e83836Smrg
62*b1e83836Smrg mptr = mask->base_addr;
63*b1e83836Smrg
64*b1e83836Smrg /* Use the same loop for all logical types, by using GFC_LOGICAL_1
65*b1e83836Smrg and using shifting to address size and endian issues. */
66*b1e83836Smrg
67*b1e83836Smrg mask_kind = GFC_DESCRIPTOR_SIZE (mask);
68*b1e83836Smrg
69*b1e83836Smrg if (mask_kind == 1 || mask_kind == 2 || mask_kind == 4 || mask_kind == 8
70*b1e83836Smrg #ifdef HAVE_GFC_LOGICAL_16
71*b1e83836Smrg || mask_kind == 16
72*b1e83836Smrg #endif
73*b1e83836Smrg )
74*b1e83836Smrg {
75*b1e83836Smrg /* Do not convert a NULL pointer as we use test for NULL below. */
76*b1e83836Smrg if (mptr)
77*b1e83836Smrg mptr = GFOR_POINTER_TO_L1 (mptr, mask_kind);
78*b1e83836Smrg }
79*b1e83836Smrg else
80*b1e83836Smrg runtime_error ("Funny sized logical array");
81*b1e83836Smrg
82*b1e83836Smrg /* Initialize to avoid -Wmaybe-uninitialized complaints. */
83*b1e83836Smrg rstride[0] = 1;
84*b1e83836Smrg if (ret->base_addr == NULL)
85*b1e83836Smrg {
86*b1e83836Smrg /* The front end has signalled that we need to populate the
87*b1e83836Smrg return array descriptor. */
88*b1e83836Smrg dim = GFC_DESCRIPTOR_RANK (mask);
89*b1e83836Smrg rs = 1;
90*b1e83836Smrg for (n = 0; n < dim; n++)
91*b1e83836Smrg {
92*b1e83836Smrg count[n] = 0;
93*b1e83836Smrg GFC_DIMENSION_SET(ret->dim[n], 0,
94*b1e83836Smrg GFC_DESCRIPTOR_EXTENT(mask,n) - 1, rs);
95*b1e83836Smrg extent[n] = GFC_DESCRIPTOR_EXTENT(ret,n);
96*b1e83836Smrg empty = empty || extent[n] <= 0;
97*b1e83836Smrg rstride[n] = GFC_DESCRIPTOR_STRIDE(ret,n);
98*b1e83836Smrg mstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(mask,n);
99*b1e83836Smrg rs *= extent[n];
100*b1e83836Smrg }
101*b1e83836Smrg ret->offset = 0;
102*b1e83836Smrg ret->base_addr = xmallocarray (rs, sizeof (GFC_COMPLEX_17));
103*b1e83836Smrg }
104*b1e83836Smrg else
105*b1e83836Smrg {
106*b1e83836Smrg dim = GFC_DESCRIPTOR_RANK (ret);
107*b1e83836Smrg for (n = 0; n < dim; n++)
108*b1e83836Smrg {
109*b1e83836Smrg count[n] = 0;
110*b1e83836Smrg extent[n] = GFC_DESCRIPTOR_EXTENT(ret,n);
111*b1e83836Smrg empty = empty || extent[n] <= 0;
112*b1e83836Smrg rstride[n] = GFC_DESCRIPTOR_STRIDE(ret,n);
113*b1e83836Smrg mstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(mask,n);
114*b1e83836Smrg }
115*b1e83836Smrg if (rstride[0] == 0)
116*b1e83836Smrg rstride[0] = 1;
117*b1e83836Smrg }
118*b1e83836Smrg
119*b1e83836Smrg if (empty)
120*b1e83836Smrg return;
121*b1e83836Smrg
122*b1e83836Smrg if (mstride[0] == 0)
123*b1e83836Smrg mstride[0] = 1;
124*b1e83836Smrg
125*b1e83836Smrg vstride0 = GFC_DESCRIPTOR_STRIDE(vector,0);
126*b1e83836Smrg if (vstride0 == 0)
127*b1e83836Smrg vstride0 = 1;
128*b1e83836Smrg rstride0 = rstride[0];
129*b1e83836Smrg mstride0 = mstride[0];
130*b1e83836Smrg rptr = ret->base_addr;
131*b1e83836Smrg vptr = vector->base_addr;
132*b1e83836Smrg
133*b1e83836Smrg while (rptr)
134*b1e83836Smrg {
135*b1e83836Smrg if (*mptr)
136*b1e83836Smrg {
137*b1e83836Smrg /* From vector. */
138*b1e83836Smrg *rptr = *vptr;
139*b1e83836Smrg vptr += vstride0;
140*b1e83836Smrg }
141*b1e83836Smrg else
142*b1e83836Smrg {
143*b1e83836Smrg /* From field. */
144*b1e83836Smrg *rptr = fval;
145*b1e83836Smrg }
146*b1e83836Smrg /* Advance to the next element. */
147*b1e83836Smrg rptr += rstride0;
148*b1e83836Smrg mptr += mstride0;
149*b1e83836Smrg count[0]++;
150*b1e83836Smrg n = 0;
151*b1e83836Smrg while (count[n] == extent[n])
152*b1e83836Smrg {
153*b1e83836Smrg /* When we get to the end of a dimension, reset it and increment
154*b1e83836Smrg the next dimension. */
155*b1e83836Smrg count[n] = 0;
156*b1e83836Smrg /* We could precalculate these products, but this is a less
157*b1e83836Smrg frequently used path so probably not worth it. */
158*b1e83836Smrg rptr -= rstride[n] * extent[n];
159*b1e83836Smrg mptr -= mstride[n] * extent[n];
160*b1e83836Smrg n++;
161*b1e83836Smrg if (n >= dim)
162*b1e83836Smrg {
163*b1e83836Smrg /* Break out of the loop. */
164*b1e83836Smrg rptr = NULL;
165*b1e83836Smrg break;
166*b1e83836Smrg }
167*b1e83836Smrg else
168*b1e83836Smrg {
169*b1e83836Smrg count[n]++;
170*b1e83836Smrg rptr += rstride[n];
171*b1e83836Smrg mptr += mstride[n];
172*b1e83836Smrg }
173*b1e83836Smrg }
174*b1e83836Smrg }
175*b1e83836Smrg }
176*b1e83836Smrg
177*b1e83836Smrg void
unpack1_c17(gfc_array_c17 * ret,const gfc_array_c17 * vector,const gfc_array_l1 * mask,const gfc_array_c17 * field)178*b1e83836Smrg unpack1_c17 (gfc_array_c17 *ret, const gfc_array_c17 *vector,
179*b1e83836Smrg const gfc_array_l1 *mask, const gfc_array_c17 *field)
180*b1e83836Smrg {
181*b1e83836Smrg /* r.* indicates the return array. */
182*b1e83836Smrg index_type rstride[GFC_MAX_DIMENSIONS];
183*b1e83836Smrg index_type rstride0;
184*b1e83836Smrg index_type rs;
185*b1e83836Smrg GFC_COMPLEX_17 * restrict rptr;
186*b1e83836Smrg /* v.* indicates the vector array. */
187*b1e83836Smrg index_type vstride0;
188*b1e83836Smrg GFC_COMPLEX_17 *vptr;
189*b1e83836Smrg /* f.* indicates the field array. */
190*b1e83836Smrg index_type fstride[GFC_MAX_DIMENSIONS];
191*b1e83836Smrg index_type fstride0;
192*b1e83836Smrg const GFC_COMPLEX_17 *fptr;
193*b1e83836Smrg /* m.* indicates the mask array. */
194*b1e83836Smrg index_type mstride[GFC_MAX_DIMENSIONS];
195*b1e83836Smrg index_type mstride0;
196*b1e83836Smrg const GFC_LOGICAL_1 *mptr;
197*b1e83836Smrg
198*b1e83836Smrg index_type count[GFC_MAX_DIMENSIONS];
199*b1e83836Smrg index_type extent[GFC_MAX_DIMENSIONS];
200*b1e83836Smrg index_type n;
201*b1e83836Smrg index_type dim;
202*b1e83836Smrg
203*b1e83836Smrg int empty;
204*b1e83836Smrg int mask_kind;
205*b1e83836Smrg
206*b1e83836Smrg empty = 0;
207*b1e83836Smrg
208*b1e83836Smrg mptr = mask->base_addr;
209*b1e83836Smrg
210*b1e83836Smrg /* Use the same loop for all logical types, by using GFC_LOGICAL_1
211*b1e83836Smrg and using shifting to address size and endian issues. */
212*b1e83836Smrg
213*b1e83836Smrg mask_kind = GFC_DESCRIPTOR_SIZE (mask);
214*b1e83836Smrg
215*b1e83836Smrg if (mask_kind == 1 || mask_kind == 2 || mask_kind == 4 || mask_kind == 8
216*b1e83836Smrg #ifdef HAVE_GFC_LOGICAL_16
217*b1e83836Smrg || mask_kind == 16
218*b1e83836Smrg #endif
219*b1e83836Smrg )
220*b1e83836Smrg {
221*b1e83836Smrg /* Do not convert a NULL pointer as we use test for NULL below. */
222*b1e83836Smrg if (mptr)
223*b1e83836Smrg mptr = GFOR_POINTER_TO_L1 (mptr, mask_kind);
224*b1e83836Smrg }
225*b1e83836Smrg else
226*b1e83836Smrg runtime_error ("Funny sized logical array");
227*b1e83836Smrg
228*b1e83836Smrg /* Initialize to avoid -Wmaybe-uninitialized complaints. */
229*b1e83836Smrg rstride[0] = 1;
230*b1e83836Smrg if (ret->base_addr == NULL)
231*b1e83836Smrg {
232*b1e83836Smrg /* The front end has signalled that we need to populate the
233*b1e83836Smrg return array descriptor. */
234*b1e83836Smrg dim = GFC_DESCRIPTOR_RANK (mask);
235*b1e83836Smrg rs = 1;
236*b1e83836Smrg for (n = 0; n < dim; n++)
237*b1e83836Smrg {
238*b1e83836Smrg count[n] = 0;
239*b1e83836Smrg GFC_DIMENSION_SET(ret->dim[n], 0,
240*b1e83836Smrg GFC_DESCRIPTOR_EXTENT(mask,n) - 1, rs);
241*b1e83836Smrg extent[n] = GFC_DESCRIPTOR_EXTENT(ret,n);
242*b1e83836Smrg empty = empty || extent[n] <= 0;
243*b1e83836Smrg rstride[n] = GFC_DESCRIPTOR_STRIDE(ret,n);
244*b1e83836Smrg fstride[n] = GFC_DESCRIPTOR_STRIDE(field,n);
245*b1e83836Smrg mstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(mask,n);
246*b1e83836Smrg rs *= extent[n];
247*b1e83836Smrg }
248*b1e83836Smrg ret->offset = 0;
249*b1e83836Smrg ret->base_addr = xmallocarray (rs, sizeof (GFC_COMPLEX_17));
250*b1e83836Smrg }
251*b1e83836Smrg else
252*b1e83836Smrg {
253*b1e83836Smrg dim = GFC_DESCRIPTOR_RANK (ret);
254*b1e83836Smrg for (n = 0; n < dim; n++)
255*b1e83836Smrg {
256*b1e83836Smrg count[n] = 0;
257*b1e83836Smrg extent[n] = GFC_DESCRIPTOR_EXTENT(ret,n);
258*b1e83836Smrg empty = empty || extent[n] <= 0;
259*b1e83836Smrg rstride[n] = GFC_DESCRIPTOR_STRIDE(ret,n);
260*b1e83836Smrg fstride[n] = GFC_DESCRIPTOR_STRIDE(field,n);
261*b1e83836Smrg mstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(mask,n);
262*b1e83836Smrg }
263*b1e83836Smrg if (rstride[0] == 0)
264*b1e83836Smrg rstride[0] = 1;
265*b1e83836Smrg }
266*b1e83836Smrg
267*b1e83836Smrg if (empty)
268*b1e83836Smrg return;
269*b1e83836Smrg
270*b1e83836Smrg if (fstride[0] == 0)
271*b1e83836Smrg fstride[0] = 1;
272*b1e83836Smrg if (mstride[0] == 0)
273*b1e83836Smrg mstride[0] = 1;
274*b1e83836Smrg
275*b1e83836Smrg vstride0 = GFC_DESCRIPTOR_STRIDE(vector,0);
276*b1e83836Smrg if (vstride0 == 0)
277*b1e83836Smrg vstride0 = 1;
278*b1e83836Smrg rstride0 = rstride[0];
279*b1e83836Smrg fstride0 = fstride[0];
280*b1e83836Smrg mstride0 = mstride[0];
281*b1e83836Smrg rptr = ret->base_addr;
282*b1e83836Smrg fptr = field->base_addr;
283*b1e83836Smrg vptr = vector->base_addr;
284*b1e83836Smrg
285*b1e83836Smrg while (rptr)
286*b1e83836Smrg {
287*b1e83836Smrg if (*mptr)
288*b1e83836Smrg {
289*b1e83836Smrg /* From vector. */
290*b1e83836Smrg *rptr = *vptr;
291*b1e83836Smrg vptr += vstride0;
292*b1e83836Smrg }
293*b1e83836Smrg else
294*b1e83836Smrg {
295*b1e83836Smrg /* From field. */
296*b1e83836Smrg *rptr = *fptr;
297*b1e83836Smrg }
298*b1e83836Smrg /* Advance to the next element. */
299*b1e83836Smrg rptr += rstride0;
300*b1e83836Smrg fptr += fstride0;
301*b1e83836Smrg mptr += mstride0;
302*b1e83836Smrg count[0]++;
303*b1e83836Smrg n = 0;
304*b1e83836Smrg while (count[n] == extent[n])
305*b1e83836Smrg {
306*b1e83836Smrg /* When we get to the end of a dimension, reset it and increment
307*b1e83836Smrg the next dimension. */
308*b1e83836Smrg count[n] = 0;
309*b1e83836Smrg /* We could precalculate these products, but this is a less
310*b1e83836Smrg frequently used path so probably not worth it. */
311*b1e83836Smrg rptr -= rstride[n] * extent[n];
312*b1e83836Smrg fptr -= fstride[n] * extent[n];
313*b1e83836Smrg mptr -= mstride[n] * extent[n];
314*b1e83836Smrg n++;
315*b1e83836Smrg if (n >= dim)
316*b1e83836Smrg {
317*b1e83836Smrg /* Break out of the loop. */
318*b1e83836Smrg rptr = NULL;
319*b1e83836Smrg break;
320*b1e83836Smrg }
321*b1e83836Smrg else
322*b1e83836Smrg {
323*b1e83836Smrg count[n]++;
324*b1e83836Smrg rptr += rstride[n];
325*b1e83836Smrg fptr += fstride[n];
326*b1e83836Smrg mptr += mstride[n];
327*b1e83836Smrg }
328*b1e83836Smrg }
329*b1e83836Smrg }
330*b1e83836Smrg }
331*b1e83836Smrg
332*b1e83836Smrg #endif
333*b1e83836Smrg
334