* events.c (hash_param_callback): Allow NULL to stand for empty
[official-gcc.git] / libgfortran / intrinsics / eoshift2.c
blob2fbf62e118c70675e7b6b83df54738a80efc1c63
1 /* Generic implementation of the EOSHIFT intrinsic
2 Copyright 2002, 2005, 2007, 2009 Free Software Foundation, Inc.
3 Contributed by Paul Brook <paul@nowt.org>
5 This file is part of the GNU Fortran 95 runtime library (libgfortran).
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.
12 Ligbfortran 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.
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.
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/>. */
26 #include "libgfortran.h"
27 #include <stdlib.h>
28 #include <assert.h>
29 #include <string.h>
31 /* TODO: make this work for large shifts when
32 sizeof(int) < sizeof (index_type). */
34 static void
35 eoshift2 (gfc_array_char *ret, const gfc_array_char *array,
36 int shift, const gfc_array_char *bound, int which,
37 const char *filler, index_type filler_len)
39 /* r.* indicates the return array. */
40 index_type rstride[GFC_MAX_DIMENSIONS];
41 index_type rstride0;
42 index_type roffset;
43 char * restrict rptr;
44 char *dest;
45 /* s.* indicates the source array. */
46 index_type sstride[GFC_MAX_DIMENSIONS];
47 index_type sstride0;
48 index_type soffset;
49 const char *sptr;
50 const char *src;
51 /* b.* indicates the bound array. */
52 index_type bstride[GFC_MAX_DIMENSIONS];
53 index_type bstride0;
54 const char *bptr;
56 index_type count[GFC_MAX_DIMENSIONS];
57 index_type extent[GFC_MAX_DIMENSIONS];
58 index_type dim;
59 index_type len;
60 index_type n;
61 index_type arraysize;
62 index_type size;
64 /* The compiler cannot figure out that these are set, initialize
65 them to avoid warnings. */
66 len = 0;
67 soffset = 0;
68 roffset = 0;
70 size = GFC_DESCRIPTOR_SIZE (array);
72 arraysize = size0 ((array_t *) array);
74 if (ret->data == NULL)
76 int i;
78 ret->offset = 0;
79 ret->dtype = array->dtype;
80 for (i = 0; i < GFC_DESCRIPTOR_RANK (array); i++)
82 index_type ub, str;
84 ub = GFC_DESCRIPTOR_EXTENT(array,i) - 1;
86 if (i == 0)
87 str = 1;
88 else
89 str = GFC_DESCRIPTOR_EXTENT(ret,i-1)
90 * GFC_DESCRIPTOR_STRIDE(ret,i-1);
92 GFC_DIMENSION_SET(ret->dim[i], 0, ub, str);
94 if (arraysize > 0)
95 ret->data = internal_malloc_size (size * arraysize);
96 else
97 ret->data = internal_malloc_size (1);
101 else if (unlikely (compile_options.bounds_check))
103 bounds_equal_extents ((array_t *) ret, (array_t *) array,
104 "return value", "EOSHIFT");
107 if (arraysize == 0)
108 return;
110 which = which - 1;
112 extent[0] = 1;
113 count[0] = 0;
114 sstride[0] = -1;
115 rstride[0] = -1;
116 bstride[0] = -1;
117 n = 0;
118 for (dim = 0; dim < GFC_DESCRIPTOR_RANK (array); dim++)
120 if (dim == which)
122 roffset = GFC_DESCRIPTOR_STRIDE_BYTES(ret,dim);
123 if (roffset == 0)
124 roffset = size;
125 soffset = GFC_DESCRIPTOR_STRIDE_BYTES(array,dim);
126 if (soffset == 0)
127 soffset = size;
128 len = GFC_DESCRIPTOR_EXTENT(array,dim);
130 else
132 count[n] = 0;
133 extent[n] = GFC_DESCRIPTOR_EXTENT(array,dim);
134 rstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(ret,dim);
135 sstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(array,dim);
136 if (bound)
137 bstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(bound,n);
138 else
139 bstride[n] = 0;
140 n++;
143 if (sstride[0] == 0)
144 sstride[0] = size;
145 if (rstride[0] == 0)
146 rstride[0] = size;
147 if (bound && bstride[0] == 0)
148 bstride[0] = size;
150 dim = GFC_DESCRIPTOR_RANK (array);
151 rstride0 = rstride[0];
152 sstride0 = sstride[0];
153 bstride0 = bstride[0];
154 rptr = ret->data;
155 sptr = array->data;
157 if ((shift >= 0 ? shift : -shift ) > len)
159 shift = len;
160 len = 0;
162 else
164 if (shift > 0)
165 len = len - shift;
166 else
167 len = len + shift;
170 if (bound)
171 bptr = bound->data;
172 else
173 bptr = NULL;
175 while (rptr)
177 /* Do the shift for this dimension. */
178 if (shift > 0)
180 src = &sptr[shift * soffset];
181 dest = rptr;
183 else
185 src = sptr;
186 dest = &rptr[-shift * roffset];
188 for (n = 0; n < len; n++)
190 memcpy (dest, src, size);
191 dest += roffset;
192 src += soffset;
194 if (shift >= 0)
196 n = shift;
198 else
200 dest = rptr;
201 n = -shift;
204 if (bptr)
205 while (n--)
207 memcpy (dest, bptr, size);
208 dest += roffset;
210 else
211 while (n--)
213 index_type i;
215 if (filler_len == 1)
216 memset (dest, filler[0], size);
217 else
218 for (i = 0; i < size ; i += filler_len)
219 memcpy (&dest[i], filler, filler_len);
221 dest += roffset;
224 /* Advance to the next section. */
225 rptr += rstride0;
226 sptr += sstride0;
227 bptr += bstride0;
228 count[0]++;
229 n = 0;
230 while (count[n] == extent[n])
232 /* When we get to the end of a dimension, reset it and increment
233 the next dimension. */
234 count[n] = 0;
235 /* We could precalculate these products, but this is a less
236 frequently used path so probably not worth it. */
237 rptr -= rstride[n] * extent[n];
238 sptr -= sstride[n] * extent[n];
239 bptr -= bstride[n] * extent[n];
240 n++;
241 if (n >= dim - 1)
243 /* Break out of the loop. */
244 rptr = NULL;
245 break;
247 else
249 count[n]++;
250 rptr += rstride[n];
251 sptr += sstride[n];
252 bptr += bstride[n];
259 #define DEFINE_EOSHIFT(N) \
260 extern void eoshift2_##N (gfc_array_char *, const gfc_array_char *, \
261 const GFC_INTEGER_##N *, const gfc_array_char *, \
262 const GFC_INTEGER_##N *); \
263 export_proto(eoshift2_##N); \
265 void \
266 eoshift2_##N (gfc_array_char *ret, const gfc_array_char *array, \
267 const GFC_INTEGER_##N *pshift, const gfc_array_char *pbound, \
268 const GFC_INTEGER_##N *pdim) \
270 eoshift2 (ret, array, *pshift, pbound, pdim ? *pdim : 1, \
271 "\0", 1); \
274 extern void eoshift2_##N##_char (gfc_array_char *, GFC_INTEGER_4, \
275 const gfc_array_char *, \
276 const GFC_INTEGER_##N *, \
277 const gfc_array_char *, \
278 const GFC_INTEGER_##N *, \
279 GFC_INTEGER_4, GFC_INTEGER_4); \
280 export_proto(eoshift2_##N##_char); \
282 void \
283 eoshift2_##N##_char (gfc_array_char *ret, \
284 GFC_INTEGER_4 ret_length __attribute__((unused)), \
285 const gfc_array_char *array, \
286 const GFC_INTEGER_##N *pshift, \
287 const gfc_array_char *pbound, \
288 const GFC_INTEGER_##N *pdim, \
289 GFC_INTEGER_4 array_length __attribute__((unused)), \
290 GFC_INTEGER_4 bound_length __attribute__((unused))) \
292 eoshift2 (ret, array, *pshift, pbound, pdim ? *pdim : 1, \
293 " ", 1); \
296 extern void eoshift2_##N##_char4 (gfc_array_char *, GFC_INTEGER_4, \
297 const gfc_array_char *, \
298 const GFC_INTEGER_##N *, \
299 const gfc_array_char *, \
300 const GFC_INTEGER_##N *, \
301 GFC_INTEGER_4, GFC_INTEGER_4); \
302 export_proto(eoshift2_##N##_char4); \
304 void \
305 eoshift2_##N##_char4 (gfc_array_char *ret, \
306 GFC_INTEGER_4 ret_length __attribute__((unused)), \
307 const gfc_array_char *array, \
308 const GFC_INTEGER_##N *pshift, \
309 const gfc_array_char *pbound, \
310 const GFC_INTEGER_##N *pdim, \
311 GFC_INTEGER_4 array_length __attribute__((unused)), \
312 GFC_INTEGER_4 bound_length __attribute__((unused))) \
314 static const gfc_char4_t space = (unsigned char) ' '; \
315 eoshift2 (ret, array, *pshift, pbound, pdim ? *pdim : 1, \
316 (const char *) &space, \
317 sizeof (gfc_char4_t)); \
320 DEFINE_EOSHIFT (1);
321 DEFINE_EOSHIFT (2);
322 DEFINE_EOSHIFT (4);
323 DEFINE_EOSHIFT (8);
324 #ifdef HAVE_GFC_INTEGER_16
325 DEFINE_EOSHIFT (16);
326 #endif