1 1.1 mrg /* Implementation of the MAXLOC intrinsic 2 1.1.1.3 mrg Copyright (C) 2017-2022 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_4) && defined (HAVE_GFC_UINTEGER_4) 34 1.1 mrg 35 1.1 mrg static inline int 36 1.1 mrg compare_fcn (const GFC_UINTEGER_4 *a, const GFC_UINTEGER_4 *b, gfc_charlen_type n) 37 1.1 mrg { 38 1.1 mrg if (sizeof (GFC_UINTEGER_4) == 1) 39 1.1 mrg return memcmp (a, b, n); 40 1.1 mrg else 41 1.1 mrg return memcmp_char4 (a, b, n); 42 1.1 mrg 43 1.1 mrg } 44 1.1 mrg 45 1.1 mrg #define INITVAL 255 46 1.1 mrg 47 1.1 mrg extern void minval0_s4 (GFC_UINTEGER_4 * restrict, 48 1.1 mrg gfc_charlen_type, 49 1.1 mrg gfc_array_s4 * const restrict array, gfc_charlen_type); 50 1.1 mrg export_proto(minval0_s4); 51 1.1 mrg 52 1.1 mrg void 53 1.1 mrg minval0_s4 (GFC_UINTEGER_4 * restrict ret, 54 1.1 mrg gfc_charlen_type xlen, 55 1.1 mrg gfc_array_s4 * const restrict array, gfc_charlen_type len) 56 1.1 mrg { 57 1.1 mrg index_type count[GFC_MAX_DIMENSIONS]; 58 1.1 mrg index_type extent[GFC_MAX_DIMENSIONS]; 59 1.1 mrg index_type sstride[GFC_MAX_DIMENSIONS]; 60 1.1 mrg const GFC_UINTEGER_4 *base; 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 assert (xlen == len); 69 1.1 mrg 70 1.1 mrg /* Initialize return value. */ 71 1.1 mrg memset (ret, INITVAL, sizeof(*ret) * len); 72 1.1 mrg 73 1.1 mrg for (n = 0; n < rank; n++) 74 1.1 mrg { 75 1.1 mrg sstride[n] = GFC_DESCRIPTOR_STRIDE(array,n) * len; 76 1.1 mrg extent[n] = GFC_DESCRIPTOR_EXTENT(array,n); 77 1.1 mrg count[n] = 0; 78 1.1 mrg if (extent[n] <= 0) 79 1.1 mrg return; 80 1.1 mrg } 81 1.1 mrg 82 1.1 mrg base = array->base_addr; 83 1.1 mrg 84 1.1 mrg { 85 1.1 mrg 86 1.1 mrg const GFC_UINTEGER_4 *retval; 87 1.1 mrg retval = ret; 88 1.1 mrg 89 1.1 mrg while (base) 90 1.1 mrg { 91 1.1 mrg do 92 1.1 mrg { 93 1.1 mrg /* Implementation start. */ 94 1.1 mrg 95 1.1 mrg if (compare_fcn (base, retval, len) < 0) 96 1.1 mrg { 97 1.1 mrg retval = base; 98 1.1 mrg } 99 1.1 mrg /* Implementation end. */ 100 1.1 mrg /* Advance to the next element. */ 101 1.1 mrg base += sstride[0]; 102 1.1 mrg } 103 1.1 mrg while (++count[0] != extent[0]); 104 1.1 mrg n = 0; 105 1.1 mrg do 106 1.1 mrg { 107 1.1 mrg /* When we get to the end of a dimension, reset it and increment 108 1.1 mrg the next dimension. */ 109 1.1 mrg count[n] = 0; 110 1.1 mrg /* We could precalculate these products, but this is a less 111 1.1 mrg frequently used path so probably not worth it. */ 112 1.1 mrg base -= sstride[n] * extent[n]; 113 1.1 mrg n++; 114 1.1 mrg if (n >= rank) 115 1.1 mrg { 116 1.1 mrg /* Break out of the loop. */ 117 1.1 mrg base = NULL; 118 1.1 mrg break; 119 1.1 mrg } 120 1.1 mrg else 121 1.1 mrg { 122 1.1 mrg count[n]++; 123 1.1 mrg base += sstride[n]; 124 1.1 mrg } 125 1.1 mrg } 126 1.1 mrg while (count[n] == extent[n]); 127 1.1 mrg } 128 1.1 mrg memcpy (ret, retval, len * sizeof (*ret)); 129 1.1 mrg } 130 1.1 mrg } 131 1.1 mrg 132 1.1 mrg 133 1.1 mrg extern void mminval0_s4 (GFC_UINTEGER_4 * restrict, 134 1.1 mrg gfc_charlen_type, gfc_array_s4 * const restrict array, 135 1.1 mrg gfc_array_l1 * const restrict mask, gfc_charlen_type len); 136 1.1 mrg export_proto(mminval0_s4); 137 1.1 mrg 138 1.1 mrg void 139 1.1 mrg mminval0_s4 (GFC_UINTEGER_4 * const restrict ret, 140 1.1 mrg gfc_charlen_type xlen, gfc_array_s4 * const restrict array, 141 1.1 mrg gfc_array_l1 * const restrict mask, gfc_charlen_type len) 142 1.1 mrg { 143 1.1 mrg index_type count[GFC_MAX_DIMENSIONS]; 144 1.1 mrg index_type extent[GFC_MAX_DIMENSIONS]; 145 1.1 mrg index_type sstride[GFC_MAX_DIMENSIONS]; 146 1.1 mrg index_type mstride[GFC_MAX_DIMENSIONS]; 147 1.1 mrg const GFC_UINTEGER_4 *base; 148 1.1 mrg GFC_LOGICAL_1 *mbase; 149 1.1 mrg int rank; 150 1.1 mrg index_type n; 151 1.1 mrg int mask_kind; 152 1.1 mrg 153 1.1 mrg if (mask == NULL) 154 1.1 mrg { 155 1.1 mrg minval0_s4 (ret, xlen, array, len); 156 1.1 mrg return; 157 1.1 mrg } 158 1.1 mrg 159 1.1 mrg rank = GFC_DESCRIPTOR_RANK (array); 160 1.1 mrg if (rank <= 0) 161 1.1 mrg runtime_error ("Rank of array needs to be > 0"); 162 1.1 mrg 163 1.1 mrg assert (xlen == len); 164 1.1 mrg 165 1.1 mrg /* Initialize return value. */ 166 1.1 mrg memset (ret, INITVAL, sizeof(*ret) * len); 167 1.1 mrg 168 1.1 mrg mask_kind = GFC_DESCRIPTOR_SIZE (mask); 169 1.1 mrg 170 1.1 mrg mbase = mask->base_addr; 171 1.1 mrg 172 1.1 mrg if (mask_kind == 1 || mask_kind == 2 || mask_kind == 4 || mask_kind == 8 173 1.1 mrg #ifdef HAVE_GFC_LOGICAL_16 174 1.1 mrg || mask_kind == 16 175 1.1 mrg #endif 176 1.1 mrg ) 177 1.1 mrg mbase = GFOR_POINTER_TO_L1 (mbase, mask_kind); 178 1.1 mrg else 179 1.1 mrg runtime_error ("Funny sized logical array"); 180 1.1 mrg 181 1.1 mrg for (n = 0; n < rank; n++) 182 1.1 mrg { 183 1.1 mrg sstride[n] = GFC_DESCRIPTOR_STRIDE(array,n) * len; 184 1.1 mrg mstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(mask,n); 185 1.1 mrg extent[n] = GFC_DESCRIPTOR_EXTENT(array,n); 186 1.1 mrg count[n] = 0; 187 1.1 mrg if (extent[n] <= 0) 188 1.1 mrg return; 189 1.1 mrg } 190 1.1 mrg 191 1.1 mrg base = array->base_addr; 192 1.1 mrg { 193 1.1 mrg 194 1.1 mrg const GFC_UINTEGER_4 *retval; 195 1.1 mrg 196 1.1 mrg retval = ret; 197 1.1 mrg 198 1.1 mrg while (base) 199 1.1 mrg { 200 1.1 mrg do 201 1.1 mrg { 202 1.1 mrg /* Implementation start. */ 203 1.1 mrg 204 1.1 mrg if (*mbase && compare_fcn (base, retval, len) < 0) 205 1.1 mrg { 206 1.1 mrg retval = base; 207 1.1 mrg } 208 1.1 mrg /* Implementation end. */ 209 1.1 mrg /* Advance to the next element. */ 210 1.1 mrg base += sstride[0]; 211 1.1 mrg mbase += mstride[0]; 212 1.1 mrg } 213 1.1 mrg while (++count[0] != extent[0]); 214 1.1 mrg n = 0; 215 1.1 mrg do 216 1.1 mrg { 217 1.1 mrg /* When we get to the end of a dimension, reset it and increment 218 1.1 mrg the next dimension. */ 219 1.1 mrg count[n] = 0; 220 1.1 mrg /* We could precalculate these products, but this is a less 221 1.1 mrg frequently used path so probably not worth it. */ 222 1.1 mrg base -= sstride[n] * extent[n]; 223 1.1 mrg mbase -= mstride[n] * extent[n]; 224 1.1 mrg n++; 225 1.1 mrg if (n >= rank) 226 1.1 mrg { 227 1.1 mrg /* Break out of the loop. */ 228 1.1 mrg base = NULL; 229 1.1 mrg break; 230 1.1 mrg } 231 1.1 mrg else 232 1.1 mrg { 233 1.1 mrg count[n]++; 234 1.1 mrg base += sstride[n]; 235 1.1 mrg mbase += mstride[n]; 236 1.1 mrg } 237 1.1 mrg } 238 1.1 mrg while (count[n] == extent[n]); 239 1.1 mrg } 240 1.1 mrg memcpy (ret, retval, len * sizeof (*ret)); 241 1.1 mrg } 242 1.1 mrg } 243 1.1 mrg 244 1.1 mrg 245 1.1 mrg extern void sminval0_s4 (GFC_UINTEGER_4 * restrict, 246 1.1 mrg gfc_charlen_type, 247 1.1 mrg gfc_array_s4 * const restrict array, GFC_LOGICAL_4 *, gfc_charlen_type); 248 1.1 mrg export_proto(sminval0_s4); 249 1.1 mrg 250 1.1 mrg void 251 1.1 mrg sminval0_s4 (GFC_UINTEGER_4 * restrict ret, 252 1.1 mrg gfc_charlen_type xlen, gfc_array_s4 * const restrict array, 253 1.1 mrg GFC_LOGICAL_4 *mask, gfc_charlen_type len) 254 1.1 mrg 255 1.1 mrg { 256 1.1 mrg if (mask == NULL || *mask) 257 1.1 mrg { 258 1.1 mrg minval0_s4 (ret, xlen, array, len); 259 1.1 mrg return; 260 1.1 mrg } 261 1.1 mrg memset (ret, INITVAL, sizeof (*ret) * len); 262 1.1 mrg } 263 1.1 mrg 264 1.1 mrg #endif 265