OSDN Git Service

PR target/36090
[pf3gnuchains/gcc-fork.git] / libgfortran / intrinsics / eoshift2.c
1 /* Generic implementation of the EOSHIFT intrinsic
2    Copyright 2002, 2005, 2007 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 2 of the License, or (at your option) any later version.
11
12 In addition to the permissions in the GNU General Public License, the
13 Free Software Foundation gives you unlimited permission to link the
14 compiled version of this file into combinations with other programs,
15 and to distribute those combinations without any restriction coming
16 from the use of this file.  (The General Public License restrictions
17 do apply in other respects; for example, they cover modification of
18 the file, and distribution when not linked into a combine
19 executable.)
20
21 Ligbfortran is distributed in the hope that it will be useful,
22 but WITHOUT ANY WARRANTY; without even the implied warranty of
23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24 GNU General Public License for more details.
25
26 You should have received a copy of the GNU General Public
27 License along with libgfortran; see the file COPYING.  If not,
28 write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
29 Boston, MA 02110-1301, USA.  */
30
31 #include "libgfortran.h"
32 #include <stdlib.h>
33 #include <assert.h>
34 #include <string.h>
35
36 /* TODO: make this work for large shifts when
37    sizeof(int) < sizeof (index_type).  */
38
39 static void
40 eoshift2 (gfc_array_char *ret, const gfc_array_char *array,
41           int shift, const gfc_array_char *bound, int which,
42           index_type size, char filler)
43 {
44   /* r.* indicates the return array.  */
45   index_type rstride[GFC_MAX_DIMENSIONS];
46   index_type rstride0;
47   index_type roffset;
48   char *rptr;
49   char *dest;
50   /* s.* indicates the source array.  */
51   index_type sstride[GFC_MAX_DIMENSIONS];
52   index_type sstride0;
53   index_type soffset;
54   const char *sptr;
55   const char *src;
56   /* b.* indicates the bound array.  */
57   index_type bstride[GFC_MAX_DIMENSIONS];
58   index_type bstride0;
59   const char *bptr;
60
61   index_type count[GFC_MAX_DIMENSIONS];
62   index_type extent[GFC_MAX_DIMENSIONS];
63   index_type dim;
64   index_type len;
65   index_type n;
66
67   /* The compiler cannot figure out that these are set, initialize
68      them to avoid warnings.  */
69   len = 0;
70   soffset = 0;
71   roffset = 0;
72
73   if (ret->data == NULL)
74     {
75       int i;
76
77       ret->data = internal_malloc_size (size * size0 ((array_t *)array));
78       ret->offset = 0;
79       ret->dtype = array->dtype;
80       for (i = 0; i < GFC_DESCRIPTOR_RANK (array); i++)
81         {
82           ret->dim[i].lbound = 0;
83           ret->dim[i].ubound = array->dim[i].ubound - array->dim[i].lbound;
84
85           if (i == 0)
86             ret->dim[i].stride = 1;
87           else
88             ret->dim[i].stride = (ret->dim[i-1].ubound + 1) * ret->dim[i-1].stride;
89         }
90     }
91
92   which = which - 1;
93
94   extent[0] = 1;
95   count[0] = 0;
96   sstride[0] = -1;
97   rstride[0] = -1;
98   bstride[0] = -1;
99   n = 0;
100   for (dim = 0; dim < GFC_DESCRIPTOR_RANK (array); dim++)
101     {
102       if (dim == which)
103         {
104           roffset = ret->dim[dim].stride * size;
105           if (roffset == 0)
106             roffset = size;
107           soffset = array->dim[dim].stride * size;
108           if (soffset == 0)
109             soffset = size;
110           len = array->dim[dim].ubound + 1 - array->dim[dim].lbound;
111         }
112       else
113         {
114           count[n] = 0;
115           extent[n] = array->dim[dim].ubound + 1 - array->dim[dim].lbound;
116           rstride[n] = ret->dim[dim].stride * size;
117           sstride[n] = array->dim[dim].stride * size;
118           if (bound)
119             bstride[n] = bound->dim[n].stride * size;
120           else
121             bstride[n] = 0;
122           n++;
123         }
124     }
125   if (sstride[0] == 0)
126     sstride[0] = size;
127   if (rstride[0] == 0)
128     rstride[0] = size;
129   if (bound && bstride[0] == 0)
130     bstride[0] = size;
131
132   dim = GFC_DESCRIPTOR_RANK (array);
133   rstride0 = rstride[0];
134   sstride0 = sstride[0];
135   bstride0 = bstride[0];
136   rptr = ret->data;
137   sptr = array->data;
138
139   if ((shift >= 0 ? shift : -shift ) > len)
140     {
141       shift = len;
142       len = 0;
143     }
144   else
145     {
146       if (shift > 0)
147         len = len - shift;
148       else
149         len = len + shift;
150     }
151   
152   if (bound)
153     bptr = bound->data;
154   else
155     bptr = NULL;
156
157   while (rptr)
158     {
159       /* Do the shift for this dimension.  */
160       if (shift > 0)
161         {
162           src = &sptr[shift * soffset];
163           dest = rptr;
164         }
165       else
166         {
167           src = sptr;
168           dest = &rptr[-shift * roffset];
169         }
170       for (n = 0; n < len; n++)
171         {
172           memcpy (dest, src, size);
173           dest += roffset;
174           src += soffset;
175         }
176       if (shift >= 0)
177         {
178           n = shift;
179         }
180       else
181         {
182           dest = rptr;
183           n = -shift;
184         }
185
186       if (bptr)
187         while (n--)
188           {
189             memcpy (dest, bptr, size);
190             dest += roffset;
191           }
192       else
193         while (n--)
194           {
195             memset (dest, filler, size);
196             dest += roffset;
197           }
198
199       /* Advance to the next section.  */
200       rptr += rstride0;
201       sptr += sstride0;
202       bptr += bstride0;
203       count[0]++;
204       n = 0;
205       while (count[n] == extent[n])
206         {
207           /* When we get to the end of a dimension, reset it and increment
208              the next dimension.  */
209           count[n] = 0;
210           /* We could precalculate these products, but this is a less
211              frequently used path so probably not worth it.  */
212           rptr -= rstride[n] * extent[n];
213           sptr -= sstride[n] * extent[n];
214           bptr -= bstride[n] * extent[n];
215           n++;
216           if (n >= dim - 1)
217             {
218               /* Break out of the loop.  */
219               rptr = NULL;
220               break;
221             }
222           else
223             {
224               count[n]++;
225               rptr += rstride[n];
226               sptr += sstride[n];
227               bptr += bstride[n];
228             }
229         }
230     }
231 }
232
233
234 #define DEFINE_EOSHIFT(N)                                                     \
235   extern void eoshift2_##N (gfc_array_char *, const gfc_array_char *,         \
236                             const GFC_INTEGER_##N *, const gfc_array_char *,  \
237                             const GFC_INTEGER_##N *);                         \
238   export_proto(eoshift2_##N);                                                 \
239                                                                               \
240   void                                                                        \
241   eoshift2_##N (gfc_array_char *ret, const gfc_array_char *array,             \
242                 const GFC_INTEGER_##N *pshift, const gfc_array_char *pbound,  \
243                 const GFC_INTEGER_##N *pdim)                                  \
244   {                                                                           \
245     eoshift2 (ret, array, *pshift, pbound, pdim ? *pdim : 1,                  \
246               GFC_DESCRIPTOR_SIZE (array), 0);                                \
247   }                                                                           \
248                                                                               \
249   extern void eoshift2_##N##_char (gfc_array_char *, GFC_INTEGER_4,           \
250                                    const gfc_array_char *,                    \
251                                    const GFC_INTEGER_##N *,                   \
252                                    const gfc_array_char *,                    \
253                                    const GFC_INTEGER_##N *,                   \
254                                    GFC_INTEGER_4, GFC_INTEGER_4);             \
255   export_proto(eoshift2_##N##_char);                                          \
256                                                                               \
257   void                                                                        \
258   eoshift2_##N##_char (gfc_array_char *ret,                                   \
259                        GFC_INTEGER_4 ret_length __attribute__((unused)),      \
260                        const gfc_array_char *array,                           \
261                        const GFC_INTEGER_##N *pshift,                         \
262                        const gfc_array_char *pbound,                          \
263                        const GFC_INTEGER_##N *pdim,                           \
264                        GFC_INTEGER_4 array_length,                            \
265                        GFC_INTEGER_4 bound_length __attribute__((unused)))    \
266   {                                                                           \
267     eoshift2 (ret, array, *pshift, pbound, pdim ? *pdim : 1,                  \
268               array_length, ' ');                                             \
269   }
270
271 DEFINE_EOSHIFT (1);
272 DEFINE_EOSHIFT (2);
273 DEFINE_EOSHIFT (4);
274 DEFINE_EOSHIFT (8);