OSDN Git Service

038588f78d2958d1a65b0b45dd3bb1278b4f1579
[pf3gnuchains/gcc-fork.git] / libgfortran / intrinsics / eoshift2.c
1 /* Generic implementation of the RESHAPE intrinsic
2    Copyright 2002 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 (libgfor).
6
7 Libgfor is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Lesser General Public
9 License as published by the Free Software Foundation; either
10 version 2.1 of the License, or (at your option) any later version.
11
12 Ligbfor 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 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public
18 License along with libgfor; see the file COPYING.LIB.  If not,
19 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA.  */
21
22 #include "config.h"
23 #include <stdlib.h>
24 #include <assert.h>
25 #include <string.h>
26 #include "libgfortran.h"
27
28 static const char zeros[16] =
29   {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
30
31 /* TODO: make this work for large shifts when
32    sizeof(int) < sizeof (index_type).  */
33
34 static void
35 __eoshift2 (const gfc_array_char * ret, const gfc_array_char * array,
36     int shift, const gfc_array_char * bound, int which)
37 {
38   /* r.* indicates the return array.  */
39   index_type rstride[GFC_MAX_DIMENSIONS - 1];
40   index_type rstride0;
41   index_type roffset;
42   char *rptr;
43   char *dest;
44   /* s.* indicates the source array.  */
45   index_type sstride[GFC_MAX_DIMENSIONS - 1];
46   index_type sstride0;
47   index_type soffset;
48   const char *sptr;
49   const char *src;
50   /* b.* indicates the bound array.  */
51   index_type bstride[GFC_MAX_DIMENSIONS - 1];
52   index_type bstride0;
53   const char *bptr;
54
55   index_type count[GFC_MAX_DIMENSIONS - 1];
56   index_type extent[GFC_MAX_DIMENSIONS - 1];
57   index_type dim;
58   index_type size;
59   index_type len;
60   index_type n;
61
62   size = GFC_DESCRIPTOR_SIZE (ret);
63
64   which = which - 1;
65
66   extent[0] = 1;
67   count[0] = 0;
68   size = GFC_DESCRIPTOR_SIZE (array);
69   n = 0;
70   for (dim = 0; dim < GFC_DESCRIPTOR_RANK (array); dim++)
71     {
72       if (dim == which)
73         {
74           roffset = ret->dim[dim].stride * size;
75           if (roffset == 0)
76             roffset = size;
77           soffset = array->dim[dim].stride * size;
78           if (soffset == 0)
79             soffset = size;
80           len = array->dim[dim].ubound + 1 - array->dim[dim].lbound;
81         }
82       else
83         {
84           count[n] = 0;
85           extent[n] = array->dim[dim].ubound + 1 - array->dim[dim].lbound;
86           rstride[n] = ret->dim[dim].stride * size;
87           sstride[n] = array->dim[dim].stride * size;
88           if (bound)
89             bstride[n] = bound->dim[n].stride * size;
90           else
91             bstride[n] = 0;
92           n++;
93         }
94     }
95   if (sstride[0] == 0)
96     sstride[0] = size;
97   if (rstride[0] == 0)
98     rstride[0] = size;
99   if (bound && bstride[0] == 0)
100     bstride[0] = size;
101
102   dim = GFC_DESCRIPTOR_RANK (array);
103   rstride0 = rstride[0];
104   sstride0 = sstride[0];
105   bstride0 = bstride[0];
106   rptr = ret->data;
107   sptr = array->data;
108   if (bound)
109     bptr = bound->data;
110   else
111     bptr = zeros;
112
113   if (shift > 0)
114     len = len - shift;
115   else
116     len = len + shift;
117
118   while (rptr)
119     {
120       /* Do the shift for this dimension.  */
121       if (shift > 0)
122         {
123           src = &sptr[shift * soffset];
124           dest = rptr;
125         }
126       else
127         {
128           src = sptr;
129           dest = &rptr[-shift * roffset];
130         }
131       for (n = 0; n < len; n++)
132         {
133           memcpy (dest, src, size);
134           dest += roffset;
135           src += soffset;
136         }
137       if (shift >= 0)
138         {
139           n = shift;
140         }
141       else
142         {
143           dest = rptr;
144           n = -shift;
145         }
146
147       while (n--)
148         {
149           memcpy (dest, bptr, size);
150           dest += roffset;
151         }
152
153       /* Advance to the next section.  */
154       rptr += rstride0;
155       sptr += sstride0;
156       bptr += bstride0;
157       count[0]++;
158       n = 0;
159       while (count[n] == extent[n])
160         {
161           /* When we get to the end of a dimension, reset it and increment
162              the next dimension.  */
163           count[n] = 0;
164           /* We could precalculate these products, but this is a less
165              frequently used path so proabably not worth it.  */
166           rptr -= rstride[n] * extent[n];
167           sptr -= sstride[n] * extent[n];
168           bptr -= bstride[n] * extent[n];
169           n++;
170           if (n >= dim - 1)
171             {
172               /* Break out of the loop.  */
173               rptr = NULL;
174               break;
175             }
176           else
177             {
178               count[n]++;
179               rptr += rstride[n];
180               sptr += sstride[n];
181               bptr += bstride[n];
182             }
183         }
184     }
185 }
186
187
188 void
189 __eoshift2_4 (const gfc_array_char * ret, const gfc_array_char * array,
190     const GFC_INTEGER_4 * pshift, const gfc_array_char * bound,
191     const GFC_INTEGER_4 * pdim)
192 {
193   __eoshift2 (ret, array, *pshift, bound, pdim ? *pdim : 1);
194 }
195
196
197 void
198 __eoshift2_8 (const gfc_array_char * ret, const gfc_array_char * array,
199     const GFC_INTEGER_8 * pshift, const gfc_array_char * bound,
200     const GFC_INTEGER_8 * pdim)
201 {
202   __eoshift2 (ret, array, *pshift, bound, pdim ? *pdim : 1);
203 }
204