1 1.1 mrg /* Implementation of the CSHIFT intrinsic 2 1.1.1.4 mrg Copyright (C) 2003-2024 Free Software Foundation, Inc. 3 1.1 mrg Contributed by Feng Wang <wf_cs (at) yahoo.com> 4 1.1 mrg 5 1.1 mrg This file is part of the GNU Fortran runtime library (libgfortran). 6 1.1 mrg 7 1.1 mrg Libgfortran is free software; you can redistribute it and/or 8 1.1 mrg modify it under the terms of the GNU General Public 9 1.1 mrg License as published by the Free Software Foundation; either 10 1.1 mrg version 3 of the License, or (at your option) any later version. 11 1.1 mrg 12 1.1 mrg Ligbfortran is distributed in the hope that it will be useful, 13 1.1 mrg but WITHOUT ANY WARRANTY; without even the implied warranty of 14 1.1 mrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 1.1 mrg GNU General Public License for more details. 16 1.1 mrg 17 1.1 mrg Under Section 7 of GPL version 3, you are granted additional 18 1.1 mrg permissions described in the GCC Runtime Library Exception, version 19 1.1 mrg 3.1, as published by the Free Software Foundation. 20 1.1 mrg 21 1.1 mrg You should have received a copy of the GNU General Public License and 22 1.1 mrg a copy of the GCC Runtime Library Exception along with this program; 23 1.1 mrg see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 24 1.1 mrg <http://www.gnu.org/licenses/>. */ 25 1.1 mrg 26 1.1 mrg #include "libgfortran.h" 27 1.1 mrg #include <string.h> 28 1.1 mrg 29 1.1 mrg 30 1.1 mrg #if defined (HAVE_GFC_INTEGER_8) 31 1.1 mrg 32 1.1 mrg static void 33 1.1 mrg cshift1 (gfc_array_char * const restrict ret, 34 1.1 mrg const gfc_array_char * const restrict array, 35 1.1 mrg const gfc_array_i8 * const restrict h, 36 1.1 mrg const GFC_INTEGER_8 * const restrict pwhich) 37 1.1 mrg { 38 1.1 mrg /* r.* indicates the return array. */ 39 1.1 mrg index_type rstride[GFC_MAX_DIMENSIONS]; 40 1.1 mrg index_type rstride0; 41 1.1 mrg index_type roffset; 42 1.1 mrg char *rptr; 43 1.1 mrg char *dest; 44 1.1 mrg /* s.* indicates the source array. */ 45 1.1 mrg index_type sstride[GFC_MAX_DIMENSIONS]; 46 1.1 mrg index_type sstride0; 47 1.1 mrg index_type soffset; 48 1.1 mrg const char *sptr; 49 1.1 mrg const char *src; 50 1.1 mrg /* h.* indicates the shift array. */ 51 1.1 mrg index_type hstride[GFC_MAX_DIMENSIONS]; 52 1.1 mrg index_type hstride0; 53 1.1 mrg const GFC_INTEGER_8 *hptr; 54 1.1 mrg 55 1.1 mrg index_type count[GFC_MAX_DIMENSIONS]; 56 1.1 mrg index_type extent[GFC_MAX_DIMENSIONS]; 57 1.1 mrg index_type dim; 58 1.1 mrg index_type len; 59 1.1 mrg index_type n; 60 1.1 mrg int which; 61 1.1 mrg GFC_INTEGER_8 sh; 62 1.1 mrg index_type arraysize; 63 1.1 mrg index_type size; 64 1.1 mrg index_type type_size; 65 1.1 mrg 66 1.1 mrg if (pwhich) 67 1.1 mrg which = *pwhich - 1; 68 1.1 mrg else 69 1.1 mrg which = 0; 70 1.1 mrg 71 1.1 mrg if (which < 0 || (which + 1) > GFC_DESCRIPTOR_RANK (array)) 72 1.1 mrg runtime_error ("Argument 'DIM' is out of range in call to 'CSHIFT'"); 73 1.1 mrg 74 1.1 mrg size = GFC_DESCRIPTOR_SIZE(array); 75 1.1 mrg 76 1.1 mrg arraysize = size0 ((array_t *)array); 77 1.1 mrg 78 1.1 mrg if (ret->base_addr == NULL) 79 1.1 mrg { 80 1.1 mrg ret->base_addr = xmallocarray (arraysize, size); 81 1.1 mrg ret->offset = 0; 82 1.1 mrg GFC_DTYPE_COPY(ret,array); 83 1.1 mrg for (index_type i = 0; i < GFC_DESCRIPTOR_RANK (array); i++) 84 1.1 mrg { 85 1.1 mrg index_type ub, str; 86 1.1 mrg 87 1.1 mrg ub = GFC_DESCRIPTOR_EXTENT(array,i) - 1; 88 1.1 mrg 89 1.1 mrg if (i == 0) 90 1.1 mrg str = 1; 91 1.1 mrg else 92 1.1 mrg str = GFC_DESCRIPTOR_EXTENT(ret,i-1) * 93 1.1 mrg GFC_DESCRIPTOR_STRIDE(ret,i-1); 94 1.1 mrg 95 1.1 mrg GFC_DIMENSION_SET(ret->dim[i], 0, ub, str); 96 1.1 mrg } 97 1.1 mrg } 98 1.1 mrg else if (unlikely (compile_options.bounds_check)) 99 1.1 mrg { 100 1.1 mrg bounds_equal_extents ((array_t *) ret, (array_t *) array, 101 1.1 mrg "return value", "CSHIFT"); 102 1.1 mrg } 103 1.1 mrg 104 1.1 mrg if (unlikely (compile_options.bounds_check)) 105 1.1 mrg { 106 1.1 mrg bounds_reduced_extents ((array_t *) h, (array_t *) array, which, 107 1.1 mrg "SHIFT argument", "CSHIFT"); 108 1.1 mrg } 109 1.1 mrg 110 1.1 mrg if (arraysize == 0) 111 1.1 mrg return; 112 1.1 mrg 113 1.1 mrg /* See if we should dispatch to a helper function. */ 114 1.1 mrg 115 1.1 mrg type_size = GFC_DTYPE_TYPE_SIZE (array); 116 1.1 mrg 117 1.1 mrg switch (type_size) 118 1.1 mrg { 119 1.1 mrg case GFC_DTYPE_LOGICAL_1: 120 1.1 mrg case GFC_DTYPE_INTEGER_1: 121 1.1 mrg cshift1_8_i1 ((gfc_array_i1 *)ret, (gfc_array_i1 *) array, 122 1.1 mrg h, pwhich); 123 1.1 mrg return; 124 1.1 mrg 125 1.1 mrg case GFC_DTYPE_LOGICAL_2: 126 1.1 mrg case GFC_DTYPE_INTEGER_2: 127 1.1 mrg cshift1_8_i2 ((gfc_array_i2 *)ret, (gfc_array_i2 *) array, 128 1.1 mrg h, pwhich); 129 1.1 mrg return; 130 1.1 mrg 131 1.1 mrg case GFC_DTYPE_LOGICAL_4: 132 1.1 mrg case GFC_DTYPE_INTEGER_4: 133 1.1 mrg cshift1_8_i4 ((gfc_array_i4 *)ret, (gfc_array_i4 *) array, 134 1.1 mrg h, pwhich); 135 1.1 mrg return; 136 1.1 mrg 137 1.1 mrg case GFC_DTYPE_LOGICAL_8: 138 1.1 mrg case GFC_DTYPE_INTEGER_8: 139 1.1 mrg cshift1_8_i8 ((gfc_array_i8 *)ret, (gfc_array_i8 *) array, 140 1.1 mrg h, pwhich); 141 1.1 mrg return; 142 1.1 mrg 143 1.1 mrg #if defined (HAVE_INTEGER_16) 144 1.1 mrg case GFC_DTYPE_LOGICAL_16: 145 1.1 mrg case GFC_DTYPE_INTEGER_16: 146 1.1 mrg cshift1_8_i16 ((gfc_array_i16 *)ret, (gfc_array_i16 *) array, 147 1.1 mrg h, pwhich); 148 1.1 mrg return; 149 1.1 mrg #endif 150 1.1 mrg 151 1.1 mrg case GFC_DTYPE_REAL_4: 152 1.1 mrg cshift1_8_r4 ((gfc_array_r4 *)ret, (gfc_array_r4 *) array, 153 1.1 mrg h, pwhich); 154 1.1 mrg return; 155 1.1 mrg 156 1.1 mrg case GFC_DTYPE_REAL_8: 157 1.1 mrg cshift1_8_r8 ((gfc_array_r8 *)ret, (gfc_array_r8 *) array, 158 1.1 mrg h, pwhich); 159 1.1 mrg return; 160 1.1 mrg 161 1.1 mrg #if defined (HAVE_REAL_10) 162 1.1 mrg case GFC_DTYPE_REAL_10: 163 1.1 mrg cshift1_8_r10 ((gfc_array_r10 *)ret, (gfc_array_r10 *) array, 164 1.1 mrg h, pwhich); 165 1.1 mrg return; 166 1.1 mrg #endif 167 1.1 mrg 168 1.1 mrg #if defined (HAVE_REAL_16) 169 1.1 mrg case GFC_DTYPE_REAL_16: 170 1.1 mrg cshift1_8_r16 ((gfc_array_r16 *)ret, (gfc_array_r16 *) array, 171 1.1 mrg h, pwhich); 172 1.1 mrg return; 173 1.1 mrg #endif 174 1.1 mrg 175 1.1 mrg case GFC_DTYPE_COMPLEX_4: 176 1.1 mrg cshift1_8_c4 ((gfc_array_c4 *)ret, (gfc_array_c4 *) array, 177 1.1 mrg h, pwhich); 178 1.1 mrg return; 179 1.1 mrg 180 1.1 mrg case GFC_DTYPE_COMPLEX_8: 181 1.1 mrg cshift1_8_c8 ((gfc_array_c8 *)ret, (gfc_array_c8 *) array, 182 1.1 mrg h, pwhich); 183 1.1 mrg return; 184 1.1 mrg 185 1.1 mrg #if defined (HAVE_COMPLEX_10) 186 1.1 mrg case GFC_DTYPE_COMPLEX_10: 187 1.1 mrg cshift1_8_c10 ((gfc_array_c10 *)ret, (gfc_array_c10 *) array, 188 1.1 mrg h, pwhich); 189 1.1 mrg return; 190 1.1 mrg #endif 191 1.1 mrg 192 1.1 mrg #if defined (HAVE_COMPLEX_16) 193 1.1 mrg case GFC_DTYPE_COMPLEX_16: 194 1.1 mrg cshift1_8_c16 ((gfc_array_c16 *)ret, (gfc_array_c16 *) array, 195 1.1 mrg h, pwhich); 196 1.1 mrg return; 197 1.1 mrg #endif 198 1.1 mrg 199 1.1 mrg default: 200 1.1 mrg break; 201 1.1 mrg 202 1.1 mrg } 203 1.1 mrg 204 1.1 mrg extent[0] = 1; 205 1.1 mrg count[0] = 0; 206 1.1 mrg n = 0; 207 1.1 mrg 208 1.1 mrg /* Initialized for avoiding compiler warnings. */ 209 1.1 mrg roffset = size; 210 1.1 mrg soffset = size; 211 1.1 mrg len = 0; 212 1.1 mrg 213 1.1 mrg for (dim = 0; dim < GFC_DESCRIPTOR_RANK (array); dim++) 214 1.1 mrg { 215 1.1 mrg if (dim == which) 216 1.1 mrg { 217 1.1 mrg roffset = GFC_DESCRIPTOR_STRIDE_BYTES(ret,dim); 218 1.1 mrg if (roffset == 0) 219 1.1 mrg roffset = size; 220 1.1 mrg soffset = GFC_DESCRIPTOR_STRIDE_BYTES(array,dim); 221 1.1 mrg if (soffset == 0) 222 1.1 mrg soffset = size; 223 1.1 mrg len = GFC_DESCRIPTOR_EXTENT(array,dim); 224 1.1 mrg } 225 1.1 mrg else 226 1.1 mrg { 227 1.1 mrg count[n] = 0; 228 1.1 mrg extent[n] = GFC_DESCRIPTOR_EXTENT(array,dim); 229 1.1 mrg rstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(ret,dim); 230 1.1 mrg sstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(array,dim); 231 1.1 mrg 232 1.1 mrg hstride[n] = GFC_DESCRIPTOR_STRIDE(h,n); 233 1.1 mrg n++; 234 1.1 mrg } 235 1.1 mrg } 236 1.1 mrg if (sstride[0] == 0) 237 1.1 mrg sstride[0] = size; 238 1.1 mrg if (rstride[0] == 0) 239 1.1 mrg rstride[0] = size; 240 1.1 mrg if (hstride[0] == 0) 241 1.1 mrg hstride[0] = 1; 242 1.1 mrg 243 1.1 mrg dim = GFC_DESCRIPTOR_RANK (array); 244 1.1 mrg rstride0 = rstride[0]; 245 1.1 mrg sstride0 = sstride[0]; 246 1.1 mrg hstride0 = hstride[0]; 247 1.1 mrg rptr = ret->base_addr; 248 1.1 mrg sptr = array->base_addr; 249 1.1 mrg hptr = h->base_addr; 250 1.1 mrg 251 1.1 mrg while (rptr) 252 1.1 mrg { 253 1.1 mrg /* Do the shift for this dimension. */ 254 1.1 mrg sh = *hptr; 255 1.1 mrg /* Normal case should be -len < sh < len; try to 256 1.1 mrg avoid the expensive remainder operation if possible. */ 257 1.1 mrg if (sh < 0) 258 1.1 mrg sh += len; 259 1.1 mrg if (unlikely (sh >= len || sh < 0)) 260 1.1 mrg { 261 1.1 mrg sh = sh % len; 262 1.1 mrg if (sh < 0) 263 1.1 mrg sh += len; 264 1.1 mrg } 265 1.1 mrg 266 1.1 mrg src = &sptr[sh * soffset]; 267 1.1 mrg dest = rptr; 268 1.1 mrg if (soffset == size && roffset == size) 269 1.1 mrg { 270 1.1 mrg size_t len1 = sh * size; 271 1.1 mrg size_t len2 = (len - sh) * size; 272 1.1 mrg memcpy (rptr, sptr + len1, len2); 273 1.1 mrg memcpy (rptr + len2, sptr, len1); 274 1.1 mrg } 275 1.1 mrg else 276 1.1 mrg { 277 1.1 mrg for (n = 0; n < len - sh; n++) 278 1.1 mrg { 279 1.1 mrg memcpy (dest, src, size); 280 1.1 mrg dest += roffset; 281 1.1 mrg src += soffset; 282 1.1 mrg } 283 1.1 mrg for (src = sptr, n = 0; n < sh; n++) 284 1.1 mrg { 285 1.1 mrg memcpy (dest, src, size); 286 1.1 mrg dest += roffset; 287 1.1 mrg src += soffset; 288 1.1 mrg } 289 1.1 mrg } 290 1.1 mrg 291 1.1 mrg /* Advance to the next section. */ 292 1.1 mrg rptr += rstride0; 293 1.1 mrg sptr += sstride0; 294 1.1 mrg hptr += hstride0; 295 1.1 mrg count[0]++; 296 1.1 mrg n = 0; 297 1.1 mrg while (count[n] == extent[n]) 298 1.1 mrg { 299 1.1 mrg /* When we get to the end of a dimension, reset it and increment 300 1.1 mrg the next dimension. */ 301 1.1 mrg count[n] = 0; 302 1.1 mrg /* We could precalculate these products, but this is a less 303 1.1 mrg frequently used path so probably not worth it. */ 304 1.1 mrg rptr -= rstride[n] * extent[n]; 305 1.1 mrg sptr -= sstride[n] * extent[n]; 306 1.1 mrg hptr -= hstride[n] * extent[n]; 307 1.1 mrg n++; 308 1.1 mrg if (n >= dim - 1) 309 1.1 mrg { 310 1.1 mrg /* Break out of the loop. */ 311 1.1 mrg rptr = NULL; 312 1.1 mrg break; 313 1.1 mrg } 314 1.1 mrg else 315 1.1 mrg { 316 1.1 mrg count[n]++; 317 1.1 mrg rptr += rstride[n]; 318 1.1 mrg sptr += sstride[n]; 319 1.1 mrg hptr += hstride[n]; 320 1.1 mrg } 321 1.1 mrg } 322 1.1 mrg } 323 1.1 mrg } 324 1.1 mrg 325 1.1 mrg void cshift1_8 (gfc_array_char * const restrict, 326 1.1 mrg const gfc_array_char * const restrict, 327 1.1 mrg const gfc_array_i8 * const restrict, 328 1.1 mrg const GFC_INTEGER_8 * const restrict); 329 1.1 mrg export_proto(cshift1_8); 330 1.1 mrg 331 1.1 mrg void 332 1.1 mrg cshift1_8 (gfc_array_char * const restrict ret, 333 1.1 mrg const gfc_array_char * const restrict array, 334 1.1 mrg const gfc_array_i8 * const restrict h, 335 1.1 mrg const GFC_INTEGER_8 * const restrict pwhich) 336 1.1 mrg { 337 1.1 mrg cshift1 (ret, array, h, pwhich); 338 1.1 mrg } 339 1.1 mrg 340 1.1 mrg 341 1.1 mrg void cshift1_8_char (gfc_array_char * const restrict ret, 342 1.1 mrg GFC_INTEGER_4, 343 1.1 mrg const gfc_array_char * const restrict array, 344 1.1 mrg const gfc_array_i8 * const restrict h, 345 1.1 mrg const GFC_INTEGER_8 * const restrict pwhich, 346 1.1 mrg GFC_INTEGER_4); 347 1.1 mrg export_proto(cshift1_8_char); 348 1.1 mrg 349 1.1 mrg void 350 1.1 mrg cshift1_8_char (gfc_array_char * const restrict ret, 351 1.1 mrg GFC_INTEGER_4 ret_length __attribute__((unused)), 352 1.1 mrg const gfc_array_char * const restrict array, 353 1.1 mrg const gfc_array_i8 * const restrict h, 354 1.1 mrg const GFC_INTEGER_8 * const restrict pwhich, 355 1.1 mrg GFC_INTEGER_4 array_length __attribute__((unused))) 356 1.1 mrg { 357 1.1 mrg cshift1 (ret, array, h, pwhich); 358 1.1 mrg } 359 1.1 mrg 360 1.1 mrg 361 1.1 mrg void cshift1_8_char4 (gfc_array_char * const restrict ret, 362 1.1 mrg GFC_INTEGER_4, 363 1.1 mrg const gfc_array_char * const restrict array, 364 1.1 mrg const gfc_array_i8 * const restrict h, 365 1.1 mrg const GFC_INTEGER_8 * const restrict pwhich, 366 1.1 mrg GFC_INTEGER_4); 367 1.1 mrg export_proto(cshift1_8_char4); 368 1.1 mrg 369 1.1 mrg void 370 1.1 mrg cshift1_8_char4 (gfc_array_char * const restrict ret, 371 1.1 mrg GFC_INTEGER_4 ret_length __attribute__((unused)), 372 1.1 mrg const gfc_array_char * const restrict array, 373 1.1 mrg const gfc_array_i8 * const restrict h, 374 1.1 mrg const GFC_INTEGER_8 * const restrict pwhich, 375 1.1 mrg GFC_INTEGER_4 array_length __attribute__((unused))) 376 1.1 mrg { 377 1.1 mrg cshift1 (ret, array, h, pwhich); 378 1.1 mrg } 379 1.1 mrg 380 1.1 mrg #endif 381