1 1.1 mrg /* Specific implementation of the UNPACK intrinsic 2 1.1.1.4 mrg Copyright (C) 2008-2024 Free Software Foundation, Inc. 3 1.1 mrg Contributed by Thomas Koenig <tkoenig (at) gcc.gnu.org>, based on 4 1.1 mrg unpack_generic.c by Paul Brook <paul (at) nowt.org>. 5 1.1 mrg 6 1.1 mrg This file is part of the GNU Fortran runtime library (libgfortran). 7 1.1 mrg 8 1.1 mrg Libgfortran is free software; you can redistribute it and/or 9 1.1 mrg modify it under the terms of the GNU General Public 10 1.1 mrg License as published by the Free Software Foundation; either 11 1.1 mrg version 3 of the License, or (at your option) any later version. 12 1.1 mrg 13 1.1 mrg Ligbfortran is distributed in the hope that it will be useful, 14 1.1 mrg but WITHOUT ANY WARRANTY; without even the implied warranty of 15 1.1 mrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 1.1 mrg GNU General Public License for more details. 17 1.1 mrg 18 1.1 mrg Under Section 7 of GPL version 3, you are granted additional 19 1.1 mrg permissions described in the GCC Runtime Library Exception, version 20 1.1 mrg 3.1, as published by the Free Software Foundation. 21 1.1 mrg 22 1.1 mrg You should have received a copy of the GNU General Public License and 23 1.1 mrg a copy of the GCC Runtime Library Exception along with this program; 24 1.1 mrg see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 25 1.1 mrg <http://www.gnu.org/licenses/>. */ 26 1.1 mrg 27 1.1 mrg #include "libgfortran.h" 28 1.1 mrg #include <string.h> 29 1.1 mrg 30 1.1 mrg 31 1.1 mrg #if defined (HAVE_GFC_INTEGER_4) 32 1.1 mrg 33 1.1 mrg void 34 1.1 mrg unpack0_i4 (gfc_array_i4 *ret, const gfc_array_i4 *vector, 35 1.1 mrg const gfc_array_l1 *mask, const GFC_INTEGER_4 *fptr) 36 1.1 mrg { 37 1.1 mrg /* r.* indicates the return array. */ 38 1.1 mrg index_type rstride[GFC_MAX_DIMENSIONS]; 39 1.1 mrg index_type rstride0; 40 1.1 mrg index_type rs; 41 1.1 mrg GFC_INTEGER_4 * restrict rptr; 42 1.1 mrg /* v.* indicates the vector array. */ 43 1.1 mrg index_type vstride0; 44 1.1 mrg GFC_INTEGER_4 *vptr; 45 1.1 mrg /* Value for field, this is constant. */ 46 1.1 mrg const GFC_INTEGER_4 fval = *fptr; 47 1.1 mrg /* m.* indicates the mask array. */ 48 1.1 mrg index_type mstride[GFC_MAX_DIMENSIONS]; 49 1.1 mrg index_type mstride0; 50 1.1 mrg const GFC_LOGICAL_1 *mptr; 51 1.1 mrg 52 1.1 mrg index_type count[GFC_MAX_DIMENSIONS]; 53 1.1 mrg index_type extent[GFC_MAX_DIMENSIONS]; 54 1.1 mrg index_type n; 55 1.1 mrg index_type dim; 56 1.1 mrg 57 1.1 mrg int empty; 58 1.1 mrg int mask_kind; 59 1.1 mrg 60 1.1 mrg empty = 0; 61 1.1 mrg 62 1.1 mrg mptr = mask->base_addr; 63 1.1 mrg 64 1.1 mrg /* Use the same loop for all logical types, by using GFC_LOGICAL_1 65 1.1 mrg and using shifting to address size and endian issues. */ 66 1.1 mrg 67 1.1 mrg mask_kind = GFC_DESCRIPTOR_SIZE (mask); 68 1.1 mrg 69 1.1 mrg if (mask_kind == 1 || mask_kind == 2 || mask_kind == 4 || mask_kind == 8 70 1.1 mrg #ifdef HAVE_GFC_LOGICAL_16 71 1.1 mrg || mask_kind == 16 72 1.1 mrg #endif 73 1.1 mrg ) 74 1.1 mrg { 75 1.1 mrg /* Do not convert a NULL pointer as we use test for NULL below. */ 76 1.1 mrg if (mptr) 77 1.1 mrg mptr = GFOR_POINTER_TO_L1 (mptr, mask_kind); 78 1.1 mrg } 79 1.1 mrg else 80 1.1 mrg runtime_error ("Funny sized logical array"); 81 1.1 mrg 82 1.1.1.3 mrg /* Initialize to avoid -Wmaybe-uninitialized complaints. */ 83 1.1.1.3 mrg rstride[0] = 1; 84 1.1 mrg if (ret->base_addr == NULL) 85 1.1 mrg { 86 1.1 mrg /* The front end has signalled that we need to populate the 87 1.1 mrg return array descriptor. */ 88 1.1 mrg dim = GFC_DESCRIPTOR_RANK (mask); 89 1.1 mrg rs = 1; 90 1.1 mrg for (n = 0; n < dim; n++) 91 1.1 mrg { 92 1.1 mrg count[n] = 0; 93 1.1 mrg GFC_DIMENSION_SET(ret->dim[n], 0, 94 1.1 mrg GFC_DESCRIPTOR_EXTENT(mask,n) - 1, rs); 95 1.1 mrg extent[n] = GFC_DESCRIPTOR_EXTENT(ret,n); 96 1.1 mrg empty = empty || extent[n] <= 0; 97 1.1 mrg rstride[n] = GFC_DESCRIPTOR_STRIDE(ret,n); 98 1.1 mrg mstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(mask,n); 99 1.1 mrg rs *= extent[n]; 100 1.1 mrg } 101 1.1 mrg ret->offset = 0; 102 1.1 mrg ret->base_addr = xmallocarray (rs, sizeof (GFC_INTEGER_4)); 103 1.1 mrg } 104 1.1 mrg else 105 1.1 mrg { 106 1.1 mrg dim = GFC_DESCRIPTOR_RANK (ret); 107 1.1 mrg for (n = 0; n < dim; n++) 108 1.1 mrg { 109 1.1 mrg count[n] = 0; 110 1.1 mrg extent[n] = GFC_DESCRIPTOR_EXTENT(ret,n); 111 1.1 mrg empty = empty || extent[n] <= 0; 112 1.1 mrg rstride[n] = GFC_DESCRIPTOR_STRIDE(ret,n); 113 1.1 mrg mstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(mask,n); 114 1.1 mrg } 115 1.1 mrg if (rstride[0] == 0) 116 1.1 mrg rstride[0] = 1; 117 1.1 mrg } 118 1.1 mrg 119 1.1 mrg if (empty) 120 1.1 mrg return; 121 1.1 mrg 122 1.1 mrg if (mstride[0] == 0) 123 1.1 mrg mstride[0] = 1; 124 1.1 mrg 125 1.1 mrg vstride0 = GFC_DESCRIPTOR_STRIDE(vector,0); 126 1.1 mrg if (vstride0 == 0) 127 1.1 mrg vstride0 = 1; 128 1.1 mrg rstride0 = rstride[0]; 129 1.1 mrg mstride0 = mstride[0]; 130 1.1 mrg rptr = ret->base_addr; 131 1.1 mrg vptr = vector->base_addr; 132 1.1 mrg 133 1.1 mrg while (rptr) 134 1.1 mrg { 135 1.1 mrg if (*mptr) 136 1.1 mrg { 137 1.1 mrg /* From vector. */ 138 1.1 mrg *rptr = *vptr; 139 1.1 mrg vptr += vstride0; 140 1.1 mrg } 141 1.1 mrg else 142 1.1 mrg { 143 1.1 mrg /* From field. */ 144 1.1 mrg *rptr = fval; 145 1.1 mrg } 146 1.1 mrg /* Advance to the next element. */ 147 1.1 mrg rptr += rstride0; 148 1.1 mrg mptr += mstride0; 149 1.1 mrg count[0]++; 150 1.1 mrg n = 0; 151 1.1 mrg while (count[n] == extent[n]) 152 1.1 mrg { 153 1.1 mrg /* When we get to the end of a dimension, reset it and increment 154 1.1 mrg the next dimension. */ 155 1.1 mrg count[n] = 0; 156 1.1 mrg /* We could precalculate these products, but this is a less 157 1.1 mrg frequently used path so probably not worth it. */ 158 1.1 mrg rptr -= rstride[n] * extent[n]; 159 1.1 mrg mptr -= mstride[n] * extent[n]; 160 1.1 mrg n++; 161 1.1 mrg if (n >= dim) 162 1.1 mrg { 163 1.1 mrg /* Break out of the loop. */ 164 1.1 mrg rptr = NULL; 165 1.1 mrg break; 166 1.1 mrg } 167 1.1 mrg else 168 1.1 mrg { 169 1.1 mrg count[n]++; 170 1.1 mrg rptr += rstride[n]; 171 1.1 mrg mptr += mstride[n]; 172 1.1 mrg } 173 1.1 mrg } 174 1.1 mrg } 175 1.1 mrg } 176 1.1 mrg 177 1.1 mrg void 178 1.1 mrg unpack1_i4 (gfc_array_i4 *ret, const gfc_array_i4 *vector, 179 1.1 mrg const gfc_array_l1 *mask, const gfc_array_i4 *field) 180 1.1 mrg { 181 1.1 mrg /* r.* indicates the return array. */ 182 1.1 mrg index_type rstride[GFC_MAX_DIMENSIONS]; 183 1.1 mrg index_type rstride0; 184 1.1 mrg index_type rs; 185 1.1 mrg GFC_INTEGER_4 * restrict rptr; 186 1.1 mrg /* v.* indicates the vector array. */ 187 1.1 mrg index_type vstride0; 188 1.1 mrg GFC_INTEGER_4 *vptr; 189 1.1 mrg /* f.* indicates the field array. */ 190 1.1 mrg index_type fstride[GFC_MAX_DIMENSIONS]; 191 1.1 mrg index_type fstride0; 192 1.1 mrg const GFC_INTEGER_4 *fptr; 193 1.1 mrg /* m.* indicates the mask array. */ 194 1.1 mrg index_type mstride[GFC_MAX_DIMENSIONS]; 195 1.1 mrg index_type mstride0; 196 1.1 mrg const GFC_LOGICAL_1 *mptr; 197 1.1 mrg 198 1.1 mrg index_type count[GFC_MAX_DIMENSIONS]; 199 1.1 mrg index_type extent[GFC_MAX_DIMENSIONS]; 200 1.1 mrg index_type n; 201 1.1 mrg index_type dim; 202 1.1 mrg 203 1.1 mrg int empty; 204 1.1 mrg int mask_kind; 205 1.1 mrg 206 1.1 mrg empty = 0; 207 1.1 mrg 208 1.1 mrg mptr = mask->base_addr; 209 1.1 mrg 210 1.1 mrg /* Use the same loop for all logical types, by using GFC_LOGICAL_1 211 1.1 mrg and using shifting to address size and endian issues. */ 212 1.1 mrg 213 1.1 mrg mask_kind = GFC_DESCRIPTOR_SIZE (mask); 214 1.1 mrg 215 1.1 mrg if (mask_kind == 1 || mask_kind == 2 || mask_kind == 4 || mask_kind == 8 216 1.1 mrg #ifdef HAVE_GFC_LOGICAL_16 217 1.1 mrg || mask_kind == 16 218 1.1 mrg #endif 219 1.1 mrg ) 220 1.1 mrg { 221 1.1 mrg /* Do not convert a NULL pointer as we use test for NULL below. */ 222 1.1 mrg if (mptr) 223 1.1 mrg mptr = GFOR_POINTER_TO_L1 (mptr, mask_kind); 224 1.1 mrg } 225 1.1 mrg else 226 1.1 mrg runtime_error ("Funny sized logical array"); 227 1.1 mrg 228 1.1.1.3 mrg /* Initialize to avoid -Wmaybe-uninitialized complaints. */ 229 1.1.1.3 mrg rstride[0] = 1; 230 1.1 mrg if (ret->base_addr == NULL) 231 1.1 mrg { 232 1.1 mrg /* The front end has signalled that we need to populate the 233 1.1 mrg return array descriptor. */ 234 1.1 mrg dim = GFC_DESCRIPTOR_RANK (mask); 235 1.1 mrg rs = 1; 236 1.1 mrg for (n = 0; n < dim; n++) 237 1.1 mrg { 238 1.1 mrg count[n] = 0; 239 1.1 mrg GFC_DIMENSION_SET(ret->dim[n], 0, 240 1.1 mrg GFC_DESCRIPTOR_EXTENT(mask,n) - 1, rs); 241 1.1 mrg extent[n] = GFC_DESCRIPTOR_EXTENT(ret,n); 242 1.1 mrg empty = empty || extent[n] <= 0; 243 1.1 mrg rstride[n] = GFC_DESCRIPTOR_STRIDE(ret,n); 244 1.1 mrg fstride[n] = GFC_DESCRIPTOR_STRIDE(field,n); 245 1.1 mrg mstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(mask,n); 246 1.1 mrg rs *= extent[n]; 247 1.1 mrg } 248 1.1 mrg ret->offset = 0; 249 1.1 mrg ret->base_addr = xmallocarray (rs, sizeof (GFC_INTEGER_4)); 250 1.1 mrg } 251 1.1 mrg else 252 1.1 mrg { 253 1.1 mrg dim = GFC_DESCRIPTOR_RANK (ret); 254 1.1 mrg for (n = 0; n < dim; n++) 255 1.1 mrg { 256 1.1 mrg count[n] = 0; 257 1.1 mrg extent[n] = GFC_DESCRIPTOR_EXTENT(ret,n); 258 1.1 mrg empty = empty || extent[n] <= 0; 259 1.1 mrg rstride[n] = GFC_DESCRIPTOR_STRIDE(ret,n); 260 1.1 mrg fstride[n] = GFC_DESCRIPTOR_STRIDE(field,n); 261 1.1 mrg mstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(mask,n); 262 1.1 mrg } 263 1.1 mrg if (rstride[0] == 0) 264 1.1 mrg rstride[0] = 1; 265 1.1 mrg } 266 1.1 mrg 267 1.1 mrg if (empty) 268 1.1 mrg return; 269 1.1 mrg 270 1.1 mrg if (fstride[0] == 0) 271 1.1 mrg fstride[0] = 1; 272 1.1 mrg if (mstride[0] == 0) 273 1.1 mrg mstride[0] = 1; 274 1.1 mrg 275 1.1 mrg vstride0 = GFC_DESCRIPTOR_STRIDE(vector,0); 276 1.1 mrg if (vstride0 == 0) 277 1.1 mrg vstride0 = 1; 278 1.1 mrg rstride0 = rstride[0]; 279 1.1 mrg fstride0 = fstride[0]; 280 1.1 mrg mstride0 = mstride[0]; 281 1.1 mrg rptr = ret->base_addr; 282 1.1 mrg fptr = field->base_addr; 283 1.1 mrg vptr = vector->base_addr; 284 1.1 mrg 285 1.1 mrg while (rptr) 286 1.1 mrg { 287 1.1 mrg if (*mptr) 288 1.1 mrg { 289 1.1 mrg /* From vector. */ 290 1.1 mrg *rptr = *vptr; 291 1.1 mrg vptr += vstride0; 292 1.1 mrg } 293 1.1 mrg else 294 1.1 mrg { 295 1.1 mrg /* From field. */ 296 1.1 mrg *rptr = *fptr; 297 1.1 mrg } 298 1.1 mrg /* Advance to the next element. */ 299 1.1 mrg rptr += rstride0; 300 1.1 mrg fptr += fstride0; 301 1.1 mrg mptr += mstride0; 302 1.1 mrg count[0]++; 303 1.1 mrg n = 0; 304 1.1 mrg while (count[n] == extent[n]) 305 1.1 mrg { 306 1.1 mrg /* When we get to the end of a dimension, reset it and increment 307 1.1 mrg the next dimension. */ 308 1.1 mrg count[n] = 0; 309 1.1 mrg /* We could precalculate these products, but this is a less 310 1.1 mrg frequently used path so probably not worth it. */ 311 1.1 mrg rptr -= rstride[n] * extent[n]; 312 1.1 mrg fptr -= fstride[n] * extent[n]; 313 1.1 mrg mptr -= mstride[n] * extent[n]; 314 1.1 mrg n++; 315 1.1 mrg if (n >= dim) 316 1.1 mrg { 317 1.1 mrg /* Break out of the loop. */ 318 1.1 mrg rptr = NULL; 319 1.1 mrg break; 320 1.1 mrg } 321 1.1 mrg else 322 1.1 mrg { 323 1.1 mrg count[n]++; 324 1.1 mrg rptr += rstride[n]; 325 1.1 mrg fptr += fstride[n]; 326 1.1 mrg mptr += mstride[n]; 327 1.1 mrg } 328 1.1 mrg } 329 1.1 mrg } 330 1.1 mrg } 331 1.1 mrg 332 1.1 mrg #endif 333 1.1 mrg 334