1 1.1 mrg `/* Implementation of the EOSHIFT intrinsic 2 1.1.1.4 mrg Copyright (C) 2002-2024 Free Software Foundation, Inc. 3 1.1 mrg Contributed by Paul Brook <paul (a] nowt.org> 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 Libgfortran 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 include(iparm.m4)dnl 30 1.1 mrg 31 1.1 mrg `#if defined (HAVE_'atype_name`) 32 1.1 mrg 33 1.1 mrg static void 34 1.1 mrg eoshift1 (gfc_array_char * const restrict ret, 35 1.1 mrg const gfc_array_char * const restrict array, 36 1.1 mrg const 'atype` * const restrict h, 37 1.1 mrg const char * const restrict pbound, 38 1.1 mrg const 'atype_name` * const restrict pwhich, 39 1.1 mrg const char * filler, index_type filler_len) 40 1.1 mrg { 41 1.1 mrg /* r.* indicates the return array. */ 42 1.1 mrg index_type rstride[GFC_MAX_DIMENSIONS]; 43 1.1 mrg index_type rstride0; 44 1.1 mrg index_type roffset; 45 1.1 mrg char *rptr; 46 1.1 mrg char * restrict dest; 47 1.1 mrg /* s.* indicates the source array. */ 48 1.1 mrg index_type sstride[GFC_MAX_DIMENSIONS]; 49 1.1 mrg index_type sstride0; 50 1.1 mrg index_type soffset; 51 1.1 mrg const char *sptr; 52 1.1 mrg const char *src; 53 1.1 mrg /* h.* indicates the shift array. */ 54 1.1 mrg index_type hstride[GFC_MAX_DIMENSIONS]; 55 1.1 mrg index_type hstride0; 56 1.1 mrg const 'atype_name` *hptr; 57 1.1 mrg 58 1.1 mrg index_type count[GFC_MAX_DIMENSIONS]; 59 1.1 mrg index_type extent[GFC_MAX_DIMENSIONS]; 60 1.1 mrg index_type dim; 61 1.1 mrg index_type len; 62 1.1 mrg index_type n; 63 1.1 mrg index_type size; 64 1.1 mrg index_type arraysize; 65 1.1 mrg int which; 66 1.1 mrg 'atype_name` sh; 67 1.1 mrg 'atype_name` delta; 68 1.1 mrg 69 1.1 mrg /* The compiler cannot figure out that these are set, initialize 70 1.1 mrg them to avoid warnings. */ 71 1.1 mrg len = 0; 72 1.1 mrg soffset = 0; 73 1.1 mrg roffset = 0; 74 1.1 mrg 75 1.1 mrg size = GFC_DESCRIPTOR_SIZE(array); 76 1.1 mrg 77 1.1 mrg if (pwhich) 78 1.1 mrg which = *pwhich - 1; 79 1.1 mrg else 80 1.1 mrg which = 0; 81 1.1 mrg 82 1.1 mrg extent[0] = 1; 83 1.1 mrg count[0] = 0; 84 1.1 mrg 85 1.1 mrg arraysize = size0 ((array_t *) array); 86 1.1 mrg if (ret->base_addr == NULL) 87 1.1 mrg { 88 1.1 mrg ret->offset = 0; 89 1.1 mrg GFC_DTYPE_COPY(ret,array); 90 1.1 mrg for (index_type i = 0; i < GFC_DESCRIPTOR_RANK (array); i++) 91 1.1 mrg { 92 1.1 mrg index_type ub, str; 93 1.1 mrg 94 1.1 mrg ub = GFC_DESCRIPTOR_EXTENT(array,i) - 1; 95 1.1 mrg 96 1.1 mrg if (i == 0) 97 1.1 mrg str = 1; 98 1.1 mrg else 99 1.1 mrg str = GFC_DESCRIPTOR_EXTENT(ret,i-1) 100 1.1 mrg * GFC_DESCRIPTOR_STRIDE(ret,i-1); 101 1.1 mrg 102 1.1 mrg GFC_DIMENSION_SET(ret->dim[i], 0, ub, str); 103 1.1 mrg 104 1.1 mrg } 105 1.1 mrg /* xmallocarray allocates a single byte for zero size. */ 106 1.1 mrg ret->base_addr = xmallocarray (arraysize, size); 107 1.1 mrg 108 1.1 mrg } 109 1.1 mrg else if (unlikely (compile_options.bounds_check)) 110 1.1 mrg { 111 1.1 mrg bounds_equal_extents ((array_t *) ret, (array_t *) array, 112 1.1 mrg "return value", "EOSHIFT"); 113 1.1 mrg } 114 1.1 mrg 115 1.1 mrg if (unlikely (compile_options.bounds_check)) 116 1.1 mrg { 117 1.1 mrg bounds_reduced_extents ((array_t *) h, (array_t *) array, which, 118 1.1 mrg "SHIFT argument", "EOSHIFT"); 119 1.1 mrg } 120 1.1 mrg 121 1.1 mrg if (arraysize == 0) 122 1.1 mrg return; 123 1.1 mrg 124 1.1 mrg n = 0; 125 1.1 mrg for (dim = 0; dim < GFC_DESCRIPTOR_RANK (array); dim++) 126 1.1 mrg { 127 1.1 mrg if (dim == which) 128 1.1 mrg { 129 1.1 mrg roffset = GFC_DESCRIPTOR_STRIDE_BYTES(ret,dim); 130 1.1 mrg if (roffset == 0) 131 1.1 mrg roffset = size; 132 1.1 mrg soffset = GFC_DESCRIPTOR_STRIDE_BYTES(array,dim); 133 1.1 mrg if (soffset == 0) 134 1.1 mrg soffset = size; 135 1.1 mrg len = GFC_DESCRIPTOR_EXTENT(array,dim); 136 1.1 mrg } 137 1.1 mrg else 138 1.1 mrg { 139 1.1 mrg count[n] = 0; 140 1.1 mrg extent[n] = GFC_DESCRIPTOR_EXTENT(array,dim); 141 1.1 mrg rstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(ret,dim); 142 1.1 mrg sstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(array,dim); 143 1.1 mrg 144 1.1 mrg hstride[n] = GFC_DESCRIPTOR_STRIDE(h,n); 145 1.1 mrg n++; 146 1.1 mrg } 147 1.1 mrg } 148 1.1 mrg if (sstride[0] == 0) 149 1.1 mrg sstride[0] = size; 150 1.1 mrg if (rstride[0] == 0) 151 1.1 mrg rstride[0] = size; 152 1.1 mrg if (hstride[0] == 0) 153 1.1 mrg hstride[0] = 1; 154 1.1 mrg 155 1.1 mrg dim = GFC_DESCRIPTOR_RANK (array); 156 1.1 mrg rstride0 = rstride[0]; 157 1.1 mrg sstride0 = sstride[0]; 158 1.1 mrg hstride0 = hstride[0]; 159 1.1 mrg rptr = ret->base_addr; 160 1.1 mrg sptr = array->base_addr; 161 1.1 mrg hptr = h->base_addr; 162 1.1 mrg 163 1.1 mrg while (rptr) 164 1.1 mrg { 165 1.1 mrg /* Do the shift for this dimension. */ 166 1.1 mrg sh = *hptr; 167 1.1 mrg if (( sh >= 0 ? sh : -sh ) > len) 168 1.1 mrg { 169 1.1 mrg delta = len; 170 1.1 mrg sh = len; 171 1.1 mrg } 172 1.1 mrg else 173 1.1 mrg delta = (sh >= 0) ? sh: -sh; 174 1.1 mrg 175 1.1 mrg if (sh > 0) 176 1.1 mrg { 177 1.1 mrg src = &sptr[delta * soffset]; 178 1.1 mrg dest = rptr; 179 1.1 mrg } 180 1.1 mrg else 181 1.1 mrg { 182 1.1 mrg src = sptr; 183 1.1 mrg dest = &rptr[delta * roffset]; 184 1.1 mrg } 185 1.1 mrg 186 1.1 mrg /* If the elements are contiguous, perform a single block move. */ 187 1.1 mrg if (soffset == size && roffset == size) 188 1.1 mrg { 189 1.1 mrg size_t chunk = size * (len - delta); 190 1.1 mrg memcpy (dest, src, chunk); 191 1.1 mrg dest += chunk; 192 1.1 mrg } 193 1.1 mrg else 194 1.1 mrg { 195 1.1 mrg for (n = 0; n < len - delta; n++) 196 1.1 mrg { 197 1.1 mrg memcpy (dest, src, size); 198 1.1 mrg dest += roffset; 199 1.1 mrg src += soffset; 200 1.1 mrg } 201 1.1 mrg } 202 1.1 mrg if (sh < 0) 203 1.1 mrg dest = rptr; 204 1.1 mrg n = delta; 205 1.1 mrg 206 1.1 mrg if (pbound) 207 1.1 mrg while (n--) 208 1.1 mrg { 209 1.1 mrg memcpy (dest, pbound, size); 210 1.1 mrg dest += roffset; 211 1.1 mrg } 212 1.1 mrg else 213 1.1 mrg while (n--) 214 1.1 mrg { 215 1.1 mrg index_type i; 216 1.1 mrg 217 1.1 mrg if (filler_len == 1) 218 1.1 mrg memset (dest, filler[0], size); 219 1.1 mrg else 220 1.1 mrg for (i = 0; i < size; i += filler_len) 221 1.1 mrg memcpy (&dest[i], filler, filler_len); 222 1.1 mrg 223 1.1 mrg dest += roffset; 224 1.1 mrg } 225 1.1 mrg 226 1.1 mrg /* Advance to the next section. */ 227 1.1 mrg rptr += rstride0; 228 1.1 mrg sptr += sstride0; 229 1.1 mrg hptr += hstride0; 230 1.1 mrg count[0]++; 231 1.1 mrg n = 0; 232 1.1 mrg while (count[n] == extent[n]) 233 1.1 mrg { 234 1.1 mrg /* When we get to the end of a dimension, reset it and increment 235 1.1 mrg the next dimension. */ 236 1.1 mrg count[n] = 0; 237 1.1 mrg /* We could precalculate these products, but this is a less 238 1.1 mrg frequently used path so probably not worth it. */ 239 1.1 mrg rptr -= rstride[n] * extent[n]; 240 1.1 mrg sptr -= sstride[n] * extent[n]; 241 1.1 mrg hptr -= hstride[n] * extent[n]; 242 1.1 mrg n++; 243 1.1 mrg if (n >= dim - 1) 244 1.1 mrg { 245 1.1 mrg /* Break out of the loop. */ 246 1.1 mrg rptr = NULL; 247 1.1 mrg break; 248 1.1 mrg } 249 1.1 mrg else 250 1.1 mrg { 251 1.1 mrg count[n]++; 252 1.1 mrg rptr += rstride[n]; 253 1.1 mrg sptr += sstride[n]; 254 1.1 mrg hptr += hstride[n]; 255 1.1 mrg } 256 1.1 mrg } 257 1.1 mrg } 258 1.1 mrg } 259 1.1 mrg 260 1.1 mrg void eoshift1_'atype_kind` (gfc_array_char * const restrict, 261 1.1 mrg const gfc_array_char * const restrict, 262 1.1 mrg const 'atype` * const restrict, const char * const restrict, 263 1.1 mrg const 'atype_name` * const restrict); 264 1.1 mrg export_proto(eoshift1_'atype_kind`); 265 1.1 mrg 266 1.1 mrg void 267 1.1 mrg eoshift1_'atype_kind` (gfc_array_char * const restrict ret, 268 1.1 mrg const gfc_array_char * const restrict array, 269 1.1 mrg const 'atype` * const restrict h, 270 1.1 mrg const char * const restrict pbound, 271 1.1 mrg const 'atype_name` * const restrict pwhich) 272 1.1 mrg { 273 1.1 mrg eoshift1 (ret, array, h, pbound, pwhich, "\0", 1); 274 1.1 mrg } 275 1.1 mrg 276 1.1 mrg 277 1.1 mrg void eoshift1_'atype_kind`_char (gfc_array_char * const restrict, 278 1.1 mrg GFC_INTEGER_4, 279 1.1 mrg const gfc_array_char * const restrict, 280 1.1 mrg const 'atype` * const restrict, 281 1.1 mrg const char * const restrict, 282 1.1 mrg const 'atype_name` * const restrict, 283 1.1 mrg GFC_INTEGER_4, GFC_INTEGER_4); 284 1.1 mrg export_proto(eoshift1_'atype_kind`_char); 285 1.1 mrg 286 1.1 mrg void 287 1.1 mrg eoshift1_'atype_kind`_char (gfc_array_char * const restrict ret, 288 1.1 mrg GFC_INTEGER_4 ret_length __attribute__((unused)), 289 1.1 mrg const gfc_array_char * const restrict array, 290 1.1 mrg const 'atype` * const restrict h, 291 1.1 mrg const char * const restrict pbound, 292 1.1 mrg const 'atype_name` * const restrict pwhich, 293 1.1 mrg GFC_INTEGER_4 array_length __attribute__((unused)), 294 1.1 mrg GFC_INTEGER_4 bound_length __attribute__((unused))) 295 1.1 mrg { 296 1.1 mrg eoshift1 (ret, array, h, pbound, pwhich, " ", 1); 297 1.1 mrg } 298 1.1 mrg 299 1.1 mrg 300 1.1 mrg void eoshift1_'atype_kind`_char4 (gfc_array_char * const restrict, 301 1.1 mrg GFC_INTEGER_4, 302 1.1 mrg const gfc_array_char * const restrict, 303 1.1 mrg const 'atype` * const restrict, 304 1.1 mrg const char * const restrict, 305 1.1 mrg const 'atype_name` * const restrict, 306 1.1 mrg GFC_INTEGER_4, GFC_INTEGER_4); 307 1.1 mrg export_proto(eoshift1_'atype_kind`_char4); 308 1.1 mrg 309 1.1 mrg void 310 1.1 mrg eoshift1_'atype_kind`_char4 (gfc_array_char * const restrict ret, 311 1.1 mrg GFC_INTEGER_4 ret_length __attribute__((unused)), 312 1.1 mrg const gfc_array_char * const restrict array, 313 1.1 mrg const 'atype` * const restrict h, 314 1.1 mrg const char * const restrict pbound, 315 1.1 mrg const 'atype_name` * const restrict pwhich, 316 1.1 mrg GFC_INTEGER_4 array_length __attribute__((unused)), 317 1.1 mrg GFC_INTEGER_4 bound_length __attribute__((unused))) 318 1.1 mrg { 319 1.1 mrg static const gfc_char4_t space = (unsigned char) ''` ''`; 320 1.1 mrg eoshift1 (ret, array, h, pbound, pwhich, 321 1.1 mrg (const char *) &space, sizeof (gfc_char4_t)); 322 1.1 mrg } 323 1.1 mrg 324 1.1 mrg #endif' 325