1 `/* Implementation of the FINDLOC intrinsic 2 Copyright (C) 2018-2024 Free Software Foundation, Inc. 3 Contributed by Thomas Knig <tk (a] tkoenig.net> 4 5 This file is part of the GNU Fortran 95 runtime library (libgfortran). 6 7 Libgfortran is free software; you can redistribute it and/or 8 modify it under the terms of the GNU General Public 9 License as published by the Free Software Foundation; either 10 version 3 of the License, or (at your option) any later version. 11 12 Libgfortran is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 Under Section 7 of GPL version 3, you are granted additional 18 permissions described in the GCC Runtime Library Exception, version 19 3.1, as published by the Free Software Foundation. 20 21 You should have received a copy of the GNU General Public License and 22 a copy of the GCC Runtime Library Exception along with this program; 23 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 24 <http://www.gnu.org/licenses/>. */ 25 26 #include "libgfortran.h" 27 #include <assert.h> 28 29 #if defined (HAVE_'atype_name`) 30 'header1` 31 { 32 index_type count[GFC_MAX_DIMENSIONS]; 33 index_type extent[GFC_MAX_DIMENSIONS]; 34 index_type sstride[GFC_MAX_DIMENSIONS]; 35 index_type dstride[GFC_MAX_DIMENSIONS]; 36 const 'atype_name`'` * restrict base; 37 index_type * restrict dest; 38 index_type rank; 39 index_type n; 40 index_type len; 41 index_type delta; 42 index_type dim; 43 int continue_loop; 44 45 /* Make dim zero based to avoid confusion. */ 46 rank = GFC_DESCRIPTOR_RANK (array) - 1; 47 dim = (*pdim) - 1; 48 49 if (unlikely (dim < 0 || dim > rank)) 50 { 51 runtime_error ("Dim argument incorrect in FINDLOC intrinsic: " 52 "is %ld, should be between 1 and %ld", 53 (long int) dim + 1, (long int) rank + 1); 54 } 55 56 len = GFC_DESCRIPTOR_EXTENT(array,dim); 57 if (len < 0) 58 len = 0; 59 delta = GFC_DESCRIPTOR_STRIDE(array,dim); 60 61 for (n = 0; n < dim; n++) 62 { 63 sstride[n] = GFC_DESCRIPTOR_STRIDE(array,n); 64 extent[n] = GFC_DESCRIPTOR_EXTENT(array,n); 65 66 if (extent[n] < 0) 67 extent[n] = 0; 68 } 69 for (n = dim; n < rank; n++) 70 { 71 sstride[n] = GFC_DESCRIPTOR_STRIDE(array, n + 1); 72 extent[n] = GFC_DESCRIPTOR_EXTENT(array, n + 1); 73 74 if (extent[n] < 0) 75 extent[n] = 0; 76 } 77 78 if (retarray->base_addr == NULL) 79 { 80 size_t alloc_size, str; 81 82 for (n = 0; n < rank; n++) 83 { 84 if (n == 0) 85 str = 1; 86 else 87 str = GFC_DESCRIPTOR_STRIDE(retarray,n-1) * extent[n-1]; 88 89 GFC_DIMENSION_SET(retarray->dim[n], 0, extent[n] - 1, str); 90 91 } 92 93 retarray->offset = 0; 94 retarray->dtype.rank = rank; 95 96 alloc_size = GFC_DESCRIPTOR_STRIDE(retarray,rank-1) * extent[rank-1]; 97 98 retarray->base_addr = xmallocarray (alloc_size, sizeof (index_type)); 99 if (alloc_size == 0) 100 return; 101 } 102 else 103 { 104 if (rank != GFC_DESCRIPTOR_RANK (retarray)) 105 runtime_error ("rank of return array incorrect in" 106 " FINDLOC intrinsic: is %ld, should be %ld", 107 (long int) (GFC_DESCRIPTOR_RANK (retarray)), 108 (long int) rank); 109 110 if (unlikely (compile_options.bounds_check)) 111 bounds_ifunction_return ((array_t *) retarray, extent, 112 "return value", "FINDLOC"); 113 } 114 115 for (n = 0; n < rank; n++) 116 { 117 count[n] = 0; 118 dstride[n] = GFC_DESCRIPTOR_STRIDE(retarray,n); 119 if (extent[n] <= 0) 120 return; 121 } 122 123 dest = retarray->base_addr; 124 continue_loop = 1; 125 126 base = array->base_addr; 127 while (continue_loop) 128 { 129 const 'atype_name`'` * restrict src; 130 index_type result; 131 132 result = 0; 133 if (back) 134 { 135 src = base + (len - 1) * delta * 'base_mult`; 136 for (n = len; n > 0; n--, src -= delta * 'base_mult`) 137 { 138 if ('comparison`'`) 139 { 140 result = n; 141 break; 142 } 143 } 144 } 145 else 146 { 147 src = base; 148 for (n = 1; n <= len; n++, src += delta * 'base_mult`) 149 { 150 if ('comparison`'`) 151 { 152 result = n; 153 break; 154 } 155 } 156 } 157 *dest = result; 158 159 count[0]++; 160 base += sstride[0] * 'base_mult`; 161 dest += dstride[0]; 162 n = 0; 163 while (count[n] == extent[n]) 164 { 165 count[n] = 0; 166 base -= sstride[n] * extent[n] * 'base_mult`; 167 dest -= dstride[n] * extent[n]; 168 n++; 169 if (n >= rank) 170 { 171 continue_loop = 0; 172 break; 173 } 174 else 175 { 176 count[n]++; 177 base += sstride[n] * 'base_mult`; 178 dest += dstride[n]; 179 } 180 } 181 } 182 } 183 'header2`'` 184 { 185 index_type count[GFC_MAX_DIMENSIONS]; 186 index_type extent[GFC_MAX_DIMENSIONS]; 187 index_type sstride[GFC_MAX_DIMENSIONS]; 188 index_type mstride[GFC_MAX_DIMENSIONS]; 189 index_type dstride[GFC_MAX_DIMENSIONS]; 190 const 'atype_name`'` * restrict base; 191 const GFC_LOGICAL_1 * restrict mbase; 192 index_type * restrict dest; 193 index_type rank; 194 index_type n; 195 index_type len; 196 index_type delta; 197 index_type mdelta; 198 index_type dim; 199 int mask_kind; 200 int continue_loop; 201 202 /* Make dim zero based to avoid confusion. */ 203 rank = GFC_DESCRIPTOR_RANK (array) - 1; 204 dim = (*pdim) - 1; 205 206 if (unlikely (dim < 0 || dim > rank)) 207 { 208 runtime_error ("Dim argument incorrect in FINDLOC intrinsic: " 209 "is %ld, should be between 1 and %ld", 210 (long int) dim + 1, (long int) rank + 1); 211 } 212 213 len = GFC_DESCRIPTOR_EXTENT(array,dim); 214 if (len < 0) 215 len = 0; 216 217 delta = GFC_DESCRIPTOR_STRIDE(array,dim); 218 mdelta = GFC_DESCRIPTOR_STRIDE_BYTES(mask,dim); 219 220 mbase = mask->base_addr; 221 222 mask_kind = GFC_DESCRIPTOR_SIZE (mask); 223 224 if (mask_kind == 1 || mask_kind == 2 || mask_kind == 4 || mask_kind == 8 225 #ifdef HAVE_GFC_LOGICAL_16 226 || mask_kind == 16 227 #endif 228 ) 229 mbase = GFOR_POINTER_TO_L1 (mbase, mask_kind); 230 else 231 internal_error (NULL, "Funny sized logical array"); 232 233 for (n = 0; n < dim; n++) 234 { 235 sstride[n] = GFC_DESCRIPTOR_STRIDE(array,n); 236 mstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(mask,n); 237 extent[n] = GFC_DESCRIPTOR_EXTENT(array,n); 238 239 if (extent[n] < 0) 240 extent[n] = 0; 241 } 242 for (n = dim; n < rank; n++) 243 { 244 sstride[n] = GFC_DESCRIPTOR_STRIDE(array, n + 1); 245 mstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(mask, n + 1); 246 extent[n] = GFC_DESCRIPTOR_EXTENT(array, n + 1); 247 248 if (extent[n] < 0) 249 extent[n] = 0; 250 } 251 252 if (retarray->base_addr == NULL) 253 { 254 size_t alloc_size, str; 255 256 for (n = 0; n < rank; n++) 257 { 258 if (n == 0) 259 str = 1; 260 else 261 str = GFC_DESCRIPTOR_STRIDE(retarray,n-1) * extent[n-1]; 262 263 GFC_DIMENSION_SET(retarray->dim[n], 0, extent[n] - 1, str); 264 265 } 266 267 retarray->offset = 0; 268 retarray->dtype.rank = rank; 269 270 alloc_size = GFC_DESCRIPTOR_STRIDE(retarray,rank-1) * extent[rank-1]; 271 272 retarray->base_addr = xmallocarray (alloc_size, sizeof (index_type)); 273 if (alloc_size == 0) 274 return; 275 } 276 else 277 { 278 if (rank != GFC_DESCRIPTOR_RANK (retarray)) 279 runtime_error ("rank of return array incorrect in" 280 " FINDLOC intrinsic: is %ld, should be %ld", 281 (long int) (GFC_DESCRIPTOR_RANK (retarray)), 282 (long int) rank); 283 284 if (unlikely (compile_options.bounds_check)) 285 bounds_ifunction_return ((array_t *) retarray, extent, 286 "return value", "FINDLOC"); 287 } 288 289 for (n = 0; n < rank; n++) 290 { 291 count[n] = 0; 292 dstride[n] = GFC_DESCRIPTOR_STRIDE(retarray,n); 293 if (extent[n] <= 0) 294 return; 295 } 296 297 dest = retarray->base_addr; 298 continue_loop = 1; 299 300 base = array->base_addr; 301 while (continue_loop) 302 { 303 const 'atype_name`'` * restrict src; 304 const GFC_LOGICAL_1 * restrict msrc; 305 index_type result; 306 307 result = 0; 308 if (back) 309 { 310 src = base + (len - 1) * delta * 'base_mult`; 311 msrc = mbase + (len - 1) * mdelta; 312 for (n = len; n > 0; n--, src -= delta * 'base_mult`, msrc -= mdelta) 313 { 314 if (*msrc && 'comparison`'`) 315 { 316 result = n; 317 break; 318 } 319 } 320 } 321 else 322 { 323 src = base; 324 msrc = mbase; 325 for (n = 1; n <= len; n++, src += delta * 'base_mult`, msrc += mdelta) 326 { 327 if (*msrc && 'comparison`'`) 328 { 329 result = n; 330 break; 331 } 332 } 333 } 334 *dest = result; 335 336 count[0]++; 337 base += sstride[0] * 'base_mult`; 338 mbase += mstride[0]; 339 dest += dstride[0]; 340 n = 0; 341 while (count[n] == extent[n]) 342 { 343 count[n] = 0; 344 base -= sstride[n] * extent[n] * 'base_mult`; 345 mbase -= mstride[n] * extent[n]; 346 dest -= dstride[n] * extent[n]; 347 n++; 348 if (n >= rank) 349 { 350 continue_loop = 0; 351 break; 352 } 353 else 354 { 355 count[n]++; 356 base += sstride[n] * 'base_mult`; 357 dest += dstride[n]; 358 } 359 } 360 } 361 } 362 'header3`'` 363 { 364 index_type count[GFC_MAX_DIMENSIONS]; 365 index_type extent[GFC_MAX_DIMENSIONS]; 366 index_type dstride[GFC_MAX_DIMENSIONS]; 367 index_type * restrict dest; 368 index_type rank; 369 index_type n; 370 index_type len; 371 index_type dim; 372 bool continue_loop; 373 374 if (mask == NULL || *mask) 375 { 376 findloc1_'atype_code`'` (retarray, array, value, pdim, back'len_arg`'`); 377 return; 378 } 379 /* Make dim zero based to avoid confusion. */ 380 rank = GFC_DESCRIPTOR_RANK (array) - 1; 381 dim = (*pdim) - 1; 382 383 if (unlikely (dim < 0 || dim > rank)) 384 { 385 runtime_error ("Dim argument incorrect in FINDLOC intrinsic: " 386 "is %ld, should be between 1 and %ld", 387 (long int) dim + 1, (long int) rank + 1); 388 } 389 390 len = GFC_DESCRIPTOR_EXTENT(array,dim); 391 if (len < 0) 392 len = 0; 393 394 for (n = 0; n < dim; n++) 395 { 396 extent[n] = GFC_DESCRIPTOR_EXTENT(array,n); 397 398 if (extent[n] <= 0) 399 extent[n] = 0; 400 } 401 402 for (n = dim; n < rank; n++) 403 { 404 extent[n] = 405 GFC_DESCRIPTOR_EXTENT(array,n + 1); 406 407 if (extent[n] <= 0) 408 extent[n] = 0; 409 } 410 411 412 if (retarray->base_addr == NULL) 413 { 414 size_t alloc_size, str; 415 416 for (n = 0; n < rank; n++) 417 { 418 if (n == 0) 419 str = 1; 420 else 421 str = GFC_DESCRIPTOR_STRIDE(retarray,n-1) * extent[n-1]; 422 423 GFC_DIMENSION_SET(retarray->dim[n], 0, extent[n] - 1, str); 424 } 425 426 retarray->offset = 0; 427 retarray->dtype.rank = rank; 428 429 alloc_size = GFC_DESCRIPTOR_STRIDE(retarray,rank-1) * extent[rank-1]; 430 431 retarray->base_addr = xmallocarray (alloc_size, sizeof (index_type)); 432 if (alloc_size == 0) 433 return; 434 } 435 else 436 { 437 if (rank != GFC_DESCRIPTOR_RANK (retarray)) 438 runtime_error ("rank of return array incorrect in" 439 " FINDLOC intrinsic: is %ld, should be %ld", 440 (long int) (GFC_DESCRIPTOR_RANK (retarray)), 441 (long int) rank); 442 443 if (unlikely (compile_options.bounds_check)) 444 bounds_ifunction_return ((array_t *) retarray, extent, 445 "return value", "FINDLOC"); 446 } 447 448 for (n = 0; n < rank; n++) 449 { 450 count[n] = 0; 451 dstride[n] = GFC_DESCRIPTOR_STRIDE(retarray,n); 452 if (extent[n] <= 0) 453 return; 454 } 455 dest = retarray->base_addr; 456 continue_loop = 1; 457 458 while (continue_loop) 459 { 460 *dest = 0; 461 462 count[0]++; 463 dest += dstride[0]; 464 n = 0; 465 while (count[n] == extent[n]) 466 { 467 count[n] = 0; 468 dest -= dstride[n] * extent[n]; 469 n++; 470 if (n >= rank) 471 { 472 continue_loop = 0; 473 break; 474 } 475 else 476 { 477 count[n]++; 478 dest += dstride[n]; 479 } 480 } 481 } 482 } 483 #endif' 484