1 1.1 mrg /* Implementation of the MINLOC intrinsic 2 1.1 mrg Copyright (C) 2002-2022 Free Software Foundation, Inc. 3 1.1 mrg Contributed by Paul Brook <paul (at) nowt.org> 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 30 1.1 mrg #if defined (HAVE_GFC_REAL_17) && defined (HAVE_GFC_INTEGER_4) 31 1.1 mrg 32 1.1 mrg 33 1.1 mrg extern void minloc0_4_r17 (gfc_array_i4 * const restrict retarray, 34 1.1 mrg gfc_array_r17 * const restrict array, GFC_LOGICAL_4); 35 1.1 mrg export_proto(minloc0_4_r17); 36 1.1 mrg 37 1.1 mrg void 38 1.1 mrg minloc0_4_r17 (gfc_array_i4 * const restrict retarray, 39 1.1 mrg gfc_array_r17 * const restrict array, GFC_LOGICAL_4 back) 40 1.1 mrg { 41 1.1 mrg index_type count[GFC_MAX_DIMENSIONS]; 42 1.1 mrg index_type extent[GFC_MAX_DIMENSIONS]; 43 1.1 mrg index_type sstride[GFC_MAX_DIMENSIONS]; 44 1.1 mrg index_type dstride; 45 1.1 mrg const GFC_REAL_17 *base; 46 1.1 mrg GFC_INTEGER_4 * restrict dest; 47 1.1 mrg index_type rank; 48 1.1 mrg index_type n; 49 1.1 mrg 50 1.1 mrg rank = GFC_DESCRIPTOR_RANK (array); 51 1.1 mrg if (rank <= 0) 52 1.1 mrg runtime_error ("Rank of array needs to be > 0"); 53 1.1 mrg 54 1.1 mrg if (retarray->base_addr == NULL) 55 1.1 mrg { 56 1.1 mrg GFC_DIMENSION_SET(retarray->dim[0], 0, rank-1, 1); 57 1.1 mrg retarray->dtype.rank = 1; 58 1.1 mrg retarray->offset = 0; 59 1.1 mrg retarray->base_addr = xmallocarray (rank, sizeof (GFC_INTEGER_4)); 60 1.1 mrg } 61 1.1 mrg else 62 1.1 mrg { 63 1.1 mrg if (unlikely (compile_options.bounds_check)) 64 1.1 mrg bounds_iforeach_return ((array_t *) retarray, (array_t *) array, 65 1.1 mrg "MINLOC"); 66 1.1 mrg } 67 1.1 mrg 68 1.1 mrg dstride = GFC_DESCRIPTOR_STRIDE(retarray,0); 69 1.1 mrg dest = retarray->base_addr; 70 1.1 mrg for (n = 0; n < rank; n++) 71 1.1 mrg { 72 1.1 mrg sstride[n] = GFC_DESCRIPTOR_STRIDE(array,n); 73 1.1 mrg extent[n] = GFC_DESCRIPTOR_EXTENT(array,n); 74 1.1 mrg count[n] = 0; 75 1.1 mrg if (extent[n] <= 0) 76 1.1 mrg { 77 1.1 mrg /* Set the return value. */ 78 1.1 mrg for (n = 0; n < rank; n++) 79 1.1 mrg dest[n * dstride] = 0; 80 1.1 mrg return; 81 1.1 mrg } 82 1.1 mrg } 83 1.1 mrg 84 1.1 mrg base = array->base_addr; 85 1.1 mrg 86 1.1 mrg /* Initialize the return value. */ 87 1.1 mrg for (n = 0; n < rank; n++) 88 1.1 mrg dest[n * dstride] = 1; 89 1.1 mrg { 90 1.1 mrg 91 1.1 mrg GFC_REAL_17 minval; 92 1.1 mrg #if defined(GFC_REAL_17_QUIET_NAN) 93 1.1 mrg int fast = 0; 94 1.1 mrg #endif 95 1.1 mrg 96 1.1 mrg #if defined(GFC_REAL_17_INFINITY) 97 1.1 mrg minval = GFC_REAL_17_INFINITY; 98 1.1 mrg #else 99 1.1 mrg minval = GFC_REAL_17_HUGE; 100 1.1 mrg #endif 101 1.1 mrg while (base) 102 1.1 mrg { 103 1.1 mrg /* Implementation start. */ 104 1.1 mrg 105 1.1 mrg #if defined(GFC_REAL_17_QUIET_NAN) 106 1.1 mrg if (unlikely (!fast)) 107 1.1 mrg { 108 1.1 mrg do 109 1.1 mrg { 110 1.1 mrg if (*base <= minval) 111 1.1 mrg { 112 1.1 mrg fast = 1; 113 1.1 mrg minval = *base; 114 1.1 mrg for (n = 0; n < rank; n++) 115 1.1 mrg dest[n * dstride] = count[n] + 1; 116 1.1 mrg break; 117 1.1 mrg } 118 1.1 mrg base += sstride[0]; 119 1.1 mrg } 120 1.1 mrg while (++count[0] != extent[0]); 121 1.1 mrg if (likely (fast)) 122 1.1 mrg continue; 123 1.1 mrg } 124 1.1 mrg else 125 1.1 mrg #endif 126 1.1 mrg if (back) 127 1.1 mrg do 128 1.1 mrg { 129 1.1 mrg if (unlikely (*base <= minval)) 130 1.1 mrg { 131 1.1 mrg minval = *base; 132 1.1 mrg for (n = 0; n < rank; n++) 133 1.1 mrg dest[n * dstride] = count[n] + 1; 134 1.1 mrg } 135 1.1 mrg base += sstride[0]; 136 1.1 mrg } 137 1.1 mrg while (++count[0] != extent[0]); 138 1.1 mrg else 139 1.1 mrg do 140 1.1 mrg { 141 1.1 mrg if (unlikely (*base < minval)) 142 1.1 mrg { 143 1.1 mrg minval = *base; 144 1.1 mrg for (n = 0; n < rank; n++) 145 1.1 mrg dest[n * dstride] = count[n] + 1; 146 1.1 mrg } 147 1.1 mrg /* Implementation end. */ 148 1.1 mrg /* Advance to the next element. */ 149 1.1 mrg base += sstride[0]; 150 1.1 mrg } 151 1.1 mrg while (++count[0] != extent[0]); 152 1.1 mrg n = 0; 153 1.1 mrg do 154 1.1 mrg { 155 1.1 mrg /* When we get to the end of a dimension, reset it and increment 156 1.1 mrg the next dimension. */ 157 1.1 mrg count[n] = 0; 158 1.1 mrg /* We could precalculate these products, but this is a less 159 1.1 mrg frequently used path so probably not worth it. */ 160 1.1 mrg base -= sstride[n] * extent[n]; 161 1.1 mrg n++; 162 1.1 mrg if (n >= rank) 163 1.1 mrg { 164 1.1 mrg /* Break out of the loop. */ 165 1.1 mrg base = NULL; 166 1.1 mrg break; 167 1.1 mrg } 168 1.1 mrg else 169 1.1 mrg { 170 1.1 mrg count[n]++; 171 1.1 mrg base += sstride[n]; 172 1.1 mrg } 173 1.1 mrg } 174 1.1 mrg while (count[n] == extent[n]); 175 1.1 mrg } 176 1.1 mrg } 177 1.1 mrg } 178 1.1 mrg 179 1.1 mrg extern void mminloc0_4_r17 (gfc_array_i4 * const restrict, 180 1.1 mrg gfc_array_r17 * const restrict, gfc_array_l1 * const restrict, 181 1.1 mrg GFC_LOGICAL_4); 182 1.1 mrg export_proto(mminloc0_4_r17); 183 1.1 mrg 184 1.1 mrg void 185 1.1 mrg mminloc0_4_r17 (gfc_array_i4 * const restrict retarray, 186 1.1 mrg gfc_array_r17 * const restrict array, 187 1.1 mrg gfc_array_l1 * const restrict mask, GFC_LOGICAL_4 back) 188 1.1 mrg { 189 1.1 mrg index_type count[GFC_MAX_DIMENSIONS]; 190 1.1 mrg index_type extent[GFC_MAX_DIMENSIONS]; 191 1.1 mrg index_type sstride[GFC_MAX_DIMENSIONS]; 192 1.1 mrg index_type mstride[GFC_MAX_DIMENSIONS]; 193 1.1 mrg index_type dstride; 194 1.1 mrg GFC_INTEGER_4 *dest; 195 1.1 mrg const GFC_REAL_17 *base; 196 1.1 mrg GFC_LOGICAL_1 *mbase; 197 1.1 mrg int rank; 198 1.1 mrg index_type n; 199 1.1 mrg int mask_kind; 200 1.1 mrg 201 1.1 mrg 202 1.1 mrg if (mask == NULL) 203 1.1 mrg { 204 1.1 mrg minloc0_4_r17 (retarray, array, back); 205 1.1 mrg return; 206 1.1 mrg } 207 1.1 mrg 208 1.1 mrg rank = GFC_DESCRIPTOR_RANK (array); 209 1.1 mrg if (rank <= 0) 210 1.1 mrg runtime_error ("Rank of array needs to be > 0"); 211 1.1 mrg 212 1.1 mrg if (retarray->base_addr == NULL) 213 1.1 mrg { 214 1.1 mrg GFC_DIMENSION_SET(retarray->dim[0], 0, rank - 1, 1); 215 1.1 mrg retarray->dtype.rank = 1; 216 1.1 mrg retarray->offset = 0; 217 1.1 mrg retarray->base_addr = xmallocarray (rank, sizeof (GFC_INTEGER_4)); 218 1.1 mrg } 219 1.1 mrg else 220 1.1 mrg { 221 1.1 mrg if (unlikely (compile_options.bounds_check)) 222 1.1 mrg { 223 1.1 mrg 224 1.1 mrg bounds_iforeach_return ((array_t *) retarray, (array_t *) array, 225 1.1 mrg "MINLOC"); 226 1.1 mrg bounds_equal_extents ((array_t *) mask, (array_t *) array, 227 1.1 mrg "MASK argument", "MINLOC"); 228 1.1 mrg } 229 1.1 mrg } 230 1.1 mrg 231 1.1 mrg mask_kind = GFC_DESCRIPTOR_SIZE (mask); 232 1.1 mrg 233 1.1 mrg mbase = mask->base_addr; 234 1.1 mrg 235 1.1 mrg if (mask_kind == 1 || mask_kind == 2 || mask_kind == 4 || mask_kind == 8 236 1.1 mrg #ifdef HAVE_GFC_LOGICAL_16 237 1.1 mrg || mask_kind == 16 238 1.1 mrg #endif 239 1.1 mrg ) 240 1.1 mrg mbase = GFOR_POINTER_TO_L1 (mbase, mask_kind); 241 1.1 mrg else 242 1.1 mrg runtime_error ("Funny sized logical array"); 243 1.1 mrg 244 1.1 mrg dstride = GFC_DESCRIPTOR_STRIDE(retarray,0); 245 1.1 mrg dest = retarray->base_addr; 246 1.1 mrg for (n = 0; n < rank; n++) 247 1.1 mrg { 248 1.1 mrg sstride[n] = GFC_DESCRIPTOR_STRIDE(array,n); 249 1.1 mrg mstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(mask,n); 250 1.1 mrg extent[n] = GFC_DESCRIPTOR_EXTENT(array,n); 251 1.1 mrg count[n] = 0; 252 1.1 mrg if (extent[n] <= 0) 253 1.1 mrg { 254 1.1 mrg /* Set the return value. */ 255 1.1 mrg for (n = 0; n < rank; n++) 256 1.1 mrg dest[n * dstride] = 0; 257 1.1 mrg return; 258 1.1 mrg } 259 1.1 mrg } 260 1.1 mrg 261 1.1 mrg base = array->base_addr; 262 1.1 mrg 263 1.1 mrg /* Initialize the return value. */ 264 1.1 mrg for (n = 0; n < rank; n++) 265 1.1 mrg dest[n * dstride] = 0; 266 1.1 mrg { 267 1.1 mrg 268 1.1 mrg GFC_REAL_17 minval; 269 1.1 mrg int fast = 0; 270 1.1 mrg 271 1.1 mrg #if defined(GFC_REAL_17_INFINITY) 272 1.1 mrg minval = GFC_REAL_17_INFINITY; 273 1.1 mrg #else 274 1.1 mrg minval = GFC_REAL_17_HUGE; 275 1.1 mrg #endif 276 1.1 mrg while (base) 277 1.1 mrg { 278 1.1 mrg /* Implementation start. */ 279 1.1 mrg 280 1.1 mrg if (unlikely (!fast)) 281 1.1 mrg { 282 1.1 mrg do 283 1.1 mrg { 284 1.1 mrg if (*mbase) 285 1.1 mrg { 286 1.1 mrg #if defined(GFC_REAL_17_QUIET_NAN) 287 1.1 mrg if (unlikely (dest[0] == 0)) 288 1.1 mrg for (n = 0; n < rank; n++) 289 1.1 mrg dest[n * dstride] = count[n] + 1; 290 1.1 mrg if (*base <= minval) 291 1.1 mrg #endif 292 1.1 mrg { 293 1.1 mrg fast = 1; 294 1.1 mrg minval = *base; 295 1.1 mrg for (n = 0; n < rank; n++) 296 1.1 mrg dest[n * dstride] = count[n] + 1; 297 1.1 mrg break; 298 1.1 mrg } 299 1.1 mrg } 300 1.1 mrg base += sstride[0]; 301 1.1 mrg mbase += mstride[0]; 302 1.1 mrg } 303 1.1 mrg while (++count[0] != extent[0]); 304 1.1 mrg if (likely (fast)) 305 1.1 mrg continue; 306 1.1 mrg } 307 1.1 mrg else 308 1.1 mrg if (back) 309 1.1 mrg do 310 1.1 mrg { 311 1.1 mrg if (unlikely (*mbase && (*base <= minval))) 312 1.1 mrg { 313 1.1 mrg minval = *base; 314 1.1 mrg for (n = 0; n < rank; n++) 315 1.1 mrg dest[n * dstride] = count[n] + 1; 316 1.1 mrg } 317 1.1 mrg base += sstride[0]; 318 1.1 mrg } 319 1.1 mrg while (++count[0] != extent[0]); 320 1.1 mrg else 321 1.1 mrg do 322 1.1 mrg { 323 1.1 mrg if (unlikely (*mbase && (*base < minval))) 324 1.1 mrg { 325 1.1 mrg minval = *base; 326 1.1 mrg for (n = 0; n < rank; n++) 327 1.1 mrg dest[n * dstride] = count[n] + 1; 328 1.1 mrg } 329 1.1 mrg /* Implementation end. */ 330 1.1 mrg /* Advance to the next element. */ 331 1.1 mrg base += sstride[0]; 332 1.1 mrg mbase += mstride[0]; 333 1.1 mrg } 334 1.1 mrg while (++count[0] != extent[0]); 335 1.1 mrg n = 0; 336 1.1 mrg do 337 1.1 mrg { 338 1.1 mrg /* When we get to the end of a dimension, reset it and increment 339 1.1 mrg the next dimension. */ 340 1.1 mrg count[n] = 0; 341 1.1 mrg /* We could precalculate these products, but this is a less 342 1.1 mrg frequently used path so probably not worth it. */ 343 1.1 mrg base -= sstride[n] * extent[n]; 344 1.1 mrg mbase -= mstride[n] * extent[n]; 345 1.1 mrg n++; 346 1.1 mrg if (n >= rank) 347 1.1 mrg { 348 1.1 mrg /* Break out of the loop. */ 349 1.1 mrg base = NULL; 350 1.1 mrg break; 351 1.1 mrg } 352 1.1 mrg else 353 1.1 mrg { 354 1.1 mrg count[n]++; 355 1.1 mrg base += sstride[n]; 356 1.1 mrg mbase += mstride[n]; 357 1.1 mrg } 358 1.1 mrg } 359 1.1 mrg while (count[n] == extent[n]); 360 1.1 mrg } 361 1.1 mrg } 362 1.1 mrg } 363 1.1 mrg 364 1.1 mrg extern void sminloc0_4_r17 (gfc_array_i4 * const restrict, 365 1.1 mrg gfc_array_r17 * const restrict, GFC_LOGICAL_4 *, GFC_LOGICAL_4); 366 1.1 mrg export_proto(sminloc0_4_r17); 367 1.1 mrg 368 1.1 mrg void 369 1.1 mrg sminloc0_4_r17 (gfc_array_i4 * const restrict retarray, 370 1.1 mrg gfc_array_r17 * const restrict array, 371 1.1 mrg GFC_LOGICAL_4 * mask, GFC_LOGICAL_4 back) 372 1.1 mrg { 373 1.1 mrg index_type rank; 374 1.1 mrg index_type dstride; 375 1.1 mrg index_type n; 376 1.1 mrg GFC_INTEGER_4 *dest; 377 1.1 mrg 378 1.1 mrg if (mask == NULL || *mask) 379 1.1 mrg { 380 1.1 mrg minloc0_4_r17 (retarray, array, back); 381 1.1 mrg return; 382 1.1 mrg } 383 1.1 mrg 384 1.1 mrg rank = GFC_DESCRIPTOR_RANK (array); 385 1.1 mrg 386 1.1 mrg if (rank <= 0) 387 1.1 mrg runtime_error ("Rank of array needs to be > 0"); 388 1.1 mrg 389 1.1 mrg if (retarray->base_addr == NULL) 390 1.1 mrg { 391 1.1 mrg GFC_DIMENSION_SET(retarray->dim[0], 0, rank-1, 1); 392 1.1 mrg retarray->dtype.rank = 1; 393 1.1 mrg retarray->offset = 0; 394 1.1 mrg retarray->base_addr = xmallocarray (rank, sizeof (GFC_INTEGER_4)); 395 1.1 mrg } 396 1.1 mrg else if (unlikely (compile_options.bounds_check)) 397 1.1 mrg { 398 1.1 mrg bounds_iforeach_return ((array_t *) retarray, (array_t *) array, 399 1.1 mrg "MINLOC"); 400 1.1 mrg } 401 1.1 mrg 402 1.1 mrg dstride = GFC_DESCRIPTOR_STRIDE(retarray,0); 403 1.1 mrg dest = retarray->base_addr; 404 1.1 mrg for (n = 0; n<rank; n++) 405 1.1 mrg dest[n * dstride] = 0 ; 406 1.1 mrg } 407 1.1 mrg #endif 408