1760c2415Smrg`/* Implementation of the CSHIFT intrinsic 2*0bfacb9bSmrg Copyright (C) 2003-2020 Free Software Foundation, Inc. 3760c2415Smrg Contributed by Feng Wang <wf_cs@yahoo.com> 4760c2415Smrg 5760c2415SmrgThis file is part of the GNU Fortran runtime library (libgfortran). 6760c2415Smrg 7760c2415SmrgLibgfortran is free software; you can redistribute it and/or 8760c2415Smrgmodify it under the terms of the GNU General Public 9760c2415SmrgLicense as published by the Free Software Foundation; either 10760c2415Smrgversion 3 of the License, or (at your option) any later version. 11760c2415Smrg 12760c2415SmrgLigbfortran is distributed in the hope that it will be useful, 13760c2415Smrgbut WITHOUT ANY WARRANTY; without even the implied warranty of 14760c2415SmrgMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15760c2415SmrgGNU General Public License for more details. 16760c2415Smrg 17760c2415SmrgUnder Section 7 of GPL version 3, you are granted additional 18760c2415Smrgpermissions described in the GCC Runtime Library Exception, version 19760c2415Smrg3.1, as published by the Free Software Foundation. 20760c2415Smrg 21760c2415SmrgYou should have received a copy of the GNU General Public License and 22760c2415Smrga copy of the GCC Runtime Library Exception along with this program; 23760c2415Smrgsee the files COPYING3 and COPYING.RUNTIME respectively. If not, see 24760c2415Smrg<http://www.gnu.org/licenses/>. */ 25760c2415Smrg 26760c2415Smrg#include "libgfortran.h" 27760c2415Smrg#include <string.h>' 28760c2415Smrg 29760c2415Smrginclude(iparm.m4)dnl 30760c2415Smrg 31760c2415Smrg`#if defined (HAVE_'atype_name`) 32760c2415Smrg 33760c2415Smrgstatic void 34760c2415Smrgcshift1 (gfc_array_char * const restrict ret, 35760c2415Smrg const gfc_array_char * const restrict array, 36760c2415Smrg const 'atype` * const restrict h, 37760c2415Smrg const 'atype_name` * const restrict pwhich) 38760c2415Smrg{ 39760c2415Smrg /* r.* indicates the return array. */ 40760c2415Smrg index_type rstride[GFC_MAX_DIMENSIONS]; 41760c2415Smrg index_type rstride0; 42760c2415Smrg index_type roffset; 43760c2415Smrg char *rptr; 44760c2415Smrg char *dest; 45760c2415Smrg /* s.* indicates the source array. */ 46760c2415Smrg index_type sstride[GFC_MAX_DIMENSIONS]; 47760c2415Smrg index_type sstride0; 48760c2415Smrg index_type soffset; 49760c2415Smrg const char *sptr; 50760c2415Smrg const char *src; 51760c2415Smrg /* h.* indicates the shift array. */ 52760c2415Smrg index_type hstride[GFC_MAX_DIMENSIONS]; 53760c2415Smrg index_type hstride0; 54760c2415Smrg const 'atype_name` *hptr; 55760c2415Smrg 56760c2415Smrg index_type count[GFC_MAX_DIMENSIONS]; 57760c2415Smrg index_type extent[GFC_MAX_DIMENSIONS]; 58760c2415Smrg index_type dim; 59760c2415Smrg index_type len; 60760c2415Smrg index_type n; 61760c2415Smrg int which; 62760c2415Smrg 'atype_name` sh; 63760c2415Smrg index_type arraysize; 64760c2415Smrg index_type size; 65760c2415Smrg index_type type_size; 66760c2415Smrg 67760c2415Smrg if (pwhich) 68760c2415Smrg which = *pwhich - 1; 69760c2415Smrg else 70760c2415Smrg which = 0; 71760c2415Smrg 72760c2415Smrg if (which < 0 || (which + 1) > GFC_DESCRIPTOR_RANK (array)) 73760c2415Smrg runtime_error ("Argument ''`DIM''` is out of range in call to ''`CSHIFT''`"); 74760c2415Smrg 75760c2415Smrg size = GFC_DESCRIPTOR_SIZE(array); 76760c2415Smrg 77760c2415Smrg arraysize = size0 ((array_t *)array); 78760c2415Smrg 79760c2415Smrg if (ret->base_addr == NULL) 80760c2415Smrg { 81760c2415Smrg ret->base_addr = xmallocarray (arraysize, size); 82760c2415Smrg ret->offset = 0; 83760c2415Smrg GFC_DTYPE_COPY(ret,array); 84760c2415Smrg for (index_type i = 0; i < GFC_DESCRIPTOR_RANK (array); i++) 85760c2415Smrg { 86760c2415Smrg index_type ub, str; 87760c2415Smrg 88760c2415Smrg ub = GFC_DESCRIPTOR_EXTENT(array,i) - 1; 89760c2415Smrg 90760c2415Smrg if (i == 0) 91760c2415Smrg str = 1; 92760c2415Smrg else 93760c2415Smrg str = GFC_DESCRIPTOR_EXTENT(ret,i-1) * 94760c2415Smrg GFC_DESCRIPTOR_STRIDE(ret,i-1); 95760c2415Smrg 96760c2415Smrg GFC_DIMENSION_SET(ret->dim[i], 0, ub, str); 97760c2415Smrg } 98760c2415Smrg } 99760c2415Smrg else if (unlikely (compile_options.bounds_check)) 100760c2415Smrg { 101760c2415Smrg bounds_equal_extents ((array_t *) ret, (array_t *) array, 102760c2415Smrg "return value", "CSHIFT"); 103760c2415Smrg } 104760c2415Smrg 105760c2415Smrg if (unlikely (compile_options.bounds_check)) 106760c2415Smrg { 107760c2415Smrg bounds_reduced_extents ((array_t *) h, (array_t *) array, which, 108760c2415Smrg "SHIFT argument", "CSHIFT"); 109760c2415Smrg } 110760c2415Smrg 111760c2415Smrg if (arraysize == 0) 112760c2415Smrg return; 113760c2415Smrg 114760c2415Smrg /* See if we should dispatch to a helper function. */ 115760c2415Smrg 116760c2415Smrg type_size = GFC_DTYPE_TYPE_SIZE (array); 117760c2415Smrg 118760c2415Smrg switch (type_size) 119760c2415Smrg { 120760c2415Smrg case GFC_DTYPE_LOGICAL_1: 121760c2415Smrg case GFC_DTYPE_INTEGER_1: 122760c2415Smrg cshift1_'atype_kind`_i1 ((gfc_array_i1 *)ret, (gfc_array_i1 *) array, 123760c2415Smrg h, pwhich); 124760c2415Smrg return; 125760c2415Smrg 126760c2415Smrg case GFC_DTYPE_LOGICAL_2: 127760c2415Smrg case GFC_DTYPE_INTEGER_2: 128760c2415Smrg cshift1_'atype_kind`_i2 ((gfc_array_i2 *)ret, (gfc_array_i2 *) array, 129760c2415Smrg h, pwhich); 130760c2415Smrg return; 131760c2415Smrg 132760c2415Smrg case GFC_DTYPE_LOGICAL_4: 133760c2415Smrg case GFC_DTYPE_INTEGER_4: 134760c2415Smrg cshift1_'atype_kind`_i4 ((gfc_array_i4 *)ret, (gfc_array_i4 *) array, 135760c2415Smrg h, pwhich); 136760c2415Smrg return; 137760c2415Smrg 138760c2415Smrg case GFC_DTYPE_LOGICAL_8: 139760c2415Smrg case GFC_DTYPE_INTEGER_8: 140760c2415Smrg cshift1_'atype_kind`_i8 ((gfc_array_i8 *)ret, (gfc_array_i8 *) array, 141760c2415Smrg h, pwhich); 142760c2415Smrg return; 143760c2415Smrg 144760c2415Smrg#if defined (HAVE_INTEGER_16) 145760c2415Smrg case GFC_DTYPE_LOGICAL_16: 146760c2415Smrg case GFC_DTYPE_INTEGER_16: 147760c2415Smrg cshift1_'atype_kind`_i16 ((gfc_array_i16 *)ret, (gfc_array_i16 *) array, 148760c2415Smrg h, pwhich); 149760c2415Smrg return; 150760c2415Smrg#endif 151760c2415Smrg 152760c2415Smrg case GFC_DTYPE_REAL_4: 153760c2415Smrg cshift1_'atype_kind`_r4 ((gfc_array_r4 *)ret, (gfc_array_r4 *) array, 154760c2415Smrg h, pwhich); 155760c2415Smrg return; 156760c2415Smrg 157760c2415Smrg case GFC_DTYPE_REAL_8: 158760c2415Smrg cshift1_'atype_kind`_r8 ((gfc_array_r8 *)ret, (gfc_array_r8 *) array, 159760c2415Smrg h, pwhich); 160760c2415Smrg return; 161760c2415Smrg 162760c2415Smrg#if defined (HAVE_REAL_10) 163760c2415Smrg case GFC_DTYPE_REAL_10: 164760c2415Smrg cshift1_'atype_kind`_r10 ((gfc_array_r10 *)ret, (gfc_array_r10 *) array, 165760c2415Smrg h, pwhich); 166760c2415Smrg return; 167760c2415Smrg#endif 168760c2415Smrg 169760c2415Smrg#if defined (HAVE_REAL_16) 170760c2415Smrg case GFC_DTYPE_REAL_16: 171760c2415Smrg cshift1_'atype_kind`_r16 ((gfc_array_r16 *)ret, (gfc_array_r16 *) array, 172760c2415Smrg h, pwhich); 173760c2415Smrg return; 174760c2415Smrg#endif 175760c2415Smrg 176760c2415Smrg case GFC_DTYPE_COMPLEX_4: 177760c2415Smrg cshift1_'atype_kind`_c4 ((gfc_array_c4 *)ret, (gfc_array_c4 *) array, 178760c2415Smrg h, pwhich); 179760c2415Smrg return; 180760c2415Smrg 181760c2415Smrg case GFC_DTYPE_COMPLEX_8: 182760c2415Smrg cshift1_'atype_kind`_c8 ((gfc_array_c8 *)ret, (gfc_array_c8 *) array, 183760c2415Smrg h, pwhich); 184760c2415Smrg return; 185760c2415Smrg 186760c2415Smrg#if defined (HAVE_COMPLEX_10) 187760c2415Smrg case GFC_DTYPE_COMPLEX_10: 188760c2415Smrg cshift1_'atype_kind`_c10 ((gfc_array_c10 *)ret, (gfc_array_c10 *) array, 189760c2415Smrg h, pwhich); 190760c2415Smrg return; 191760c2415Smrg#endif 192760c2415Smrg 193760c2415Smrg#if defined (HAVE_COMPLEX_16) 194760c2415Smrg case GFC_DTYPE_COMPLEX_16: 195760c2415Smrg cshift1_'atype_kind`_c16 ((gfc_array_c16 *)ret, (gfc_array_c16 *) array, 196760c2415Smrg h, pwhich); 197760c2415Smrg return; 198760c2415Smrg#endif 199760c2415Smrg 200760c2415Smrg default: 201760c2415Smrg break; 202760c2415Smrg 203760c2415Smrg } 204760c2415Smrg 205760c2415Smrg extent[0] = 1; 206760c2415Smrg count[0] = 0; 207760c2415Smrg n = 0; 208760c2415Smrg 209760c2415Smrg /* Initialized for avoiding compiler warnings. */ 210760c2415Smrg roffset = size; 211760c2415Smrg soffset = size; 212760c2415Smrg len = 0; 213760c2415Smrg 214760c2415Smrg for (dim = 0; dim < GFC_DESCRIPTOR_RANK (array); dim++) 215760c2415Smrg { 216760c2415Smrg if (dim == which) 217760c2415Smrg { 218760c2415Smrg roffset = GFC_DESCRIPTOR_STRIDE_BYTES(ret,dim); 219760c2415Smrg if (roffset == 0) 220760c2415Smrg roffset = size; 221760c2415Smrg soffset = GFC_DESCRIPTOR_STRIDE_BYTES(array,dim); 222760c2415Smrg if (soffset == 0) 223760c2415Smrg soffset = size; 224760c2415Smrg len = GFC_DESCRIPTOR_EXTENT(array,dim); 225760c2415Smrg } 226760c2415Smrg else 227760c2415Smrg { 228760c2415Smrg count[n] = 0; 229760c2415Smrg extent[n] = GFC_DESCRIPTOR_EXTENT(array,dim); 230760c2415Smrg rstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(ret,dim); 231760c2415Smrg sstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(array,dim); 232760c2415Smrg 233760c2415Smrg hstride[n] = GFC_DESCRIPTOR_STRIDE(h,n); 234760c2415Smrg n++; 235760c2415Smrg } 236760c2415Smrg } 237760c2415Smrg if (sstride[0] == 0) 238760c2415Smrg sstride[0] = size; 239760c2415Smrg if (rstride[0] == 0) 240760c2415Smrg rstride[0] = size; 241760c2415Smrg if (hstride[0] == 0) 242760c2415Smrg hstride[0] = 1; 243760c2415Smrg 244760c2415Smrg dim = GFC_DESCRIPTOR_RANK (array); 245760c2415Smrg rstride0 = rstride[0]; 246760c2415Smrg sstride0 = sstride[0]; 247760c2415Smrg hstride0 = hstride[0]; 248760c2415Smrg rptr = ret->base_addr; 249760c2415Smrg sptr = array->base_addr; 250760c2415Smrg hptr = h->base_addr; 251760c2415Smrg 252760c2415Smrg while (rptr) 253760c2415Smrg { 254760c2415Smrg /* Do the shift for this dimension. */ 255760c2415Smrg sh = *hptr; 256760c2415Smrg /* Normal case should be -len < sh < len; try to 257760c2415Smrg avoid the expensive remainder operation if possible. */ 258760c2415Smrg if (sh < 0) 259760c2415Smrg sh += len; 260760c2415Smrg if (unlikely (sh >= len || sh < 0)) 261760c2415Smrg { 262760c2415Smrg sh = sh % len; 263760c2415Smrg if (sh < 0) 264760c2415Smrg sh += len; 265760c2415Smrg } 266760c2415Smrg 267760c2415Smrg src = &sptr[sh * soffset]; 268760c2415Smrg dest = rptr; 269760c2415Smrg if (soffset == size && roffset == size) 270760c2415Smrg { 271760c2415Smrg size_t len1 = sh * size; 272760c2415Smrg size_t len2 = (len - sh) * size; 273760c2415Smrg memcpy (rptr, sptr + len1, len2); 274760c2415Smrg memcpy (rptr + len2, sptr, len1); 275760c2415Smrg } 276760c2415Smrg else 277760c2415Smrg { 278760c2415Smrg for (n = 0; n < len - sh; n++) 279760c2415Smrg { 280760c2415Smrg memcpy (dest, src, size); 281760c2415Smrg dest += roffset; 282760c2415Smrg src += soffset; 283760c2415Smrg } 284760c2415Smrg for (src = sptr, n = 0; n < sh; n++) 285760c2415Smrg { 286760c2415Smrg memcpy (dest, src, size); 287760c2415Smrg dest += roffset; 288760c2415Smrg src += soffset; 289760c2415Smrg } 290760c2415Smrg } 291760c2415Smrg 292760c2415Smrg /* Advance to the next section. */ 293760c2415Smrg rptr += rstride0; 294760c2415Smrg sptr += sstride0; 295760c2415Smrg hptr += hstride0; 296760c2415Smrg count[0]++; 297760c2415Smrg n = 0; 298760c2415Smrg while (count[n] == extent[n]) 299760c2415Smrg { 300760c2415Smrg /* When we get to the end of a dimension, reset it and increment 301760c2415Smrg the next dimension. */ 302760c2415Smrg count[n] = 0; 303760c2415Smrg /* We could precalculate these products, but this is a less 304760c2415Smrg frequently used path so probably not worth it. */ 305760c2415Smrg rptr -= rstride[n] * extent[n]; 306760c2415Smrg sptr -= sstride[n] * extent[n]; 307760c2415Smrg hptr -= hstride[n] * extent[n]; 308760c2415Smrg n++; 309760c2415Smrg if (n >= dim - 1) 310760c2415Smrg { 311760c2415Smrg /* Break out of the loop. */ 312760c2415Smrg rptr = NULL; 313760c2415Smrg break; 314760c2415Smrg } 315760c2415Smrg else 316760c2415Smrg { 317760c2415Smrg count[n]++; 318760c2415Smrg rptr += rstride[n]; 319760c2415Smrg sptr += sstride[n]; 320760c2415Smrg hptr += hstride[n]; 321760c2415Smrg } 322760c2415Smrg } 323760c2415Smrg } 324760c2415Smrg} 325760c2415Smrg 326760c2415Smrgvoid cshift1_'atype_kind` (gfc_array_char * const restrict, 327760c2415Smrg const gfc_array_char * const restrict, 328760c2415Smrg const 'atype` * const restrict, 329760c2415Smrg const 'atype_name` * const restrict); 330760c2415Smrgexport_proto(cshift1_'atype_kind`); 331760c2415Smrg 332760c2415Smrgvoid 333760c2415Smrgcshift1_'atype_kind` (gfc_array_char * const restrict ret, 334760c2415Smrg const gfc_array_char * const restrict array, 335760c2415Smrg const 'atype` * const restrict h, 336760c2415Smrg const 'atype_name` * const restrict pwhich) 337760c2415Smrg{ 338760c2415Smrg cshift1 (ret, array, h, pwhich); 339760c2415Smrg} 340760c2415Smrg 341760c2415Smrg 342760c2415Smrgvoid cshift1_'atype_kind`_char (gfc_array_char * const restrict ret, 343760c2415Smrg GFC_INTEGER_4, 344760c2415Smrg const gfc_array_char * const restrict array, 345760c2415Smrg const 'atype` * const restrict h, 346760c2415Smrg const 'atype_name` * const restrict pwhich, 347760c2415Smrg GFC_INTEGER_4); 348760c2415Smrgexport_proto(cshift1_'atype_kind`_char); 349760c2415Smrg 350760c2415Smrgvoid 351760c2415Smrgcshift1_'atype_kind`_char (gfc_array_char * const restrict ret, 352760c2415Smrg GFC_INTEGER_4 ret_length __attribute__((unused)), 353760c2415Smrg const gfc_array_char * const restrict array, 354760c2415Smrg const 'atype` * const restrict h, 355760c2415Smrg const 'atype_name` * const restrict pwhich, 356760c2415Smrg GFC_INTEGER_4 array_length __attribute__((unused))) 357760c2415Smrg{ 358760c2415Smrg cshift1 (ret, array, h, pwhich); 359760c2415Smrg} 360760c2415Smrg 361760c2415Smrg 362760c2415Smrgvoid cshift1_'atype_kind`_char4 (gfc_array_char * const restrict ret, 363760c2415Smrg GFC_INTEGER_4, 364760c2415Smrg const gfc_array_char * const restrict array, 365760c2415Smrg const 'atype` * const restrict h, 366760c2415Smrg const 'atype_name` * const restrict pwhich, 367760c2415Smrg GFC_INTEGER_4); 368760c2415Smrgexport_proto(cshift1_'atype_kind`_char4); 369760c2415Smrg 370760c2415Smrgvoid 371760c2415Smrgcshift1_'atype_kind`_char4 (gfc_array_char * const restrict ret, 372760c2415Smrg GFC_INTEGER_4 ret_length __attribute__((unused)), 373760c2415Smrg const gfc_array_char * const restrict array, 374760c2415Smrg const 'atype` * const restrict h, 375760c2415Smrg const 'atype_name` * const restrict pwhich, 376760c2415Smrg GFC_INTEGER_4 array_length __attribute__((unused))) 377760c2415Smrg{ 378760c2415Smrg cshift1 (ret, array, h, pwhich); 379760c2415Smrg} 380760c2415Smrg 381760c2415Smrg#endif' 382