]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/libgfortran/lib/contrib/intrinsics/cshift0.c
Update
[l4.git] / l4 / pkg / libgfortran / lib / contrib / intrinsics / cshift0.c
1 /* Generic implementation of the CSHIFT intrinsic
2    Copyright (C) 2003-2015 Free Software Foundation, Inc.
3    Contributed by Feng Wang <wf_cs@yahoo.com>
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 <stdlib.h>
28 #include <assert.h>
29 #include <string.h>
30
31 static void
32 cshift0 (gfc_array_char * ret, const gfc_array_char * array,
33          ptrdiff_t shift, int which, index_type size)
34 {
35   /* r.* indicates the return array.  */
36   index_type rstride[GFC_MAX_DIMENSIONS];
37   index_type rstride0;
38   index_type roffset;
39   char *rptr;
40
41   /* s.* indicates the source array.  */
42   index_type sstride[GFC_MAX_DIMENSIONS];
43   index_type sstride0;
44   index_type soffset;
45   const char *sptr;
46
47   index_type count[GFC_MAX_DIMENSIONS];
48   index_type extent[GFC_MAX_DIMENSIONS];
49   index_type dim;
50   index_type len;
51   index_type n;
52   index_type arraysize;
53
54   index_type type_size;
55
56   if (which < 1 || which > GFC_DESCRIPTOR_RANK (array))
57     runtime_error ("Argument 'DIM' is out of range in call to 'CSHIFT'");
58
59   arraysize = size0 ((array_t *) array);
60
61   if (ret->base_addr == NULL)
62     {
63       int i;
64
65       ret->offset = 0;
66       ret->dtype = array->dtype;
67       for (i = 0; i < GFC_DESCRIPTOR_RANK (array); i++)
68         {
69           index_type ub, str;
70
71           ub = GFC_DESCRIPTOR_EXTENT(array,i) - 1;
72
73           if (i == 0)
74             str = 1;
75           else
76             str = GFC_DESCRIPTOR_EXTENT(ret,i-1) *
77               GFC_DESCRIPTOR_STRIDE(ret,i-1);
78
79           GFC_DIMENSION_SET(ret->dim[i], 0, ub, str);
80         }
81
82       /* xmallocarray allocates a single byte for zero size.  */
83       ret->base_addr = xmallocarray (arraysize, size);
84     }
85   else if (unlikely (compile_options.bounds_check))
86     {
87       bounds_equal_extents ((array_t *) ret, (array_t *) array,
88                                  "return value", "CSHIFT");
89     }
90
91   if (arraysize == 0)
92     return;
93
94   type_size = GFC_DTYPE_TYPE_SIZE (array);
95
96   switch(type_size)
97     {
98     case GFC_DTYPE_LOGICAL_1:
99     case GFC_DTYPE_INTEGER_1:
100     case GFC_DTYPE_DERIVED_1:
101       cshift0_i1 ((gfc_array_i1 *)ret, (gfc_array_i1 *) array, shift, which);
102       return;
103
104     case GFC_DTYPE_LOGICAL_2:
105     case GFC_DTYPE_INTEGER_2:
106       cshift0_i2 ((gfc_array_i2 *)ret, (gfc_array_i2 *) array, shift, which);
107       return;
108
109     case GFC_DTYPE_LOGICAL_4:
110     case GFC_DTYPE_INTEGER_4:
111       cshift0_i4 ((gfc_array_i4 *)ret, (gfc_array_i4 *) array, shift, which);
112       return;
113
114     case GFC_DTYPE_LOGICAL_8:
115     case GFC_DTYPE_INTEGER_8:
116       cshift0_i8 ((gfc_array_i8 *)ret, (gfc_array_i8 *) array, shift, which);
117       return;
118
119 #ifdef HAVE_GFC_INTEGER_16
120     case GFC_DTYPE_LOGICAL_16:
121     case GFC_DTYPE_INTEGER_16:
122       cshift0_i16 ((gfc_array_i16 *)ret, (gfc_array_i16 *) array, shift,
123                    which);
124       return;
125 #endif
126
127     case GFC_DTYPE_REAL_4:
128       cshift0_r4 ((gfc_array_r4 *)ret, (gfc_array_r4 *) array, shift, which);
129       return;
130
131     case GFC_DTYPE_REAL_8:
132       cshift0_r8 ((gfc_array_r8 *)ret, (gfc_array_r8 *) array, shift, which);
133       return;
134
135 /* FIXME: This here is a hack, which will have to be removed when
136    the array descriptor is reworked.  Currently, we don't store the
137    kind value for the type, but only the size.  Because on targets with
138    __float128, we have sizeof(logn double) == sizeof(__float128),
139    we cannot discriminate here and have to fall back to the generic
140    handling (which is suboptimal).  */
141 #if !defined(GFC_REAL_16_IS_FLOAT128)
142 # ifdef HAVE_GFC_REAL_10
143     case GFC_DTYPE_REAL_10:
144       cshift0_r10 ((gfc_array_r10 *)ret, (gfc_array_r10 *) array, shift,
145                    which);
146       return;
147 # endif
148
149 # ifdef HAVE_GFC_REAL_16
150     case GFC_DTYPE_REAL_16:
151       cshift0_r16 ((gfc_array_r16 *)ret, (gfc_array_r16 *) array, shift,
152                    which);
153       return;
154 # endif
155 #endif
156
157     case GFC_DTYPE_COMPLEX_4:
158       cshift0_c4 ((gfc_array_c4 *)ret, (gfc_array_c4 *) array, shift, which);
159       return;
160
161     case GFC_DTYPE_COMPLEX_8:
162       cshift0_c8 ((gfc_array_c8 *)ret, (gfc_array_c8 *) array, shift, which);
163       return;
164
165 /* FIXME: This here is a hack, which will have to be removed when
166    the array descriptor is reworked.  Currently, we don't store the
167    kind value for the type, but only the size.  Because on targets with
168    __float128, we have sizeof(logn double) == sizeof(__float128),
169    we cannot discriminate here and have to fall back to the generic
170    handling (which is suboptimal).  */
171 #if !defined(GFC_REAL_16_IS_FLOAT128)
172 # ifdef HAVE_GFC_COMPLEX_10
173     case GFC_DTYPE_COMPLEX_10:
174       cshift0_c10 ((gfc_array_c10 *)ret, (gfc_array_c10 *) array, shift,
175                    which);
176       return;
177 # endif
178
179 # ifdef HAVE_GFC_COMPLEX_16
180     case GFC_DTYPE_COMPLEX_16:
181       cshift0_c16 ((gfc_array_c16 *)ret, (gfc_array_c16 *) array, shift,
182                    which);
183       return;
184 # endif
185 #endif
186
187     default:
188       break;
189     }
190
191   switch (size)
192     {
193       /* Let's check the actual alignment of the data pointers.  If they
194          are suitably aligned, we can safely call the unpack functions.  */
195
196     case sizeof (GFC_INTEGER_1):
197       cshift0_i1 ((gfc_array_i1 *) ret, (gfc_array_i1 *) array, shift,
198                   which);
199       break;
200
201     case sizeof (GFC_INTEGER_2):
202       if (GFC_UNALIGNED_2(ret->base_addr) || GFC_UNALIGNED_2(array->base_addr))
203         break;
204       else
205         {
206           cshift0_i2 ((gfc_array_i2 *) ret, (gfc_array_i2 *) array, shift,
207                       which);
208           return;
209         }
210
211     case sizeof (GFC_INTEGER_4):
212       if (GFC_UNALIGNED_4(ret->base_addr) || GFC_UNALIGNED_4(array->base_addr))
213         break;
214       else
215         {
216           cshift0_i4 ((gfc_array_i4 *)ret, (gfc_array_i4 *) array, shift,
217                       which);
218           return;
219         }
220
221     case sizeof (GFC_INTEGER_8):
222       if (GFC_UNALIGNED_8(ret->base_addr) || GFC_UNALIGNED_8(array->base_addr))
223         {
224           /* Let's try to use the complex routines.  First, a sanity
225              check that the sizes match; this should be optimized to
226              a no-op.  */
227           if (sizeof(GFC_INTEGER_8) != sizeof(GFC_COMPLEX_4))
228             break;
229
230           if (GFC_UNALIGNED_C4(ret->base_addr)
231               || GFC_UNALIGNED_C4(array->base_addr))
232             break;
233
234           cshift0_c4 ((gfc_array_c4 *) ret, (gfc_array_c4 *) array, shift,
235                       which);
236           return;
237         }
238       else
239         {
240           cshift0_i8 ((gfc_array_i8 *)ret, (gfc_array_i8 *) array, shift,
241                       which);
242           return;
243         }
244
245 #ifdef HAVE_GFC_INTEGER_16
246     case sizeof (GFC_INTEGER_16):
247       if (GFC_UNALIGNED_16(ret->base_addr)
248           || GFC_UNALIGNED_16(array->base_addr))
249         {
250           /* Let's try to use the complex routines.  First, a sanity
251              check that the sizes match; this should be optimized to
252              a no-op.  */
253           if (sizeof(GFC_INTEGER_16) != sizeof(GFC_COMPLEX_8))
254             break;
255
256           if (GFC_UNALIGNED_C8(ret->base_addr)
257               || GFC_UNALIGNED_C8(array->base_addr))
258             break;
259
260           cshift0_c8 ((gfc_array_c8 *) ret, (gfc_array_c8 *) array, shift,
261                       which);
262           return;
263         }
264       else
265         {
266           cshift0_i16 ((gfc_array_i16 *) ret, (gfc_array_i16 *) array,
267                        shift, which);
268           return;
269         }
270 #else
271     case sizeof (GFC_COMPLEX_8):
272
273       if (GFC_UNALIGNED_C8(ret->base_addr)
274           || GFC_UNALIGNED_C8(array->base_addr))
275         break;
276       else
277         {
278           cshift0_c8 ((gfc_array_c8 *) ret, (gfc_array_c8 *) array, shift,
279                       which);
280           return;
281         }
282 #endif
283
284     default:
285       break;
286     }
287
288
289   which = which - 1;
290   sstride[0] = 0;
291   rstride[0] = 0;
292
293   extent[0] = 1;
294   count[0] = 0;
295   n = 0;
296   /* Initialized for avoiding compiler warnings.  */
297   roffset = size;
298   soffset = size;
299   len = 0;
300
301   for (dim = 0; dim < GFC_DESCRIPTOR_RANK (array); dim++)
302     {
303       if (dim == which)
304         {
305           roffset = GFC_DESCRIPTOR_STRIDE_BYTES(ret,dim);
306           if (roffset == 0)
307             roffset = size;
308           soffset = GFC_DESCRIPTOR_STRIDE_BYTES(array,dim);
309           if (soffset == 0)
310             soffset = size;
311           len = GFC_DESCRIPTOR_EXTENT(array,dim);
312         }
313       else
314         {
315           count[n] = 0;
316           extent[n] = GFC_DESCRIPTOR_EXTENT(array,dim);
317           rstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(ret,dim);
318           sstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(array,dim);
319           n++;
320         }
321     }
322   if (sstride[0] == 0)
323     sstride[0] = size;
324   if (rstride[0] == 0)
325     rstride[0] = size;
326
327   dim = GFC_DESCRIPTOR_RANK (array);
328   rstride0 = rstride[0];
329   sstride0 = sstride[0];
330   rptr = ret->base_addr;
331   sptr = array->base_addr;
332
333   shift = len == 0 ? 0 : shift % (ptrdiff_t)len;
334   if (shift < 0)
335     shift += len;
336
337   while (rptr)
338     {
339       /* Do the shift for this dimension.  */
340
341       /* If elements are contiguous, perform the operation
342          in two block moves.  */
343       if (soffset == size && roffset == size)
344         {
345           size_t len1 = shift * size;
346           size_t len2 = (len - shift) * size;
347           memcpy (rptr, sptr + len1, len2);
348           memcpy (rptr + len2, sptr, len1);
349         }
350       else
351         {
352           /* Otherwise, we'll have to perform the copy one element at
353              a time.  */
354           char *dest = rptr;
355           const char *src = &sptr[shift * soffset];
356
357           for (n = 0; n < len - shift; n++)
358             {
359               memcpy (dest, src, size);
360               dest += roffset;
361               src += soffset;
362             }
363           for (src = sptr, n = 0; n < shift; n++)
364             {
365               memcpy (dest, src, size);
366               dest += roffset;
367               src += soffset;
368             }
369         }
370
371       /* Advance to the next section.  */
372       rptr += rstride0;
373       sptr += sstride0;
374       count[0]++;
375       n = 0;
376       while (count[n] == extent[n])
377         {
378           /* When we get to the end of a dimension, reset it and increment
379              the next dimension.  */
380           count[n] = 0;
381           /* We could precalculate these products, but this is a less
382              frequently used path so probably not worth it.  */
383           rptr -= rstride[n] * extent[n];
384           sptr -= sstride[n] * extent[n];
385           n++;
386           if (n >= dim - 1)
387             {
388               /* Break out of the loop.  */
389               rptr = NULL;
390               break;
391             }
392           else
393             {
394               count[n]++;
395               rptr += rstride[n];
396               sptr += sstride[n];
397             }
398         }
399     }
400 }
401
402 #define DEFINE_CSHIFT(N)                                                      \
403   extern void cshift0_##N (gfc_array_char *, const gfc_array_char *,          \
404                            const GFC_INTEGER_##N *, const GFC_INTEGER_##N *); \
405   export_proto(cshift0_##N);                                                  \
406                                                                               \
407   void                                                                        \
408   cshift0_##N (gfc_array_char *ret, const gfc_array_char *array,              \
409                const GFC_INTEGER_##N *pshift, const GFC_INTEGER_##N *pdim)    \
410   {                                                                           \
411     cshift0 (ret, array, *pshift, pdim ? *pdim : 1,                           \
412              GFC_DESCRIPTOR_SIZE (array));                                    \
413   }                                                                           \
414                                                                               \
415   extern void cshift0_##N##_char (gfc_array_char *, GFC_INTEGER_4,            \
416                                   const gfc_array_char *,                     \
417                                   const GFC_INTEGER_##N *,                    \
418                                   const GFC_INTEGER_##N *, GFC_INTEGER_4);    \
419   export_proto(cshift0_##N##_char);                                           \
420                                                                               \
421   void                                                                        \
422   cshift0_##N##_char (gfc_array_char *ret,                                    \
423                       GFC_INTEGER_4 ret_length __attribute__((unused)),       \
424                       const gfc_array_char *array,                            \
425                       const GFC_INTEGER_##N *pshift,                          \
426                       const GFC_INTEGER_##N *pdim,                            \
427                       GFC_INTEGER_4 array_length)                             \
428   {                                                                           \
429     cshift0 (ret, array, *pshift, pdim ? *pdim : 1, array_length);            \
430   }                                                                           \
431                                                                               \
432   extern void cshift0_##N##_char4 (gfc_array_char *, GFC_INTEGER_4,           \
433                                    const gfc_array_char *,                    \
434                                    const GFC_INTEGER_##N *,                   \
435                                    const GFC_INTEGER_##N *, GFC_INTEGER_4);   \
436   export_proto(cshift0_##N##_char4);                                          \
437                                                                               \
438   void                                                                        \
439   cshift0_##N##_char4 (gfc_array_char *ret,                                   \
440                        GFC_INTEGER_4 ret_length __attribute__((unused)),      \
441                        const gfc_array_char *array,                           \
442                        const GFC_INTEGER_##N *pshift,                         \
443                        const GFC_INTEGER_##N *pdim,                           \
444                        GFC_INTEGER_4 array_length)                            \
445   {                                                                           \
446     cshift0 (ret, array, *pshift, pdim ? *pdim : 1,                           \
447              array_length * sizeof (gfc_char4_t));                            \
448   }
449
450 DEFINE_CSHIFT (1);
451 DEFINE_CSHIFT (2);
452 DEFINE_CSHIFT (4);
453 DEFINE_CSHIFT (8);
454 #ifdef HAVE_GFC_INTEGER_16
455 DEFINE_CSHIFT (16);
456 #endif