1 1.1 mrg `/* Implementation of the FINDLOC intrinsic 2 1.1.1.4 mrg Copyright (C) 2018-2024 Free Software Foundation, Inc. 3 1.1 mrg Contributed by Thomas Knig <tk (a] tkoenig.net> 4 1.1 mrg 5 1.1 mrg This file is part of the GNU Fortran 95 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 <assert.h> 28 1.1 mrg 29 1.1 mrg #if defined (HAVE_'atype_name`) 30 1.1 mrg 'header1` 31 1.1 mrg { 32 1.1 mrg index_type count[GFC_MAX_DIMENSIONS]; 33 1.1 mrg index_type extent[GFC_MAX_DIMENSIONS]; 34 1.1 mrg index_type sstride[GFC_MAX_DIMENSIONS]; 35 1.1 mrg index_type dstride; 36 1.1 mrg const 'atype_name` *base; 37 1.1 mrg index_type * restrict dest; 38 1.1 mrg index_type rank; 39 1.1 mrg index_type n; 40 1.1 mrg index_type sz; 41 1.1 mrg 42 1.1 mrg rank = GFC_DESCRIPTOR_RANK (array); 43 1.1 mrg if (rank <= 0) 44 1.1 mrg runtime_error ("Rank of array needs to be > 0"); 45 1.1 mrg 46 1.1 mrg if (retarray->base_addr == NULL) 47 1.1 mrg { 48 1.1 mrg GFC_DIMENSION_SET(retarray->dim[0], 0, rank-1, 1); 49 1.1 mrg retarray->dtype.rank = 1; 50 1.1 mrg retarray->offset = 0; 51 1.1 mrg retarray->base_addr = xmallocarray (rank, sizeof (index_type)); 52 1.1 mrg } 53 1.1 mrg else 54 1.1 mrg { 55 1.1 mrg if (unlikely (compile_options.bounds_check)) 56 1.1 mrg bounds_iforeach_return ((array_t *) retarray, (array_t *) array, 57 1.1 mrg "FINDLOC"); 58 1.1 mrg } 59 1.1 mrg 60 1.1 mrg dstride = GFC_DESCRIPTOR_STRIDE(retarray,0); 61 1.1 mrg dest = retarray->base_addr; 62 1.1 mrg 63 1.1 mrg /* Set the return value. */ 64 1.1 mrg for (n = 0; n < rank; n++) 65 1.1 mrg dest[n * dstride] = 0; 66 1.1 mrg 67 1.1 mrg sz = 1; 68 1.1 mrg for (n = 0; n < rank; n++) 69 1.1 mrg { 70 1.1 mrg sstride[n] = GFC_DESCRIPTOR_STRIDE(array,n); 71 1.1 mrg extent[n] = GFC_DESCRIPTOR_EXTENT(array,n); 72 1.1 mrg sz *= extent[n]; 73 1.1 mrg if (extent[n] <= 0) 74 1.1 mrg return; 75 1.1 mrg } 76 1.1 mrg 77 1.1 mrg for (n = 0; n < rank; n++) 78 1.1 mrg count[n] = 0; 79 1.1 mrg 80 1.1 mrg if (back) 81 1.1 mrg { 82 1.1 mrg base = array->base_addr + (sz - 1) * 'base_mult`'`; 83 1.1 mrg 84 1.1 mrg while (1) 85 1.1 mrg { 86 1.1 mrg do 87 1.1 mrg { 88 1.1 mrg if (unlikely('comparison`)) 89 1.1 mrg { 90 1.1 mrg for (n = 0; n < rank; n++) 91 1.1 mrg dest[n * dstride] = extent[n] - count[n]; 92 1.1 mrg 93 1.1 mrg return; 94 1.1 mrg } 95 1.1 mrg base -= sstride[0] * 'base_mult`'`; 96 1.1 mrg } while(++count[0] != extent[0]); 97 1.1 mrg 98 1.1 mrg n = 0; 99 1.1 mrg do 100 1.1 mrg { 101 1.1 mrg /* When we get to the end of a dimension, reset it and increment 102 1.1 mrg the next dimension. */ 103 1.1 mrg count[n] = 0; 104 1.1 mrg /* We could precalculate these products, but this is a less 105 1.1 mrg frequently used path so probably not worth it. */ 106 1.1 mrg base += sstride[n] * extent[n] * 'base_mult`'`; 107 1.1 mrg n++; 108 1.1 mrg if (n >= rank) 109 1.1 mrg return; 110 1.1 mrg else 111 1.1 mrg { 112 1.1 mrg count[n]++; 113 1.1 mrg base -= sstride[n] * 'base_mult`'`; 114 1.1 mrg } 115 1.1 mrg } while (count[n] == extent[n]); 116 1.1 mrg } 117 1.1 mrg } 118 1.1 mrg else 119 1.1 mrg { 120 1.1 mrg base = array->base_addr; 121 1.1 mrg while (1) 122 1.1 mrg { 123 1.1 mrg do 124 1.1 mrg { 125 1.1 mrg if (unlikely('comparison`)) 126 1.1 mrg { 127 1.1 mrg for (n = 0; n < rank; n++) 128 1.1 mrg dest[n * dstride] = count[n] + 1; 129 1.1 mrg 130 1.1 mrg return; 131 1.1 mrg } 132 1.1 mrg base += sstride[0] * 'base_mult`'`; 133 1.1 mrg } while(++count[0] != extent[0]); 134 1.1 mrg 135 1.1 mrg n = 0; 136 1.1 mrg do 137 1.1 mrg { 138 1.1 mrg /* When we get to the end of a dimension, reset it and increment 139 1.1 mrg the next dimension. */ 140 1.1 mrg count[n] = 0; 141 1.1 mrg /* We could precalculate these products, but this is a less 142 1.1 mrg frequently used path so probably not worth it. */ 143 1.1 mrg base -= sstride[n] * extent[n] * 'base_mult`'`; 144 1.1 mrg n++; 145 1.1 mrg if (n >= rank) 146 1.1 mrg return; 147 1.1 mrg else 148 1.1 mrg { 149 1.1 mrg count[n]++; 150 1.1 mrg base += sstride[n] * 'base_mult`'`; 151 1.1 mrg } 152 1.1 mrg } while (count[n] == extent[n]); 153 1.1 mrg } 154 1.1 mrg } 155 1.1 mrg return; 156 1.1 mrg } 157 1.1 mrg 158 1.1 mrg 'header2` 159 1.1 mrg { 160 1.1 mrg index_type count[GFC_MAX_DIMENSIONS]; 161 1.1 mrg index_type extent[GFC_MAX_DIMENSIONS]; 162 1.1 mrg index_type sstride[GFC_MAX_DIMENSIONS]; 163 1.1 mrg index_type mstride[GFC_MAX_DIMENSIONS]; 164 1.1 mrg index_type dstride; 165 1.1 mrg const 'atype_name` *base; 166 1.1 mrg index_type * restrict dest; 167 1.1 mrg GFC_LOGICAL_1 *mbase; 168 1.1 mrg index_type rank; 169 1.1 mrg index_type n; 170 1.1 mrg int mask_kind; 171 1.1 mrg index_type sz; 172 1.1 mrg 173 1.1 mrg rank = GFC_DESCRIPTOR_RANK (array); 174 1.1 mrg if (rank <= 0) 175 1.1 mrg runtime_error ("Rank of array needs to be > 0"); 176 1.1 mrg 177 1.1 mrg if (retarray->base_addr == NULL) 178 1.1 mrg { 179 1.1 mrg GFC_DIMENSION_SET(retarray->dim[0], 0, rank-1, 1); 180 1.1 mrg retarray->dtype.rank = 1; 181 1.1 mrg retarray->offset = 0; 182 1.1 mrg retarray->base_addr = xmallocarray (rank, sizeof (index_type)); 183 1.1 mrg } 184 1.1 mrg else 185 1.1 mrg { 186 1.1 mrg if (unlikely (compile_options.bounds_check)) 187 1.1 mrg { 188 1.1 mrg bounds_iforeach_return ((array_t *) retarray, (array_t *) array, 189 1.1 mrg "FINDLOC"); 190 1.1 mrg bounds_equal_extents ((array_t *) mask, (array_t *) array, 191 1.1 mrg "MASK argument", "FINDLOC"); 192 1.1 mrg } 193 1.1 mrg } 194 1.1 mrg 195 1.1 mrg mask_kind = GFC_DESCRIPTOR_SIZE (mask); 196 1.1 mrg 197 1.1 mrg mbase = mask->base_addr; 198 1.1 mrg 199 1.1 mrg if (mask_kind == 1 || mask_kind == 2 || mask_kind == 4 || mask_kind == 8 200 1.1 mrg #ifdef HAVE_GFC_LOGICAL_16 201 1.1 mrg || mask_kind == 16 202 1.1 mrg #endif 203 1.1 mrg ) 204 1.1 mrg mbase = GFOR_POINTER_TO_L1 (mbase, mask_kind); 205 1.1 mrg else 206 1.1 mrg internal_error (NULL, "Funny sized logical array"); 207 1.1 mrg 208 1.1 mrg dstride = GFC_DESCRIPTOR_STRIDE(retarray,0); 209 1.1 mrg dest = retarray->base_addr; 210 1.1 mrg 211 1.1 mrg /* Set the return value. */ 212 1.1 mrg for (n = 0; n < rank; n++) 213 1.1 mrg dest[n * dstride] = 0; 214 1.1 mrg 215 1.1 mrg sz = 1; 216 1.1 mrg for (n = 0; n < rank; n++) 217 1.1 mrg { 218 1.1 mrg sstride[n] = GFC_DESCRIPTOR_STRIDE(array,n); 219 1.1 mrg mstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(mask,n); 220 1.1 mrg extent[n] = GFC_DESCRIPTOR_EXTENT(array,n); 221 1.1 mrg sz *= extent[n]; 222 1.1 mrg if (extent[n] <= 0) 223 1.1 mrg return; 224 1.1 mrg } 225 1.1 mrg 226 1.1 mrg for (n = 0; n < rank; n++) 227 1.1 mrg count[n] = 0; 228 1.1 mrg 229 1.1 mrg if (back) 230 1.1 mrg { 231 1.1 mrg base = array->base_addr + (sz - 1) * 'base_mult`'`; 232 1.1 mrg mbase = mbase + (sz - 1) * mask_kind; 233 1.1 mrg while (1) 234 1.1 mrg { 235 1.1 mrg do 236 1.1 mrg { 237 1.1 mrg if (unlikely(*mbase && 'comparison`)) 238 1.1 mrg { 239 1.1 mrg for (n = 0; n < rank; n++) 240 1.1 mrg dest[n * dstride] = extent[n] - count[n]; 241 1.1 mrg 242 1.1 mrg return; 243 1.1 mrg } 244 1.1 mrg base -= sstride[0] * 'base_mult`'`; 245 1.1 mrg mbase -= mstride[0]; 246 1.1 mrg } while(++count[0] != extent[0]); 247 1.1 mrg 248 1.1 mrg n = 0; 249 1.1 mrg do 250 1.1 mrg { 251 1.1 mrg /* When we get to the end of a dimension, reset it and increment 252 1.1 mrg the next dimension. */ 253 1.1 mrg count[n] = 0; 254 1.1 mrg /* We could precalculate these products, but this is a less 255 1.1 mrg frequently used path so probably not worth it. */ 256 1.1 mrg base += sstride[n] * extent[n] * 'base_mult`'`; 257 1.1 mrg mbase -= mstride[n] * extent[n]; 258 1.1 mrg n++; 259 1.1 mrg if (n >= rank) 260 1.1 mrg return; 261 1.1 mrg else 262 1.1 mrg { 263 1.1 mrg count[n]++; 264 1.1 mrg base -= sstride[n] * 'base_mult`'`; 265 1.1 mrg mbase += mstride[n]; 266 1.1 mrg } 267 1.1 mrg } while (count[n] == extent[n]); 268 1.1 mrg } 269 1.1 mrg } 270 1.1 mrg else 271 1.1 mrg { 272 1.1 mrg base = array->base_addr; 273 1.1 mrg while (1) 274 1.1 mrg { 275 1.1 mrg do 276 1.1 mrg { 277 1.1 mrg if (unlikely(*mbase && 'comparison`)) 278 1.1 mrg { 279 1.1 mrg for (n = 0; n < rank; n++) 280 1.1 mrg dest[n * dstride] = count[n] + 1; 281 1.1 mrg 282 1.1 mrg return; 283 1.1 mrg } 284 1.1 mrg base += sstride[0] * 'base_mult`'`; 285 1.1 mrg mbase += mstride[0]; 286 1.1 mrg } while(++count[0] != extent[0]); 287 1.1 mrg 288 1.1 mrg n = 0; 289 1.1 mrg do 290 1.1 mrg { 291 1.1 mrg /* When we get to the end of a dimension, reset it and increment 292 1.1 mrg the next dimension. */ 293 1.1 mrg count[n] = 0; 294 1.1 mrg /* We could precalculate these products, but this is a less 295 1.1 mrg frequently used path so probably not worth it. */ 296 1.1 mrg base -= sstride[n] * extent[n] * 'base_mult`'`; 297 1.1 mrg mbase -= mstride[n] * extent[n]; 298 1.1 mrg n++; 299 1.1 mrg if (n >= rank) 300 1.1 mrg return; 301 1.1 mrg else 302 1.1 mrg { 303 1.1 mrg count[n]++; 304 1.1 mrg base += sstride[n]* 'base_mult`'`; 305 1.1 mrg mbase += mstride[n]; 306 1.1 mrg } 307 1.1 mrg } while (count[n] == extent[n]); 308 1.1 mrg } 309 1.1 mrg } 310 1.1 mrg return; 311 1.1 mrg } 312 1.1 mrg 313 1.1 mrg 'header3` 314 1.1 mrg { 315 1.1 mrg index_type rank; 316 1.1 mrg index_type dstride; 317 1.1 mrg index_type * restrict dest; 318 1.1 mrg index_type n; 319 1.1 mrg 320 1.1 mrg if (mask == NULL || *mask) 321 1.1 mrg { 322 1.1 mrg findloc0_'atype_code` (retarray, array, value, back'len_arg`); 323 1.1 mrg return; 324 1.1 mrg } 325 1.1 mrg 326 1.1 mrg rank = GFC_DESCRIPTOR_RANK (array); 327 1.1 mrg 328 1.1 mrg if (rank <= 0) 329 1.1 mrg internal_error (NULL, "Rank of array needs to be > 0"); 330 1.1 mrg 331 1.1 mrg if (retarray->base_addr == NULL) 332 1.1 mrg { 333 1.1 mrg GFC_DIMENSION_SET(retarray->dim[0], 0, rank-1, 1); 334 1.1 mrg retarray->dtype.rank = 1; 335 1.1 mrg retarray->offset = 0; 336 1.1 mrg retarray->base_addr = xmallocarray (rank, sizeof (index_type)); 337 1.1 mrg } 338 1.1 mrg else if (unlikely (compile_options.bounds_check)) 339 1.1 mrg { 340 1.1 mrg bounds_iforeach_return ((array_t *) retarray, (array_t *) array, 341 1.1 mrg "FINDLOC"); 342 1.1 mrg } 343 1.1 mrg 344 1.1 mrg dstride = GFC_DESCRIPTOR_STRIDE(retarray,0); 345 1.1 mrg dest = retarray->base_addr; 346 1.1 mrg for (n = 0; n<rank; n++) 347 1.1 mrg dest[n * dstride] = 0 ; 348 1.1 mrg } 349 1.1 mrg 350 1.1 mrg #endif' 351