xref: /netbsd-src/external/gpl3/gcc/dist/libgfortran/runtime/in_pack_generic.c (revision b1e838363e3c6fc78a55519254d99869742dd33c)
1 /* Generic helper function for repacking arrays.
2    Copyright (C) 2003-2022 Free Software Foundation, Inc.
3    Contributed by Paul Brook <paul@nowt.org>
4 
5 This file is part of the GNU Fortran runtime library (libgfortran).
6 
7 Libgfortran is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public
9 License as published by the Free Software Foundation; either
10 version 3 of the License, or (at your option) any later version.
11 
12 Libgfortran is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16 
17 Under Section 7 of GPL version 3, you are granted additional
18 permissions described in the GCC Runtime Library Exception, version
19 3.1, as published by the Free Software Foundation.
20 
21 You should have received a copy of the GNU General Public License and
22 a copy of the GCC Runtime Library Exception along with this program;
23 see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
24 <http://www.gnu.org/licenses/>.  */
25 
26 #include "libgfortran.h"
27 #include <string.h>
28 
29 extern void *internal_pack (gfc_array_char *);
30 export_proto(internal_pack);
31 
32 void *
internal_pack(gfc_array_char * source)33 internal_pack (gfc_array_char * source)
34 {
35   index_type count[GFC_MAX_DIMENSIONS];
36   index_type extent[GFC_MAX_DIMENSIONS];
37   index_type stride[GFC_MAX_DIMENSIONS];
38   index_type stride0;
39   index_type dim;
40   index_type ssize;
41   const char *src;
42   char *dest;
43   void *destptr;
44   int packed;
45   index_type size;
46   index_type type_size;
47 
48   if (source->base_addr == NULL)
49     return NULL;
50 
51   type_size = GFC_DTYPE_TYPE_SIZE(source);
52   size = GFC_DESCRIPTOR_SIZE (source);
53   switch (type_size)
54     {
55     case GFC_DTYPE_INTEGER_1:
56     case GFC_DTYPE_LOGICAL_1:
57       return internal_pack_1 ((gfc_array_i1 *) source);
58 
59     case GFC_DTYPE_INTEGER_2:
60     case GFC_DTYPE_LOGICAL_2:
61       return internal_pack_2 ((gfc_array_i2 *) source);
62 
63     case GFC_DTYPE_INTEGER_4:
64     case GFC_DTYPE_LOGICAL_4:
65       return internal_pack_4 ((gfc_array_i4 *) source);
66 
67     case GFC_DTYPE_INTEGER_8:
68     case GFC_DTYPE_LOGICAL_8:
69       return internal_pack_8 ((gfc_array_i8 *) source);
70 
71 #if defined(HAVE_GFC_INTEGER_16)
72     case GFC_DTYPE_INTEGER_16:
73     case GFC_DTYPE_LOGICAL_16:
74       return internal_pack_16 ((gfc_array_i16 *) source);
75 #endif
76     case GFC_DTYPE_REAL_4:
77       return internal_pack_r4 ((gfc_array_r4 *) source);
78 
79     case GFC_DTYPE_REAL_8:
80       return internal_pack_r8 ((gfc_array_r8 *) source);
81 
82 /* FIXME: This here is a hack, which will have to be removed when
83    the array descriptor is reworked.  Currently, we don't store the
84    kind value for the type, but only the size.  Because on targets with
85    __float128, we have sizeof(logn double) == sizeof(__float128),
86    we cannot discriminate here and have to fall back to the generic
87    handling (which is suboptimal).  */
88 #if !defined(GFC_REAL_16_IS_FLOAT128)
89 # if defined (HAVE_GFC_REAL_10)
90     case GFC_DTYPE_REAL_10:
91       return internal_pack_r10 ((gfc_array_r10 *) source);
92 # endif
93 
94 # if defined (HAVE_GFC_REAL_16)
95     case GFC_DTYPE_REAL_16:
96       return internal_pack_r16 ((gfc_array_r16 *) source);
97 # endif
98 #endif
99 
100     case GFC_DTYPE_COMPLEX_4:
101       return internal_pack_c4 ((gfc_array_c4 *) source);
102 
103     case GFC_DTYPE_COMPLEX_8:
104       return internal_pack_c8 ((gfc_array_c8 *) source);
105 
106 /* FIXME: This here is a hack, which will have to be removed when
107    the array descriptor is reworked.  Currently, we don't store the
108    kind value for the type, but only the size.  Because on targets with
109    __float128, we have sizeof(logn double) == sizeof(__float128),
110    we cannot discriminate here and have to fall back to the generic
111    handling (which is suboptimal).  */
112 #if !defined(GFC_REAL_16_IS_FLOAT128)
113 # if defined (HAVE_GFC_COMPLEX_10)
114     case GFC_DTYPE_COMPLEX_10:
115       return internal_pack_c10 ((gfc_array_c10 *) source);
116 # endif
117 
118 # if defined (HAVE_GFC_COMPLEX_16)
119     case GFC_DTYPE_COMPLEX_16:
120       return internal_pack_c16 ((gfc_array_c16 *) source);
121 # endif
122 #endif
123 
124     default:
125       break;
126     }
127 
128   switch(GFC_DESCRIPTOR_SIZE (source))
129     {
130     case 1:
131       return internal_pack_1 ((gfc_array_i1 *) source);
132 
133     case 2:
134       if (GFC_UNALIGNED_2(source->base_addr))
135 	break;
136       else
137 	return internal_pack_2 ((gfc_array_i2 *) source);
138 
139     case 4:
140       if (GFC_UNALIGNED_4(source->base_addr))
141 	break;
142       else
143 	return internal_pack_4 ((gfc_array_i4 *) source);
144 
145     case 8:
146       if (GFC_UNALIGNED_8(source->base_addr))
147 	break;
148       else
149 	return internal_pack_8 ((gfc_array_i8 *) source);
150 
151 #ifdef HAVE_GFC_INTEGER_16
152     case 16:
153       if (GFC_UNALIGNED_16(source->base_addr))
154 	break;
155       else
156 	return internal_pack_16 ((gfc_array_i16 *) source);
157 #endif
158     default:
159       break;
160     }
161 
162   dim = GFC_DESCRIPTOR_RANK (source);
163   ssize = 1;
164   packed = 1;
165   for (index_type n = 0; n < dim; n++)
166     {
167       count[n] = 0;
168       stride[n] = GFC_DESCRIPTOR_STRIDE(source,n);
169       extent[n] = GFC_DESCRIPTOR_EXTENT(source,n);
170       if (extent[n] <= 0)
171         {
172           /* Do nothing.  */
173           packed = 1;
174           break;
175         }
176 
177       if (ssize != stride[n])
178         packed = 0;
179 
180       ssize *= extent[n];
181     }
182 
183   if (packed)
184     return source->base_addr;
185 
186    /* Allocate storage for the destination.  */
187   destptr = xmallocarray (ssize, size);
188   dest = (char *)destptr;
189   src = source->base_addr;
190   stride0 = stride[0] * size;
191 
192   while (src)
193     {
194       /* Copy the data.  */
195       memcpy(dest, src, size);
196       /* Advance to the next element.  */
197       dest += size;
198       src += stride0;
199       count[0]++;
200       /* Advance to the next source element.  */
201       index_type n = 0;
202       while (count[n] == extent[n])
203         {
204           /* When we get to the end of a dimension, reset it and increment
205              the next dimension.  */
206           count[n] = 0;
207           /* We could precalculate these products, but this is a less
208              frequently used path so probably not worth it.  */
209           src -= stride[n] * extent[n] * size;
210           n++;
211           if (n == dim)
212             {
213               src = NULL;
214               break;
215             }
216           else
217             {
218               count[n]++;
219               src += stride[n] * size;
220             }
221         }
222     }
223   return destptr;
224 }
225