]> git.ipfire.org Git - thirdparty/gcc.git/blame - libgfortran/intrinsics/cshift0.c
[multiple changes]
[thirdparty/gcc.git] / libgfortran / intrinsics / cshift0.c
CommitLineData
6de9cd9a 1/* Generic implementation of the CSHIFT intrinsic
dfb55fdc 2 Copyright 2003, 2005, 2006, 2007 Free Software Foundation, Inc.
6de9cd9a
DN
3 Contributed by Feng Wang <wf_cs@yahoo.com>
4
5This file is part of the GNU Fortran 95 runtime library (libgfortran).
6
7Libgfortran is free software; you can redistribute it and/or
57dea9f6 8modify it under the terms of the GNU General Public
6de9cd9a 9License as published by the Free Software Foundation; either
dfb55fdc
TK
10version 2 of the License, or (at your option) any later version.
11
12In addition to the permissions in the GNU General Public License, the
13Free Software Foundation gives you unlimited permission to link the
14compiled version of this file into combinations with other programs,
15and to distribute those combinations without any restriction coming
16from the use of this file. (The General Public License restrictions
17do apply in other respects; for example, they cover modification of
18the file, and distribution when not linked into a combine
19executable.)
57dea9f6
TM
20
21Libgfortran is distributed in the hope that it will be useful,
6de9cd9a
DN
22but WITHOUT ANY WARRANTY; without even the implied warranty of
23MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
57dea9f6 24GNU General Public License for more details.
6de9cd9a 25
dfb55fdc
TK
26You should have received a copy of the GNU General Public
27License along with libgfortran; see the file COPYING. If not,
28write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
29Boston, MA 02110-1301, USA. */
6de9cd9a 30
36ae8a61 31#include "libgfortran.h"
6de9cd9a
DN
32#include <stdlib.h>
33#include <assert.h>
34#include <string.h>
6de9cd9a 35
6de9cd9a 36static void
7f68c75f 37cshift0 (gfc_array_char * ret, const gfc_array_char * array,
dfb55fdc 38 ssize_t shift, int which, index_type size)
6de9cd9a
DN
39{
40 /* r.* indicates the return array. */
e33e218b 41 index_type rstride[GFC_MAX_DIMENSIONS];
6de9cd9a
DN
42 index_type rstride0;
43 index_type roffset;
44 char *rptr;
803a6ff5 45
6de9cd9a 46 /* s.* indicates the source array. */
e33e218b 47 index_type sstride[GFC_MAX_DIMENSIONS];
6de9cd9a
DN
48 index_type sstride0;
49 index_type soffset;
50 const char *sptr;
6de9cd9a 51
e33e218b
TK
52 index_type count[GFC_MAX_DIMENSIONS];
53 index_type extent[GFC_MAX_DIMENSIONS];
6de9cd9a 54 index_type dim;
6de9cd9a
DN
55 index_type len;
56 index_type n;
c44109aa 57 index_type arraysize;
6de9cd9a 58
c2b00cdc
TK
59 index_type type_size;
60
6de9cd9a
DN
61 if (which < 1 || which > GFC_DESCRIPTOR_RANK (array))
62 runtime_error ("Argument 'DIM' is out of range in call to 'CSHIFT'");
63
c44109aa
TK
64 arraysize = size0 ((array_t *) array);
65
66 if (ret->data == NULL)
67 {
68 int i;
69
70 ret->offset = 0;
71 ret->dtype = array->dtype;
72 for (i = 0; i < GFC_DESCRIPTOR_RANK (array); i++)
73 {
dfb55fdc
TK
74 index_type ub, str;
75
76 ub = GFC_DESCRIPTOR_EXTENT(array,i) - 1;
c44109aa
TK
77
78 if (i == 0)
dfb55fdc 79 str = 1;
c44109aa 80 else
dfb55fdc
TK
81 str = GFC_DESCRIPTOR_EXTENT(ret,i-1) *
82 GFC_DESCRIPTOR_STRIDE(ret,i-1);
83
84 GFC_DIMENSION_SET(ret->dim[i], 0, ub, str);
c44109aa
TK
85 }
86
87 if (arraysize > 0)
88 ret->data = internal_malloc_size (size * arraysize);
89 else
16bff921 90 ret->data = internal_malloc_size (1);
c44109aa 91 }
16bff921
TK
92 else if (unlikely (compile_options.bounds_check))
93 {
94 bounds_equal_extents ((array_t *) ret, (array_t *) array,
95 "return value", "CSHIFT");
96 }
97
c44109aa
TK
98 if (arraysize == 0)
99 return;
16bff921 100
c2b00cdc 101 type_size = GFC_DTYPE_TYPE_SIZE (array);
c44109aa 102
c2b00cdc
TK
103 switch(type_size)
104 {
105 case GFC_DTYPE_LOGICAL_1:
106 case GFC_DTYPE_INTEGER_1:
107 case GFC_DTYPE_DERIVED_1:
108 cshift0_i1 ((gfc_array_i1 *)ret, (gfc_array_i1 *) array, shift, which);
109 return;
110
111 case GFC_DTYPE_LOGICAL_2:
112 case GFC_DTYPE_INTEGER_2:
113 cshift0_i2 ((gfc_array_i2 *)ret, (gfc_array_i2 *) array, shift, which);
114 return;
115
116 case GFC_DTYPE_LOGICAL_4:
117 case GFC_DTYPE_INTEGER_4:
118 cshift0_i4 ((gfc_array_i4 *)ret, (gfc_array_i4 *) array, shift, which);
119 return;
120
121 case GFC_DTYPE_LOGICAL_8:
122 case GFC_DTYPE_INTEGER_8:
123 cshift0_i8 ((gfc_array_i8 *)ret, (gfc_array_i8 *) array, shift, which);
124 return;
125
126#ifdef HAVE_GFC_INTEGER_16
127 case GFC_DTYPE_LOGICAL_16:
128 case GFC_DTYPE_INTEGER_16:
6f010296 129 cshift0_i16 ((gfc_array_i16 *)ret, (gfc_array_i16 *) array, shift,
c2b00cdc
TK
130 which);
131 return;
132#endif
133
134 case GFC_DTYPE_REAL_4:
135 cshift0_r4 ((gfc_array_r4 *)ret, (gfc_array_r4 *) array, shift, which);
136 return;
137
138 case GFC_DTYPE_REAL_8:
139 cshift0_r8 ((gfc_array_r8 *)ret, (gfc_array_r8 *) array, shift, which);
140 return;
141
142#ifdef HAVE_GFC_REAL_10
143 case GFC_DTYPE_REAL_10:
144 cshift0_r10 ((gfc_array_r10 *)ret, (gfc_array_r10 *) array, shift,
145 which);
146 return;
147#endif
148
149#ifdef HAVE_GFC_REAL_16
150 case GFC_DTYPE_REAL_16:
151 cshift0_r16 ((gfc_array_r16 *)ret, (gfc_array_r16 *) array, shift,
152 which);
153 return;
154#endif
155
156 case GFC_DTYPE_COMPLEX_4:
157 cshift0_c4 ((gfc_array_c4 *)ret, (gfc_array_c4 *) array, shift, which);
158 return;
159
160 case GFC_DTYPE_COMPLEX_8:
161 cshift0_c8 ((gfc_array_c8 *)ret, (gfc_array_c8 *) array, shift, which);
162 return;
163
164#ifdef HAVE_GFC_COMPLEX_10
165 case GFC_DTYPE_COMPLEX_10:
166 cshift0_c10 ((gfc_array_c10 *)ret, (gfc_array_c10 *) array, shift,
167 which);
168 return;
169#endif
170
171#ifdef HAVE_GFC_COMPLEX_16
172 case GFC_DTYPE_COMPLEX_16:
173 cshift0_c16 ((gfc_array_c16 *)ret, (gfc_array_c16 *) array, shift,
174 which);
175 return;
176#endif
6de9cd9a 177
c2b00cdc
TK
178 default:
179 break;
180 }
6de9cd9a 181
c2b00cdc 182 switch (size)
58757957 183 {
c2b00cdc
TK
184 /* Let's check the actual alignment of the data pointers. If they
185 are suitably aligned, we can safely call the unpack functions. */
58757957 186
c2b00cdc
TK
187 case sizeof (GFC_INTEGER_1):
188 cshift0_i1 ((gfc_array_i1 *) ret, (gfc_array_i1 *) array, shift,
189 which);
58757957
JM
190 break;
191
c2b00cdc
TK
192 case sizeof (GFC_INTEGER_2):
193 if (GFC_UNALIGNED_2(ret->data) || GFC_UNALIGNED_2(array->data))
194 break;
195 else
196 {
197 cshift0_i2 ((gfc_array_i2 *) ret, (gfc_array_i2 *) array, shift,
198 which);
199 return;
200 }
201
202 case sizeof (GFC_INTEGER_4):
203 if (GFC_UNALIGNED_4(ret->data) || GFC_UNALIGNED_4(array->data))
204 break;
205 else
206 {
207 cshift0_i4 ((gfc_array_i4 *)ret, (gfc_array_i4 *) array, shift,
208 which);
209 return;
210 }
211
212 case sizeof (GFC_INTEGER_8):
213 if (GFC_UNALIGNED_8(ret->data) || GFC_UNALIGNED_8(array->data))
214 {
215 /* Let's try to use the complex routines. First, a sanity
216 check that the sizes match; this should be optimized to
217 a no-op. */
218 if (sizeof(GFC_INTEGER_8) != sizeof(GFC_COMPLEX_4))
219 break;
220
221 if (GFC_UNALIGNED_C4(ret->data) || GFC_UNALIGNED_C4(array->data))
222 break;
223
224 cshift0_c4 ((gfc_array_c4 *) ret, (gfc_array_c4 *) array, shift,
225 which);
226 return;
227 }
228 else
229 {
230 cshift0_i8 ((gfc_array_i8 *)ret, (gfc_array_i8 *) array, shift,
231 which);
232 return;
233 }
234
235#ifdef HAVE_GFC_INTEGER_16
236 case sizeof (GFC_INTEGER_16):
237 if (GFC_UNALIGNED_16(ret->data) || GFC_UNALIGNED_16(array->data))
238 {
239 /* Let's try to use the complex routines. First, a sanity
240 check that the sizes match; this should be optimized to
241 a no-op. */
6f010296 242 if (sizeof(GFC_INTEGER_16) != sizeof(GFC_COMPLEX_8))
c2b00cdc
TK
243 break;
244
245 if (GFC_UNALIGNED_C8(ret->data) || GFC_UNALIGNED_C8(array->data))
246 break;
247
248 cshift0_c8 ((gfc_array_c8 *) ret, (gfc_array_c8 *) array, shift,
249 which);
250 return;
251 }
252 else
253 {
254 cshift0_i16 ((gfc_array_i16 *) ret, (gfc_array_i16 *) array,
255 shift, which);
256 return;
257 }
258#else
259 case sizeof (GFC_COMPLEX_8):
260
261 if (GFC_UNALIGNED_C8(ret->data) || GFC_UNALIGNED_C8(array->data))
262 break;
263 else
264 {
265 cshift0_c8 ((gfc_array_c8 *) ret, (gfc_array_c8 *) array, shift,
266 which);
267 return;
268 }
269#endif
270
58757957
JM
271 default:
272 break;
273 }
274
c2b00cdc
TK
275
276 which = which - 1;
277 sstride[0] = 0;
278 rstride[0] = 0;
279
280 extent[0] = 1;
281 count[0] = 0;
282 n = 0;
803a6ff5 283 /* Initialized for avoiding compiler warnings. */
6de9cd9a
DN
284 roffset = size;
285 soffset = size;
286 len = 0;
287
288 for (dim = 0; dim < GFC_DESCRIPTOR_RANK (array); dim++)
289 {
290 if (dim == which)
291 {
dfb55fdc 292 roffset = GFC_DESCRIPTOR_STRIDE_BYTES(ret,dim);
6de9cd9a
DN
293 if (roffset == 0)
294 roffset = size;
dfb55fdc 295 soffset = GFC_DESCRIPTOR_STRIDE_BYTES(array,dim);
6de9cd9a
DN
296 if (soffset == 0)
297 soffset = size;
dfb55fdc 298 len = GFC_DESCRIPTOR_EXTENT(array,dim);
6de9cd9a
DN
299 }
300 else
301 {
302 count[n] = 0;
dfb55fdc
TK
303 extent[n] = GFC_DESCRIPTOR_EXTENT(array,dim);
304 rstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(ret,dim);
305 sstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(array,dim);
6de9cd9a
DN
306 n++;
307 }
308 }
309 if (sstride[0] == 0)
310 sstride[0] = size;
311 if (rstride[0] == 0)
312 rstride[0] = size;
313
314 dim = GFC_DESCRIPTOR_RANK (array);
315 rstride0 = rstride[0];
316 sstride0 = sstride[0];
317 rptr = ret->data;
318 sptr = array->data;
319
dfb55fdc 320 shift = len == 0 ? 0 : shift % (ssize_t)len;
6de9cd9a
DN
321 if (shift < 0)
322 shift += len;
323
324 while (rptr)
325 {
326 /* Do the shift for this dimension. */
803a6ff5
RH
327
328 /* If elements are contiguous, perform the operation
329 in two block moves. */
330 if (soffset == size && roffset == size)
331 {
332 size_t len1 = shift * size;
333 size_t len2 = (len - shift) * size;
334 memcpy (rptr, sptr + len1, len2);
335 memcpy (rptr + len2, sptr, len1);
336 }
337 else
338 {
339 /* Otherwise, we'll have to perform the copy one element at
c2b00cdc
TK
340 a time. */
341 char *dest = rptr;
342 const char *src = &sptr[shift * soffset];
343
344 for (n = 0; n < len - shift; n++)
345 {
346 memcpy (dest, src, size);
347 dest += roffset;
348 src += soffset;
349 }
350 for (src = sptr, n = 0; n < shift; n++)
803a6ff5 351 {
c2b00cdc
TK
352 memcpy (dest, src, size);
353 dest += roffset;
354 src += soffset;
803a6ff5
RH
355 }
356 }
6de9cd9a
DN
357
358 /* Advance to the next section. */
359 rptr += rstride0;
360 sptr += sstride0;
361 count[0]++;
362 n = 0;
363 while (count[n] == extent[n])
364 {
365 /* When we get to the end of a dimension, reset it and increment
366 the next dimension. */
367 count[n] = 0;
368 /* We could precalculate these products, but this is a less
8b6dba81 369 frequently used path so probably not worth it. */
6de9cd9a
DN
370 rptr -= rstride[n] * extent[n];
371 sptr -= sstride[n] * extent[n];
372 n++;
373 if (n >= dim - 1)
374 {
375 /* Break out of the loop. */
376 rptr = NULL;
377 break;
378 }
379 else
380 {
381 count[n]++;
382 rptr += rstride[n];
383 sptr += sstride[n];
384 }
385 }
386 }
387}
388
7823229b
RS
389#define DEFINE_CSHIFT(N) \
390 extern void cshift0_##N (gfc_array_char *, const gfc_array_char *, \
391 const GFC_INTEGER_##N *, const GFC_INTEGER_##N *); \
392 export_proto(cshift0_##N); \
393 \
394 void \
395 cshift0_##N (gfc_array_char *ret, const gfc_array_char *array, \
396 const GFC_INTEGER_##N *pshift, const GFC_INTEGER_##N *pdim) \
397 { \
398 cshift0 (ret, array, *pshift, pdim ? *pdim : 1, \
399 GFC_DESCRIPTOR_SIZE (array)); \
400 } \
401 \
402 extern void cshift0_##N##_char (gfc_array_char *, GFC_INTEGER_4, \
403 const gfc_array_char *, \
404 const GFC_INTEGER_##N *, \
405 const GFC_INTEGER_##N *, GFC_INTEGER_4); \
406 export_proto(cshift0_##N##_char); \
407 \
408 void \
409 cshift0_##N##_char (gfc_array_char *ret, \
410 GFC_INTEGER_4 ret_length __attribute__((unused)), \
411 const gfc_array_char *array, \
412 const GFC_INTEGER_##N *pshift, \
413 const GFC_INTEGER_##N *pdim, \
414 GFC_INTEGER_4 array_length) \
415 { \
416 cshift0 (ret, array, *pshift, pdim ? *pdim : 1, array_length); \
691da334
FXC
417 } \
418 \
419 extern void cshift0_##N##_char4 (gfc_array_char *, GFC_INTEGER_4, \
420 const gfc_array_char *, \
421 const GFC_INTEGER_##N *, \
422 const GFC_INTEGER_##N *, GFC_INTEGER_4); \
423 export_proto(cshift0_##N##_char4); \
424 \
425 void \
426 cshift0_##N##_char4 (gfc_array_char *ret, \
427 GFC_INTEGER_4 ret_length __attribute__((unused)), \
428 const gfc_array_char *array, \
429 const GFC_INTEGER_##N *pshift, \
430 const GFC_INTEGER_##N *pdim, \
431 GFC_INTEGER_4 array_length) \
432 { \
433 cshift0 (ret, array, *pshift, pdim ? *pdim : 1, \
434 array_length * sizeof (gfc_char4_t)); \
7823229b
RS
435 }
436
437DEFINE_CSHIFT (1);
438DEFINE_CSHIFT (2);
439DEFINE_CSHIFT (4);
440DEFINE_CSHIFT (8);
143350a8
TK
441#ifdef HAVE_GFC_INTEGER_16
442DEFINE_CSHIFT (16);
443#endif