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