1627f7eb2Smrg`/* Implementation of the CSHIFT intrinsic 2*4c3eb207Smrg Copyright (C) 2003-2020 Free Software Foundation, Inc. 3627f7eb2Smrg Contributed by Feng Wang <wf_cs@yahoo.com> 4627f7eb2Smrg 5627f7eb2SmrgThis file is part of the GNU Fortran runtime library (libgfortran). 6627f7eb2Smrg 7627f7eb2SmrgLibgfortran is free software; you can redistribute it and/or 8627f7eb2Smrgmodify it under the terms of the GNU General Public 9627f7eb2SmrgLicense as published by the Free Software Foundation; either 10627f7eb2Smrgversion 3 of the License, or (at your option) any later version. 11627f7eb2Smrg 12627f7eb2SmrgLigbfortran is distributed in the hope that it will be useful, 13627f7eb2Smrgbut WITHOUT ANY WARRANTY; without even the implied warranty of 14627f7eb2SmrgMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15627f7eb2SmrgGNU General Public License for more details. 16627f7eb2Smrg 17627f7eb2SmrgUnder Section 7 of GPL version 3, you are granted additional 18627f7eb2Smrgpermissions described in the GCC Runtime Library Exception, version 19627f7eb2Smrg3.1, as published by the Free Software Foundation. 20627f7eb2Smrg 21627f7eb2SmrgYou should have received a copy of the GNU General Public License and 22627f7eb2Smrga copy of the GCC Runtime Library Exception along with this program; 23627f7eb2Smrgsee the files COPYING3 and COPYING.RUNTIME respectively. If not, see 24627f7eb2Smrg<http://www.gnu.org/licenses/>. */ 25627f7eb2Smrg 26627f7eb2Smrg#include "libgfortran.h" 27627f7eb2Smrg#include <string.h>' 28627f7eb2Smrg 29627f7eb2Smrginclude(iparm.m4)dnl 30627f7eb2Smrg 31627f7eb2Smrg`#if defined (HAVE_'atype_name`) 32627f7eb2Smrg 33627f7eb2Smrgstatic void 34627f7eb2Smrgcshift1 (gfc_array_char * const restrict ret, 35627f7eb2Smrg const gfc_array_char * const restrict array, 36627f7eb2Smrg const 'atype` * const restrict h, 37627f7eb2Smrg const 'atype_name` * const restrict pwhich) 38627f7eb2Smrg{ 39627f7eb2Smrg /* r.* indicates the return array. */ 40627f7eb2Smrg index_type rstride[GFC_MAX_DIMENSIONS]; 41627f7eb2Smrg index_type rstride0; 42627f7eb2Smrg index_type roffset; 43627f7eb2Smrg char *rptr; 44627f7eb2Smrg char *dest; 45627f7eb2Smrg /* s.* indicates the source array. */ 46627f7eb2Smrg index_type sstride[GFC_MAX_DIMENSIONS]; 47627f7eb2Smrg index_type sstride0; 48627f7eb2Smrg index_type soffset; 49627f7eb2Smrg const char *sptr; 50627f7eb2Smrg const char *src; 51627f7eb2Smrg /* h.* indicates the shift array. */ 52627f7eb2Smrg index_type hstride[GFC_MAX_DIMENSIONS]; 53627f7eb2Smrg index_type hstride0; 54627f7eb2Smrg const 'atype_name` *hptr; 55627f7eb2Smrg 56627f7eb2Smrg index_type count[GFC_MAX_DIMENSIONS]; 57627f7eb2Smrg index_type extent[GFC_MAX_DIMENSIONS]; 58627f7eb2Smrg index_type dim; 59627f7eb2Smrg index_type len; 60627f7eb2Smrg index_type n; 61627f7eb2Smrg int which; 62627f7eb2Smrg 'atype_name` sh; 63627f7eb2Smrg index_type arraysize; 64627f7eb2Smrg index_type size; 65627f7eb2Smrg index_type type_size; 66627f7eb2Smrg 67627f7eb2Smrg if (pwhich) 68627f7eb2Smrg which = *pwhich - 1; 69627f7eb2Smrg else 70627f7eb2Smrg which = 0; 71627f7eb2Smrg 72627f7eb2Smrg if (which < 0 || (which + 1) > GFC_DESCRIPTOR_RANK (array)) 73627f7eb2Smrg runtime_error ("Argument ''`DIM''` is out of range in call to ''`CSHIFT''`"); 74627f7eb2Smrg 75627f7eb2Smrg size = GFC_DESCRIPTOR_SIZE(array); 76627f7eb2Smrg 77627f7eb2Smrg arraysize = size0 ((array_t *)array); 78627f7eb2Smrg 79627f7eb2Smrg if (ret->base_addr == NULL) 80627f7eb2Smrg { 81627f7eb2Smrg ret->base_addr = xmallocarray (arraysize, size); 82627f7eb2Smrg ret->offset = 0; 83627f7eb2Smrg GFC_DTYPE_COPY(ret,array); 84627f7eb2Smrg for (index_type i = 0; i < GFC_DESCRIPTOR_RANK (array); i++) 85627f7eb2Smrg { 86627f7eb2Smrg index_type ub, str; 87627f7eb2Smrg 88627f7eb2Smrg ub = GFC_DESCRIPTOR_EXTENT(array,i) - 1; 89627f7eb2Smrg 90627f7eb2Smrg if (i == 0) 91627f7eb2Smrg str = 1; 92627f7eb2Smrg else 93627f7eb2Smrg str = GFC_DESCRIPTOR_EXTENT(ret,i-1) * 94627f7eb2Smrg GFC_DESCRIPTOR_STRIDE(ret,i-1); 95627f7eb2Smrg 96627f7eb2Smrg GFC_DIMENSION_SET(ret->dim[i], 0, ub, str); 97627f7eb2Smrg } 98627f7eb2Smrg } 99627f7eb2Smrg else if (unlikely (compile_options.bounds_check)) 100627f7eb2Smrg { 101627f7eb2Smrg bounds_equal_extents ((array_t *) ret, (array_t *) array, 102627f7eb2Smrg "return value", "CSHIFT"); 103627f7eb2Smrg } 104627f7eb2Smrg 105627f7eb2Smrg if (unlikely (compile_options.bounds_check)) 106627f7eb2Smrg { 107627f7eb2Smrg bounds_reduced_extents ((array_t *) h, (array_t *) array, which, 108627f7eb2Smrg "SHIFT argument", "CSHIFT"); 109627f7eb2Smrg } 110627f7eb2Smrg 111627f7eb2Smrg if (arraysize == 0) 112627f7eb2Smrg return; 113627f7eb2Smrg 114627f7eb2Smrg /* See if we should dispatch to a helper function. */ 115627f7eb2Smrg 116627f7eb2Smrg type_size = GFC_DTYPE_TYPE_SIZE (array); 117627f7eb2Smrg 118627f7eb2Smrg switch (type_size) 119627f7eb2Smrg { 120627f7eb2Smrg case GFC_DTYPE_LOGICAL_1: 121627f7eb2Smrg case GFC_DTYPE_INTEGER_1: 122627f7eb2Smrg cshift1_'atype_kind`_i1 ((gfc_array_i1 *)ret, (gfc_array_i1 *) array, 123627f7eb2Smrg h, pwhich); 124627f7eb2Smrg return; 125627f7eb2Smrg 126627f7eb2Smrg case GFC_DTYPE_LOGICAL_2: 127627f7eb2Smrg case GFC_DTYPE_INTEGER_2: 128627f7eb2Smrg cshift1_'atype_kind`_i2 ((gfc_array_i2 *)ret, (gfc_array_i2 *) array, 129627f7eb2Smrg h, pwhich); 130627f7eb2Smrg return; 131627f7eb2Smrg 132627f7eb2Smrg case GFC_DTYPE_LOGICAL_4: 133627f7eb2Smrg case GFC_DTYPE_INTEGER_4: 134627f7eb2Smrg cshift1_'atype_kind`_i4 ((gfc_array_i4 *)ret, (gfc_array_i4 *) array, 135627f7eb2Smrg h, pwhich); 136627f7eb2Smrg return; 137627f7eb2Smrg 138627f7eb2Smrg case GFC_DTYPE_LOGICAL_8: 139627f7eb2Smrg case GFC_DTYPE_INTEGER_8: 140627f7eb2Smrg cshift1_'atype_kind`_i8 ((gfc_array_i8 *)ret, (gfc_array_i8 *) array, 141627f7eb2Smrg h, pwhich); 142627f7eb2Smrg return; 143627f7eb2Smrg 144627f7eb2Smrg#if defined (HAVE_INTEGER_16) 145627f7eb2Smrg case GFC_DTYPE_LOGICAL_16: 146627f7eb2Smrg case GFC_DTYPE_INTEGER_16: 147627f7eb2Smrg cshift1_'atype_kind`_i16 ((gfc_array_i16 *)ret, (gfc_array_i16 *) array, 148627f7eb2Smrg h, pwhich); 149627f7eb2Smrg return; 150627f7eb2Smrg#endif 151627f7eb2Smrg 152627f7eb2Smrg case GFC_DTYPE_REAL_4: 153627f7eb2Smrg cshift1_'atype_kind`_r4 ((gfc_array_r4 *)ret, (gfc_array_r4 *) array, 154627f7eb2Smrg h, pwhich); 155627f7eb2Smrg return; 156627f7eb2Smrg 157627f7eb2Smrg case GFC_DTYPE_REAL_8: 158627f7eb2Smrg cshift1_'atype_kind`_r8 ((gfc_array_r8 *)ret, (gfc_array_r8 *) array, 159627f7eb2Smrg h, pwhich); 160627f7eb2Smrg return; 161627f7eb2Smrg 162627f7eb2Smrg#if defined (HAVE_REAL_10) 163627f7eb2Smrg case GFC_DTYPE_REAL_10: 164627f7eb2Smrg cshift1_'atype_kind`_r10 ((gfc_array_r10 *)ret, (gfc_array_r10 *) array, 165627f7eb2Smrg h, pwhich); 166627f7eb2Smrg return; 167627f7eb2Smrg#endif 168627f7eb2Smrg 169627f7eb2Smrg#if defined (HAVE_REAL_16) 170627f7eb2Smrg case GFC_DTYPE_REAL_16: 171627f7eb2Smrg cshift1_'atype_kind`_r16 ((gfc_array_r16 *)ret, (gfc_array_r16 *) array, 172627f7eb2Smrg h, pwhich); 173627f7eb2Smrg return; 174627f7eb2Smrg#endif 175627f7eb2Smrg 176627f7eb2Smrg case GFC_DTYPE_COMPLEX_4: 177627f7eb2Smrg cshift1_'atype_kind`_c4 ((gfc_array_c4 *)ret, (gfc_array_c4 *) array, 178627f7eb2Smrg h, pwhich); 179627f7eb2Smrg return; 180627f7eb2Smrg 181627f7eb2Smrg case GFC_DTYPE_COMPLEX_8: 182627f7eb2Smrg cshift1_'atype_kind`_c8 ((gfc_array_c8 *)ret, (gfc_array_c8 *) array, 183627f7eb2Smrg h, pwhich); 184627f7eb2Smrg return; 185627f7eb2Smrg 186627f7eb2Smrg#if defined (HAVE_COMPLEX_10) 187627f7eb2Smrg case GFC_DTYPE_COMPLEX_10: 188627f7eb2Smrg cshift1_'atype_kind`_c10 ((gfc_array_c10 *)ret, (gfc_array_c10 *) array, 189627f7eb2Smrg h, pwhich); 190627f7eb2Smrg return; 191627f7eb2Smrg#endif 192627f7eb2Smrg 193627f7eb2Smrg#if defined (HAVE_COMPLEX_16) 194627f7eb2Smrg case GFC_DTYPE_COMPLEX_16: 195627f7eb2Smrg cshift1_'atype_kind`_c16 ((gfc_array_c16 *)ret, (gfc_array_c16 *) array, 196627f7eb2Smrg h, pwhich); 197627f7eb2Smrg return; 198627f7eb2Smrg#endif 199627f7eb2Smrg 200627f7eb2Smrg default: 201627f7eb2Smrg break; 202627f7eb2Smrg 203627f7eb2Smrg } 204627f7eb2Smrg 205627f7eb2Smrg extent[0] = 1; 206627f7eb2Smrg count[0] = 0; 207627f7eb2Smrg n = 0; 208627f7eb2Smrg 209627f7eb2Smrg /* Initialized for avoiding compiler warnings. */ 210627f7eb2Smrg roffset = size; 211627f7eb2Smrg soffset = size; 212627f7eb2Smrg len = 0; 213627f7eb2Smrg 214627f7eb2Smrg for (dim = 0; dim < GFC_DESCRIPTOR_RANK (array); dim++) 215627f7eb2Smrg { 216627f7eb2Smrg if (dim == which) 217627f7eb2Smrg { 218627f7eb2Smrg roffset = GFC_DESCRIPTOR_STRIDE_BYTES(ret,dim); 219627f7eb2Smrg if (roffset == 0) 220627f7eb2Smrg roffset = size; 221627f7eb2Smrg soffset = GFC_DESCRIPTOR_STRIDE_BYTES(array,dim); 222627f7eb2Smrg if (soffset == 0) 223627f7eb2Smrg soffset = size; 224627f7eb2Smrg len = GFC_DESCRIPTOR_EXTENT(array,dim); 225627f7eb2Smrg } 226627f7eb2Smrg else 227627f7eb2Smrg { 228627f7eb2Smrg count[n] = 0; 229627f7eb2Smrg extent[n] = GFC_DESCRIPTOR_EXTENT(array,dim); 230627f7eb2Smrg rstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(ret,dim); 231627f7eb2Smrg sstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(array,dim); 232627f7eb2Smrg 233627f7eb2Smrg hstride[n] = GFC_DESCRIPTOR_STRIDE(h,n); 234627f7eb2Smrg n++; 235627f7eb2Smrg } 236627f7eb2Smrg } 237627f7eb2Smrg if (sstride[0] == 0) 238627f7eb2Smrg sstride[0] = size; 239627f7eb2Smrg if (rstride[0] == 0) 240627f7eb2Smrg rstride[0] = size; 241627f7eb2Smrg if (hstride[0] == 0) 242627f7eb2Smrg hstride[0] = 1; 243627f7eb2Smrg 244627f7eb2Smrg dim = GFC_DESCRIPTOR_RANK (array); 245627f7eb2Smrg rstride0 = rstride[0]; 246627f7eb2Smrg sstride0 = sstride[0]; 247627f7eb2Smrg hstride0 = hstride[0]; 248627f7eb2Smrg rptr = ret->base_addr; 249627f7eb2Smrg sptr = array->base_addr; 250627f7eb2Smrg hptr = h->base_addr; 251627f7eb2Smrg 252627f7eb2Smrg while (rptr) 253627f7eb2Smrg { 254627f7eb2Smrg /* Do the shift for this dimension. */ 255627f7eb2Smrg sh = *hptr; 256627f7eb2Smrg /* Normal case should be -len < sh < len; try to 257627f7eb2Smrg avoid the expensive remainder operation if possible. */ 258627f7eb2Smrg if (sh < 0) 259627f7eb2Smrg sh += len; 260627f7eb2Smrg if (unlikely (sh >= len || sh < 0)) 261627f7eb2Smrg { 262627f7eb2Smrg sh = sh % len; 263627f7eb2Smrg if (sh < 0) 264627f7eb2Smrg sh += len; 265627f7eb2Smrg } 266627f7eb2Smrg 267627f7eb2Smrg src = &sptr[sh * soffset]; 268627f7eb2Smrg dest = rptr; 269627f7eb2Smrg if (soffset == size && roffset == size) 270627f7eb2Smrg { 271627f7eb2Smrg size_t len1 = sh * size; 272627f7eb2Smrg size_t len2 = (len - sh) * size; 273627f7eb2Smrg memcpy (rptr, sptr + len1, len2); 274627f7eb2Smrg memcpy (rptr + len2, sptr, len1); 275627f7eb2Smrg } 276627f7eb2Smrg else 277627f7eb2Smrg { 278627f7eb2Smrg for (n = 0; n < len - sh; n++) 279627f7eb2Smrg { 280627f7eb2Smrg memcpy (dest, src, size); 281627f7eb2Smrg dest += roffset; 282627f7eb2Smrg src += soffset; 283627f7eb2Smrg } 284627f7eb2Smrg for (src = sptr, n = 0; n < sh; n++) 285627f7eb2Smrg { 286627f7eb2Smrg memcpy (dest, src, size); 287627f7eb2Smrg dest += roffset; 288627f7eb2Smrg src += soffset; 289627f7eb2Smrg } 290627f7eb2Smrg } 291627f7eb2Smrg 292627f7eb2Smrg /* Advance to the next section. */ 293627f7eb2Smrg rptr += rstride0; 294627f7eb2Smrg sptr += sstride0; 295627f7eb2Smrg hptr += hstride0; 296627f7eb2Smrg count[0]++; 297627f7eb2Smrg n = 0; 298627f7eb2Smrg while (count[n] == extent[n]) 299627f7eb2Smrg { 300627f7eb2Smrg /* When we get to the end of a dimension, reset it and increment 301627f7eb2Smrg the next dimension. */ 302627f7eb2Smrg count[n] = 0; 303627f7eb2Smrg /* We could precalculate these products, but this is a less 304627f7eb2Smrg frequently used path so probably not worth it. */ 305627f7eb2Smrg rptr -= rstride[n] * extent[n]; 306627f7eb2Smrg sptr -= sstride[n] * extent[n]; 307627f7eb2Smrg hptr -= hstride[n] * extent[n]; 308627f7eb2Smrg n++; 309627f7eb2Smrg if (n >= dim - 1) 310627f7eb2Smrg { 311627f7eb2Smrg /* Break out of the loop. */ 312627f7eb2Smrg rptr = NULL; 313627f7eb2Smrg break; 314627f7eb2Smrg } 315627f7eb2Smrg else 316627f7eb2Smrg { 317627f7eb2Smrg count[n]++; 318627f7eb2Smrg rptr += rstride[n]; 319627f7eb2Smrg sptr += sstride[n]; 320627f7eb2Smrg hptr += hstride[n]; 321627f7eb2Smrg } 322627f7eb2Smrg } 323627f7eb2Smrg } 324627f7eb2Smrg} 325627f7eb2Smrg 326627f7eb2Smrgvoid cshift1_'atype_kind` (gfc_array_char * const restrict, 327627f7eb2Smrg const gfc_array_char * const restrict, 328627f7eb2Smrg const 'atype` * const restrict, 329627f7eb2Smrg const 'atype_name` * const restrict); 330627f7eb2Smrgexport_proto(cshift1_'atype_kind`); 331627f7eb2Smrg 332627f7eb2Smrgvoid 333627f7eb2Smrgcshift1_'atype_kind` (gfc_array_char * const restrict ret, 334627f7eb2Smrg const gfc_array_char * const restrict array, 335627f7eb2Smrg const 'atype` * const restrict h, 336627f7eb2Smrg const 'atype_name` * const restrict pwhich) 337627f7eb2Smrg{ 338627f7eb2Smrg cshift1 (ret, array, h, pwhich); 339627f7eb2Smrg} 340627f7eb2Smrg 341627f7eb2Smrg 342627f7eb2Smrgvoid cshift1_'atype_kind`_char (gfc_array_char * const restrict ret, 343627f7eb2Smrg GFC_INTEGER_4, 344627f7eb2Smrg const gfc_array_char * const restrict array, 345627f7eb2Smrg const 'atype` * const restrict h, 346627f7eb2Smrg const 'atype_name` * const restrict pwhich, 347627f7eb2Smrg GFC_INTEGER_4); 348627f7eb2Smrgexport_proto(cshift1_'atype_kind`_char); 349627f7eb2Smrg 350627f7eb2Smrgvoid 351627f7eb2Smrgcshift1_'atype_kind`_char (gfc_array_char * const restrict ret, 352627f7eb2Smrg GFC_INTEGER_4 ret_length __attribute__((unused)), 353627f7eb2Smrg const gfc_array_char * const restrict array, 354627f7eb2Smrg const 'atype` * const restrict h, 355627f7eb2Smrg const 'atype_name` * const restrict pwhich, 356627f7eb2Smrg GFC_INTEGER_4 array_length __attribute__((unused))) 357627f7eb2Smrg{ 358627f7eb2Smrg cshift1 (ret, array, h, pwhich); 359627f7eb2Smrg} 360627f7eb2Smrg 361627f7eb2Smrg 362627f7eb2Smrgvoid cshift1_'atype_kind`_char4 (gfc_array_char * const restrict ret, 363627f7eb2Smrg GFC_INTEGER_4, 364627f7eb2Smrg const gfc_array_char * const restrict array, 365627f7eb2Smrg const 'atype` * const restrict h, 366627f7eb2Smrg const 'atype_name` * const restrict pwhich, 367627f7eb2Smrg GFC_INTEGER_4); 368627f7eb2Smrgexport_proto(cshift1_'atype_kind`_char4); 369627f7eb2Smrg 370627f7eb2Smrgvoid 371627f7eb2Smrgcshift1_'atype_kind`_char4 (gfc_array_char * const restrict ret, 372627f7eb2Smrg GFC_INTEGER_4 ret_length __attribute__((unused)), 373627f7eb2Smrg const gfc_array_char * const restrict array, 374627f7eb2Smrg const 'atype` * const restrict h, 375627f7eb2Smrg const 'atype_name` * const restrict pwhich, 376627f7eb2Smrg GFC_INTEGER_4 array_length __attribute__((unused))) 377627f7eb2Smrg{ 378627f7eb2Smrg cshift1 (ret, array, h, pwhich); 379627f7eb2Smrg} 380627f7eb2Smrg 381627f7eb2Smrg#endif' 382