OSDN Git Service

70baf3c18d1524479e8ec405586aeb5cfc01ed84
[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   if (bound)
143     bptr = bound->data;
144   else
145     bptr = zeros;
146
147   if (shift > 0)
148     len = len - shift;
149   else
150     len = len + shift;
151
152   while (rptr)
153     {
154       /* Do the shift for this dimension.  */
155       if (shift > 0)
156         {
157           src = &sptr[shift * soffset];
158           dest = rptr;
159         }
160       else
161         {
162           src = sptr;
163           dest = &rptr[-shift * roffset];
164         }
165       for (n = 0; n < len; n++)
166         {
167           memcpy (dest, src, size);
168           dest += roffset;
169           src += soffset;
170         }
171       if (shift >= 0)
172         {
173           n = shift;
174         }
175       else
176         {
177           dest = rptr;
178           n = -shift;
179         }
180
181       while (n--)
182         {
183           memcpy (dest, bptr, size);
184           dest += roffset;
185         }
186
187       /* Advance to the next section.  */
188       rptr += rstride0;
189       sptr += sstride0;
190       bptr += bstride0;
191       count[0]++;
192       n = 0;
193       while (count[n] == extent[n])
194         {
195           /* When we get to the end of a dimension, reset it and increment
196              the next dimension.  */
197           count[n] = 0;
198           /* We could precalculate these products, but this is a less
199              frequently used path so proabably not worth it.  */
200           rptr -= rstride[n] * extent[n];
201           sptr -= sstride[n] * extent[n];
202           bptr -= bstride[n] * extent[n];
203           n++;
204           if (n >= dim - 1)
205             {
206               /* Break out of the loop.  */
207               rptr = NULL;
208               break;
209             }
210           else
211             {
212               count[n]++;
213               rptr += rstride[n];
214               sptr += sstride[n];
215               bptr += bstride[n];
216             }
217         }
218     }
219 }
220
221
222 extern void eoshift2_1 (gfc_array_char *, const gfc_array_char *,
223                         const GFC_INTEGER_1 *, const gfc_array_char *,
224                         const GFC_INTEGER_1 *);
225 export_proto(eoshift2_1);
226
227 void
228 eoshift2_1 (gfc_array_char *ret, const gfc_array_char *array,
229             const GFC_INTEGER_1 *pshift, const gfc_array_char *bound,
230             const GFC_INTEGER_1 *pdim)
231 {
232   eoshift2 (ret, array, *pshift, bound, pdim ? *pdim : 1);
233 }
234
235
236 extern void eoshift2_2 (gfc_array_char *, const gfc_array_char *,
237                         const GFC_INTEGER_2 *, const gfc_array_char *,
238                         const GFC_INTEGER_2 *);
239 export_proto(eoshift2_2);
240
241 void
242 eoshift2_2 (gfc_array_char *ret, const gfc_array_char *array,
243             const GFC_INTEGER_2 *pshift, const gfc_array_char *bound,
244             const GFC_INTEGER_2 *pdim)
245 {
246   eoshift2 (ret, array, *pshift, bound, pdim ? *pdim : 1);
247 }
248
249
250 extern void eoshift2_4 (gfc_array_char *, const gfc_array_char *,
251                         const GFC_INTEGER_4 *, const gfc_array_char *,
252                         const GFC_INTEGER_4 *);
253 export_proto(eoshift2_4);
254
255 void
256 eoshift2_4 (gfc_array_char *ret, const gfc_array_char *array,
257             const GFC_INTEGER_4 *pshift, const gfc_array_char *bound,
258             const GFC_INTEGER_4 *pdim)
259 {
260   eoshift2 (ret, array, *pshift, bound, pdim ? *pdim : 1);
261 }
262
263
264 extern void eoshift2_8 (gfc_array_char *, const gfc_array_char *,
265                         const GFC_INTEGER_8 *, const gfc_array_char *,
266                         const GFC_INTEGER_8 *);
267 export_proto(eoshift2_8);
268
269 void
270 eoshift2_8 (gfc_array_char *ret, const gfc_array_char *array,
271             const GFC_INTEGER_8 *pshift, const gfc_array_char *bound,
272             const GFC_INTEGER_8 *pdim)
273 {
274   eoshift2 (ret, array, *pshift, bound, pdim ? *pdim : 1);
275 }