1 dnl Support macro file for intrinsic functions. 2 dnl Contains the generic sections of the array functions. 3 dnl This file is part of the GNU Fortran Runtime Library (libgfortran) 4 dnl Distributed under the GNU GPL with exception. See COPYING for details. 5 dnl 6 dnl Pass the implementation for a single section as the parameter to 7 dnl {MASK_}ARRAY_FUNCTION. 8 dnl The variables base, delta, and len describe the input section. 9 dnl For masked section the mask is described by mbase and mdelta. 10 dnl These should not be modified. The result should be stored in *dest. 11 dnl The names count, extent, sstride, dstride, base, dest, rank, dim 12 dnl retarray, array, pdim and mstride should not be used. 13 dnl The variable n is declared as index_type and may be used. 14 dnl Other variable declarations may be placed at the start of the code, 15 dnl The types of the array parameter and the return value are 16 dnl atype_name and rtype_name respectively. 17 dnl Execution should be allowed to continue to the end of the block. 18 dnl You should not return or break from the inner loop of the implementation. 19 dnl Care should also be taken to avoid using the names defined in iparm.m4 20 define(START_ARRAY_FUNCTION, 21 `#include <string.h> 22 #include <assert.h> 23 24 static inline int 25 compare_fcn (const atype_name *a, const atype_name *b, gfc_charlen_type n) 26 { 27 if (sizeof ('atype_name`) == 1) 28 return memcmp (a, b, n); 29 else 30 return memcmp_char4 (a, b, n); 31 } 32 33 extern void name`'rtype_qual`_'atype_code (rtype * const restrict, 34 gfc_charlen_type, atype * const restrict, 35 const index_type * const restrict, gfc_charlen_type); 36 export_proto(name`'rtype_qual`_'atype_code); 37 38 void 39 name`'rtype_qual`_'atype_code (rtype * const restrict retarray, 40 gfc_charlen_type xlen, atype * const restrict array, 41 const index_type * const restrict pdim, gfc_charlen_type string_len) 42 { 43 index_type count[GFC_MAX_DIMENSIONS]; 44 index_type extent[GFC_MAX_DIMENSIONS]; 45 index_type sstride[GFC_MAX_DIMENSIONS]; 46 index_type dstride[GFC_MAX_DIMENSIONS]; 47 const atype_name * restrict base; 48 rtype_name * restrict dest; 49 index_type rank; 50 index_type n; 51 index_type len; 52 index_type delta; 53 index_type dim; 54 int continue_loop; 55 56 assert (xlen == string_len); 57 /* Make dim zero based to avoid confusion. */ 58 rank = GFC_DESCRIPTOR_RANK (array) - 1; 59 dim = (*pdim) - 1; 60 61 if (unlikely (dim < 0 || dim > rank)) 62 { 63 runtime_error ("Dim argument incorrect in u_name intrinsic: " 64 "is %ld, should be between 1 and %ld", 65 (long int) dim + 1, (long int) rank + 1); 66 } 67 68 len = GFC_DESCRIPTOR_EXTENT(array,dim); 69 if (len < 0) 70 len = 0; 71 72 delta = GFC_DESCRIPTOR_STRIDE(array,dim) * string_len; 73 74 for (n = 0; n < dim; n++) 75 { 76 sstride[n] = GFC_DESCRIPTOR_STRIDE(array,n) * string_len; 77 extent[n] = GFC_DESCRIPTOR_EXTENT(array,n); 78 79 if (extent[n] < 0) 80 extent[n] = 0; 81 } 82 for (n = dim; n < rank; n++) 83 { 84 sstride[n] = GFC_DESCRIPTOR_STRIDE(array, n + 1) * string_len; 85 extent[n] = GFC_DESCRIPTOR_EXTENT(array, n + 1); 86 87 if (extent[n] < 0) 88 extent[n] = 0; 89 } 90 91 if (retarray->base_addr == NULL) 92 { 93 size_t alloc_size, str; 94 95 for (n = 0; n < rank; n++) 96 { 97 if (n == 0) 98 str = 1; 99 else 100 str = GFC_DESCRIPTOR_STRIDE(retarray,n-1) * extent[n-1]; 101 102 GFC_DIMENSION_SET(retarray->dim[n], 0, extent[n] - 1, str); 103 104 } 105 106 retarray->offset = 0; 107 retarray->dtype.rank = rank; 108 109 alloc_size = GFC_DESCRIPTOR_STRIDE(retarray,rank-1) * extent[rank-1] 110 * string_len; 111 112 retarray->base_addr = xmallocarray (alloc_size, sizeof (rtype_name)); 113 if (alloc_size == 0) 114 return; 115 } 116 else 117 { 118 if (rank != GFC_DESCRIPTOR_RANK (retarray)) 119 runtime_error ("rank of return array incorrect in" 120 " u_name intrinsic: is %ld, should be %ld", 121 (long int) (GFC_DESCRIPTOR_RANK (retarray)), 122 (long int) rank); 123 124 if (unlikely (compile_options.bounds_check)) 125 bounds_ifunction_return ((array_t *) retarray, extent, 126 "return value", "u_name"); 127 } 128 129 for (n = 0; n < rank; n++) 130 { 131 count[n] = 0; 132 dstride[n] = GFC_DESCRIPTOR_STRIDE(retarray,n) * string_len; 133 if (extent[n] <= 0) 134 return; 135 } 136 137 base = array->base_addr; 138 dest = retarray->base_addr; 139 140 continue_loop = 1; 141 while (continue_loop) 142 { 143 const atype_name * restrict src; 144 src = base; 145 { 146 ')dnl 147 define(START_ARRAY_BLOCK, 148 ` if (len <= 0) 149 memset (dest, '$1`, sizeof (*dest) * string_len); 150 else 151 { 152 for (n = 0; n < len; n++, src += delta) 153 { 154 ')dnl 155 define(FINISH_ARRAY_FUNCTION, 156 ` } 157 '$1` 158 memcpy (dest, retval, sizeof (*dest) * string_len); 159 } 160 } 161 /* Advance to the next element. */ 162 count[0]++; 163 base += sstride[0]; 164 dest += dstride[0]; 165 n = 0; 166 while (count[n] == extent[n]) 167 { 168 /* When we get to the end of a dimension, reset it and increment 169 the next dimension. */ 170 count[n] = 0; 171 /* We could precalculate these products, but this is a less 172 frequently used path so probably not worth it. */ 173 base -= sstride[n] * extent[n]; 174 dest -= dstride[n] * extent[n]; 175 n++; 176 if (n >= rank) 177 { 178 /* Break out of the loop. */ 179 continue_loop = 0; 180 break; 181 } 182 else 183 { 184 count[n]++; 185 base += sstride[n]; 186 dest += dstride[n]; 187 } 188 } 189 } 190 }')dnl 191 define(START_MASKED_ARRAY_FUNCTION, 192 ` 193 extern void `m'name`'rtype_qual`_'atype_code (rtype * const restrict, 194 gfc_charlen_type, atype * const restrict, 195 const index_type * const restrict, 196 gfc_array_l1 * const restrict, gfc_charlen_type); 197 export_proto(`m'name`'rtype_qual`_'atype_code); 198 199 void 200 `m'name`'rtype_qual`_'atype_code (rtype * const restrict retarray, 201 gfc_charlen_type xlen, atype * const restrict array, 202 const index_type * const restrict pdim, 203 gfc_array_l1 * const restrict mask, 204 gfc_charlen_type string_len) 205 206 { 207 index_type count[GFC_MAX_DIMENSIONS]; 208 index_type extent[GFC_MAX_DIMENSIONS]; 209 index_type sstride[GFC_MAX_DIMENSIONS]; 210 index_type dstride[GFC_MAX_DIMENSIONS]; 211 index_type mstride[GFC_MAX_DIMENSIONS]; 212 rtype_name * restrict dest; 213 const atype_name * restrict base; 214 const GFC_LOGICAL_1 * restrict mbase; 215 index_type rank; 216 index_type dim; 217 index_type n; 218 index_type len; 219 index_type delta; 220 index_type mdelta; 221 int mask_kind; 222 223 if (mask == NULL) 224 { 225 name`'rtype_qual`_'atype_code (retarray, xlen, array, pdim, string_len); 226 return; 227 } 228 229 assert (xlen == string_len); 230 231 dim = (*pdim) - 1; 232 rank = GFC_DESCRIPTOR_RANK (array) - 1; 233 234 if (unlikely (dim < 0 || dim > rank)) 235 { 236 runtime_error ("Dim argument incorrect in u_name intrinsic: " 237 "is %ld, should be between 1 and %ld", 238 (long int) dim + 1, (long int) rank + 1); 239 } 240 241 len = GFC_DESCRIPTOR_EXTENT(array,dim); 242 if (len < 0) 243 len = 0; 244 245 mbase = mask->base_addr; 246 247 mask_kind = GFC_DESCRIPTOR_SIZE (mask); 248 249 if (mask_kind == 1 || mask_kind == 2 || mask_kind == 4 || mask_kind == 8 250 #ifdef HAVE_GFC_LOGICAL_16 251 || mask_kind == 16 252 #endif 253 ) 254 mbase = GFOR_POINTER_TO_L1 (mbase, mask_kind); 255 else 256 runtime_error ("Funny sized logical array"); 257 258 delta = GFC_DESCRIPTOR_STRIDE(array,dim) * string_len; 259 mdelta = GFC_DESCRIPTOR_STRIDE_BYTES(mask,dim); 260 261 for (n = 0; n < dim; n++) 262 { 263 sstride[n] = GFC_DESCRIPTOR_STRIDE(array,n) * string_len; 264 mstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(mask,n); 265 extent[n] = GFC_DESCRIPTOR_EXTENT(array,n); 266 267 if (extent[n] < 0) 268 extent[n] = 0; 269 270 } 271 for (n = dim; n < rank; n++) 272 { 273 sstride[n] = GFC_DESCRIPTOR_STRIDE(array,n + 1) * string_len; 274 mstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(mask, n + 1); 275 extent[n] = GFC_DESCRIPTOR_EXTENT(array, n + 1); 276 277 if (extent[n] < 0) 278 extent[n] = 0; 279 } 280 281 if (retarray->base_addr == NULL) 282 { 283 size_t alloc_size, str; 284 285 for (n = 0; n < rank; n++) 286 { 287 if (n == 0) 288 str = 1; 289 else 290 str= GFC_DESCRIPTOR_STRIDE(retarray,n-1) * extent[n-1]; 291 292 GFC_DIMENSION_SET(retarray->dim[n], 0, extent[n] - 1, str); 293 294 } 295 296 alloc_size = GFC_DESCRIPTOR_STRIDE(retarray,rank-1) * extent[rank-1] 297 * string_len; 298 299 retarray->offset = 0; 300 retarray->dtype.rank = rank; 301 302 retarray->base_addr = xmallocarray (alloc_size, sizeof (rtype_name)); 303 if (alloc_size == 0) 304 return; 305 } 306 else 307 { 308 if (rank != GFC_DESCRIPTOR_RANK (retarray)) 309 runtime_error ("rank of return array incorrect in u_name intrinsic"); 310 311 if (unlikely (compile_options.bounds_check)) 312 { 313 bounds_ifunction_return ((array_t *) retarray, extent, 314 "return value", "u_name"); 315 bounds_equal_extents ((array_t *) mask, (array_t *) array, 316 "MASK argument", "u_name"); 317 } 318 } 319 320 for (n = 0; n < rank; n++) 321 { 322 count[n] = 0; 323 dstride[n] = GFC_DESCRIPTOR_STRIDE(retarray,n) * string_len; 324 if (extent[n] <= 0) 325 return; 326 } 327 328 dest = retarray->base_addr; 329 base = array->base_addr; 330 331 while (base) 332 { 333 const atype_name * restrict src; 334 const GFC_LOGICAL_1 * restrict msrc; 335 336 src = base; 337 msrc = mbase; 338 { 339 ')dnl 340 define(START_MASKED_ARRAY_BLOCK, 341 ` for (n = 0; n < len; n++, src += delta, msrc += mdelta) 342 { 343 ')dnl 344 define(FINISH_MASKED_ARRAY_FUNCTION, 345 ` } 346 memcpy (dest, retval, sizeof (*dest) * string_len); 347 } 348 /* Advance to the next element. */ 349 count[0]++; 350 base += sstride[0]; 351 mbase += mstride[0]; 352 dest += dstride[0]; 353 n = 0; 354 while (count[n] == extent[n]) 355 { 356 /* When we get to the end of a dimension, reset it and increment 357 the next dimension. */ 358 count[n] = 0; 359 /* We could precalculate these products, but this is a less 360 frequently used path so probably not worth it. */ 361 base -= sstride[n] * extent[n]; 362 mbase -= mstride[n] * extent[n]; 363 dest -= dstride[n] * extent[n]; 364 n++; 365 if (n >= rank) 366 { 367 /* Break out of the loop. */ 368 base = NULL; 369 break; 370 } 371 else 372 { 373 count[n]++; 374 base += sstride[n]; 375 mbase += mstride[n]; 376 dest += dstride[n]; 377 } 378 } 379 } 380 }')dnl 381 define(SCALAR_ARRAY_FUNCTION, 382 ` 383 void `s'name`'rtype_qual`_'atype_code (rtype * const restrict, 384 gfc_charlen_type, atype * const restrict, 385 const index_type * const restrict, 386 GFC_LOGICAL_4 *, gfc_charlen_type); 387 388 export_proto(`s'name`'rtype_qual`_'atype_code); 389 390 void 391 `s'name`'rtype_qual`_'atype_code (rtype * const restrict retarray, 392 gfc_charlen_type xlen, atype * const restrict array, 393 const index_type * const restrict pdim, 394 GFC_LOGICAL_4 *mask, gfc_charlen_type string_len) 395 396 { 397 index_type count[GFC_MAX_DIMENSIONS]; 398 index_type extent[GFC_MAX_DIMENSIONS]; 399 index_type dstride[GFC_MAX_DIMENSIONS]; 400 rtype_name * restrict dest; 401 index_type rank; 402 index_type n; 403 index_type dim; 404 405 406 if (mask == NULL || *mask) 407 { 408 name`'rtype_qual`_'atype_code (retarray, xlen, array, pdim, string_len); 409 return; 410 } 411 /* Make dim zero based to avoid confusion. */ 412 dim = (*pdim) - 1; 413 rank = GFC_DESCRIPTOR_RANK (array) - 1; 414 415 if (unlikely (dim < 0 || dim > rank)) 416 { 417 runtime_error ("Dim argument incorrect in u_name intrinsic: " 418 "is %ld, should be between 1 and %ld", 419 (long int) dim + 1, (long int) rank + 1); 420 } 421 422 for (n = 0; n < dim; n++) 423 { 424 extent[n] = GFC_DESCRIPTOR_EXTENT(array,n); 425 426 if (extent[n] <= 0) 427 extent[n] = 0; 428 } 429 430 for (n = dim; n < rank; n++) 431 { 432 extent[n] = 433 GFC_DESCRIPTOR_EXTENT(array,n + 1); 434 435 if (extent[n] <= 0) 436 extent[n] = 0; 437 } 438 439 if (retarray->base_addr == NULL) 440 { 441 size_t alloc_size, str; 442 443 for (n = 0; n < rank; n++) 444 { 445 if (n == 0) 446 str = 1; 447 else 448 str = GFC_DESCRIPTOR_STRIDE(retarray,n-1) * extent[n-1]; 449 450 GFC_DIMENSION_SET(retarray->dim[n], 0, extent[n] - 1, str); 451 452 } 453 454 retarray->offset = 0; 455 retarray->dtype.rank = rank; 456 457 alloc_size = GFC_DESCRIPTOR_STRIDE(retarray,rank-1) * extent[rank-1] 458 * string_len; 459 460 retarray->base_addr = xmallocarray (alloc_size, sizeof (rtype_name)); 461 if (alloc_size == 0) 462 return; 463 } 464 else 465 { 466 if (rank != GFC_DESCRIPTOR_RANK (retarray)) 467 runtime_error ("rank of return array incorrect in" 468 " u_name intrinsic: is %ld, should be %ld", 469 (long int) (GFC_DESCRIPTOR_RANK (retarray)), 470 (long int) rank); 471 472 if (unlikely (compile_options.bounds_check)) 473 { 474 for (n=0; n < rank; n++) 475 { 476 index_type ret_extent; 477 478 ret_extent = GFC_DESCRIPTOR_EXTENT(retarray,n); 479 if (extent[n] != ret_extent) 480 runtime_error ("Incorrect extent in return value of" 481 " u_name intrinsic in dimension %ld:" 482 " is %ld, should be %ld", (long int) n + 1, 483 (long int) ret_extent, (long int) extent[n]); 484 } 485 } 486 } 487 488 for (n = 0; n < rank; n++) 489 { 490 count[n] = 0; 491 dstride[n] = GFC_DESCRIPTOR_STRIDE(retarray,n) * string_len; 492 } 493 494 dest = retarray->base_addr; 495 496 while(1) 497 { 498 memset (dest, '$1`, sizeof (*dest) * string_len); 499 count[0]++; 500 dest += dstride[0]; 501 n = 0; 502 while (count[n] == extent[n]) 503 { 504 /* When we get to the end of a dimension, reset it and increment 505 the next dimension. */ 506 count[n] = 0; 507 /* We could precalculate these products, but this is a less 508 frequently used path so probably not worth it. */ 509 dest -= dstride[n] * extent[n]; 510 n++; 511 if (n >= rank) 512 return; 513 else 514 { 515 count[n]++; 516 dest += dstride[n]; 517 } 518 } 519 } 520 }')dnl 521 define(ARRAY_FUNCTION, 522 `START_ARRAY_FUNCTION($1) 523 $2 524 START_ARRAY_BLOCK($1) 525 $3 526 FINISH_ARRAY_FUNCTION($4)')dnl 527 define(MASKED_ARRAY_FUNCTION, 528 `START_MASKED_ARRAY_FUNCTION 529 $2 530 START_MASKED_ARRAY_BLOCK 531 $3 532 FINISH_MASKED_ARRAY_FUNCTION')dnl 533