OSDN Git Service

2fbf62e118c70675e7b6b83df54738a80efc1c63
[pf3gnuchains/gcc-fork.git] / libgfortran / intrinsics / eoshift2.c
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>
4
5 This file is part of the GNU Fortran 95 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 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.
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 /* TODO: make this work for large shifts when
32    sizeof(int) < sizeof (index_type).  */
33
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)
38 {
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;
55
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;
63
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;
69
70   size = GFC_DESCRIPTOR_SIZE (array);
71
72   arraysize = size0 ((array_t *) array);
73
74   if (ret->data == NULL)
75     {
76       int i;
77
78       ret->offset = 0;
79       ret->dtype = array->dtype;
80       for (i = 0; i < GFC_DESCRIPTOR_RANK (array); i++)
81         {
82           index_type ub, str;
83
84           ub = GFC_DESCRIPTOR_EXTENT(array,i) - 1;
85
86           if (i == 0)
87             str = 1;
88           else
89             str = GFC_DESCRIPTOR_EXTENT(ret,i-1)
90               * GFC_DESCRIPTOR_STRIDE(ret,i-1);
91
92           GFC_DIMENSION_SET(ret->dim[i], 0, ub, str);
93
94           if (arraysize > 0)
95             ret->data = internal_malloc_size (size * arraysize);
96           else
97             ret->data = internal_malloc_size (1);
98
99         }
100     }
101   else if (unlikely (compile_options.bounds_check))
102     {
103       bounds_equal_extents ((array_t *) ret, (array_t *) array,
104                                  "return value", "EOSHIFT");
105     }
106
107   if (arraysize == 0)
108     return;
109
110   which = which - 1;
111
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++)
119     {
120       if (dim == which)
121         {
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);
129         }
130       else
131         {
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++;
141         }
142     }
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;
149
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;
156
157   if ((shift >= 0 ? shift : -shift ) > len)
158     {
159       shift = len;
160       len = 0;
161     }
162   else
163     {
164       if (shift > 0)
165         len = len - shift;
166       else
167         len = len + shift;
168     }
169   
170   if (bound)
171     bptr = bound->data;
172   else
173     bptr = NULL;
174
175   while (rptr)
176     {
177       /* Do the shift for this dimension.  */
178       if (shift > 0)
179         {
180           src = &sptr[shift * soffset];
181           dest = rptr;
182         }
183       else
184         {
185           src = sptr;
186           dest = &rptr[-shift * roffset];
187         }
188       for (n = 0; n < len; n++)
189         {
190           memcpy (dest, src, size);
191           dest += roffset;
192           src += soffset;
193         }
194       if (shift >= 0)
195         {
196           n = shift;
197         }
198       else
199         {
200           dest = rptr;
201           n = -shift;
202         }
203
204       if (bptr)
205         while (n--)
206           {
207             memcpy (dest, bptr, size);
208             dest += roffset;
209           }
210       else
211         while (n--)
212           {
213             index_type i;
214
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);
220
221             dest += roffset;
222           }
223
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])
231         {
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)
242             {
243               /* Break out of the loop.  */
244               rptr = NULL;
245               break;
246             }
247           else
248             {
249               count[n]++;
250               rptr += rstride[n];
251               sptr += sstride[n];
252               bptr += bstride[n];
253             }
254         }
255     }
256 }
257
258
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);                                                 \
264                                                                               \
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)                                  \
269   {                                                                           \
270     eoshift2 (ret, array, *pshift, pbound, pdim ? *pdim : 1,                  \
271               "\0", 1);                       \
272   }                                                                           \
273                                                                               \
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);                                          \
281                                                                               \
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)))    \
291   {                                                                           \
292     eoshift2 (ret, array, *pshift, pbound, pdim ? *pdim : 1,                  \
293               " ", 1);                                                        \
294   }                                                                           \
295                                                                               \
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);                                         \
303                                                                               \
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)))   \
313   {                                                                           \
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));                                          \
318   }
319
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