OSDN Git Service

2005-07-07 Thomas Koenig <Thomas.Koenig@online.de>
[pf3gnuchains/gcc-fork.git] / libgfortran / intrinsics / eoshift2.c
1 /* Generic implementation of the EOSHIFT intrinsic
2    Copyright 2002, 2005 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., 59 Temple Place - Suite 330,
29 Boston, MA 02111-1307, USA.  */
30
31 #include "config.h"
32 #include <stdlib.h>
33 #include <assert.h>
34 #include <string.h>
35 #include "libgfortran.h"
36
37 static const char zeros[16] =
38   {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
39
40 /* TODO: make this work for large shifts when
41    sizeof(int) < sizeof (index_type).  */
42
43 static void
44 eoshift2 (gfc_array_char *ret, const gfc_array_char *array,
45           int shift, const gfc_array_char *bound, int which)
46 {
47   /* r.* indicates the return array.  */
48   index_type rstride[GFC_MAX_DIMENSIONS];
49   index_type rstride0;
50   index_type roffset;
51   char *rptr;
52   char *dest;
53   /* s.* indicates the source array.  */
54   index_type sstride[GFC_MAX_DIMENSIONS];
55   index_type sstride0;
56   index_type soffset;
57   const char *sptr;
58   const char *src;
59   /* b.* indicates the bound array.  */
60   index_type bstride[GFC_MAX_DIMENSIONS];
61   index_type bstride0;
62   const char *bptr;
63
64   index_type count[GFC_MAX_DIMENSIONS];
65   index_type extent[GFC_MAX_DIMENSIONS];
66   index_type dim;
67   index_type size;
68   index_type len;
69   index_type n;
70
71   /* The compiler cannot figure out that these are set, initialize
72      them to avoid warnings.  */
73   len = 0;
74   soffset = 0;
75   roffset = 0;
76
77   size = GFC_DESCRIPTOR_SIZE (ret);
78
79   if (ret->data == NULL)
80     {
81       int i;
82
83       ret->data = internal_malloc_size (size * size0 ((array_t *)array));
84       ret->base = 0;
85       ret->dtype = array->dtype;
86       for (i = 0; i < GFC_DESCRIPTOR_RANK (array); i++)
87         {
88           ret->dim[i].lbound = 0;
89           ret->dim[i].ubound = array->dim[i].ubound - array->dim[i].lbound;
90
91           if (i == 0)
92             ret->dim[i].stride = 1;
93           else
94             ret->dim[i].stride = (ret->dim[i-1].ubound + 1) * ret->dim[i-1].stride;
95         }
96     }
97
98   which = which - 1;
99
100   extent[0] = 1;
101   count[0] = 0;
102   size = GFC_DESCRIPTOR_SIZE (array);
103   n = 0;
104   for (dim = 0; dim < GFC_DESCRIPTOR_RANK (array); dim++)
105     {
106       if (dim == which)
107         {
108           roffset = ret->dim[dim].stride * size;
109           if (roffset == 0)
110             roffset = size;
111           soffset = array->dim[dim].stride * size;
112           if (soffset == 0)
113             soffset = size;
114           len = array->dim[dim].ubound + 1 - array->dim[dim].lbound;
115         }
116       else
117         {
118           count[n] = 0;
119           extent[n] = array->dim[dim].ubound + 1 - array->dim[dim].lbound;
120           rstride[n] = ret->dim[dim].stride * size;
121           sstride[n] = array->dim[dim].stride * size;
122           if (bound)
123             bstride[n] = bound->dim[n].stride * size;
124           else
125             bstride[n] = 0;
126           n++;
127         }
128     }
129   if (sstride[0] == 0)
130     sstride[0] = size;
131   if (rstride[0] == 0)
132     rstride[0] = size;
133   if (bound && bstride[0] == 0)
134     bstride[0] = size;
135
136   dim = GFC_DESCRIPTOR_RANK (array);
137   rstride0 = rstride[0];
138   sstride0 = sstride[0];
139   bstride0 = bstride[0];
140   rptr = ret->data;
141   sptr = array->data;
142
143   if ((shift >= 0 ? shift : -shift ) > len)
144     {
145       shift = len;
146       len = 0;
147     }
148   else
149     {
150       if (shift > 0)
151         len = len - shift;
152       else
153         len = len + shift;
154     }
155   
156   if (bound)
157     bptr = bound->data;
158   else
159     bptr = zeros;
160
161   while (rptr)
162     {
163       /* Do the shift for this dimension.  */
164       if (shift > 0)
165         {
166           src = &sptr[shift * soffset];
167           dest = rptr;
168         }
169       else
170         {
171           src = sptr;
172           dest = &rptr[-shift * roffset];
173         }
174       for (n = 0; n < len; n++)
175         {
176           memcpy (dest, src, size);
177           dest += roffset;
178           src += soffset;
179         }
180       if (shift >= 0)
181         {
182           n = shift;
183         }
184       else
185         {
186           dest = rptr;
187           n = -shift;
188         }
189
190       while (n--)
191         {
192           memcpy (dest, bptr, size);
193           dest += roffset;
194         }
195
196       /* Advance to the next section.  */
197       rptr += rstride0;
198       sptr += sstride0;
199       bptr += bstride0;
200       count[0]++;
201       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 proabably not worth it.  */
209           rptr -= rstride[n] * extent[n];
210           sptr -= sstride[n] * extent[n];
211           bptr -= bstride[n] * extent[n];
212           n++;
213           if (n >= dim - 1)
214             {
215               /* Break out of the loop.  */
216               rptr = NULL;
217               break;
218             }
219           else
220             {
221               count[n]++;
222               rptr += rstride[n];
223               sptr += sstride[n];
224               bptr += bstride[n];
225             }
226         }
227     }
228 }
229
230
231 extern void eoshift2_1 (gfc_array_char *, const gfc_array_char *,
232                         const GFC_INTEGER_1 *, const gfc_array_char *,
233                         const GFC_INTEGER_1 *);
234 export_proto(eoshift2_1);
235
236 void
237 eoshift2_1 (gfc_array_char *ret, const gfc_array_char *array,
238             const GFC_INTEGER_1 *pshift, const gfc_array_char *bound,
239             const GFC_INTEGER_1 *pdim)
240 {
241   eoshift2 (ret, array, *pshift, bound, pdim ? *pdim : 1);
242 }
243
244
245 extern void eoshift2_2 (gfc_array_char *, const gfc_array_char *,
246                         const GFC_INTEGER_2 *, const gfc_array_char *,
247                         const GFC_INTEGER_2 *);
248 export_proto(eoshift2_2);
249
250 void
251 eoshift2_2 (gfc_array_char *ret, const gfc_array_char *array,
252             const GFC_INTEGER_2 *pshift, const gfc_array_char *bound,
253             const GFC_INTEGER_2 *pdim)
254 {
255   eoshift2 (ret, array, *pshift, bound, pdim ? *pdim : 1);
256 }
257
258
259 extern void eoshift2_4 (gfc_array_char *, const gfc_array_char *,
260                         const GFC_INTEGER_4 *, const gfc_array_char *,
261                         const GFC_INTEGER_4 *);
262 export_proto(eoshift2_4);
263
264 void
265 eoshift2_4 (gfc_array_char *ret, const gfc_array_char *array,
266             const GFC_INTEGER_4 *pshift, const gfc_array_char *bound,
267             const GFC_INTEGER_4 *pdim)
268 {
269   eoshift2 (ret, array, *pshift, bound, pdim ? *pdim : 1);
270 }
271
272
273 extern void eoshift2_8 (gfc_array_char *, const gfc_array_char *,
274                         const GFC_INTEGER_8 *, const gfc_array_char *,
275                         const GFC_INTEGER_8 *);
276 export_proto(eoshift2_8);
277
278 void
279 eoshift2_8 (gfc_array_char *ret, const gfc_array_char *array,
280             const GFC_INTEGER_8 *pshift, const gfc_array_char *bound,
281             const GFC_INTEGER_8 *pdim)
282 {
283   eoshift2 (ret, array, *pshift, bound, pdim ? *pdim : 1);
284 }