1627f7eb2Smrg /* Specific implementation of the UNPACK intrinsic
2*4c3eb207Smrg Copyright (C) 2008-2020 Free Software Foundation, Inc.
3627f7eb2Smrg Contributed by Thomas Koenig <tkoenig@gcc.gnu.org>, based on
4627f7eb2Smrg unpack_generic.c by Paul Brook <paul@nowt.org>.
5627f7eb2Smrg
6627f7eb2Smrg This file is part of the GNU Fortran runtime library (libgfortran).
7627f7eb2Smrg
8627f7eb2Smrg Libgfortran is free software; you can redistribute it and/or
9627f7eb2Smrg modify it under the terms of the GNU General Public
10627f7eb2Smrg License as published by the Free Software Foundation; either
11627f7eb2Smrg version 3 of the License, or (at your option) any later version.
12627f7eb2Smrg
13627f7eb2Smrg Ligbfortran is distributed in the hope that it will be useful,
14627f7eb2Smrg but WITHOUT ANY WARRANTY; without even the implied warranty of
15627f7eb2Smrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16627f7eb2Smrg GNU General Public License for more details.
17627f7eb2Smrg
18627f7eb2Smrg Under Section 7 of GPL version 3, you are granted additional
19627f7eb2Smrg permissions described in the GCC Runtime Library Exception, version
20627f7eb2Smrg 3.1, as published by the Free Software Foundation.
21627f7eb2Smrg
22627f7eb2Smrg You should have received a copy of the GNU General Public License and
23627f7eb2Smrg a copy of the GCC Runtime Library Exception along with this program;
24627f7eb2Smrg see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
25627f7eb2Smrg <http://www.gnu.org/licenses/>. */
26627f7eb2Smrg
27627f7eb2Smrg #include "libgfortran.h"
28627f7eb2Smrg #include <string.h>
29627f7eb2Smrg
30627f7eb2Smrg
31627f7eb2Smrg #if defined (HAVE_GFC_INTEGER_2)
32627f7eb2Smrg
33627f7eb2Smrg void
unpack0_i2(gfc_array_i2 * ret,const gfc_array_i2 * vector,const gfc_array_l1 * mask,const GFC_INTEGER_2 * fptr)34627f7eb2Smrg unpack0_i2 (gfc_array_i2 *ret, const gfc_array_i2 *vector,
35627f7eb2Smrg const gfc_array_l1 *mask, const GFC_INTEGER_2 *fptr)
36627f7eb2Smrg {
37627f7eb2Smrg /* r.* indicates the return array. */
38627f7eb2Smrg index_type rstride[GFC_MAX_DIMENSIONS];
39627f7eb2Smrg index_type rstride0;
40627f7eb2Smrg index_type rs;
41627f7eb2Smrg GFC_INTEGER_2 * restrict rptr;
42627f7eb2Smrg /* v.* indicates the vector array. */
43627f7eb2Smrg index_type vstride0;
44627f7eb2Smrg GFC_INTEGER_2 *vptr;
45627f7eb2Smrg /* Value for field, this is constant. */
46627f7eb2Smrg const GFC_INTEGER_2 fval = *fptr;
47627f7eb2Smrg /* m.* indicates the mask array. */
48627f7eb2Smrg index_type mstride[GFC_MAX_DIMENSIONS];
49627f7eb2Smrg index_type mstride0;
50627f7eb2Smrg const GFC_LOGICAL_1 *mptr;
51627f7eb2Smrg
52627f7eb2Smrg index_type count[GFC_MAX_DIMENSIONS];
53627f7eb2Smrg index_type extent[GFC_MAX_DIMENSIONS];
54627f7eb2Smrg index_type n;
55627f7eb2Smrg index_type dim;
56627f7eb2Smrg
57627f7eb2Smrg int empty;
58627f7eb2Smrg int mask_kind;
59627f7eb2Smrg
60627f7eb2Smrg empty = 0;
61627f7eb2Smrg
62627f7eb2Smrg mptr = mask->base_addr;
63627f7eb2Smrg
64627f7eb2Smrg /* Use the same loop for all logical types, by using GFC_LOGICAL_1
65627f7eb2Smrg and using shifting to address size and endian issues. */
66627f7eb2Smrg
67627f7eb2Smrg mask_kind = GFC_DESCRIPTOR_SIZE (mask);
68627f7eb2Smrg
69627f7eb2Smrg if (mask_kind == 1 || mask_kind == 2 || mask_kind == 4 || mask_kind == 8
70627f7eb2Smrg #ifdef HAVE_GFC_LOGICAL_16
71627f7eb2Smrg || mask_kind == 16
72627f7eb2Smrg #endif
73627f7eb2Smrg )
74627f7eb2Smrg {
75627f7eb2Smrg /* Do not convert a NULL pointer as we use test for NULL below. */
76627f7eb2Smrg if (mptr)
77627f7eb2Smrg mptr = GFOR_POINTER_TO_L1 (mptr, mask_kind);
78627f7eb2Smrg }
79627f7eb2Smrg else
80627f7eb2Smrg runtime_error ("Funny sized logical array");
81627f7eb2Smrg
82627f7eb2Smrg if (ret->base_addr == NULL)
83627f7eb2Smrg {
84627f7eb2Smrg /* The front end has signalled that we need to populate the
85627f7eb2Smrg return array descriptor. */
86627f7eb2Smrg dim = GFC_DESCRIPTOR_RANK (mask);
87627f7eb2Smrg rs = 1;
88627f7eb2Smrg for (n = 0; n < dim; n++)
89627f7eb2Smrg {
90627f7eb2Smrg count[n] = 0;
91627f7eb2Smrg GFC_DIMENSION_SET(ret->dim[n], 0,
92627f7eb2Smrg GFC_DESCRIPTOR_EXTENT(mask,n) - 1, rs);
93627f7eb2Smrg extent[n] = GFC_DESCRIPTOR_EXTENT(ret,n);
94627f7eb2Smrg empty = empty || extent[n] <= 0;
95627f7eb2Smrg rstride[n] = GFC_DESCRIPTOR_STRIDE(ret,n);
96627f7eb2Smrg mstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(mask,n);
97627f7eb2Smrg rs *= extent[n];
98627f7eb2Smrg }
99627f7eb2Smrg ret->offset = 0;
100627f7eb2Smrg ret->base_addr = xmallocarray (rs, sizeof (GFC_INTEGER_2));
101627f7eb2Smrg }
102627f7eb2Smrg else
103627f7eb2Smrg {
104627f7eb2Smrg dim = GFC_DESCRIPTOR_RANK (ret);
105627f7eb2Smrg /* Initialize to avoid -Wmaybe-uninitialized complaints. */
106627f7eb2Smrg rstride[0] = 1;
107627f7eb2Smrg for (n = 0; n < dim; n++)
108627f7eb2Smrg {
109627f7eb2Smrg count[n] = 0;
110627f7eb2Smrg extent[n] = GFC_DESCRIPTOR_EXTENT(ret,n);
111627f7eb2Smrg empty = empty || extent[n] <= 0;
112627f7eb2Smrg rstride[n] = GFC_DESCRIPTOR_STRIDE(ret,n);
113627f7eb2Smrg mstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(mask,n);
114627f7eb2Smrg }
115627f7eb2Smrg if (rstride[0] == 0)
116627f7eb2Smrg rstride[0] = 1;
117627f7eb2Smrg }
118627f7eb2Smrg
119627f7eb2Smrg if (empty)
120627f7eb2Smrg return;
121627f7eb2Smrg
122627f7eb2Smrg if (mstride[0] == 0)
123627f7eb2Smrg mstride[0] = 1;
124627f7eb2Smrg
125627f7eb2Smrg vstride0 = GFC_DESCRIPTOR_STRIDE(vector,0);
126627f7eb2Smrg if (vstride0 == 0)
127627f7eb2Smrg vstride0 = 1;
128627f7eb2Smrg rstride0 = rstride[0];
129627f7eb2Smrg mstride0 = mstride[0];
130627f7eb2Smrg rptr = ret->base_addr;
131627f7eb2Smrg vptr = vector->base_addr;
132627f7eb2Smrg
133627f7eb2Smrg while (rptr)
134627f7eb2Smrg {
135627f7eb2Smrg if (*mptr)
136627f7eb2Smrg {
137627f7eb2Smrg /* From vector. */
138627f7eb2Smrg *rptr = *vptr;
139627f7eb2Smrg vptr += vstride0;
140627f7eb2Smrg }
141627f7eb2Smrg else
142627f7eb2Smrg {
143627f7eb2Smrg /* From field. */
144627f7eb2Smrg *rptr = fval;
145627f7eb2Smrg }
146627f7eb2Smrg /* Advance to the next element. */
147627f7eb2Smrg rptr += rstride0;
148627f7eb2Smrg mptr += mstride0;
149627f7eb2Smrg count[0]++;
150627f7eb2Smrg n = 0;
151627f7eb2Smrg while (count[n] == extent[n])
152627f7eb2Smrg {
153627f7eb2Smrg /* When we get to the end of a dimension, reset it and increment
154627f7eb2Smrg the next dimension. */
155627f7eb2Smrg count[n] = 0;
156627f7eb2Smrg /* We could precalculate these products, but this is a less
157627f7eb2Smrg frequently used path so probably not worth it. */
158627f7eb2Smrg rptr -= rstride[n] * extent[n];
159627f7eb2Smrg mptr -= mstride[n] * extent[n];
160627f7eb2Smrg n++;
161627f7eb2Smrg if (n >= dim)
162627f7eb2Smrg {
163627f7eb2Smrg /* Break out of the loop. */
164627f7eb2Smrg rptr = NULL;
165627f7eb2Smrg break;
166627f7eb2Smrg }
167627f7eb2Smrg else
168627f7eb2Smrg {
169627f7eb2Smrg count[n]++;
170627f7eb2Smrg rptr += rstride[n];
171627f7eb2Smrg mptr += mstride[n];
172627f7eb2Smrg }
173627f7eb2Smrg }
174627f7eb2Smrg }
175627f7eb2Smrg }
176627f7eb2Smrg
177627f7eb2Smrg void
unpack1_i2(gfc_array_i2 * ret,const gfc_array_i2 * vector,const gfc_array_l1 * mask,const gfc_array_i2 * field)178627f7eb2Smrg unpack1_i2 (gfc_array_i2 *ret, const gfc_array_i2 *vector,
179627f7eb2Smrg const gfc_array_l1 *mask, const gfc_array_i2 *field)
180627f7eb2Smrg {
181627f7eb2Smrg /* r.* indicates the return array. */
182627f7eb2Smrg index_type rstride[GFC_MAX_DIMENSIONS];
183627f7eb2Smrg index_type rstride0;
184627f7eb2Smrg index_type rs;
185627f7eb2Smrg GFC_INTEGER_2 * restrict rptr;
186627f7eb2Smrg /* v.* indicates the vector array. */
187627f7eb2Smrg index_type vstride0;
188627f7eb2Smrg GFC_INTEGER_2 *vptr;
189627f7eb2Smrg /* f.* indicates the field array. */
190627f7eb2Smrg index_type fstride[GFC_MAX_DIMENSIONS];
191627f7eb2Smrg index_type fstride0;
192627f7eb2Smrg const GFC_INTEGER_2 *fptr;
193627f7eb2Smrg /* m.* indicates the mask array. */
194627f7eb2Smrg index_type mstride[GFC_MAX_DIMENSIONS];
195627f7eb2Smrg index_type mstride0;
196627f7eb2Smrg const GFC_LOGICAL_1 *mptr;
197627f7eb2Smrg
198627f7eb2Smrg index_type count[GFC_MAX_DIMENSIONS];
199627f7eb2Smrg index_type extent[GFC_MAX_DIMENSIONS];
200627f7eb2Smrg index_type n;
201627f7eb2Smrg index_type dim;
202627f7eb2Smrg
203627f7eb2Smrg int empty;
204627f7eb2Smrg int mask_kind;
205627f7eb2Smrg
206627f7eb2Smrg empty = 0;
207627f7eb2Smrg
208627f7eb2Smrg mptr = mask->base_addr;
209627f7eb2Smrg
210627f7eb2Smrg /* Use the same loop for all logical types, by using GFC_LOGICAL_1
211627f7eb2Smrg and using shifting to address size and endian issues. */
212627f7eb2Smrg
213627f7eb2Smrg mask_kind = GFC_DESCRIPTOR_SIZE (mask);
214627f7eb2Smrg
215627f7eb2Smrg if (mask_kind == 1 || mask_kind == 2 || mask_kind == 4 || mask_kind == 8
216627f7eb2Smrg #ifdef HAVE_GFC_LOGICAL_16
217627f7eb2Smrg || mask_kind == 16
218627f7eb2Smrg #endif
219627f7eb2Smrg )
220627f7eb2Smrg {
221627f7eb2Smrg /* Do not convert a NULL pointer as we use test for NULL below. */
222627f7eb2Smrg if (mptr)
223627f7eb2Smrg mptr = GFOR_POINTER_TO_L1 (mptr, mask_kind);
224627f7eb2Smrg }
225627f7eb2Smrg else
226627f7eb2Smrg runtime_error ("Funny sized logical array");
227627f7eb2Smrg
228627f7eb2Smrg if (ret->base_addr == NULL)
229627f7eb2Smrg {
230627f7eb2Smrg /* The front end has signalled that we need to populate the
231627f7eb2Smrg return array descriptor. */
232627f7eb2Smrg dim = GFC_DESCRIPTOR_RANK (mask);
233627f7eb2Smrg rs = 1;
234627f7eb2Smrg for (n = 0; n < dim; n++)
235627f7eb2Smrg {
236627f7eb2Smrg count[n] = 0;
237627f7eb2Smrg GFC_DIMENSION_SET(ret->dim[n], 0,
238627f7eb2Smrg GFC_DESCRIPTOR_EXTENT(mask,n) - 1, rs);
239627f7eb2Smrg extent[n] = GFC_DESCRIPTOR_EXTENT(ret,n);
240627f7eb2Smrg empty = empty || extent[n] <= 0;
241627f7eb2Smrg rstride[n] = GFC_DESCRIPTOR_STRIDE(ret,n);
242627f7eb2Smrg fstride[n] = GFC_DESCRIPTOR_STRIDE(field,n);
243627f7eb2Smrg mstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(mask,n);
244627f7eb2Smrg rs *= extent[n];
245627f7eb2Smrg }
246627f7eb2Smrg ret->offset = 0;
247627f7eb2Smrg ret->base_addr = xmallocarray (rs, sizeof (GFC_INTEGER_2));
248627f7eb2Smrg }
249627f7eb2Smrg else
250627f7eb2Smrg {
251627f7eb2Smrg dim = GFC_DESCRIPTOR_RANK (ret);
252627f7eb2Smrg /* Initialize to avoid -Wmaybe-uninitialized complaints. */
253627f7eb2Smrg rstride[0] = 1;
254627f7eb2Smrg for (n = 0; n < dim; n++)
255627f7eb2Smrg {
256627f7eb2Smrg count[n] = 0;
257627f7eb2Smrg extent[n] = GFC_DESCRIPTOR_EXTENT(ret,n);
258627f7eb2Smrg empty = empty || extent[n] <= 0;
259627f7eb2Smrg rstride[n] = GFC_DESCRIPTOR_STRIDE(ret,n);
260627f7eb2Smrg fstride[n] = GFC_DESCRIPTOR_STRIDE(field,n);
261627f7eb2Smrg mstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(mask,n);
262627f7eb2Smrg }
263627f7eb2Smrg if (rstride[0] == 0)
264627f7eb2Smrg rstride[0] = 1;
265627f7eb2Smrg }
266627f7eb2Smrg
267627f7eb2Smrg if (empty)
268627f7eb2Smrg return;
269627f7eb2Smrg
270627f7eb2Smrg if (fstride[0] == 0)
271627f7eb2Smrg fstride[0] = 1;
272627f7eb2Smrg if (mstride[0] == 0)
273627f7eb2Smrg mstride[0] = 1;
274627f7eb2Smrg
275627f7eb2Smrg vstride0 = GFC_DESCRIPTOR_STRIDE(vector,0);
276627f7eb2Smrg if (vstride0 == 0)
277627f7eb2Smrg vstride0 = 1;
278627f7eb2Smrg rstride0 = rstride[0];
279627f7eb2Smrg fstride0 = fstride[0];
280627f7eb2Smrg mstride0 = mstride[0];
281627f7eb2Smrg rptr = ret->base_addr;
282627f7eb2Smrg fptr = field->base_addr;
283627f7eb2Smrg vptr = vector->base_addr;
284627f7eb2Smrg
285627f7eb2Smrg while (rptr)
286627f7eb2Smrg {
287627f7eb2Smrg if (*mptr)
288627f7eb2Smrg {
289627f7eb2Smrg /* From vector. */
290627f7eb2Smrg *rptr = *vptr;
291627f7eb2Smrg vptr += vstride0;
292627f7eb2Smrg }
293627f7eb2Smrg else
294627f7eb2Smrg {
295627f7eb2Smrg /* From field. */
296627f7eb2Smrg *rptr = *fptr;
297627f7eb2Smrg }
298627f7eb2Smrg /* Advance to the next element. */
299627f7eb2Smrg rptr += rstride0;
300627f7eb2Smrg fptr += fstride0;
301627f7eb2Smrg mptr += mstride0;
302627f7eb2Smrg count[0]++;
303627f7eb2Smrg n = 0;
304627f7eb2Smrg while (count[n] == extent[n])
305627f7eb2Smrg {
306627f7eb2Smrg /* When we get to the end of a dimension, reset it and increment
307627f7eb2Smrg the next dimension. */
308627f7eb2Smrg count[n] = 0;
309627f7eb2Smrg /* We could precalculate these products, but this is a less
310627f7eb2Smrg frequently used path so probably not worth it. */
311627f7eb2Smrg rptr -= rstride[n] * extent[n];
312627f7eb2Smrg fptr -= fstride[n] * extent[n];
313627f7eb2Smrg mptr -= mstride[n] * extent[n];
314627f7eb2Smrg n++;
315627f7eb2Smrg if (n >= dim)
316627f7eb2Smrg {
317627f7eb2Smrg /* Break out of the loop. */
318627f7eb2Smrg rptr = NULL;
319627f7eb2Smrg break;
320627f7eb2Smrg }
321627f7eb2Smrg else
322627f7eb2Smrg {
323627f7eb2Smrg count[n]++;
324627f7eb2Smrg rptr += rstride[n];
325627f7eb2Smrg fptr += fstride[n];
326627f7eb2Smrg mptr += mstride[n];
327627f7eb2Smrg }
328627f7eb2Smrg }
329627f7eb2Smrg }
330627f7eb2Smrg }
331627f7eb2Smrg
332627f7eb2Smrg #endif
333627f7eb2Smrg
334