1181254a7Smrg /* Generic helper function for repacking arrays.
2*b1e83836Smrg Copyright (C) 2003-2022 Free Software Foundation, Inc.
3181254a7Smrg Contributed by Paul Brook <paul@nowt.org>
4181254a7Smrg
5181254a7Smrg This file is part of the GNU Fortran runtime library (libgfortran).
6181254a7Smrg
7181254a7Smrg Libgfortran is free software; you can redistribute it and/or
8181254a7Smrg modify it under the terms of the GNU General Public
9181254a7Smrg License as published by the Free Software Foundation; either
10181254a7Smrg version 3 of the License, or (at your option) any later version.
11181254a7Smrg
12181254a7Smrg Libgfortran is distributed in the hope that it will be useful,
13181254a7Smrg but WITHOUT ANY WARRANTY; without even the implied warranty of
14181254a7Smrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15181254a7Smrg GNU General Public License for more details.
16181254a7Smrg
17181254a7Smrg Under Section 7 of GPL version 3, you are granted additional
18181254a7Smrg permissions described in the GCC Runtime Library Exception, version
19181254a7Smrg 3.1, as published by the Free Software Foundation.
20181254a7Smrg
21181254a7Smrg You should have received a copy of the GNU General Public License and
22181254a7Smrg a copy of the GCC Runtime Library Exception along with this program;
23181254a7Smrg see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
24181254a7Smrg <http://www.gnu.org/licenses/>. */
25181254a7Smrg
26181254a7Smrg #include "libgfortran.h"
27181254a7Smrg #include <string.h>
28181254a7Smrg
29181254a7Smrg extern void *internal_pack (gfc_array_char *);
30181254a7Smrg export_proto(internal_pack);
31181254a7Smrg
32181254a7Smrg void *
internal_pack(gfc_array_char * source)33181254a7Smrg internal_pack (gfc_array_char * source)
34181254a7Smrg {
35181254a7Smrg index_type count[GFC_MAX_DIMENSIONS];
36181254a7Smrg index_type extent[GFC_MAX_DIMENSIONS];
37181254a7Smrg index_type stride[GFC_MAX_DIMENSIONS];
38181254a7Smrg index_type stride0;
39181254a7Smrg index_type dim;
40181254a7Smrg index_type ssize;
41181254a7Smrg const char *src;
42181254a7Smrg char *dest;
43181254a7Smrg void *destptr;
44181254a7Smrg int packed;
45181254a7Smrg index_type size;
46181254a7Smrg index_type type_size;
47181254a7Smrg
48181254a7Smrg if (source->base_addr == NULL)
49181254a7Smrg return NULL;
50181254a7Smrg
51181254a7Smrg type_size = GFC_DTYPE_TYPE_SIZE(source);
52181254a7Smrg size = GFC_DESCRIPTOR_SIZE (source);
53181254a7Smrg switch (type_size)
54181254a7Smrg {
55181254a7Smrg case GFC_DTYPE_INTEGER_1:
56181254a7Smrg case GFC_DTYPE_LOGICAL_1:
57181254a7Smrg return internal_pack_1 ((gfc_array_i1 *) source);
58181254a7Smrg
59181254a7Smrg case GFC_DTYPE_INTEGER_2:
60181254a7Smrg case GFC_DTYPE_LOGICAL_2:
61181254a7Smrg return internal_pack_2 ((gfc_array_i2 *) source);
62181254a7Smrg
63181254a7Smrg case GFC_DTYPE_INTEGER_4:
64181254a7Smrg case GFC_DTYPE_LOGICAL_4:
65181254a7Smrg return internal_pack_4 ((gfc_array_i4 *) source);
66181254a7Smrg
67181254a7Smrg case GFC_DTYPE_INTEGER_8:
68181254a7Smrg case GFC_DTYPE_LOGICAL_8:
69181254a7Smrg return internal_pack_8 ((gfc_array_i8 *) source);
70181254a7Smrg
71181254a7Smrg #if defined(HAVE_GFC_INTEGER_16)
72181254a7Smrg case GFC_DTYPE_INTEGER_16:
73181254a7Smrg case GFC_DTYPE_LOGICAL_16:
74181254a7Smrg return internal_pack_16 ((gfc_array_i16 *) source);
75181254a7Smrg #endif
76181254a7Smrg case GFC_DTYPE_REAL_4:
77181254a7Smrg return internal_pack_r4 ((gfc_array_r4 *) source);
78181254a7Smrg
79181254a7Smrg case GFC_DTYPE_REAL_8:
80181254a7Smrg return internal_pack_r8 ((gfc_array_r8 *) source);
81181254a7Smrg
82181254a7Smrg /* FIXME: This here is a hack, which will have to be removed when
83181254a7Smrg the array descriptor is reworked. Currently, we don't store the
84181254a7Smrg kind value for the type, but only the size. Because on targets with
85181254a7Smrg __float128, we have sizeof(logn double) == sizeof(__float128),
86181254a7Smrg we cannot discriminate here and have to fall back to the generic
87181254a7Smrg handling (which is suboptimal). */
88181254a7Smrg #if !defined(GFC_REAL_16_IS_FLOAT128)
89181254a7Smrg # if defined (HAVE_GFC_REAL_10)
90181254a7Smrg case GFC_DTYPE_REAL_10:
91181254a7Smrg return internal_pack_r10 ((gfc_array_r10 *) source);
92181254a7Smrg # endif
93181254a7Smrg
94181254a7Smrg # if defined (HAVE_GFC_REAL_16)
95181254a7Smrg case GFC_DTYPE_REAL_16:
96181254a7Smrg return internal_pack_r16 ((gfc_array_r16 *) source);
97181254a7Smrg # endif
98181254a7Smrg #endif
99181254a7Smrg
100181254a7Smrg case GFC_DTYPE_COMPLEX_4:
101181254a7Smrg return internal_pack_c4 ((gfc_array_c4 *) source);
102181254a7Smrg
103181254a7Smrg case GFC_DTYPE_COMPLEX_8:
104181254a7Smrg return internal_pack_c8 ((gfc_array_c8 *) source);
105181254a7Smrg
106181254a7Smrg /* FIXME: This here is a hack, which will have to be removed when
107181254a7Smrg the array descriptor is reworked. Currently, we don't store the
108181254a7Smrg kind value for the type, but only the size. Because on targets with
109181254a7Smrg __float128, we have sizeof(logn double) == sizeof(__float128),
110181254a7Smrg we cannot discriminate here and have to fall back to the generic
111181254a7Smrg handling (which is suboptimal). */
112181254a7Smrg #if !defined(GFC_REAL_16_IS_FLOAT128)
113181254a7Smrg # if defined (HAVE_GFC_COMPLEX_10)
114181254a7Smrg case GFC_DTYPE_COMPLEX_10:
115181254a7Smrg return internal_pack_c10 ((gfc_array_c10 *) source);
116181254a7Smrg # endif
117181254a7Smrg
118181254a7Smrg # if defined (HAVE_GFC_COMPLEX_16)
119181254a7Smrg case GFC_DTYPE_COMPLEX_16:
120181254a7Smrg return internal_pack_c16 ((gfc_array_c16 *) source);
121181254a7Smrg # endif
122181254a7Smrg #endif
123181254a7Smrg
124181254a7Smrg default:
125181254a7Smrg break;
126181254a7Smrg }
127181254a7Smrg
128181254a7Smrg switch(GFC_DESCRIPTOR_SIZE (source))
129181254a7Smrg {
130181254a7Smrg case 1:
131181254a7Smrg return internal_pack_1 ((gfc_array_i1 *) source);
132181254a7Smrg
133181254a7Smrg case 2:
134181254a7Smrg if (GFC_UNALIGNED_2(source->base_addr))
135181254a7Smrg break;
136181254a7Smrg else
137181254a7Smrg return internal_pack_2 ((gfc_array_i2 *) source);
138181254a7Smrg
139181254a7Smrg case 4:
140181254a7Smrg if (GFC_UNALIGNED_4(source->base_addr))
141181254a7Smrg break;
142181254a7Smrg else
143181254a7Smrg return internal_pack_4 ((gfc_array_i4 *) source);
144181254a7Smrg
145181254a7Smrg case 8:
146181254a7Smrg if (GFC_UNALIGNED_8(source->base_addr))
147181254a7Smrg break;
148181254a7Smrg else
149181254a7Smrg return internal_pack_8 ((gfc_array_i8 *) source);
150181254a7Smrg
151181254a7Smrg #ifdef HAVE_GFC_INTEGER_16
152181254a7Smrg case 16:
153181254a7Smrg if (GFC_UNALIGNED_16(source->base_addr))
154181254a7Smrg break;
155181254a7Smrg else
156181254a7Smrg return internal_pack_16 ((gfc_array_i16 *) source);
157181254a7Smrg #endif
158181254a7Smrg default:
159181254a7Smrg break;
160181254a7Smrg }
161181254a7Smrg
162181254a7Smrg dim = GFC_DESCRIPTOR_RANK (source);
163181254a7Smrg ssize = 1;
164181254a7Smrg packed = 1;
165181254a7Smrg for (index_type n = 0; n < dim; n++)
166181254a7Smrg {
167181254a7Smrg count[n] = 0;
168181254a7Smrg stride[n] = GFC_DESCRIPTOR_STRIDE(source,n);
169181254a7Smrg extent[n] = GFC_DESCRIPTOR_EXTENT(source,n);
170181254a7Smrg if (extent[n] <= 0)
171181254a7Smrg {
172181254a7Smrg /* Do nothing. */
173181254a7Smrg packed = 1;
174181254a7Smrg break;
175181254a7Smrg }
176181254a7Smrg
177181254a7Smrg if (ssize != stride[n])
178181254a7Smrg packed = 0;
179181254a7Smrg
180181254a7Smrg ssize *= extent[n];
181181254a7Smrg }
182181254a7Smrg
183181254a7Smrg if (packed)
184181254a7Smrg return source->base_addr;
185181254a7Smrg
186181254a7Smrg /* Allocate storage for the destination. */
187181254a7Smrg destptr = xmallocarray (ssize, size);
188181254a7Smrg dest = (char *)destptr;
189181254a7Smrg src = source->base_addr;
190181254a7Smrg stride0 = stride[0] * size;
191181254a7Smrg
192181254a7Smrg while (src)
193181254a7Smrg {
194181254a7Smrg /* Copy the data. */
195181254a7Smrg memcpy(dest, src, size);
196181254a7Smrg /* Advance to the next element. */
197181254a7Smrg dest += size;
198181254a7Smrg src += stride0;
199181254a7Smrg count[0]++;
200181254a7Smrg /* Advance to the next source element. */
201181254a7Smrg index_type n = 0;
202181254a7Smrg while (count[n] == extent[n])
203181254a7Smrg {
204181254a7Smrg /* When we get to the end of a dimension, reset it and increment
205181254a7Smrg the next dimension. */
206181254a7Smrg count[n] = 0;
207181254a7Smrg /* We could precalculate these products, but this is a less
208181254a7Smrg frequently used path so probably not worth it. */
209181254a7Smrg src -= stride[n] * extent[n] * size;
210181254a7Smrg n++;
211181254a7Smrg if (n == dim)
212181254a7Smrg {
213181254a7Smrg src = NULL;
214181254a7Smrg break;
215181254a7Smrg }
216181254a7Smrg else
217181254a7Smrg {
218181254a7Smrg count[n]++;
219181254a7Smrg src += stride[n] * size;
220181254a7Smrg }
221181254a7Smrg }
222181254a7Smrg }
223181254a7Smrg return destptr;
224181254a7Smrg }
225