diff options
author | Thomas Koenig <tkoenig@gcc.gnu.org> | 2018-10-28 11:05:05 +0000 |
---|---|---|
committer | Thomas Koenig <tkoenig@gcc.gnu.org> | 2018-10-28 11:05:05 +0000 |
commit | 01ce9e31a02c8039d88e90f983735104417bf034 (patch) | |
tree | 186e264d66218f12fbd3d71ace05c275c82f7518 /gcc/fortran/simplify.c | |
parent | b10fb07830939a34f822008d61ed104be40123e0 (diff) | |
download | gcc-01ce9e31a02c8039d88e90f983735104417bf034.zip gcc-01ce9e31a02c8039d88e90f983735104417bf034.tar.gz gcc-01ce9e31a02c8039d88e90f983735104417bf034.tar.bz2 |
re PR fortran/54613 ([F08] Add FINDLOC plus support MAXLOC/MINLOC with KIND=/BACK=)
2017-10-28 Thomas Koenig <tkoenig@gcc.gnu.org>
PR fortran/54613
* gfortran.h (gfc_isym_id): Add GFC_ISYM_FINDLOC.
(gfc_check_f): Add f6fl field.
(gfc_simplify_f): Add f6 field.
(gfc_resolve_f): Likewise.
(gfc_type_letter): Add optional logical_equas_int flag.
* check.c (intrinsic_type_check): New function.
(gfc_check_findloc): New function.
* intrinsics.c (gfc_type_letter): If logical_equals_int is
set, act accordingly.
(add_sym_5ml): Reformat comment.
(add_sym_6fl): New function.
(add_functions): Add findloc.
(check_arglist): Add sixth argument, handle it.
(resolve_intrinsic): Likewise.
(check_specific): Handle findloc.
* intrinsic.h (gfc_check_findloc): Add prototype.
(gfc_simplify_findloc): Likewise.
(gfc_resolve_findloc): Likewise.
(MAX_INTRINSIC_ARGS): Adjust.
* iresolve.c (gfc_resolve_findloc): New function.
* simplify.c (gfc_simplify_minmaxloc): Make static.
(simplify_findloc_to_scalar): New function.
(simplify_findloc_nodim): New function.
(simplify_findloc_to_array): New function.
(gfc_simplify_findloc): New function.
(gfc_conv_intrinsic_findloc): New function.
(gfc_conv_intrinsic_function): Handle GFC_ISYM_FINDLOC.
(gfc_is_intrinsic_libcall): Likewise.
2017-10-28 Thomas Koenig <tkoenig@gcc.gnu.org>
PR fortran/54613
* Makefile.am: Add files for findloc.
* Makefile.in: Regenerated.
* libgfortran.h (gfc_array_index_type): Add.
(gfc_array_s1): Add using GFC_UINTEGER_1.
(gfc_array_s4): Likewise.
Replace unnecessary comment.
(HAVE_GFC_UINTEGER_1): Define.
(HAVE_GFC_UINTEGER_4): Define.
* m4/findloc0.m4: New file.
* m4/findloc0s.m4: New file.
* m4/findloc1.m4: New file.
* m4/findloc1s.m4: New file.
* m4/findloc2s.m4: New file.
* m4/ifindloc0.m4: New file.
* m4/ifindloc1.m4: New file.
* m4/ifindloc2.m4: New file.
* m4/iparm.m4: Use unsigned integer for characters.
* generated/findloc0_c16.c: New file.
* generated/findloc0_c4.c: New file.
* generated/findloc0_c8.c: New file.
* generated/findloc0_i1.c: New file.
* generated/findloc0_i16.c: New file.
* generated/findloc0_i2.c: New file.
* generated/findloc0_i4.c: New file.
* generated/findloc0_i8.c: New file.
* generated/findloc0_r16.c: New file.
* generated/findloc0_r4.c: New file.
* generated/findloc0_r8.c: New file.
* generated/findloc0_s1.c: New file.
* generated/findloc0_s4.c: New file.
* generated/findloc1_c16.c: New file.
* generated/findloc1_c4.c: New file.
* generated/findloc1_c8.c: New file.
* generated/findloc1_i1.c: New file.
* generated/findloc1_i16.c: New file.
* generated/findloc1_i2.c: New file.
* generated/findloc1_i4.c: New file.
* generated/findloc1_i8.c: New file.
* generated/findloc1_r16.c: New file.
* generated/findloc1_r4.c: New file.
* generated/findloc1_r8.c: New file.
* generated/findloc1_s1.c: New file.
* generated/findloc1_s4.c: New file.
* generated/findloc2_s1.c: New file.
* generated/findloc2_s4.c: New file.
* generated/maxloc0_16_s1.c: Regenerated.
* generated/maxloc0_16_s4.c: Regenerated.
* generated/maxloc0_4_s1.c: Regenerated.
* generated/maxloc0_4_s4.c: Regenerated.
* generated/maxloc0_8_s1.c: Regenerated.
* generated/maxloc0_8_s4.c: Regenerated.
* generated/maxloc1_16_s1.c: Regenerated.
* generated/maxloc1_16_s4.c: Regenerated.
* generated/maxloc1_4_s1.c: Regenerated.
* generated/maxloc1_4_s4.c: Regenerated.
* generated/maxloc1_8_s1.c: Regenerated.
* generated/maxloc1_8_s4.c: Regenerated.
* generated/maxloc2_16_s1.c: Regenerated.
* generated/maxloc2_16_s4.c: Regenerated.
* generated/maxloc2_4_s1.c: Regenerated.
* generated/maxloc2_4_s4.c: Regenerated.
* generated/maxloc2_8_s1.c: Regenerated.
* generated/maxloc2_8_s4.c: Regenerated.
* generated/maxval0_s1.c: Regenerated.
* generated/maxval0_s4.c: Regenerated.
* generated/maxval1_s1.c: Regenerated.
* generated/maxval1_s4.c: Regenerated.
* generated/minloc0_16_s1.c: Regenerated.
* generated/minloc0_16_s4.c: Regenerated.
* generated/minloc0_4_s1.c: Regenerated.
* generated/minloc0_4_s4.c: Regenerated.
* generated/minloc0_8_s1.c: Regenerated.
* generated/minloc0_8_s4.c: Regenerated.
* generated/minloc1_16_s1.c: Regenerated.
* generated/minloc1_16_s4.c: Regenerated.
* generated/minloc1_4_s1.c: Regenerated.
* generated/minloc1_4_s4.c: Regenerated.
* generated/minloc1_8_s1.c: Regenerated.
* generated/minloc1_8_s4.c: Regenerated.
* generated/minloc2_16_s1.c: Regenerated.
* generated/minloc2_16_s4.c: Regenerated.
* generated/minloc2_4_s1.c: Regenerated.
* generated/minloc2_4_s4.c: Regenerated.
* generated/minloc2_8_s1.c: Regenerated.
* generated/minloc2_8_s4.c: Regenerated.
* generated/minval0_s1.c: Regenerated.
* generated/minval0_s4.c: Regenerated.
* generated/minval1_s1.c: Regenerated.
* generated/minval1_s4.c: Regenerated.
2017-10-28 Thomas Koenig <tkoenig@gcc.gnu.org>
PR fortran/54613
* gfortran.dg/findloc_1.f90: New test.
* gfortran.dg/findloc_2.f90: New test.
* gfortran.dg/findloc_3.f90: New test.
* gfortran.dg/findloc_4.f90: New test.
* gfortran.dg/findloc_5.f90: New test.
* gfortran.dg/findloc_6.f90: New test.
From-SVN: r265570
Diffstat (limited to 'gcc/fortran/simplify.c')
-rw-r--r-- | gcc/fortran/simplify.c | 354 |
1 files changed, 353 insertions, 1 deletions
diff --git a/gcc/fortran/simplify.c b/gcc/fortran/simplify.c index 7bdd23d..3939d26 100644 --- a/gcc/fortran/simplify.c +++ b/gcc/fortran/simplify.c @@ -5372,7 +5372,7 @@ simplify_minmaxloc_to_array (gfc_expr *result, gfc_expr *array, /* Simplify minloc and maxloc for constant arrays. */ -gfc_expr * +static gfc_expr * gfc_simplify_minmaxloc (gfc_expr *array, gfc_expr *dim, gfc_expr *mask, gfc_expr *kind, gfc_expr *back, int sign) { @@ -5452,6 +5452,358 @@ gfc_simplify_maxloc (gfc_expr *array, gfc_expr *dim, gfc_expr *mask, gfc_expr *k return gfc_simplify_minmaxloc (array, dim, mask, kind, back, 1); } +/* Simplify findloc to scalar. Similar to + simplify_minmaxloc_to_scalar. */ + +static gfc_expr * +simplify_findloc_to_scalar (gfc_expr *result, gfc_expr *array, gfc_expr *value, + gfc_expr *mask, int back_val) +{ + gfc_expr *a, *m; + gfc_constructor *array_ctor, *mask_ctor; + mpz_t count; + + mpz_set_si (result->value.integer, 0); + + /* Shortcut for constant .FALSE. MASK. */ + if (mask + && mask->expr_type == EXPR_CONSTANT + && !mask->value.logical) + return result; + + array_ctor = gfc_constructor_first (array->value.constructor); + if (mask && mask->expr_type == EXPR_ARRAY) + mask_ctor = gfc_constructor_first (mask->value.constructor); + else + mask_ctor = NULL; + + mpz_init_set_si (count, 0); + while (array_ctor) + { + mpz_add_ui (count, count, 1); + a = array_ctor->expr; + array_ctor = gfc_constructor_next (array_ctor); + /* A constant MASK equals .TRUE. here and can be ignored. */ + if (mask_ctor) + { + m = mask_ctor->expr; + mask_ctor = gfc_constructor_next (mask_ctor); + if (!m->value.logical) + continue; + } + if (gfc_compare_expr (a, value, INTRINSIC_EQ) == 0) + { + /* We have a match. If BACK is true, continue so we find + the last one. */ + mpz_set (result->value.integer, count); + if (!back_val) + break; + } + } + mpz_clear (count); + return result; +} + +/* Simplify findloc in the absence of a dim argument. Similar to + simplify_minmaxloc_nodim. */ + +static gfc_expr * +simplify_findloc_nodim (gfc_expr *result, gfc_expr *value, gfc_expr *array, + gfc_expr *mask, bool back_val) +{ + ssize_t res[GFC_MAX_DIMENSIONS]; + int i, n; + gfc_constructor *result_ctor, *array_ctor, *mask_ctor; + ssize_t count[GFC_MAX_DIMENSIONS], extent[GFC_MAX_DIMENSIONS], + sstride[GFC_MAX_DIMENSIONS]; + gfc_expr *a, *m; + bool continue_loop; + bool ma; + + for (i = 0; i<array->rank; i++) + res[i] = -1; + + /* Shortcut for constant .FALSE. MASK. */ + if (mask + && mask->expr_type == EXPR_CONSTANT + && !mask->value.logical) + goto finish; + + for (i = 0; i < array->rank; i++) + { + count[i] = 0; + sstride[i] = (i == 0) ? 1 : sstride[i-1] * mpz_get_si (array->shape[i-1]); + extent[i] = mpz_get_si (array->shape[i]); + if (extent[i] <= 0) + goto finish; + } + + continue_loop = true; + array_ctor = gfc_constructor_first (array->value.constructor); + if (mask && mask->rank > 0) + mask_ctor = gfc_constructor_first (mask->value.constructor); + else + mask_ctor = NULL; + + /* Loop over the array elements (and mask), keeping track of + the indices to return. */ + while (continue_loop) + { + do + { + a = array_ctor->expr; + if (mask_ctor) + { + m = mask_ctor->expr; + ma = m->value.logical; + mask_ctor = gfc_constructor_next (mask_ctor); + } + else + ma = true; + + if (ma && gfc_compare_expr (a, value, INTRINSIC_EQ) == 0) + { + for (i = 0; i<array->rank; i++) + res[i] = count[i]; + if (!back_val) + goto finish; + } + array_ctor = gfc_constructor_next (array_ctor); + count[0] ++; + } while (count[0] != extent[0]); + n = 0; + do + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + n++; + if (n >= array->rank) + { + continue_loop = false; + break; + } + else + count[n] ++; + } while (count[n] == extent[n]); + } + + finish: + result_ctor = gfc_constructor_first (result->value.constructor); + for (i = 0; i<array->rank; i++) + { + gfc_expr *r_expr; + r_expr = result_ctor->expr; + mpz_set_si (r_expr->value.integer, res[i] + 1); + result_ctor = gfc_constructor_next (result_ctor); + } + return result; +} + + +/* Simplify findloc to an array. Similar to + simplify_minmaxloc_to_array. */ + +static gfc_expr * +simplify_findloc_to_array (gfc_expr *result, gfc_expr *array, gfc_expr *value, + gfc_expr *dim, gfc_expr *mask, bool back_val) +{ + mpz_t size; + int done, i, n, arraysize, resultsize, dim_index, dim_extent, dim_stride; + gfc_expr **arrayvec, **resultvec, **base, **src, **dest; + gfc_constructor *array_ctor, *mask_ctor, *result_ctor; + + int count[GFC_MAX_DIMENSIONS], extent[GFC_MAX_DIMENSIONS], + sstride[GFC_MAX_DIMENSIONS], dstride[GFC_MAX_DIMENSIONS], + tmpstride[GFC_MAX_DIMENSIONS]; + + /* Shortcut for constant .FALSE. MASK. */ + if (mask + && mask->expr_type == EXPR_CONSTANT + && !mask->value.logical) + return result; + + /* Build an indexed table for array element expressions to minimize + linked-list traversal. Masked elements are set to NULL. */ + gfc_array_size (array, &size); + arraysize = mpz_get_ui (size); + mpz_clear (size); + + arrayvec = XCNEWVEC (gfc_expr*, arraysize); + + array_ctor = gfc_constructor_first (array->value.constructor); + mask_ctor = NULL; + if (mask && mask->expr_type == EXPR_ARRAY) + mask_ctor = gfc_constructor_first (mask->value.constructor); + + for (i = 0; i < arraysize; ++i) + { + arrayvec[i] = array_ctor->expr; + array_ctor = gfc_constructor_next (array_ctor); + + if (mask_ctor) + { + if (!mask_ctor->expr->value.logical) + arrayvec[i] = NULL; + + mask_ctor = gfc_constructor_next (mask_ctor); + } + } + + /* Same for the result expression. */ + gfc_array_size (result, &size); + resultsize = mpz_get_ui (size); + mpz_clear (size); + + resultvec = XCNEWVEC (gfc_expr*, resultsize); + result_ctor = gfc_constructor_first (result->value.constructor); + for (i = 0; i < resultsize; ++i) + { + resultvec[i] = result_ctor->expr; + result_ctor = gfc_constructor_next (result_ctor); + } + + gfc_extract_int (dim, &dim_index); + + dim_index -= 1; /* Zero-base index. */ + dim_extent = 0; + dim_stride = 0; + + for (i = 0, n = 0; i < array->rank; ++i) + { + count[i] = 0; + tmpstride[i] = (i == 0) ? 1 : tmpstride[i-1] * mpz_get_si (array->shape[i-1]); + if (i == dim_index) + { + dim_extent = mpz_get_si (array->shape[i]); + dim_stride = tmpstride[i]; + continue; + } + + extent[n] = mpz_get_si (array->shape[i]); + sstride[n] = tmpstride[i]; + dstride[n] = (n == 0) ? 1 : dstride[n-1] * extent[n-1]; + n += 1; + } + + done = resultsize <= 0; + base = arrayvec; + dest = resultvec; + while (!done) + { + for (src = base, n = 0; n < dim_extent; src += dim_stride, ++n) + { + if (*src && gfc_compare_expr (*src, value, INTRINSIC_EQ) == 0) + { + mpz_set_si ((*dest)->value.integer, n + 1); + if (!back_val) + break; + } + } + + count[0]++; + base += sstride[0]; + dest += dstride[0]; + + n = 0; + while (!done && count[n] == extent[n]) + { + count[n] = 0; + base -= sstride[n] * extent[n]; + dest -= dstride[n] * extent[n]; + + n++; + if (n < result->rank) + { + /* If the nested loop is unrolled GFC_MAX_DIMENSIONS + times, we'd warn for the last iteration, because the + array index will have already been incremented to the + array sizes, and we can't tell that this must make + the test against result->rank false, because ranks + must not exceed GFC_MAX_DIMENSIONS. */ + GCC_DIAGNOSTIC_PUSH_IGNORED (-Warray-bounds) + count[n]++; + base += sstride[n]; + dest += dstride[n]; + GCC_DIAGNOSTIC_POP + } + else + done = true; + } + } + + /* Place updated expression in result constructor. */ + result_ctor = gfc_constructor_first (result->value.constructor); + for (i = 0; i < resultsize; ++i) + { + result_ctor->expr = resultvec[i]; + result_ctor = gfc_constructor_next (result_ctor); + } + + free (arrayvec); + free (resultvec); + return result; +} + +/* Simplify findloc. */ + +gfc_expr * +gfc_simplify_findloc (gfc_expr *array, gfc_expr *value, gfc_expr *dim, + gfc_expr *mask, gfc_expr *kind, gfc_expr *back) +{ + gfc_expr *result; + int ikind; + bool back_val = false; + + if (!is_constant_array_expr (array) + || !gfc_is_constant_expr (dim)) + return NULL; + + if (! gfc_is_constant_expr (value)) + return 0; + + if (mask + && !is_constant_array_expr (mask) + && mask->expr_type != EXPR_CONSTANT) + return NULL; + + if (kind) + { + if (gfc_extract_int (kind, &ikind, -1)) + return NULL; + } + else + ikind = gfc_default_integer_kind; + + if (back) + { + if (back->expr_type != EXPR_CONSTANT) + return NULL; + + back_val = back->value.logical; + } + + if (dim) + { + result = transformational_result (array, dim, BT_INTEGER, + ikind, &array->where); + init_result_expr (result, 0, array); + + if (array->rank == 1) + return simplify_findloc_to_scalar (result, array, value, mask, + back_val); + else + return simplify_findloc_to_array (result, array, value, dim, mask, + back_val); + } + else + { + result = new_array (BT_INTEGER, ikind, array->rank, &array->where); + return simplify_findloc_nodim (result, value, array, mask, back_val); + } + return NULL; +} + gfc_expr * gfc_simplify_maxexponent (gfc_expr *x) { |