diff options
Diffstat (limited to 'gcc/fortran/simplify.c')
-rw-r--r-- | gcc/fortran/simplify.c | 8966 |
1 files changed, 0 insertions, 8966 deletions
diff --git a/gcc/fortran/simplify.c b/gcc/fortran/simplify.c deleted file mode 100644 index cc7d33a..0000000 --- a/gcc/fortran/simplify.c +++ /dev/null @@ -1,8966 +0,0 @@ -/* Simplify intrinsic functions at compile-time. - Copyright (C) 2000-2022 Free Software Foundation, Inc. - Contributed by Andy Vaught & Katherine Holcomb - -This file is part of GCC. - -GCC is free software; you can redistribute it and/or modify it under -the terms of the GNU General Public License as published by the Free -Software Foundation; either version 3, or (at your option) any later -version. - -GCC is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with GCC; see the file COPYING3. If not see -<http://www.gnu.org/licenses/>. */ - -#include "config.h" -#include "system.h" -#include "coretypes.h" -#include "tm.h" /* For BITS_PER_UNIT. */ -#include "gfortran.h" -#include "arith.h" -#include "intrinsic.h" -#include "match.h" -#include "target-memory.h" -#include "constructor.h" -#include "version.h" /* For version_string. */ - -/* Prototypes. */ - -static int min_max_choose (gfc_expr *, gfc_expr *, int, bool back_val = false); - -gfc_expr gfc_bad_expr; - -static gfc_expr *simplify_size (gfc_expr *, gfc_expr *, int); - - -/* Note that 'simplification' is not just transforming expressions. - For functions that are not simplified at compile time, range - checking is done if possible. - - The return convention is that each simplification function returns: - - A new expression node corresponding to the simplified arguments. - The original arguments are destroyed by the caller, and must not - be a part of the new expression. - - NULL pointer indicating that no simplification was possible and - the original expression should remain intact. - - An expression pointer to gfc_bad_expr (a static placeholder) - indicating that some error has prevented simplification. The - error is generated within the function and should be propagated - upwards - - By the time a simplification function gets control, it has been - decided that the function call is really supposed to be the - intrinsic. No type checking is strictly necessary, since only - valid types will be passed on. On the other hand, a simplification - subroutine may have to look at the type of an argument as part of - its processing. - - Array arguments are only passed to these subroutines that implement - the simplification of transformational intrinsics. - - The functions in this file don't have much comment with them, but - everything is reasonably straight-forward. The Standard, chapter 13 - is the best comment you'll find for this file anyway. */ - -/* Range checks an expression node. If all goes well, returns the - node, otherwise returns &gfc_bad_expr and frees the node. */ - -static gfc_expr * -range_check (gfc_expr *result, const char *name) -{ - if (result == NULL) - return &gfc_bad_expr; - - if (result->expr_type != EXPR_CONSTANT) - return result; - - switch (gfc_range_check (result)) - { - case ARITH_OK: - return result; - - case ARITH_OVERFLOW: - gfc_error ("Result of %s overflows its kind at %L", name, - &result->where); - break; - - case ARITH_UNDERFLOW: - gfc_error ("Result of %s underflows its kind at %L", name, - &result->where); - break; - - case ARITH_NAN: - gfc_error ("Result of %s is NaN at %L", name, &result->where); - break; - - default: - gfc_error ("Result of %s gives range error for its kind at %L", name, - &result->where); - break; - } - - gfc_free_expr (result); - return &gfc_bad_expr; -} - - -/* A helper function that gets an optional and possibly missing - kind parameter. Returns the kind, -1 if something went wrong. */ - -static int -get_kind (bt type, gfc_expr *k, const char *name, int default_kind) -{ - int kind; - - if (k == NULL) - return default_kind; - - if (k->expr_type != EXPR_CONSTANT) - { - gfc_error ("KIND parameter of %s at %L must be an initialization " - "expression", name, &k->where); - return -1; - } - - if (gfc_extract_int (k, &kind) - || gfc_validate_kind (type, kind, true) < 0) - { - gfc_error ("Invalid KIND parameter of %s at %L", name, &k->where); - return -1; - } - - return kind; -} - - -/* Converts an mpz_t signed variable into an unsigned one, assuming - two's complement representations and a binary width of bitsize. - The conversion is a no-op unless x is negative; otherwise, it can - be accomplished by masking out the high bits. */ - -static void -convert_mpz_to_unsigned (mpz_t x, int bitsize) -{ - mpz_t mask; - - if (mpz_sgn (x) < 0) - { - /* Confirm that no bits above the signed range are unset if we - are doing range checking. */ - if (flag_range_check != 0) - gcc_assert (mpz_scan0 (x, bitsize-1) == ULONG_MAX); - - mpz_init_set_ui (mask, 1); - mpz_mul_2exp (mask, mask, bitsize); - mpz_sub_ui (mask, mask, 1); - - mpz_and (x, x, mask); - - mpz_clear (mask); - } - else - { - /* Confirm that no bits above the signed range are set if we - are doing range checking. */ - if (flag_range_check != 0) - gcc_assert (mpz_scan1 (x, bitsize-1) == ULONG_MAX); - } -} - - -/* Converts an mpz_t unsigned variable into a signed one, assuming - two's complement representations and a binary width of bitsize. - If the bitsize-1 bit is set, this is taken as a sign bit and - the number is converted to the corresponding negative number. */ - -void -gfc_convert_mpz_to_signed (mpz_t x, int bitsize) -{ - mpz_t mask; - - /* Confirm that no bits above the unsigned range are set if we are - doing range checking. */ - if (flag_range_check != 0) - gcc_assert (mpz_scan1 (x, bitsize) == ULONG_MAX); - - if (mpz_tstbit (x, bitsize - 1) == 1) - { - mpz_init_set_ui (mask, 1); - mpz_mul_2exp (mask, mask, bitsize); - mpz_sub_ui (mask, mask, 1); - - /* We negate the number by hand, zeroing the high bits, that is - make it the corresponding positive number, and then have it - negated by GMP, giving the correct representation of the - negative number. */ - mpz_com (x, x); - mpz_add_ui (x, x, 1); - mpz_and (x, x, mask); - - mpz_neg (x, x); - - mpz_clear (mask); - } -} - - -/* Test that the expression is a constant array, simplifying if - we are dealing with a parameter array. */ - -static bool -is_constant_array_expr (gfc_expr *e) -{ - gfc_constructor *c; - bool array_OK = true; - mpz_t size; - - if (e == NULL) - return true; - - if (e->expr_type == EXPR_VARIABLE && e->rank > 0 - && e->symtree->n.sym->attr.flavor == FL_PARAMETER) - gfc_simplify_expr (e, 1); - - if (e->expr_type != EXPR_ARRAY || !gfc_is_constant_expr (e)) - return false; - - for (c = gfc_constructor_first (e->value.constructor); - c; c = gfc_constructor_next (c)) - if (c->expr->expr_type != EXPR_CONSTANT - && c->expr->expr_type != EXPR_STRUCTURE) - { - array_OK = false; - break; - } - - /* Check and expand the constructor. */ - if (!array_OK && gfc_init_expr_flag && e->rank == 1) - { - array_OK = gfc_reduce_init_expr (e); - /* gfc_reduce_init_expr resets the flag. */ - gfc_init_expr_flag = true; - } - else - return array_OK; - - /* Recheck to make sure that any EXPR_ARRAYs have gone. */ - for (c = gfc_constructor_first (e->value.constructor); - c; c = gfc_constructor_next (c)) - if (c->expr->expr_type != EXPR_CONSTANT - && c->expr->expr_type != EXPR_STRUCTURE) - return false; - - /* Make sure that the array has a valid shape. */ - if (e->shape == NULL && e->rank == 1) - { - if (!gfc_array_size(e, &size)) - return false; - e->shape = gfc_get_shape (1); - mpz_init_set (e->shape[0], size); - mpz_clear (size); - } - - return array_OK; -} - -/* Test for a size zero array. */ -bool -gfc_is_size_zero_array (gfc_expr *array) -{ - - if (array->rank == 0) - return false; - - if (array->expr_type == EXPR_VARIABLE && array->rank > 0 - && array->symtree->n.sym->attr.flavor == FL_PARAMETER - && array->shape != NULL) - { - for (int i = 0; i < array->rank; i++) - if (mpz_cmp_si (array->shape[i], 0) <= 0) - return true; - - return false; - } - - if (array->expr_type == EXPR_ARRAY) - return array->value.constructor == NULL; - - return false; -} - - -/* Initialize a transformational result expression with a given value. */ - -static void -init_result_expr (gfc_expr *e, int init, gfc_expr *array) -{ - if (e && e->expr_type == EXPR_ARRAY) - { - gfc_constructor *ctor = gfc_constructor_first (e->value.constructor); - while (ctor) - { - init_result_expr (ctor->expr, init, array); - ctor = gfc_constructor_next (ctor); - } - } - else if (e && e->expr_type == EXPR_CONSTANT) - { - int i = gfc_validate_kind (e->ts.type, e->ts.kind, false); - HOST_WIDE_INT length; - gfc_char_t *string; - - switch (e->ts.type) - { - case BT_LOGICAL: - e->value.logical = (init ? 1 : 0); - break; - - case BT_INTEGER: - if (init == INT_MIN) - mpz_set (e->value.integer, gfc_integer_kinds[i].min_int); - else if (init == INT_MAX) - mpz_set (e->value.integer, gfc_integer_kinds[i].huge); - else - mpz_set_si (e->value.integer, init); - break; - - case BT_REAL: - if (init == INT_MIN) - { - mpfr_set (e->value.real, gfc_real_kinds[i].huge, GFC_RND_MODE); - mpfr_neg (e->value.real, e->value.real, GFC_RND_MODE); - } - else if (init == INT_MAX) - mpfr_set (e->value.real, gfc_real_kinds[i].huge, GFC_RND_MODE); - else - mpfr_set_si (e->value.real, init, GFC_RND_MODE); - break; - - case BT_COMPLEX: - mpc_set_si (e->value.complex, init, GFC_MPC_RND_MODE); - break; - - case BT_CHARACTER: - if (init == INT_MIN) - { - gfc_expr *len = gfc_simplify_len (array, NULL); - gfc_extract_hwi (len, &length); - string = gfc_get_wide_string (length + 1); - gfc_wide_memset (string, 0, length); - } - else if (init == INT_MAX) - { - gfc_expr *len = gfc_simplify_len (array, NULL); - gfc_extract_hwi (len, &length); - string = gfc_get_wide_string (length + 1); - gfc_wide_memset (string, 255, length); - } - else - { - length = 0; - string = gfc_get_wide_string (1); - } - - string[length] = '\0'; - e->value.character.length = length; - e->value.character.string = string; - break; - - default: - gcc_unreachable(); - } - } - else - gcc_unreachable(); -} - - -/* Helper function for gfc_simplify_dot_product() and gfc_simplify_matmul; - if conj_a is true, the matrix_a is complex conjugated. */ - -static gfc_expr * -compute_dot_product (gfc_expr *matrix_a, int stride_a, int offset_a, - gfc_expr *matrix_b, int stride_b, int offset_b, - bool conj_a) -{ - gfc_expr *result, *a, *b, *c; - - /* Set result to an INTEGER(1) 0 for numeric types and .false. for - LOGICAL. Mixed-mode math in the loop will promote result to the - correct type and kind. */ - if (matrix_a->ts.type == BT_LOGICAL) - result = gfc_get_logical_expr (gfc_default_logical_kind, NULL, false); - else - result = gfc_get_int_expr (1, NULL, 0); - result->where = matrix_a->where; - - a = gfc_constructor_lookup_expr (matrix_a->value.constructor, offset_a); - b = gfc_constructor_lookup_expr (matrix_b->value.constructor, offset_b); - while (a && b) - { - /* Copying of expressions is required as operands are free'd - by the gfc_arith routines. */ - switch (result->ts.type) - { - case BT_LOGICAL: - result = gfc_or (result, - gfc_and (gfc_copy_expr (a), - gfc_copy_expr (b))); - break; - - case BT_INTEGER: - case BT_REAL: - case BT_COMPLEX: - if (conj_a && a->ts.type == BT_COMPLEX) - c = gfc_simplify_conjg (a); - else - c = gfc_copy_expr (a); - result = gfc_add (result, gfc_multiply (c, gfc_copy_expr (b))); - break; - - default: - gcc_unreachable(); - } - - offset_a += stride_a; - a = gfc_constructor_lookup_expr (matrix_a->value.constructor, offset_a); - - offset_b += stride_b; - b = gfc_constructor_lookup_expr (matrix_b->value.constructor, offset_b); - } - - return result; -} - - -/* Build a result expression for transformational intrinsics, - depending on DIM. */ - -static gfc_expr * -transformational_result (gfc_expr *array, gfc_expr *dim, bt type, - int kind, locus* where) -{ - gfc_expr *result; - int i, nelem; - - if (!dim || array->rank == 1) - return gfc_get_constant_expr (type, kind, where); - - result = gfc_get_array_expr (type, kind, where); - result->shape = gfc_copy_shape_excluding (array->shape, array->rank, dim); - result->rank = array->rank - 1; - - /* gfc_array_size() would count the number of elements in the constructor, - we have not built those yet. */ - nelem = 1; - for (i = 0; i < result->rank; ++i) - nelem *= mpz_get_ui (result->shape[i]); - - for (i = 0; i < nelem; ++i) - { - gfc_constructor_append_expr (&result->value.constructor, - gfc_get_constant_expr (type, kind, where), - NULL); - } - - return result; -} - - -typedef gfc_expr* (*transformational_op)(gfc_expr*, gfc_expr*); - -/* Wrapper function, implements 'op1 += 1'. Only called if MASK - of COUNT intrinsic is .TRUE.. - - Interface and implementation mimics arith functions as - gfc_add, gfc_multiply, etc. */ - -static gfc_expr * -gfc_count (gfc_expr *op1, gfc_expr *op2) -{ - gfc_expr *result; - - gcc_assert (op1->ts.type == BT_INTEGER); - gcc_assert (op2->ts.type == BT_LOGICAL); - gcc_assert (op2->value.logical); - - result = gfc_copy_expr (op1); - mpz_add_ui (result->value.integer, result->value.integer, 1); - - gfc_free_expr (op1); - gfc_free_expr (op2); - return result; -} - - -/* Transforms an ARRAY with operation OP, according to MASK, to a - scalar RESULT. E.g. called if - - REAL, PARAMETER :: array(n, m) = ... - REAL, PARAMETER :: s = SUM(array) - - where OP == gfc_add(). */ - -static gfc_expr * -simplify_transformation_to_scalar (gfc_expr *result, gfc_expr *array, gfc_expr *mask, - transformational_op op) -{ - gfc_expr *a, *m; - gfc_constructor *array_ctor, *mask_ctor; - - /* 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); - mask_ctor = NULL; - if (mask && mask->expr_type == EXPR_ARRAY) - mask_ctor = gfc_constructor_first (mask->value.constructor); - - while (array_ctor) - { - 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; - } - - result = op (result, gfc_copy_expr (a)); - if (!result) - return result; - } - - return result; -} - -/* Transforms an ARRAY with operation OP, according to MASK, to an - array RESULT. E.g. called if - - REAL, PARAMETER :: array(n, m) = ... - REAL, PARAMETER :: s(n) = PROD(array, DIM=1) - - where OP == gfc_multiply(). - The result might be post processed using post_op. */ - -static gfc_expr * -simplify_transformation_to_array (gfc_expr *result, gfc_expr *array, gfc_expr *dim, - gfc_expr *mask, transformational_op op, - transformational_op post_op) -{ - 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) - *dest = op (*dest, gfc_copy_expr (*src)); - - if (post_op) - *dest = post_op (*dest, *dest); - - 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; -} - - -static gfc_expr * -simplify_transformation (gfc_expr *array, gfc_expr *dim, gfc_expr *mask, - int init_val, transformational_op op) -{ - gfc_expr *result; - bool size_zero; - - size_zero = gfc_is_size_zero_array (array); - - if (!(is_constant_array_expr (array) || size_zero) - || !gfc_is_constant_expr (dim)) - return NULL; - - if (mask - && !is_constant_array_expr (mask) - && mask->expr_type != EXPR_CONSTANT) - return NULL; - - result = transformational_result (array, dim, array->ts.type, - array->ts.kind, &array->where); - init_result_expr (result, init_val, array); - - if (size_zero) - return result; - - return !dim || array->rank == 1 ? - simplify_transformation_to_scalar (result, array, mask, op) : - simplify_transformation_to_array (result, array, dim, mask, op, NULL); -} - - -/********************** Simplification functions *****************************/ - -gfc_expr * -gfc_simplify_abs (gfc_expr *e) -{ - gfc_expr *result; - - if (e->expr_type != EXPR_CONSTANT) - return NULL; - - switch (e->ts.type) - { - case BT_INTEGER: - result = gfc_get_constant_expr (BT_INTEGER, e->ts.kind, &e->where); - mpz_abs (result->value.integer, e->value.integer); - return range_check (result, "IABS"); - - case BT_REAL: - result = gfc_get_constant_expr (BT_REAL, e->ts.kind, &e->where); - mpfr_abs (result->value.real, e->value.real, GFC_RND_MODE); - return range_check (result, "ABS"); - - case BT_COMPLEX: - gfc_set_model_kind (e->ts.kind); - result = gfc_get_constant_expr (BT_REAL, e->ts.kind, &e->where); - mpc_abs (result->value.real, e->value.complex, GFC_RND_MODE); - return range_check (result, "CABS"); - - default: - gfc_internal_error ("gfc_simplify_abs(): Bad type"); - } -} - - -static gfc_expr * -simplify_achar_char (gfc_expr *e, gfc_expr *k, const char *name, bool ascii) -{ - gfc_expr *result; - int kind; - bool too_large = false; - - if (e->expr_type != EXPR_CONSTANT) - return NULL; - - kind = get_kind (BT_CHARACTER, k, name, gfc_default_character_kind); - if (kind == -1) - return &gfc_bad_expr; - - if (mpz_cmp_si (e->value.integer, 0) < 0) - { - gfc_error ("Argument of %s function at %L is negative", name, - &e->where); - return &gfc_bad_expr; - } - - if (ascii && warn_surprising && mpz_cmp_si (e->value.integer, 127) > 0) - gfc_warning (OPT_Wsurprising, - "Argument of %s function at %L outside of range [0,127]", - name, &e->where); - - if (kind == 1 && mpz_cmp_si (e->value.integer, 255) > 0) - too_large = true; - else if (kind == 4) - { - mpz_t t; - mpz_init_set_ui (t, 2); - mpz_pow_ui (t, t, 32); - mpz_sub_ui (t, t, 1); - if (mpz_cmp (e->value.integer, t) > 0) - too_large = true; - mpz_clear (t); - } - - if (too_large) - { - gfc_error ("Argument of %s function at %L is too large for the " - "collating sequence of kind %d", name, &e->where, kind); - return &gfc_bad_expr; - } - - result = gfc_get_character_expr (kind, &e->where, NULL, 1); - result->value.character.string[0] = mpz_get_ui (e->value.integer); - - return result; -} - - - -/* We use the processor's collating sequence, because all - systems that gfortran currently works on are ASCII. */ - -gfc_expr * -gfc_simplify_achar (gfc_expr *e, gfc_expr *k) -{ - return simplify_achar_char (e, k, "ACHAR", true); -} - - -gfc_expr * -gfc_simplify_acos (gfc_expr *x) -{ - gfc_expr *result; - - if (x->expr_type != EXPR_CONSTANT) - return NULL; - - switch (x->ts.type) - { - case BT_REAL: - if (mpfr_cmp_si (x->value.real, 1) > 0 - || mpfr_cmp_si (x->value.real, -1) < 0) - { - gfc_error ("Argument of ACOS at %L must be between -1 and 1", - &x->where); - return &gfc_bad_expr; - } - result = gfc_get_constant_expr (x->ts.type, x->ts.kind, &x->where); - mpfr_acos (result->value.real, x->value.real, GFC_RND_MODE); - break; - - case BT_COMPLEX: - result = gfc_get_constant_expr (x->ts.type, x->ts.kind, &x->where); - mpc_acos (result->value.complex, x->value.complex, GFC_MPC_RND_MODE); - break; - - default: - gfc_internal_error ("in gfc_simplify_acos(): Bad type"); - } - - return range_check (result, "ACOS"); -} - -gfc_expr * -gfc_simplify_acosh (gfc_expr *x) -{ - gfc_expr *result; - - if (x->expr_type != EXPR_CONSTANT) - return NULL; - - switch (x->ts.type) - { - case BT_REAL: - if (mpfr_cmp_si (x->value.real, 1) < 0) - { - gfc_error ("Argument of ACOSH at %L must not be less than 1", - &x->where); - return &gfc_bad_expr; - } - - result = gfc_get_constant_expr (x->ts.type, x->ts.kind, &x->where); - mpfr_acosh (result->value.real, x->value.real, GFC_RND_MODE); - break; - - case BT_COMPLEX: - result = gfc_get_constant_expr (x->ts.type, x->ts.kind, &x->where); - mpc_acosh (result->value.complex, x->value.complex, GFC_MPC_RND_MODE); - break; - - default: - gfc_internal_error ("in gfc_simplify_acosh(): Bad type"); - } - - return range_check (result, "ACOSH"); -} - -gfc_expr * -gfc_simplify_adjustl (gfc_expr *e) -{ - gfc_expr *result; - int count, i, len; - gfc_char_t ch; - - if (e->expr_type != EXPR_CONSTANT) - return NULL; - - len = e->value.character.length; - - for (count = 0, i = 0; i < len; ++i) - { - ch = e->value.character.string[i]; - if (ch != ' ') - break; - ++count; - } - - result = gfc_get_character_expr (e->ts.kind, &e->where, NULL, len); - for (i = 0; i < len - count; ++i) - result->value.character.string[i] = e->value.character.string[count + i]; - - return result; -} - - -gfc_expr * -gfc_simplify_adjustr (gfc_expr *e) -{ - gfc_expr *result; - int count, i, len; - gfc_char_t ch; - - if (e->expr_type != EXPR_CONSTANT) - return NULL; - - len = e->value.character.length; - - for (count = 0, i = len - 1; i >= 0; --i) - { - ch = e->value.character.string[i]; - if (ch != ' ') - break; - ++count; - } - - result = gfc_get_character_expr (e->ts.kind, &e->where, NULL, len); - for (i = 0; i < count; ++i) - result->value.character.string[i] = ' '; - - for (i = count; i < len; ++i) - result->value.character.string[i] = e->value.character.string[i - count]; - - return result; -} - - -gfc_expr * -gfc_simplify_aimag (gfc_expr *e) -{ - gfc_expr *result; - - if (e->expr_type != EXPR_CONSTANT) - return NULL; - - result = gfc_get_constant_expr (BT_REAL, e->ts.kind, &e->where); - mpfr_set (result->value.real, mpc_imagref (e->value.complex), GFC_RND_MODE); - - return range_check (result, "AIMAG"); -} - - -gfc_expr * -gfc_simplify_aint (gfc_expr *e, gfc_expr *k) -{ - gfc_expr *rtrunc, *result; - int kind; - - kind = get_kind (BT_REAL, k, "AINT", e->ts.kind); - if (kind == -1) - return &gfc_bad_expr; - - if (e->expr_type != EXPR_CONSTANT) - return NULL; - - rtrunc = gfc_copy_expr (e); - mpfr_trunc (rtrunc->value.real, e->value.real); - - result = gfc_real2real (rtrunc, kind); - - gfc_free_expr (rtrunc); - - return range_check (result, "AINT"); -} - - -gfc_expr * -gfc_simplify_all (gfc_expr *mask, gfc_expr *dim) -{ - return simplify_transformation (mask, dim, NULL, true, gfc_and); -} - - -gfc_expr * -gfc_simplify_dint (gfc_expr *e) -{ - gfc_expr *rtrunc, *result; - - if (e->expr_type != EXPR_CONSTANT) - return NULL; - - rtrunc = gfc_copy_expr (e); - mpfr_trunc (rtrunc->value.real, e->value.real); - - result = gfc_real2real (rtrunc, gfc_default_double_kind); - - gfc_free_expr (rtrunc); - - return range_check (result, "DINT"); -} - - -gfc_expr * -gfc_simplify_dreal (gfc_expr *e) -{ - gfc_expr *result = NULL; - - if (e->expr_type != EXPR_CONSTANT) - return NULL; - - result = gfc_get_constant_expr (BT_REAL, e->ts.kind, &e->where); - mpc_real (result->value.real, e->value.complex, GFC_RND_MODE); - - return range_check (result, "DREAL"); -} - - -gfc_expr * -gfc_simplify_anint (gfc_expr *e, gfc_expr *k) -{ - gfc_expr *result; - int kind; - - kind = get_kind (BT_REAL, k, "ANINT", e->ts.kind); - if (kind == -1) - return &gfc_bad_expr; - - if (e->expr_type != EXPR_CONSTANT) - return NULL; - - result = gfc_get_constant_expr (e->ts.type, kind, &e->where); - mpfr_round (result->value.real, e->value.real); - - return range_check (result, "ANINT"); -} - - -gfc_expr * -gfc_simplify_and (gfc_expr *x, gfc_expr *y) -{ - gfc_expr *result; - int kind; - - if (x->expr_type != EXPR_CONSTANT || y->expr_type != EXPR_CONSTANT) - return NULL; - - kind = x->ts.kind > y->ts.kind ? x->ts.kind : y->ts.kind; - - switch (x->ts.type) - { - case BT_INTEGER: - result = gfc_get_constant_expr (BT_INTEGER, kind, &x->where); - mpz_and (result->value.integer, x->value.integer, y->value.integer); - return range_check (result, "AND"); - - case BT_LOGICAL: - return gfc_get_logical_expr (kind, &x->where, - x->value.logical && y->value.logical); - - default: - gcc_unreachable (); - } -} - - -gfc_expr * -gfc_simplify_any (gfc_expr *mask, gfc_expr *dim) -{ - return simplify_transformation (mask, dim, NULL, false, gfc_or); -} - - -gfc_expr * -gfc_simplify_dnint (gfc_expr *e) -{ - gfc_expr *result; - - if (e->expr_type != EXPR_CONSTANT) - return NULL; - - result = gfc_get_constant_expr (BT_REAL, gfc_default_double_kind, &e->where); - mpfr_round (result->value.real, e->value.real); - - return range_check (result, "DNINT"); -} - - -gfc_expr * -gfc_simplify_asin (gfc_expr *x) -{ - gfc_expr *result; - - if (x->expr_type != EXPR_CONSTANT) - return NULL; - - switch (x->ts.type) - { - case BT_REAL: - if (mpfr_cmp_si (x->value.real, 1) > 0 - || mpfr_cmp_si (x->value.real, -1) < 0) - { - gfc_error ("Argument of ASIN at %L must be between -1 and 1", - &x->where); - return &gfc_bad_expr; - } - result = gfc_get_constant_expr (x->ts.type, x->ts.kind, &x->where); - mpfr_asin (result->value.real, x->value.real, GFC_RND_MODE); - break; - - case BT_COMPLEX: - result = gfc_get_constant_expr (x->ts.type, x->ts.kind, &x->where); - mpc_asin (result->value.complex, x->value.complex, GFC_MPC_RND_MODE); - break; - - default: - gfc_internal_error ("in gfc_simplify_asin(): Bad type"); - } - - return range_check (result, "ASIN"); -} - - -/* Convert radians to degrees, i.e., x * 180 / pi. */ - -static void -rad2deg (mpfr_t x) -{ - mpfr_t tmp; - - mpfr_init (tmp); - mpfr_const_pi (tmp, GFC_RND_MODE); - mpfr_mul_ui (x, x, 180, GFC_RND_MODE); - mpfr_div (x, x, tmp, GFC_RND_MODE); - mpfr_clear (tmp); -} - - -/* Simplify ACOSD(X) where the returned value has units of degree. */ - -gfc_expr * -gfc_simplify_acosd (gfc_expr *x) -{ - gfc_expr *result; - - if (x->expr_type != EXPR_CONSTANT) - return NULL; - - if (mpfr_cmp_si (x->value.real, 1) > 0 - || mpfr_cmp_si (x->value.real, -1) < 0) - { - gfc_error ("Argument of ACOSD at %L must be between -1 and 1", - &x->where); - return &gfc_bad_expr; - } - - result = gfc_get_constant_expr (x->ts.type, x->ts.kind, &x->where); - mpfr_acos (result->value.real, x->value.real, GFC_RND_MODE); - rad2deg (result->value.real); - - return range_check (result, "ACOSD"); -} - - -/* Simplify asind (x) where the returned value has units of degree. */ - -gfc_expr * -gfc_simplify_asind (gfc_expr *x) -{ - gfc_expr *result; - - if (x->expr_type != EXPR_CONSTANT) - return NULL; - - if (mpfr_cmp_si (x->value.real, 1) > 0 - || mpfr_cmp_si (x->value.real, -1) < 0) - { - gfc_error ("Argument of ASIND at %L must be between -1 and 1", - &x->where); - return &gfc_bad_expr; - } - - result = gfc_get_constant_expr (x->ts.type, x->ts.kind, &x->where); - mpfr_asin (result->value.real, x->value.real, GFC_RND_MODE); - rad2deg (result->value.real); - - return range_check (result, "ASIND"); -} - - -/* Simplify atand (x) where the returned value has units of degree. */ - -gfc_expr * -gfc_simplify_atand (gfc_expr *x) -{ - gfc_expr *result; - - if (x->expr_type != EXPR_CONSTANT) - return NULL; - - result = gfc_get_constant_expr (x->ts.type, x->ts.kind, &x->where); - mpfr_atan (result->value.real, x->value.real, GFC_RND_MODE); - rad2deg (result->value.real); - - return range_check (result, "ATAND"); -} - - -gfc_expr * -gfc_simplify_asinh (gfc_expr *x) -{ - gfc_expr *result; - - if (x->expr_type != EXPR_CONSTANT) - return NULL; - - result = gfc_get_constant_expr (x->ts.type, x->ts.kind, &x->where); - - switch (x->ts.type) - { - case BT_REAL: - mpfr_asinh (result->value.real, x->value.real, GFC_RND_MODE); - break; - - case BT_COMPLEX: - mpc_asinh (result->value.complex, x->value.complex, GFC_MPC_RND_MODE); - break; - - default: - gfc_internal_error ("in gfc_simplify_asinh(): Bad type"); - } - - return range_check (result, "ASINH"); -} - - -gfc_expr * -gfc_simplify_atan (gfc_expr *x) -{ - gfc_expr *result; - - if (x->expr_type != EXPR_CONSTANT) - return NULL; - - result = gfc_get_constant_expr (x->ts.type, x->ts.kind, &x->where); - - switch (x->ts.type) - { - case BT_REAL: - mpfr_atan (result->value.real, x->value.real, GFC_RND_MODE); - break; - - case BT_COMPLEX: - mpc_atan (result->value.complex, x->value.complex, GFC_MPC_RND_MODE); - break; - - default: - gfc_internal_error ("in gfc_simplify_atan(): Bad type"); - } - - return range_check (result, "ATAN"); -} - - -gfc_expr * -gfc_simplify_atanh (gfc_expr *x) -{ - gfc_expr *result; - - if (x->expr_type != EXPR_CONSTANT) - return NULL; - - switch (x->ts.type) - { - case BT_REAL: - if (mpfr_cmp_si (x->value.real, 1) >= 0 - || mpfr_cmp_si (x->value.real, -1) <= 0) - { - gfc_error ("Argument of ATANH at %L must be inside the range -1 " - "to 1", &x->where); - return &gfc_bad_expr; - } - result = gfc_get_constant_expr (x->ts.type, x->ts.kind, &x->where); - mpfr_atanh (result->value.real, x->value.real, GFC_RND_MODE); - break; - - case BT_COMPLEX: - result = gfc_get_constant_expr (x->ts.type, x->ts.kind, &x->where); - mpc_atanh (result->value.complex, x->value.complex, GFC_MPC_RND_MODE); - break; - - default: - gfc_internal_error ("in gfc_simplify_atanh(): Bad type"); - } - - return range_check (result, "ATANH"); -} - - -gfc_expr * -gfc_simplify_atan2 (gfc_expr *y, gfc_expr *x) -{ - gfc_expr *result; - - if (x->expr_type != EXPR_CONSTANT || y->expr_type != EXPR_CONSTANT) - return NULL; - - if (mpfr_zero_p (y->value.real) && mpfr_zero_p (x->value.real)) - { - gfc_error ("If first argument of ATAN2 at %L is zero, then the " - "second argument must not be zero", &y->where); - return &gfc_bad_expr; - } - - result = gfc_get_constant_expr (x->ts.type, x->ts.kind, &x->where); - mpfr_atan2 (result->value.real, y->value.real, x->value.real, GFC_RND_MODE); - - return range_check (result, "ATAN2"); -} - - -gfc_expr * -gfc_simplify_bessel_j0 (gfc_expr *x) -{ - gfc_expr *result; - - if (x->expr_type != EXPR_CONSTANT) - return NULL; - - result = gfc_get_constant_expr (x->ts.type, x->ts.kind, &x->where); - mpfr_j0 (result->value.real, x->value.real, GFC_RND_MODE); - - return range_check (result, "BESSEL_J0"); -} - - -gfc_expr * -gfc_simplify_bessel_j1 (gfc_expr *x) -{ - gfc_expr *result; - - if (x->expr_type != EXPR_CONSTANT) - return NULL; - - result = gfc_get_constant_expr (x->ts.type, x->ts.kind, &x->where); - mpfr_j1 (result->value.real, x->value.real, GFC_RND_MODE); - - return range_check (result, "BESSEL_J1"); -} - - -gfc_expr * -gfc_simplify_bessel_jn (gfc_expr *order, gfc_expr *x) -{ - gfc_expr *result; - long n; - - if (x->expr_type != EXPR_CONSTANT || order->expr_type != EXPR_CONSTANT) - return NULL; - - n = mpz_get_si (order->value.integer); - result = gfc_get_constant_expr (x->ts.type, x->ts.kind, &x->where); - mpfr_jn (result->value.real, n, x->value.real, GFC_RND_MODE); - - return range_check (result, "BESSEL_JN"); -} - - -/* Simplify transformational form of JN and YN. */ - -static gfc_expr * -gfc_simplify_bessel_n2 (gfc_expr *order1, gfc_expr *order2, gfc_expr *x, - bool jn) -{ - gfc_expr *result; - gfc_expr *e; - long n1, n2; - int i; - mpfr_t x2rev, last1, last2; - - if (x->expr_type != EXPR_CONSTANT || order1->expr_type != EXPR_CONSTANT - || order2->expr_type != EXPR_CONSTANT) - return NULL; - - n1 = mpz_get_si (order1->value.integer); - n2 = mpz_get_si (order2->value.integer); - result = gfc_get_array_expr (x->ts.type, x->ts.kind, &x->where); - result->rank = 1; - result->shape = gfc_get_shape (1); - mpz_init_set_ui (result->shape[0], MAX (n2-n1+1, 0)); - - if (n2 < n1) - return result; - - /* Special case: x == 0; it is J0(0.0) == 1, JN(N > 0, 0.0) == 0; and - YN(N, 0.0) = -Inf. */ - - if (mpfr_cmp_ui (x->value.real, 0.0) == 0) - { - if (!jn && flag_range_check) - { - gfc_error ("Result of BESSEL_YN is -INF at %L", &result->where); - gfc_free_expr (result); - return &gfc_bad_expr; - } - - if (jn && n1 == 0) - { - e = gfc_get_constant_expr (x->ts.type, x->ts.kind, &x->where); - mpfr_set_ui (e->value.real, 1, GFC_RND_MODE); - gfc_constructor_append_expr (&result->value.constructor, e, - &x->where); - n1++; - } - - for (i = n1; i <= n2; i++) - { - e = gfc_get_constant_expr (x->ts.type, x->ts.kind, &x->where); - if (jn) - mpfr_set_ui (e->value.real, 0, GFC_RND_MODE); - else - mpfr_set_inf (e->value.real, -1); - gfc_constructor_append_expr (&result->value.constructor, e, - &x->where); - } - - return result; - } - - /* Use the faster but more verbose recurrence algorithm. Bessel functions - are stable for downward recursion and Neumann functions are stable - for upward recursion. It is - x2rev = 2.0/x, - J(N-1, x) = x2rev * N * J(N, x) - J(N+1, x), - Y(N+1, x) = x2rev * N * Y(N, x) - Y(N-1, x). - Cf. http://dlmf.nist.gov/10.74#iv and http://dlmf.nist.gov/10.6#E1 */ - - gfc_set_model_kind (x->ts.kind); - - /* Get first recursion anchor. */ - - mpfr_init (last1); - if (jn) - mpfr_jn (last1, n2, x->value.real, GFC_RND_MODE); - else - mpfr_yn (last1, n1, x->value.real, GFC_RND_MODE); - - e = gfc_get_constant_expr (x->ts.type, x->ts.kind, &x->where); - mpfr_set (e->value.real, last1, GFC_RND_MODE); - if (range_check (e, jn ? "BESSEL_JN" : "BESSEL_YN") == &gfc_bad_expr) - { - mpfr_clear (last1); - gfc_free_expr (e); - gfc_free_expr (result); - return &gfc_bad_expr; - } - gfc_constructor_append_expr (&result->value.constructor, e, &x->where); - - if (n1 == n2) - { - mpfr_clear (last1); - return result; - } - - /* Get second recursion anchor. */ - - mpfr_init (last2); - if (jn) - mpfr_jn (last2, n2-1, x->value.real, GFC_RND_MODE); - else - mpfr_yn (last2, n1+1, x->value.real, GFC_RND_MODE); - - e = gfc_get_constant_expr (x->ts.type, x->ts.kind, &x->where); - mpfr_set (e->value.real, last2, GFC_RND_MODE); - if (range_check (e, jn ? "BESSEL_JN" : "BESSEL_YN") == &gfc_bad_expr) - { - mpfr_clear (last1); - mpfr_clear (last2); - gfc_free_expr (e); - gfc_free_expr (result); - return &gfc_bad_expr; - } - if (jn) - gfc_constructor_insert_expr (&result->value.constructor, e, &x->where, -2); - else - gfc_constructor_append_expr (&result->value.constructor, e, &x->where); - - if (n1 + 1 == n2) - { - mpfr_clear (last1); - mpfr_clear (last2); - return result; - } - - /* Start actual recursion. */ - - mpfr_init (x2rev); - mpfr_ui_div (x2rev, 2, x->value.real, GFC_RND_MODE); - - for (i = 2; i <= n2-n1; i++) - { - e = gfc_get_constant_expr (x->ts.type, x->ts.kind, &x->where); - - /* Special case: For YN, if the previous N gave -INF, set - also N+1 to -INF. */ - if (!jn && !flag_range_check && mpfr_inf_p (last2)) - { - mpfr_set_inf (e->value.real, -1); - gfc_constructor_append_expr (&result->value.constructor, e, - &x->where); - continue; - } - - mpfr_mul_si (e->value.real, x2rev, jn ? (n2-i+1) : (n1+i-1), - GFC_RND_MODE); - mpfr_mul (e->value.real, e->value.real, last2, GFC_RND_MODE); - mpfr_sub (e->value.real, e->value.real, last1, GFC_RND_MODE); - - if (range_check (e, jn ? "BESSEL_JN" : "BESSEL_YN") == &gfc_bad_expr) - { - /* Range_check frees "e" in that case. */ - e = NULL; - goto error; - } - - if (jn) - gfc_constructor_insert_expr (&result->value.constructor, e, &x->where, - -i-1); - else - gfc_constructor_append_expr (&result->value.constructor, e, &x->where); - - mpfr_set (last1, last2, GFC_RND_MODE); - mpfr_set (last2, e->value.real, GFC_RND_MODE); - } - - mpfr_clear (last1); - mpfr_clear (last2); - mpfr_clear (x2rev); - return result; - -error: - mpfr_clear (last1); - mpfr_clear (last2); - mpfr_clear (x2rev); - gfc_free_expr (e); - gfc_free_expr (result); - return &gfc_bad_expr; -} - - -gfc_expr * -gfc_simplify_bessel_jn2 (gfc_expr *order1, gfc_expr *order2, gfc_expr *x) -{ - return gfc_simplify_bessel_n2 (order1, order2, x, true); -} - - -gfc_expr * -gfc_simplify_bessel_y0 (gfc_expr *x) -{ - gfc_expr *result; - - if (x->expr_type != EXPR_CONSTANT) - return NULL; - - result = gfc_get_constant_expr (x->ts.type, x->ts.kind, &x->where); - mpfr_y0 (result->value.real, x->value.real, GFC_RND_MODE); - - return range_check (result, "BESSEL_Y0"); -} - - -gfc_expr * -gfc_simplify_bessel_y1 (gfc_expr *x) -{ - gfc_expr *result; - - if (x->expr_type != EXPR_CONSTANT) - return NULL; - - result = gfc_get_constant_expr (x->ts.type, x->ts.kind, &x->where); - mpfr_y1 (result->value.real, x->value.real, GFC_RND_MODE); - - return range_check (result, "BESSEL_Y1"); -} - - -gfc_expr * -gfc_simplify_bessel_yn (gfc_expr *order, gfc_expr *x) -{ - gfc_expr *result; - long n; - - if (x->expr_type != EXPR_CONSTANT || order->expr_type != EXPR_CONSTANT) - return NULL; - - n = mpz_get_si (order->value.integer); - result = gfc_get_constant_expr (x->ts.type, x->ts.kind, &x->where); - mpfr_yn (result->value.real, n, x->value.real, GFC_RND_MODE); - - return range_check (result, "BESSEL_YN"); -} - - -gfc_expr * -gfc_simplify_bessel_yn2 (gfc_expr *order1, gfc_expr *order2, gfc_expr *x) -{ - return gfc_simplify_bessel_n2 (order1, order2, x, false); -} - - -gfc_expr * -gfc_simplify_bit_size (gfc_expr *e) -{ - int i = gfc_validate_kind (e->ts.type, e->ts.kind, false); - return gfc_get_int_expr (e->ts.kind, &e->where, - gfc_integer_kinds[i].bit_size); -} - - -gfc_expr * -gfc_simplify_btest (gfc_expr *e, gfc_expr *bit) -{ - int b; - - if (e->expr_type != EXPR_CONSTANT || bit->expr_type != EXPR_CONSTANT) - return NULL; - - if (gfc_extract_int (bit, &b) || b < 0) - return gfc_get_logical_expr (gfc_default_logical_kind, &e->where, false); - - return gfc_get_logical_expr (gfc_default_logical_kind, &e->where, - mpz_tstbit (e->value.integer, b)); -} - - -static int -compare_bitwise (gfc_expr *i, gfc_expr *j) -{ - mpz_t x, y; - int k, res; - - gcc_assert (i->ts.type == BT_INTEGER); - gcc_assert (j->ts.type == BT_INTEGER); - - mpz_init_set (x, i->value.integer); - k = gfc_validate_kind (i->ts.type, i->ts.kind, false); - convert_mpz_to_unsigned (x, gfc_integer_kinds[k].bit_size); - - mpz_init_set (y, j->value.integer); - k = gfc_validate_kind (j->ts.type, j->ts.kind, false); - convert_mpz_to_unsigned (y, gfc_integer_kinds[k].bit_size); - - res = mpz_cmp (x, y); - mpz_clear (x); - mpz_clear (y); - return res; -} - - -gfc_expr * -gfc_simplify_bge (gfc_expr *i, gfc_expr *j) -{ - if (i->expr_type != EXPR_CONSTANT || j->expr_type != EXPR_CONSTANT) - return NULL; - - return gfc_get_logical_expr (gfc_default_logical_kind, &i->where, - compare_bitwise (i, j) >= 0); -} - - -gfc_expr * -gfc_simplify_bgt (gfc_expr *i, gfc_expr *j) -{ - if (i->expr_type != EXPR_CONSTANT || j->expr_type != EXPR_CONSTANT) - return NULL; - - return gfc_get_logical_expr (gfc_default_logical_kind, &i->where, - compare_bitwise (i, j) > 0); -} - - -gfc_expr * -gfc_simplify_ble (gfc_expr *i, gfc_expr *j) -{ - if (i->expr_type != EXPR_CONSTANT || j->expr_type != EXPR_CONSTANT) - return NULL; - - return gfc_get_logical_expr (gfc_default_logical_kind, &i->where, - compare_bitwise (i, j) <= 0); -} - - -gfc_expr * -gfc_simplify_blt (gfc_expr *i, gfc_expr *j) -{ - if (i->expr_type != EXPR_CONSTANT || j->expr_type != EXPR_CONSTANT) - return NULL; - - return gfc_get_logical_expr (gfc_default_logical_kind, &i->where, - compare_bitwise (i, j) < 0); -} - - -gfc_expr * -gfc_simplify_ceiling (gfc_expr *e, gfc_expr *k) -{ - gfc_expr *ceil, *result; - int kind; - - kind = get_kind (BT_INTEGER, k, "CEILING", gfc_default_integer_kind); - if (kind == -1) - return &gfc_bad_expr; - - if (e->expr_type != EXPR_CONSTANT) - return NULL; - - ceil = gfc_copy_expr (e); - mpfr_ceil (ceil->value.real, e->value.real); - - result = gfc_get_constant_expr (BT_INTEGER, kind, &e->where); - gfc_mpfr_to_mpz (result->value.integer, ceil->value.real, &e->where); - - gfc_free_expr (ceil); - - return range_check (result, "CEILING"); -} - - -gfc_expr * -gfc_simplify_char (gfc_expr *e, gfc_expr *k) -{ - return simplify_achar_char (e, k, "CHAR", false); -} - - -/* Common subroutine for simplifying CMPLX, COMPLEX and DCMPLX. */ - -static gfc_expr * -simplify_cmplx (const char *name, gfc_expr *x, gfc_expr *y, int kind) -{ - gfc_expr *result; - - if (x->expr_type != EXPR_CONSTANT - || (y != NULL && y->expr_type != EXPR_CONSTANT)) - return NULL; - - result = gfc_get_constant_expr (BT_COMPLEX, kind, &x->where); - - switch (x->ts.type) - { - case BT_INTEGER: - mpc_set_z (result->value.complex, x->value.integer, GFC_MPC_RND_MODE); - break; - - case BT_REAL: - mpc_set_fr (result->value.complex, x->value.real, GFC_RND_MODE); - break; - - case BT_COMPLEX: - mpc_set (result->value.complex, x->value.complex, GFC_MPC_RND_MODE); - break; - - default: - gfc_internal_error ("gfc_simplify_dcmplx(): Bad type (x)"); - } - - if (!y) - return range_check (result, name); - - switch (y->ts.type) - { - case BT_INTEGER: - mpfr_set_z (mpc_imagref (result->value.complex), - y->value.integer, GFC_RND_MODE); - break; - - case BT_REAL: - mpfr_set (mpc_imagref (result->value.complex), - y->value.real, GFC_RND_MODE); - break; - - default: - gfc_internal_error ("gfc_simplify_dcmplx(): Bad type (y)"); - } - - return range_check (result, name); -} - - -gfc_expr * -gfc_simplify_cmplx (gfc_expr *x, gfc_expr *y, gfc_expr *k) -{ - int kind; - - kind = get_kind (BT_REAL, k, "CMPLX", gfc_default_complex_kind); - if (kind == -1) - return &gfc_bad_expr; - - return simplify_cmplx ("CMPLX", x, y, kind); -} - - -gfc_expr * -gfc_simplify_complex (gfc_expr *x, gfc_expr *y) -{ - int kind; - - if (x->ts.type == BT_INTEGER && y->ts.type == BT_INTEGER) - kind = gfc_default_complex_kind; - else if (x->ts.type == BT_REAL || y->ts.type == BT_INTEGER) - kind = x->ts.kind; - else if (x->ts.type == BT_INTEGER || y->ts.type == BT_REAL) - kind = y->ts.kind; - else if (x->ts.type == BT_REAL && y->ts.type == BT_REAL) - kind = (x->ts.kind > y->ts.kind) ? x->ts.kind : y->ts.kind; - else - gcc_unreachable (); - - return simplify_cmplx ("COMPLEX", x, y, kind); -} - - -gfc_expr * -gfc_simplify_conjg (gfc_expr *e) -{ - gfc_expr *result; - - if (e->expr_type != EXPR_CONSTANT) - return NULL; - - result = gfc_copy_expr (e); - mpc_conj (result->value.complex, result->value.complex, GFC_MPC_RND_MODE); - - return range_check (result, "CONJG"); -} - - -/* Simplify atan2d (x) where the unit is degree. */ - -gfc_expr * -gfc_simplify_atan2d (gfc_expr *y, gfc_expr *x) -{ - gfc_expr *result; - - if (x->expr_type != EXPR_CONSTANT || y->expr_type != EXPR_CONSTANT) - return NULL; - - if (mpfr_zero_p (y->value.real) && mpfr_zero_p (x->value.real)) - { - gfc_error ("If first argument of ATAN2D at %L is zero, then the " - "second argument must not be zero", &y->where); - return &gfc_bad_expr; - } - - result = gfc_get_constant_expr (x->ts.type, x->ts.kind, &x->where); - mpfr_atan2 (result->value.real, y->value.real, x->value.real, GFC_RND_MODE); - rad2deg (result->value.real); - - return range_check (result, "ATAN2D"); -} - - -gfc_expr * -gfc_simplify_cos (gfc_expr *x) -{ - gfc_expr *result; - - if (x->expr_type != EXPR_CONSTANT) - return NULL; - - result = gfc_get_constant_expr (x->ts.type, x->ts.kind, &x->where); - - switch (x->ts.type) - { - case BT_REAL: - mpfr_cos (result->value.real, x->value.real, GFC_RND_MODE); - break; - - case BT_COMPLEX: - gfc_set_model_kind (x->ts.kind); - mpc_cos (result->value.complex, x->value.complex, GFC_MPC_RND_MODE); - break; - - default: - gfc_internal_error ("in gfc_simplify_cos(): Bad type"); - } - - return range_check (result, "COS"); -} - - -static void -deg2rad (mpfr_t x) -{ - mpfr_t d2r; - - mpfr_init (d2r); - mpfr_const_pi (d2r, GFC_RND_MODE); - mpfr_div_ui (d2r, d2r, 180, GFC_RND_MODE); - mpfr_mul (x, x, d2r, GFC_RND_MODE); - mpfr_clear (d2r); -} - - -/* Simplification routines for SIND, COSD, TAND. */ -#include "trigd_fe.inc" - - -/* Simplify COSD(X) where X has the unit of degree. */ - -gfc_expr * -gfc_simplify_cosd (gfc_expr *x) -{ - gfc_expr *result; - - if (x->expr_type != EXPR_CONSTANT) - return NULL; - - result = gfc_get_constant_expr (x->ts.type, x->ts.kind, &x->where); - mpfr_set (result->value.real, x->value.real, GFC_RND_MODE); - simplify_cosd (result->value.real); - - return range_check (result, "COSD"); -} - - -/* Simplify SIND(X) where X has the unit of degree. */ - -gfc_expr * -gfc_simplify_sind (gfc_expr *x) -{ - gfc_expr *result; - - if (x->expr_type != EXPR_CONSTANT) - return NULL; - - result = gfc_get_constant_expr (x->ts.type, x->ts.kind, &x->where); - mpfr_set (result->value.real, x->value.real, GFC_RND_MODE); - simplify_sind (result->value.real); - - return range_check (result, "SIND"); -} - - -/* Simplify TAND(X) where X has the unit of degree. */ - -gfc_expr * -gfc_simplify_tand (gfc_expr *x) -{ - gfc_expr *result; - - if (x->expr_type != EXPR_CONSTANT) - return NULL; - - result = gfc_get_constant_expr (x->ts.type, x->ts.kind, &x->where); - mpfr_set (result->value.real, x->value.real, GFC_RND_MODE); - simplify_tand (result->value.real); - - return range_check (result, "TAND"); -} - - -/* Simplify COTAND(X) where X has the unit of degree. */ - -gfc_expr * -gfc_simplify_cotand (gfc_expr *x) -{ - gfc_expr *result; - - if (x->expr_type != EXPR_CONSTANT) - return NULL; - - /* Implement COTAND = -TAND(x+90). - TAND offers correct exact values for multiples of 30 degrees. - This implementation is also compatible with the behavior of some legacy - compilers. Keep this consistent with gfc_conv_intrinsic_cotand. */ - result = gfc_get_constant_expr (x->ts.type, x->ts.kind, &x->where); - mpfr_set (result->value.real, x->value.real, GFC_RND_MODE); - mpfr_add_ui (result->value.real, result->value.real, 90, GFC_RND_MODE); - simplify_tand (result->value.real); - mpfr_neg (result->value.real, result->value.real, GFC_RND_MODE); - - return range_check (result, "COTAND"); -} - - -gfc_expr * -gfc_simplify_cosh (gfc_expr *x) -{ - gfc_expr *result; - - if (x->expr_type != EXPR_CONSTANT) - return NULL; - - result = gfc_get_constant_expr (x->ts.type, x->ts.kind, &x->where); - - switch (x->ts.type) - { - case BT_REAL: - mpfr_cosh (result->value.real, x->value.real, GFC_RND_MODE); - break; - - case BT_COMPLEX: - mpc_cosh (result->value.complex, x->value.complex, GFC_MPC_RND_MODE); - break; - - default: - gcc_unreachable (); - } - - return range_check (result, "COSH"); -} - - -gfc_expr * -gfc_simplify_count (gfc_expr *mask, gfc_expr *dim, gfc_expr *kind) -{ - gfc_expr *result; - bool size_zero; - - size_zero = gfc_is_size_zero_array (mask); - - if (!(is_constant_array_expr (mask) || size_zero) - || !gfc_is_constant_expr (dim) - || !gfc_is_constant_expr (kind)) - return NULL; - - result = transformational_result (mask, dim, - BT_INTEGER, - get_kind (BT_INTEGER, kind, "COUNT", - gfc_default_integer_kind), - &mask->where); - - init_result_expr (result, 0, NULL); - - if (size_zero) - return result; - - /* Passing MASK twice, once as data array, once as mask. - Whenever gfc_count is called, '1' is added to the result. */ - return !dim || mask->rank == 1 ? - simplify_transformation_to_scalar (result, mask, mask, gfc_count) : - simplify_transformation_to_array (result, mask, dim, mask, gfc_count, NULL); -} - -/* Simplification routine for cshift. This works by copying the array - expressions into a one-dimensional array, shuffling the values into another - one-dimensional array and creating the new array expression from this. The - shuffling part is basically taken from the library routine. */ - -gfc_expr * -gfc_simplify_cshift (gfc_expr *array, gfc_expr *shift, gfc_expr *dim) -{ - gfc_expr *result; - int which; - gfc_expr **arrayvec, **resultvec; - gfc_expr **rptr, **sptr; - mpz_t size; - size_t arraysize, shiftsize, i; - gfc_constructor *array_ctor, *shift_ctor; - ssize_t *shiftvec, *hptr; - ssize_t shift_val, len; - ssize_t count[GFC_MAX_DIMENSIONS], extent[GFC_MAX_DIMENSIONS], - hs_ex[GFC_MAX_DIMENSIONS + 1], - hstride[GFC_MAX_DIMENSIONS], sstride[GFC_MAX_DIMENSIONS], - a_extent[GFC_MAX_DIMENSIONS], a_stride[GFC_MAX_DIMENSIONS], - h_extent[GFC_MAX_DIMENSIONS], - ss_ex[GFC_MAX_DIMENSIONS + 1]; - ssize_t rsoffset; - int d, n; - bool continue_loop; - gfc_expr **src, **dest; - - if (!is_constant_array_expr (array)) - return NULL; - - if (shift->rank > 0) - gfc_simplify_expr (shift, 1); - - if (!gfc_is_constant_expr (shift)) - return NULL; - - /* Make dim zero-based. */ - if (dim) - { - if (!gfc_is_constant_expr (dim)) - return NULL; - which = mpz_get_si (dim->value.integer) - 1; - } - else - which = 0; - - if (array->shape == NULL) - return NULL; - - gfc_array_size (array, &size); - arraysize = mpz_get_ui (size); - mpz_clear (size); - - result = gfc_get_array_expr (array->ts.type, array->ts.kind, &array->where); - result->shape = gfc_copy_shape (array->shape, array->rank); - result->rank = array->rank; - result->ts.u.derived = array->ts.u.derived; - - if (arraysize == 0) - return result; - - arrayvec = XCNEWVEC (gfc_expr *, arraysize); - array_ctor = gfc_constructor_first (array->value.constructor); - for (i = 0; i < arraysize; i++) - { - arrayvec[i] = array_ctor->expr; - array_ctor = gfc_constructor_next (array_ctor); - } - - resultvec = XCNEWVEC (gfc_expr *, arraysize); - - extent[0] = 1; - count[0] = 0; - - for (d=0; d < array->rank; d++) - { - a_extent[d] = mpz_get_si (array->shape[d]); - a_stride[d] = d == 0 ? 1 : a_stride[d-1] * a_extent[d-1]; - } - - if (shift->rank > 0) - { - gfc_array_size (shift, &size); - shiftsize = mpz_get_ui (size); - mpz_clear (size); - shiftvec = XCNEWVEC (ssize_t, shiftsize); - shift_ctor = gfc_constructor_first (shift->value.constructor); - for (d = 0; d < shift->rank; d++) - { - h_extent[d] = mpz_get_si (shift->shape[d]); - hstride[d] = d == 0 ? 1 : hstride[d-1] * h_extent[d-1]; - } - } - else - shiftvec = NULL; - - /* Shut up compiler */ - len = 1; - rsoffset = 1; - - n = 0; - for (d=0; d < array->rank; d++) - { - if (d == which) - { - rsoffset = a_stride[d]; - len = a_extent[d]; - } - else - { - count[n] = 0; - extent[n] = a_extent[d]; - sstride[n] = a_stride[d]; - ss_ex[n] = sstride[n] * extent[n]; - if (shiftvec) - hs_ex[n] = hstride[n] * extent[n]; - n++; - } - } - ss_ex[n] = 0; - hs_ex[n] = 0; - - if (shiftvec) - { - for (i = 0; i < shiftsize; i++) - { - ssize_t val; - val = mpz_get_si (shift_ctor->expr->value.integer); - val = val % len; - if (val < 0) - val += len; - shiftvec[i] = val; - shift_ctor = gfc_constructor_next (shift_ctor); - } - shift_val = 0; - } - else - { - shift_val = mpz_get_si (shift->value.integer); - shift_val = shift_val % len; - if (shift_val < 0) - shift_val += len; - } - - continue_loop = true; - d = array->rank; - rptr = resultvec; - sptr = arrayvec; - hptr = shiftvec; - - while (continue_loop) - { - ssize_t sh; - if (shiftvec) - sh = *hptr; - else - sh = shift_val; - - src = &sptr[sh * rsoffset]; - dest = rptr; - for (n = 0; n < len - sh; n++) - { - *dest = *src; - dest += rsoffset; - src += rsoffset; - } - src = sptr; - for ( n = 0; n < sh; n++) - { - *dest = *src; - dest += rsoffset; - src += rsoffset; - } - rptr += sstride[0]; - sptr += sstride[0]; - if (shiftvec) - hptr += hstride[0]; - count[0]++; - n = 0; - while (count[n] == extent[n]) - { - count[n] = 0; - rptr -= ss_ex[n]; - sptr -= ss_ex[n]; - if (shiftvec) - hptr -= hs_ex[n]; - n++; - if (n >= d - 1) - { - continue_loop = false; - break; - } - else - { - count[n]++; - rptr += sstride[n]; - sptr += sstride[n]; - if (shiftvec) - hptr += hstride[n]; - } - } - } - - for (i = 0; i < arraysize; i++) - { - gfc_constructor_append_expr (&result->value.constructor, - gfc_copy_expr (resultvec[i]), - NULL); - } - return result; -} - - -gfc_expr * -gfc_simplify_dcmplx (gfc_expr *x, gfc_expr *y) -{ - return simplify_cmplx ("DCMPLX", x, y, gfc_default_double_kind); -} - - -gfc_expr * -gfc_simplify_dble (gfc_expr *e) -{ - gfc_expr *result = NULL; - int tmp1, tmp2; - - if (e->expr_type != EXPR_CONSTANT) - return NULL; - - /* For explicit conversion, turn off -Wconversion and -Wconversion-extra - warnings. */ - tmp1 = warn_conversion; - tmp2 = warn_conversion_extra; - warn_conversion = warn_conversion_extra = 0; - - result = gfc_convert_constant (e, BT_REAL, gfc_default_double_kind); - - warn_conversion = tmp1; - warn_conversion_extra = tmp2; - - if (result == &gfc_bad_expr) - return &gfc_bad_expr; - - return range_check (result, "DBLE"); -} - - -gfc_expr * -gfc_simplify_digits (gfc_expr *x) -{ - int i, digits; - - i = gfc_validate_kind (x->ts.type, x->ts.kind, false); - - switch (x->ts.type) - { - case BT_INTEGER: - digits = gfc_integer_kinds[i].digits; - break; - - case BT_REAL: - case BT_COMPLEX: - digits = gfc_real_kinds[i].digits; - break; - - default: - gcc_unreachable (); - } - - return gfc_get_int_expr (gfc_default_integer_kind, NULL, digits); -} - - -gfc_expr * -gfc_simplify_dim (gfc_expr *x, gfc_expr *y) -{ - gfc_expr *result; - int kind; - - if (x->expr_type != EXPR_CONSTANT || y->expr_type != EXPR_CONSTANT) - return NULL; - - kind = x->ts.kind > y->ts.kind ? x->ts.kind : y->ts.kind; - result = gfc_get_constant_expr (x->ts.type, kind, &x->where); - - switch (x->ts.type) - { - case BT_INTEGER: - if (mpz_cmp (x->value.integer, y->value.integer) > 0) - mpz_sub (result->value.integer, x->value.integer, y->value.integer); - else - mpz_set_ui (result->value.integer, 0); - - break; - - case BT_REAL: - if (mpfr_cmp (x->value.real, y->value.real) > 0) - mpfr_sub (result->value.real, x->value.real, y->value.real, - GFC_RND_MODE); - else - mpfr_set_ui (result->value.real, 0, GFC_RND_MODE); - - break; - - default: - gfc_internal_error ("gfc_simplify_dim(): Bad type"); - } - - return range_check (result, "DIM"); -} - - -gfc_expr* -gfc_simplify_dot_product (gfc_expr *vector_a, gfc_expr *vector_b) -{ - /* If vector_a is a zero-sized array, the result is 0 for INTEGER, - REAL, and COMPLEX types and .false. for LOGICAL. */ - if (vector_a->shape && mpz_get_si (vector_a->shape[0]) == 0) - { - if (vector_a->ts.type == BT_LOGICAL) - return gfc_get_logical_expr (gfc_default_logical_kind, NULL, false); - else - return gfc_get_int_expr (gfc_default_integer_kind, NULL, 0); - } - - if (!is_constant_array_expr (vector_a) - || !is_constant_array_expr (vector_b)) - return NULL; - - return compute_dot_product (vector_a, 1, 0, vector_b, 1, 0, true); -} - - -gfc_expr * -gfc_simplify_dprod (gfc_expr *x, gfc_expr *y) -{ - gfc_expr *a1, *a2, *result; - - if (x->expr_type != EXPR_CONSTANT || y->expr_type != EXPR_CONSTANT) - return NULL; - - a1 = gfc_real2real (x, gfc_default_double_kind); - a2 = gfc_real2real (y, gfc_default_double_kind); - - result = gfc_get_constant_expr (BT_REAL, gfc_default_double_kind, &x->where); - mpfr_mul (result->value.real, a1->value.real, a2->value.real, GFC_RND_MODE); - - gfc_free_expr (a2); - gfc_free_expr (a1); - - return range_check (result, "DPROD"); -} - - -static gfc_expr * -simplify_dshift (gfc_expr *arg1, gfc_expr *arg2, gfc_expr *shiftarg, - bool right) -{ - gfc_expr *result; - int i, k, size, shift; - - if (arg1->expr_type != EXPR_CONSTANT || arg2->expr_type != EXPR_CONSTANT - || shiftarg->expr_type != EXPR_CONSTANT) - return NULL; - - k = gfc_validate_kind (BT_INTEGER, arg1->ts.kind, false); - size = gfc_integer_kinds[k].bit_size; - - gfc_extract_int (shiftarg, &shift); - - /* DSHIFTR(I,J,SHIFT) = DSHIFTL(I,J,SIZE-SHIFT). */ - if (right) - shift = size - shift; - - result = gfc_get_constant_expr (BT_INTEGER, arg1->ts.kind, &arg1->where); - mpz_set_ui (result->value.integer, 0); - - for (i = 0; i < shift; i++) - if (mpz_tstbit (arg2->value.integer, size - shift + i)) - mpz_setbit (result->value.integer, i); - - for (i = 0; i < size - shift; i++) - if (mpz_tstbit (arg1->value.integer, i)) - mpz_setbit (result->value.integer, shift + i); - - /* Convert to a signed value. */ - gfc_convert_mpz_to_signed (result->value.integer, size); - - return result; -} - - -gfc_expr * -gfc_simplify_dshiftr (gfc_expr *arg1, gfc_expr *arg2, gfc_expr *shiftarg) -{ - return simplify_dshift (arg1, arg2, shiftarg, true); -} - - -gfc_expr * -gfc_simplify_dshiftl (gfc_expr *arg1, gfc_expr *arg2, gfc_expr *shiftarg) -{ - return simplify_dshift (arg1, arg2, shiftarg, false); -} - - -gfc_expr * -gfc_simplify_eoshift (gfc_expr *array, gfc_expr *shift, gfc_expr *boundary, - gfc_expr *dim) -{ - bool temp_boundary; - gfc_expr *bnd; - gfc_expr *result; - int which; - gfc_expr **arrayvec, **resultvec; - gfc_expr **rptr, **sptr; - mpz_t size; - size_t arraysize, i; - gfc_constructor *array_ctor, *shift_ctor, *bnd_ctor; - ssize_t shift_val, len; - ssize_t count[GFC_MAX_DIMENSIONS], extent[GFC_MAX_DIMENSIONS], - sstride[GFC_MAX_DIMENSIONS], a_extent[GFC_MAX_DIMENSIONS], - a_stride[GFC_MAX_DIMENSIONS], ss_ex[GFC_MAX_DIMENSIONS + 1]; - ssize_t rsoffset; - int d, n; - bool continue_loop; - gfc_expr **src, **dest; - size_t s_len; - - if (!is_constant_array_expr (array)) - return NULL; - - if (shift->rank > 0) - gfc_simplify_expr (shift, 1); - - if (!gfc_is_constant_expr (shift)) - return NULL; - - if (boundary) - { - if (boundary->rank > 0) - gfc_simplify_expr (boundary, 1); - - if (!gfc_is_constant_expr (boundary)) - return NULL; - } - - if (dim) - { - if (!gfc_is_constant_expr (dim)) - return NULL; - which = mpz_get_si (dim->value.integer) - 1; - } - else - which = 0; - - s_len = 0; - if (boundary == NULL) - { - temp_boundary = true; - switch (array->ts.type) - { - - case BT_INTEGER: - bnd = gfc_get_int_expr (array->ts.kind, NULL, 0); - break; - - case BT_LOGICAL: - bnd = gfc_get_logical_expr (array->ts.kind, NULL, 0); - break; - - case BT_REAL: - bnd = gfc_get_constant_expr (array->ts.type, array->ts.kind, &gfc_current_locus); - mpfr_set_ui (bnd->value.real, 0, GFC_RND_MODE); - break; - - case BT_COMPLEX: - bnd = gfc_get_constant_expr (array->ts.type, array->ts.kind, &gfc_current_locus); - mpc_set_ui (bnd->value.complex, 0, GFC_RND_MODE); - break; - - case BT_CHARACTER: - s_len = mpz_get_ui (array->ts.u.cl->length->value.integer); - bnd = gfc_get_character_expr (array->ts.kind, &gfc_current_locus, NULL, s_len); - break; - - default: - gcc_unreachable(); - - } - } - else - { - temp_boundary = false; - bnd = boundary; - } - - gfc_array_size (array, &size); - arraysize = mpz_get_ui (size); - mpz_clear (size); - - result = gfc_get_array_expr (array->ts.type, array->ts.kind, &array->where); - result->shape = gfc_copy_shape (array->shape, array->rank); - result->rank = array->rank; - result->ts = array->ts; - - if (arraysize == 0) - goto final; - - arrayvec = XCNEWVEC (gfc_expr *, arraysize); - array_ctor = gfc_constructor_first (array->value.constructor); - for (i = 0; i < arraysize; i++) - { - arrayvec[i] = array_ctor->expr; - array_ctor = gfc_constructor_next (array_ctor); - } - - resultvec = XCNEWVEC (gfc_expr *, arraysize); - - extent[0] = 1; - count[0] = 0; - - for (d=0; d < array->rank; d++) - { - a_extent[d] = mpz_get_si (array->shape[d]); - a_stride[d] = d == 0 ? 1 : a_stride[d-1] * a_extent[d-1]; - } - - if (shift->rank > 0) - { - shift_ctor = gfc_constructor_first (shift->value.constructor); - shift_val = 0; - } - else - { - shift_ctor = NULL; - shift_val = mpz_get_si (shift->value.integer); - } - - if (bnd->rank > 0) - bnd_ctor = gfc_constructor_first (bnd->value.constructor); - else - bnd_ctor = NULL; - - /* Shut up compiler */ - len = 1; - rsoffset = 1; - - n = 0; - for (d=0; d < array->rank; d++) - { - if (d == which) - { - rsoffset = a_stride[d]; - len = a_extent[d]; - } - else - { - count[n] = 0; - extent[n] = a_extent[d]; - sstride[n] = a_stride[d]; - ss_ex[n] = sstride[n] * extent[n]; - n++; - } - } - ss_ex[n] = 0; - - continue_loop = true; - d = array->rank; - rptr = resultvec; - sptr = arrayvec; - - while (continue_loop) - { - ssize_t sh, delta; - - if (shift_ctor) - sh = mpz_get_si (shift_ctor->expr->value.integer); - else - sh = shift_val; - - if (( sh >= 0 ? sh : -sh ) > len) - { - delta = len; - sh = len; - } - else - delta = (sh >= 0) ? sh: -sh; - - if (sh > 0) - { - src = &sptr[delta * rsoffset]; - dest = rptr; - } - else - { - src = sptr; - dest = &rptr[delta * rsoffset]; - } - - for (n = 0; n < len - delta; n++) - { - *dest = *src; - dest += rsoffset; - src += rsoffset; - } - - if (sh < 0) - dest = rptr; - - n = delta; - - if (bnd_ctor) - { - while (n--) - { - *dest = gfc_copy_expr (bnd_ctor->expr); - dest += rsoffset; - } - } - else - { - while (n--) - { - *dest = gfc_copy_expr (bnd); - dest += rsoffset; - } - } - rptr += sstride[0]; - sptr += sstride[0]; - if (shift_ctor) - shift_ctor = gfc_constructor_next (shift_ctor); - - if (bnd_ctor) - bnd_ctor = gfc_constructor_next (bnd_ctor); - - count[0]++; - n = 0; - while (count[n] == extent[n]) - { - count[n] = 0; - rptr -= ss_ex[n]; - sptr -= ss_ex[n]; - n++; - if (n >= d - 1) - { - continue_loop = false; - break; - } - else - { - count[n]++; - rptr += sstride[n]; - sptr += sstride[n]; - } - } - } - - for (i = 0; i < arraysize; i++) - { - gfc_constructor_append_expr (&result->value.constructor, - gfc_copy_expr (resultvec[i]), - NULL); - } - - final: - if (temp_boundary) - gfc_free_expr (bnd); - - return result; -} - -gfc_expr * -gfc_simplify_erf (gfc_expr *x) -{ - gfc_expr *result; - - if (x->expr_type != EXPR_CONSTANT) - return NULL; - - result = gfc_get_constant_expr (x->ts.type, x->ts.kind, &x->where); - mpfr_erf (result->value.real, x->value.real, GFC_RND_MODE); - - return range_check (result, "ERF"); -} - - -gfc_expr * -gfc_simplify_erfc (gfc_expr *x) -{ - gfc_expr *result; - - if (x->expr_type != EXPR_CONSTANT) - return NULL; - - result = gfc_get_constant_expr (x->ts.type, x->ts.kind, &x->where); - mpfr_erfc (result->value.real, x->value.real, GFC_RND_MODE); - - return range_check (result, "ERFC"); -} - - -/* Helper functions to simplify ERFC_SCALED(x) = ERFC(x) * EXP(X**2). */ - -#define MAX_ITER 200 -#define ARG_LIMIT 12 - -/* Calculate ERFC_SCALED directly by its definition: - - ERFC_SCALED(x) = ERFC(x) * EXP(X**2) - - using a large precision for intermediate results. This is used for all - but large values of the argument. */ -static void -fullprec_erfc_scaled (mpfr_t res, mpfr_t arg) -{ - mpfr_prec_t prec; - mpfr_t a, b; - - prec = mpfr_get_default_prec (); - mpfr_set_default_prec (10 * prec); - - mpfr_init (a); - mpfr_init (b); - - mpfr_set (a, arg, GFC_RND_MODE); - mpfr_sqr (b, a, GFC_RND_MODE); - mpfr_exp (b, b, GFC_RND_MODE); - mpfr_erfc (a, a, GFC_RND_MODE); - mpfr_mul (a, a, b, GFC_RND_MODE); - - mpfr_set (res, a, GFC_RND_MODE); - mpfr_set_default_prec (prec); - - mpfr_clear (a); - mpfr_clear (b); -} - -/* Calculate ERFC_SCALED using a power series expansion in 1/arg: - - ERFC_SCALED(x) = 1 / (x * sqrt(pi)) - * (1 + Sum_n (-1)**n * (1 * 3 * 5 * ... * (2n-1)) - / (2 * x**2)**n) - - This is used for large values of the argument. Intermediate calculations - are performed with twice the precision. We don't do a fixed number of - iterations of the sum, but stop when it has converged to the required - precision. */ -static void -asympt_erfc_scaled (mpfr_t res, mpfr_t arg) -{ - mpfr_t sum, x, u, v, w, oldsum, sumtrunc; - mpz_t num; - mpfr_prec_t prec; - unsigned i; - - prec = mpfr_get_default_prec (); - mpfr_set_default_prec (2 * prec); - - mpfr_init (sum); - mpfr_init (x); - mpfr_init (u); - mpfr_init (v); - mpfr_init (w); - mpz_init (num); - - mpfr_init (oldsum); - mpfr_init (sumtrunc); - mpfr_set_prec (oldsum, prec); - mpfr_set_prec (sumtrunc, prec); - - mpfr_set (x, arg, GFC_RND_MODE); - mpfr_set_ui (sum, 1, GFC_RND_MODE); - mpz_set_ui (num, 1); - - mpfr_set (u, x, GFC_RND_MODE); - mpfr_sqr (u, u, GFC_RND_MODE); - mpfr_mul_ui (u, u, 2, GFC_RND_MODE); - mpfr_pow_si (u, u, -1, GFC_RND_MODE); - - for (i = 1; i < MAX_ITER; i++) - { - mpfr_set (oldsum, sum, GFC_RND_MODE); - - mpz_mul_ui (num, num, 2 * i - 1); - mpz_neg (num, num); - - mpfr_set (w, u, GFC_RND_MODE); - mpfr_pow_ui (w, w, i, GFC_RND_MODE); - - mpfr_set_z (v, num, GFC_RND_MODE); - mpfr_mul (v, v, w, GFC_RND_MODE); - - mpfr_add (sum, sum, v, GFC_RND_MODE); - - mpfr_set (sumtrunc, sum, GFC_RND_MODE); - if (mpfr_cmp (sumtrunc, oldsum) == 0) - break; - } - - /* We should have converged by now; otherwise, ARG_LIMIT is probably - set too low. */ - gcc_assert (i < MAX_ITER); - - /* Divide by x * sqrt(Pi). */ - mpfr_const_pi (u, GFC_RND_MODE); - mpfr_sqrt (u, u, GFC_RND_MODE); - mpfr_mul (u, u, x, GFC_RND_MODE); - mpfr_div (sum, sum, u, GFC_RND_MODE); - - mpfr_set (res, sum, GFC_RND_MODE); - mpfr_set_default_prec (prec); - - mpfr_clears (sum, x, u, v, w, oldsum, sumtrunc, NULL); - mpz_clear (num); -} - - -gfc_expr * -gfc_simplify_erfc_scaled (gfc_expr *x) -{ - gfc_expr *result; - - if (x->expr_type != EXPR_CONSTANT) - return NULL; - - result = gfc_get_constant_expr (x->ts.type, x->ts.kind, &x->where); - if (mpfr_cmp_d (x->value.real, ARG_LIMIT) >= 0) - asympt_erfc_scaled (result->value.real, x->value.real); - else - fullprec_erfc_scaled (result->value.real, x->value.real); - - return range_check (result, "ERFC_SCALED"); -} - -#undef MAX_ITER -#undef ARG_LIMIT - - -gfc_expr * -gfc_simplify_epsilon (gfc_expr *e) -{ - gfc_expr *result; - int i; - - i = gfc_validate_kind (e->ts.type, e->ts.kind, false); - - result = gfc_get_constant_expr (BT_REAL, e->ts.kind, &e->where); - mpfr_set (result->value.real, gfc_real_kinds[i].epsilon, GFC_RND_MODE); - - return range_check (result, "EPSILON"); -} - - -gfc_expr * -gfc_simplify_exp (gfc_expr *x) -{ - gfc_expr *result; - - if (x->expr_type != EXPR_CONSTANT) - return NULL; - - result = gfc_get_constant_expr (x->ts.type, x->ts.kind, &x->where); - - switch (x->ts.type) - { - case BT_REAL: - mpfr_exp (result->value.real, x->value.real, GFC_RND_MODE); - break; - - case BT_COMPLEX: - gfc_set_model_kind (x->ts.kind); - mpc_exp (result->value.complex, x->value.complex, GFC_MPC_RND_MODE); - break; - - default: - gfc_internal_error ("in gfc_simplify_exp(): Bad type"); - } - - return range_check (result, "EXP"); -} - - -gfc_expr * -gfc_simplify_exponent (gfc_expr *x) -{ - long int val; - gfc_expr *result; - - if (x->expr_type != EXPR_CONSTANT) - return NULL; - - result = gfc_get_constant_expr (BT_INTEGER, gfc_default_integer_kind, - &x->where); - - /* EXPONENT(inf) = EXPONENT(nan) = HUGE(0) */ - if (mpfr_inf_p (x->value.real) || mpfr_nan_p (x->value.real)) - { - int i = gfc_validate_kind (BT_INTEGER, gfc_default_integer_kind, false); - mpz_set (result->value.integer, gfc_integer_kinds[i].huge); - return result; - } - - /* EXPONENT(+/- 0.0) = 0 */ - if (mpfr_zero_p (x->value.real)) - { - mpz_set_ui (result->value.integer, 0); - return result; - } - - gfc_set_model (x->value.real); - - val = (long int) mpfr_get_exp (x->value.real); - mpz_set_si (result->value.integer, val); - - return range_check (result, "EXPONENT"); -} - - -gfc_expr * -gfc_simplify_failed_or_stopped_images (gfc_expr *team ATTRIBUTE_UNUSED, - gfc_expr *kind) -{ - if (flag_coarray == GFC_FCOARRAY_NONE) - { - gfc_current_locus = *gfc_current_intrinsic_where; - gfc_fatal_error ("Coarrays disabled at %C, use %<-fcoarray=%> to enable"); - return &gfc_bad_expr; - } - - if (flag_coarray == GFC_FCOARRAY_SINGLE) - { - gfc_expr *result; - int actual_kind; - if (kind) - gfc_extract_int (kind, &actual_kind); - else - actual_kind = gfc_default_integer_kind; - - result = gfc_get_array_expr (BT_INTEGER, actual_kind, &gfc_current_locus); - result->rank = 1; - return result; - } - - /* For fcoarray = lib no simplification is possible, because it is not known - what images failed or are stopped at compile time. */ - return NULL; -} - - -gfc_expr * -gfc_simplify_get_team (gfc_expr *level ATTRIBUTE_UNUSED) -{ - if (flag_coarray == GFC_FCOARRAY_NONE) - { - gfc_current_locus = *gfc_current_intrinsic_where; - gfc_fatal_error ("Coarrays disabled at %C, use %<-fcoarray=%> to enable"); - return &gfc_bad_expr; - } - - if (flag_coarray == GFC_FCOARRAY_SINGLE) - { - gfc_expr *result; - result = gfc_get_array_expr (BT_INTEGER, gfc_default_integer_kind, &gfc_current_locus); - result->rank = 0; - return result; - } - - /* For fcoarray = lib no simplification is possible, because it is not known - what images failed or are stopped at compile time. */ - return NULL; -} - - -gfc_expr * -gfc_simplify_float (gfc_expr *a) -{ - gfc_expr *result; - - if (a->expr_type != EXPR_CONSTANT) - return NULL; - - result = gfc_int2real (a, gfc_default_real_kind); - - return range_check (result, "FLOAT"); -} - - -static bool -is_last_ref_vtab (gfc_expr *e) -{ - gfc_ref *ref; - gfc_component *comp = NULL; - - if (e->expr_type != EXPR_VARIABLE) - return false; - - for (ref = e->ref; ref; ref = ref->next) - if (ref->type == REF_COMPONENT) - comp = ref->u.c.component; - - if (!e->ref || !comp) - return e->symtree->n.sym->attr.vtab; - - if (comp->name[0] == '_' && strcmp (comp->name, "_vptr") == 0) - return true; - - return false; -} - - -gfc_expr * -gfc_simplify_extends_type_of (gfc_expr *a, gfc_expr *mold) -{ - /* Avoid simplification of resolved symbols. */ - if (is_last_ref_vtab (a) || is_last_ref_vtab (mold)) - return NULL; - - if (a->ts.type == BT_DERIVED && mold->ts.type == BT_DERIVED) - return gfc_get_logical_expr (gfc_default_logical_kind, &a->where, - gfc_type_is_extension_of (mold->ts.u.derived, - a->ts.u.derived)); - - if (UNLIMITED_POLY (a) || UNLIMITED_POLY (mold)) - return NULL; - - /* Return .false. if the dynamic type can never be an extension. */ - if ((a->ts.type == BT_CLASS && mold->ts.type == BT_CLASS - && !gfc_type_is_extension_of - (mold->ts.u.derived->components->ts.u.derived, - a->ts.u.derived->components->ts.u.derived) - && !gfc_type_is_extension_of - (a->ts.u.derived->components->ts.u.derived, - mold->ts.u.derived->components->ts.u.derived)) - || (a->ts.type == BT_DERIVED && mold->ts.type == BT_CLASS - && !gfc_type_is_extension_of - (mold->ts.u.derived->components->ts.u.derived, - a->ts.u.derived)) - || (a->ts.type == BT_CLASS && mold->ts.type == BT_DERIVED - && !gfc_type_is_extension_of - (mold->ts.u.derived, - a->ts.u.derived->components->ts.u.derived) - && !gfc_type_is_extension_of - (a->ts.u.derived->components->ts.u.derived, - mold->ts.u.derived))) - return gfc_get_logical_expr (gfc_default_logical_kind, &a->where, false); - - /* Return .true. if the dynamic type is guaranteed to be an extension. */ - if (a->ts.type == BT_CLASS && mold->ts.type == BT_DERIVED - && gfc_type_is_extension_of (mold->ts.u.derived, - a->ts.u.derived->components->ts.u.derived)) - return gfc_get_logical_expr (gfc_default_logical_kind, &a->where, true); - - return NULL; -} - - -gfc_expr * -gfc_simplify_same_type_as (gfc_expr *a, gfc_expr *b) -{ - /* Avoid simplification of resolved symbols. */ - if (is_last_ref_vtab (a) || is_last_ref_vtab (b)) - return NULL; - - /* Return .false. if the dynamic type can never be the - same. */ - if (((a->ts.type == BT_CLASS && gfc_expr_attr (a).class_ok) - || (b->ts.type == BT_CLASS && gfc_expr_attr (b).class_ok)) - && !gfc_type_compatible (&a->ts, &b->ts) - && !gfc_type_compatible (&b->ts, &a->ts)) - return gfc_get_logical_expr (gfc_default_logical_kind, &a->where, false); - - if (a->ts.type != BT_DERIVED || b->ts.type != BT_DERIVED) - return NULL; - - return gfc_get_logical_expr (gfc_default_logical_kind, &a->where, - gfc_compare_derived_types (a->ts.u.derived, - b->ts.u.derived)); -} - - -gfc_expr * -gfc_simplify_floor (gfc_expr *e, gfc_expr *k) -{ - gfc_expr *result; - mpfr_t floor; - int kind; - - kind = get_kind (BT_INTEGER, k, "FLOOR", gfc_default_integer_kind); - if (kind == -1) - gfc_internal_error ("gfc_simplify_floor(): Bad kind"); - - if (e->expr_type != EXPR_CONSTANT) - return NULL; - - mpfr_init2 (floor, mpfr_get_prec (e->value.real)); - mpfr_floor (floor, e->value.real); - - result = gfc_get_constant_expr (BT_INTEGER, kind, &e->where); - gfc_mpfr_to_mpz (result->value.integer, floor, &e->where); - - mpfr_clear (floor); - - return range_check (result, "FLOOR"); -} - - -gfc_expr * -gfc_simplify_fraction (gfc_expr *x) -{ - gfc_expr *result; - mpfr_exp_t e; - - if (x->expr_type != EXPR_CONSTANT) - return NULL; - - result = gfc_get_constant_expr (BT_REAL, x->ts.kind, &x->where); - - /* FRACTION(inf) = NaN. */ - if (mpfr_inf_p (x->value.real)) - { - mpfr_set_nan (result->value.real); - return result; - } - - /* mpfr_frexp() correctly handles zeros and NaNs. */ - mpfr_frexp (&e, result->value.real, x->value.real, GFC_RND_MODE); - - return range_check (result, "FRACTION"); -} - - -gfc_expr * -gfc_simplify_gamma (gfc_expr *x) -{ - gfc_expr *result; - - if (x->expr_type != EXPR_CONSTANT) - return NULL; - - result = gfc_get_constant_expr (x->ts.type, x->ts.kind, &x->where); - mpfr_gamma (result->value.real, x->value.real, GFC_RND_MODE); - - return range_check (result, "GAMMA"); -} - - -gfc_expr * -gfc_simplify_huge (gfc_expr *e) -{ - gfc_expr *result; - int i; - - i = gfc_validate_kind (e->ts.type, e->ts.kind, false); - result = gfc_get_constant_expr (e->ts.type, e->ts.kind, &e->where); - - switch (e->ts.type) - { - case BT_INTEGER: - mpz_set (result->value.integer, gfc_integer_kinds[i].huge); - break; - - case BT_REAL: - mpfr_set (result->value.real, gfc_real_kinds[i].huge, GFC_RND_MODE); - break; - - default: - gcc_unreachable (); - } - - return result; -} - - -gfc_expr * -gfc_simplify_hypot (gfc_expr *x, gfc_expr *y) -{ - gfc_expr *result; - - if (x->expr_type != EXPR_CONSTANT || y->expr_type != EXPR_CONSTANT) - return NULL; - - result = gfc_get_constant_expr (x->ts.type, x->ts.kind, &x->where); - mpfr_hypot (result->value.real, x->value.real, y->value.real, GFC_RND_MODE); - return range_check (result, "HYPOT"); -} - - -/* We use the processor's collating sequence, because all - systems that gfortran currently works on are ASCII. */ - -gfc_expr * -gfc_simplify_iachar (gfc_expr *e, gfc_expr *kind) -{ - gfc_expr *result; - gfc_char_t index; - int k; - - if (e->expr_type != EXPR_CONSTANT) - return NULL; - - if (e->value.character.length != 1) - { - gfc_error ("Argument of IACHAR at %L must be of length one", &e->where); - return &gfc_bad_expr; - } - - index = e->value.character.string[0]; - - if (warn_surprising && index > 127) - gfc_warning (OPT_Wsurprising, - "Argument of IACHAR function at %L outside of range 0..127", - &e->where); - - k = get_kind (BT_INTEGER, kind, "IACHAR", gfc_default_integer_kind); - if (k == -1) - return &gfc_bad_expr; - - result = gfc_get_int_expr (k, &e->where, index); - - return range_check (result, "IACHAR"); -} - - -static gfc_expr * -do_bit_and (gfc_expr *result, gfc_expr *e) -{ - gcc_assert (e->ts.type == BT_INTEGER && e->expr_type == EXPR_CONSTANT); - gcc_assert (result->ts.type == BT_INTEGER - && result->expr_type == EXPR_CONSTANT); - - mpz_and (result->value.integer, result->value.integer, e->value.integer); - return result; -} - - -gfc_expr * -gfc_simplify_iall (gfc_expr *array, gfc_expr *dim, gfc_expr *mask) -{ - return simplify_transformation (array, dim, mask, -1, do_bit_and); -} - - -static gfc_expr * -do_bit_ior (gfc_expr *result, gfc_expr *e) -{ - gcc_assert (e->ts.type == BT_INTEGER && e->expr_type == EXPR_CONSTANT); - gcc_assert (result->ts.type == BT_INTEGER - && result->expr_type == EXPR_CONSTANT); - - mpz_ior (result->value.integer, result->value.integer, e->value.integer); - return result; -} - - -gfc_expr * -gfc_simplify_iany (gfc_expr *array, gfc_expr *dim, gfc_expr *mask) -{ - return simplify_transformation (array, dim, mask, 0, do_bit_ior); -} - - -gfc_expr * -gfc_simplify_iand (gfc_expr *x, gfc_expr *y) -{ - gfc_expr *result; - - if (x->expr_type != EXPR_CONSTANT || y->expr_type != EXPR_CONSTANT) - return NULL; - - result = gfc_get_constant_expr (BT_INTEGER, x->ts.kind, &x->where); - mpz_and (result->value.integer, x->value.integer, y->value.integer); - - return range_check (result, "IAND"); -} - - -gfc_expr * -gfc_simplify_ibclr (gfc_expr *x, gfc_expr *y) -{ - gfc_expr *result; - int k, pos; - - if (x->expr_type != EXPR_CONSTANT || y->expr_type != EXPR_CONSTANT) - return NULL; - - gfc_extract_int (y, &pos); - - k = gfc_validate_kind (x->ts.type, x->ts.kind, false); - - result = gfc_copy_expr (x); - - convert_mpz_to_unsigned (result->value.integer, - gfc_integer_kinds[k].bit_size); - - mpz_clrbit (result->value.integer, pos); - - gfc_convert_mpz_to_signed (result->value.integer, - gfc_integer_kinds[k].bit_size); - - return result; -} - - -gfc_expr * -gfc_simplify_ibits (gfc_expr *x, gfc_expr *y, gfc_expr *z) -{ - gfc_expr *result; - int pos, len; - int i, k, bitsize; - int *bits; - - if (x->expr_type != EXPR_CONSTANT - || y->expr_type != EXPR_CONSTANT - || z->expr_type != EXPR_CONSTANT) - return NULL; - - gfc_extract_int (y, &pos); - gfc_extract_int (z, &len); - - k = gfc_validate_kind (BT_INTEGER, x->ts.kind, false); - - bitsize = gfc_integer_kinds[k].bit_size; - - if (pos + len > bitsize) - { - gfc_error ("Sum of second and third arguments of IBITS exceeds " - "bit size at %L", &y->where); - return &gfc_bad_expr; - } - - result = gfc_get_constant_expr (x->ts.type, x->ts.kind, &x->where); - convert_mpz_to_unsigned (result->value.integer, - gfc_integer_kinds[k].bit_size); - - bits = XCNEWVEC (int, bitsize); - - for (i = 0; i < bitsize; i++) - bits[i] = 0; - - for (i = 0; i < len; i++) - bits[i] = mpz_tstbit (x->value.integer, i + pos); - - for (i = 0; i < bitsize; i++) - { - if (bits[i] == 0) - mpz_clrbit (result->value.integer, i); - else if (bits[i] == 1) - mpz_setbit (result->value.integer, i); - else - gfc_internal_error ("IBITS: Bad bit"); - } - - free (bits); - - gfc_convert_mpz_to_signed (result->value.integer, - gfc_integer_kinds[k].bit_size); - - return result; -} - - -gfc_expr * -gfc_simplify_ibset (gfc_expr *x, gfc_expr *y) -{ - gfc_expr *result; - int k, pos; - - if (x->expr_type != EXPR_CONSTANT || y->expr_type != EXPR_CONSTANT) - return NULL; - - gfc_extract_int (y, &pos); - - k = gfc_validate_kind (x->ts.type, x->ts.kind, false); - - result = gfc_copy_expr (x); - - convert_mpz_to_unsigned (result->value.integer, - gfc_integer_kinds[k].bit_size); - - mpz_setbit (result->value.integer, pos); - - gfc_convert_mpz_to_signed (result->value.integer, - gfc_integer_kinds[k].bit_size); - - return result; -} - - -gfc_expr * -gfc_simplify_ichar (gfc_expr *e, gfc_expr *kind) -{ - gfc_expr *result; - gfc_char_t index; - int k; - - if (e->expr_type != EXPR_CONSTANT) - return NULL; - - if (e->value.character.length != 1) - { - gfc_error ("Argument of ICHAR at %L must be of length one", &e->where); - return &gfc_bad_expr; - } - - index = e->value.character.string[0]; - - k = get_kind (BT_INTEGER, kind, "ICHAR", gfc_default_integer_kind); - if (k == -1) - return &gfc_bad_expr; - - result = gfc_get_int_expr (k, &e->where, index); - - return range_check (result, "ICHAR"); -} - - -gfc_expr * -gfc_simplify_ieor (gfc_expr *x, gfc_expr *y) -{ - gfc_expr *result; - - if (x->expr_type != EXPR_CONSTANT || y->expr_type != EXPR_CONSTANT) - return NULL; - - result = gfc_get_constant_expr (BT_INTEGER, x->ts.kind, &x->where); - mpz_xor (result->value.integer, x->value.integer, y->value.integer); - - return range_check (result, "IEOR"); -} - - -gfc_expr * -gfc_simplify_index (gfc_expr *x, gfc_expr *y, gfc_expr *b, gfc_expr *kind) -{ - gfc_expr *result; - int back, len, lensub; - int i, j, k, count, index = 0, start; - - if (x->expr_type != EXPR_CONSTANT || y->expr_type != EXPR_CONSTANT - || ( b != NULL && b->expr_type != EXPR_CONSTANT)) - return NULL; - - if (b != NULL && b->value.logical != 0) - back = 1; - else - back = 0; - - k = get_kind (BT_INTEGER, kind, "INDEX", gfc_default_integer_kind); - if (k == -1) - return &gfc_bad_expr; - - result = gfc_get_constant_expr (BT_INTEGER, k, &x->where); - - len = x->value.character.length; - lensub = y->value.character.length; - - if (len < lensub) - { - mpz_set_si (result->value.integer, 0); - return result; - } - - if (back == 0) - { - if (lensub == 0) - { - mpz_set_si (result->value.integer, 1); - return result; - } - else if (lensub == 1) - { - for (i = 0; i < len; i++) - { - for (j = 0; j < lensub; j++) - { - if (y->value.character.string[j] - == x->value.character.string[i]) - { - index = i + 1; - goto done; - } - } - } - } - else - { - for (i = 0; i < len; i++) - { - for (j = 0; j < lensub; j++) - { - if (y->value.character.string[j] - == x->value.character.string[i]) - { - start = i; - count = 0; - - for (k = 0; k < lensub; k++) - { - if (y->value.character.string[k] - == x->value.character.string[k + start]) - count++; - } - - if (count == lensub) - { - index = start + 1; - goto done; - } - } - } - } - } - - } - else - { - if (lensub == 0) - { - mpz_set_si (result->value.integer, len + 1); - return result; - } - else if (lensub == 1) - { - for (i = 0; i < len; i++) - { - for (j = 0; j < lensub; j++) - { - if (y->value.character.string[j] - == x->value.character.string[len - i]) - { - index = len - i + 1; - goto done; - } - } - } - } - else - { - for (i = 0; i < len; i++) - { - for (j = 0; j < lensub; j++) - { - if (y->value.character.string[j] - == x->value.character.string[len - i]) - { - start = len - i; - if (start <= len - lensub) - { - count = 0; - for (k = 0; k < lensub; k++) - if (y->value.character.string[k] - == x->value.character.string[k + start]) - count++; - - if (count == lensub) - { - index = start + 1; - goto done; - } - } - else - { - continue; - } - } - } - } - } - } - -done: - mpz_set_si (result->value.integer, index); - return range_check (result, "INDEX"); -} - - -static gfc_expr * -simplify_intconv (gfc_expr *e, int kind, const char *name) -{ - gfc_expr *result = NULL; - int tmp1, tmp2; - - /* Convert BOZ to integer, and return without range checking. */ - if (e->ts.type == BT_BOZ) - { - if (!gfc_boz2int (e, kind)) - return NULL; - result = gfc_copy_expr (e); - return result; - } - - if (e->expr_type != EXPR_CONSTANT) - return NULL; - - /* For explicit conversion, turn off -Wconversion and -Wconversion-extra - warnings. */ - tmp1 = warn_conversion; - tmp2 = warn_conversion_extra; - warn_conversion = warn_conversion_extra = 0; - - result = gfc_convert_constant (e, BT_INTEGER, kind); - - warn_conversion = tmp1; - warn_conversion_extra = tmp2; - - if (result == &gfc_bad_expr) - return &gfc_bad_expr; - - return range_check (result, name); -} - - -gfc_expr * -gfc_simplify_int (gfc_expr *e, gfc_expr *k) -{ - int kind; - - kind = get_kind (BT_INTEGER, k, "INT", gfc_default_integer_kind); - if (kind == -1) - return &gfc_bad_expr; - - return simplify_intconv (e, kind, "INT"); -} - -gfc_expr * -gfc_simplify_int2 (gfc_expr *e) -{ - return simplify_intconv (e, 2, "INT2"); -} - - -gfc_expr * -gfc_simplify_int8 (gfc_expr *e) -{ - return simplify_intconv (e, 8, "INT8"); -} - - -gfc_expr * -gfc_simplify_long (gfc_expr *e) -{ - return simplify_intconv (e, 4, "LONG"); -} - - -gfc_expr * -gfc_simplify_ifix (gfc_expr *e) -{ - gfc_expr *rtrunc, *result; - - if (e->expr_type != EXPR_CONSTANT) - return NULL; - - rtrunc = gfc_copy_expr (e); - mpfr_trunc (rtrunc->value.real, e->value.real); - - result = gfc_get_constant_expr (BT_INTEGER, gfc_default_integer_kind, - &e->where); - gfc_mpfr_to_mpz (result->value.integer, rtrunc->value.real, &e->where); - - gfc_free_expr (rtrunc); - - return range_check (result, "IFIX"); -} - - -gfc_expr * -gfc_simplify_idint (gfc_expr *e) -{ - gfc_expr *rtrunc, *result; - - if (e->expr_type != EXPR_CONSTANT) - return NULL; - - rtrunc = gfc_copy_expr (e); - mpfr_trunc (rtrunc->value.real, e->value.real); - - result = gfc_get_constant_expr (BT_INTEGER, gfc_default_integer_kind, - &e->where); - gfc_mpfr_to_mpz (result->value.integer, rtrunc->value.real, &e->where); - - gfc_free_expr (rtrunc); - - return range_check (result, "IDINT"); -} - - -gfc_expr * -gfc_simplify_ior (gfc_expr *x, gfc_expr *y) -{ - gfc_expr *result; - - if (x->expr_type != EXPR_CONSTANT || y->expr_type != EXPR_CONSTANT) - return NULL; - - result = gfc_get_constant_expr (BT_INTEGER, x->ts.kind, &x->where); - mpz_ior (result->value.integer, x->value.integer, y->value.integer); - - return range_check (result, "IOR"); -} - - -static gfc_expr * -do_bit_xor (gfc_expr *result, gfc_expr *e) -{ - gcc_assert (e->ts.type == BT_INTEGER && e->expr_type == EXPR_CONSTANT); - gcc_assert (result->ts.type == BT_INTEGER - && result->expr_type == EXPR_CONSTANT); - - mpz_xor (result->value.integer, result->value.integer, e->value.integer); - return result; -} - - -gfc_expr * -gfc_simplify_iparity (gfc_expr *array, gfc_expr *dim, gfc_expr *mask) -{ - return simplify_transformation (array, dim, mask, 0, do_bit_xor); -} - - -gfc_expr * -gfc_simplify_is_iostat_end (gfc_expr *x) -{ - if (x->expr_type != EXPR_CONSTANT) - return NULL; - - return gfc_get_logical_expr (gfc_default_logical_kind, &x->where, - mpz_cmp_si (x->value.integer, - LIBERROR_END) == 0); -} - - -gfc_expr * -gfc_simplify_is_iostat_eor (gfc_expr *x) -{ - if (x->expr_type != EXPR_CONSTANT) - return NULL; - - return gfc_get_logical_expr (gfc_default_logical_kind, &x->where, - mpz_cmp_si (x->value.integer, - LIBERROR_EOR) == 0); -} - - -gfc_expr * -gfc_simplify_isnan (gfc_expr *x) -{ - if (x->expr_type != EXPR_CONSTANT) - return NULL; - - return gfc_get_logical_expr (gfc_default_logical_kind, &x->where, - mpfr_nan_p (x->value.real)); -} - - -/* Performs a shift on its first argument. Depending on the last - argument, the shift can be arithmetic, i.e. with filling from the - left like in the SHIFTA intrinsic. */ -static gfc_expr * -simplify_shift (gfc_expr *e, gfc_expr *s, const char *name, - bool arithmetic, int direction) -{ - gfc_expr *result; - int ashift, *bits, i, k, bitsize, shift; - - if (e->expr_type != EXPR_CONSTANT || s->expr_type != EXPR_CONSTANT) - return NULL; - - gfc_extract_int (s, &shift); - - k = gfc_validate_kind (BT_INTEGER, e->ts.kind, false); - bitsize = gfc_integer_kinds[k].bit_size; - - result = gfc_get_constant_expr (e->ts.type, e->ts.kind, &e->where); - - if (shift == 0) - { - mpz_set (result->value.integer, e->value.integer); - return result; - } - - if (direction > 0 && shift < 0) - { - /* Left shift, as in SHIFTL. */ - gfc_error ("Second argument of %s is negative at %L", name, &e->where); - return &gfc_bad_expr; - } - else if (direction < 0) - { - /* Right shift, as in SHIFTR or SHIFTA. */ - if (shift < 0) - { - gfc_error ("Second argument of %s is negative at %L", - name, &e->where); - return &gfc_bad_expr; - } - - shift = -shift; - } - - ashift = (shift >= 0 ? shift : -shift); - - if (ashift > bitsize) - { - gfc_error ("Magnitude of second argument of %s exceeds bit size " - "at %L", name, &e->where); - return &gfc_bad_expr; - } - - bits = XCNEWVEC (int, bitsize); - - for (i = 0; i < bitsize; i++) - bits[i] = mpz_tstbit (e->value.integer, i); - - if (shift > 0) - { - /* Left shift. */ - for (i = 0; i < shift; i++) - mpz_clrbit (result->value.integer, i); - - for (i = 0; i < bitsize - shift; i++) - { - if (bits[i] == 0) - mpz_clrbit (result->value.integer, i + shift); - else - mpz_setbit (result->value.integer, i + shift); - } - } - else - { - /* Right shift. */ - if (arithmetic && bits[bitsize - 1]) - for (i = bitsize - 1; i >= bitsize - ashift; i--) - mpz_setbit (result->value.integer, i); - else - for (i = bitsize - 1; i >= bitsize - ashift; i--) - mpz_clrbit (result->value.integer, i); - - for (i = bitsize - 1; i >= ashift; i--) - { - if (bits[i] == 0) - mpz_clrbit (result->value.integer, i - ashift); - else - mpz_setbit (result->value.integer, i - ashift); - } - } - - gfc_convert_mpz_to_signed (result->value.integer, bitsize); - free (bits); - - return result; -} - - -gfc_expr * -gfc_simplify_ishft (gfc_expr *e, gfc_expr *s) -{ - return simplify_shift (e, s, "ISHFT", false, 0); -} - - -gfc_expr * -gfc_simplify_lshift (gfc_expr *e, gfc_expr *s) -{ - return simplify_shift (e, s, "LSHIFT", false, 1); -} - - -gfc_expr * -gfc_simplify_rshift (gfc_expr *e, gfc_expr *s) -{ - return simplify_shift (e, s, "RSHIFT", true, -1); -} - - -gfc_expr * -gfc_simplify_shifta (gfc_expr *e, gfc_expr *s) -{ - return simplify_shift (e, s, "SHIFTA", true, -1); -} - - -gfc_expr * -gfc_simplify_shiftl (gfc_expr *e, gfc_expr *s) -{ - return simplify_shift (e, s, "SHIFTL", false, 1); -} - - -gfc_expr * -gfc_simplify_shiftr (gfc_expr *e, gfc_expr *s) -{ - return simplify_shift (e, s, "SHIFTR", false, -1); -} - - -gfc_expr * -gfc_simplify_ishftc (gfc_expr *e, gfc_expr *s, gfc_expr *sz) -{ - gfc_expr *result; - int shift, ashift, isize, ssize, delta, k; - int i, *bits; - - if (e->expr_type != EXPR_CONSTANT || s->expr_type != EXPR_CONSTANT) - return NULL; - - gfc_extract_int (s, &shift); - - k = gfc_validate_kind (e->ts.type, e->ts.kind, false); - isize = gfc_integer_kinds[k].bit_size; - - if (sz != NULL) - { - if (sz->expr_type != EXPR_CONSTANT) - return NULL; - - gfc_extract_int (sz, &ssize); - } - else - ssize = isize; - - if (shift >= 0) - ashift = shift; - else - ashift = -shift; - - if (ashift > ssize) - { - if (sz == NULL) - gfc_error ("Magnitude of second argument of ISHFTC exceeds " - "BIT_SIZE of first argument at %C"); - else - gfc_error ("Absolute value of SHIFT shall be less than or equal " - "to SIZE at %C"); - return &gfc_bad_expr; - } - - result = gfc_get_constant_expr (e->ts.type, e->ts.kind, &e->where); - - mpz_set (result->value.integer, e->value.integer); - - if (shift == 0) - return result; - - convert_mpz_to_unsigned (result->value.integer, isize); - - bits = XCNEWVEC (int, ssize); - - for (i = 0; i < ssize; i++) - bits[i] = mpz_tstbit (e->value.integer, i); - - delta = ssize - ashift; - - if (shift > 0) - { - for (i = 0; i < delta; i++) - { - if (bits[i] == 0) - mpz_clrbit (result->value.integer, i + shift); - else - mpz_setbit (result->value.integer, i + shift); - } - - for (i = delta; i < ssize; i++) - { - if (bits[i] == 0) - mpz_clrbit (result->value.integer, i - delta); - else - mpz_setbit (result->value.integer, i - delta); - } - } - else - { - for (i = 0; i < ashift; i++) - { - if (bits[i] == 0) - mpz_clrbit (result->value.integer, i + delta); - else - mpz_setbit (result->value.integer, i + delta); - } - - for (i = ashift; i < ssize; i++) - { - if (bits[i] == 0) - mpz_clrbit (result->value.integer, i + shift); - else - mpz_setbit (result->value.integer, i + shift); - } - } - - gfc_convert_mpz_to_signed (result->value.integer, isize); - - free (bits); - return result; -} - - -gfc_expr * -gfc_simplify_kind (gfc_expr *e) -{ - return gfc_get_int_expr (gfc_default_integer_kind, NULL, e->ts.kind); -} - - -static gfc_expr * -simplify_bound_dim (gfc_expr *array, gfc_expr *kind, int d, int upper, - gfc_array_spec *as, gfc_ref *ref, bool coarray) -{ - gfc_expr *l, *u, *result; - int k; - - k = get_kind (BT_INTEGER, kind, upper ? "UBOUND" : "LBOUND", - gfc_default_integer_kind); - if (k == -1) - return &gfc_bad_expr; - - result = gfc_get_constant_expr (BT_INTEGER, k, &array->where); - - /* For non-variables, LBOUND(expr, DIM=n) = 1 and - UBOUND(expr, DIM=n) = SIZE(expr, DIM=n). */ - if (!coarray && array->expr_type != EXPR_VARIABLE) - { - if (upper) - { - gfc_expr* dim = result; - mpz_set_si (dim->value.integer, d); - - result = simplify_size (array, dim, k); - gfc_free_expr (dim); - if (!result) - goto returnNull; - } - else - mpz_set_si (result->value.integer, 1); - - goto done; - } - - /* Otherwise, we have a variable expression. */ - gcc_assert (array->expr_type == EXPR_VARIABLE); - gcc_assert (as); - - if (!gfc_resolve_array_spec (as, 0)) - return NULL; - - /* The last dimension of an assumed-size array is special. */ - if ((!coarray && d == as->rank && as->type == AS_ASSUMED_SIZE && !upper) - || (coarray && d == as->rank + as->corank - && (!upper || flag_coarray == GFC_FCOARRAY_SINGLE))) - { - if (as->lower[d-1] && as->lower[d-1]->expr_type == EXPR_CONSTANT) - { - gfc_free_expr (result); - return gfc_copy_expr (as->lower[d-1]); - } - - goto returnNull; - } - - result = gfc_get_constant_expr (BT_INTEGER, k, &array->where); - - /* Then, we need to know the extent of the given dimension. */ - if (coarray || (ref->u.ar.type == AR_FULL && !ref->next)) - { - gfc_expr *declared_bound; - int empty_bound; - bool constant_lbound, constant_ubound; - - l = as->lower[d-1]; - u = as->upper[d-1]; - - gcc_assert (l != NULL); - - constant_lbound = l->expr_type == EXPR_CONSTANT; - constant_ubound = u && u->expr_type == EXPR_CONSTANT; - - empty_bound = upper ? 0 : 1; - declared_bound = upper ? u : l; - - if ((!upper && !constant_lbound) - || (upper && !constant_ubound)) - goto returnNull; - - if (!coarray) - { - /* For {L,U}BOUND, the value depends on whether the array - is empty. We can nevertheless simplify if the declared bound - has the same value as that of an empty array, in which case - the result isn't dependent on the array emptyness. */ - if (mpz_cmp_si (declared_bound->value.integer, empty_bound) == 0) - mpz_set_si (result->value.integer, empty_bound); - else if (!constant_lbound || !constant_ubound) - /* Array emptyness can't be determined, we can't simplify. */ - goto returnNull; - else if (mpz_cmp (l->value.integer, u->value.integer) > 0) - mpz_set_si (result->value.integer, empty_bound); - else - mpz_set (result->value.integer, declared_bound->value.integer); - } - else - mpz_set (result->value.integer, declared_bound->value.integer); - } - else - { - if (upper) - { - int d2 = 0, cnt = 0; - for (int idx = 0; idx < ref->u.ar.dimen; ++idx) - { - if (ref->u.ar.dimen_type[idx] == DIMEN_ELEMENT) - d2++; - else if (cnt < d - 1) - cnt++; - else - break; - } - if (!gfc_ref_dimen_size (&ref->u.ar, d2 + d - 1, &result->value.integer, NULL)) - goto returnNull; - } - else - mpz_set_si (result->value.integer, (long int) 1); - } - -done: - return range_check (result, upper ? "UBOUND" : "LBOUND"); - -returnNull: - gfc_free_expr (result); - return NULL; -} - - -static gfc_expr * -simplify_bound (gfc_expr *array, gfc_expr *dim, gfc_expr *kind, int upper) -{ - gfc_ref *ref; - gfc_array_spec *as; - ar_type type = AR_UNKNOWN; - int d; - - if (array->ts.type == BT_CLASS) - return NULL; - - if (array->expr_type != EXPR_VARIABLE) - { - as = NULL; - ref = NULL; - goto done; - } - - /* Do not attempt to resolve if error has already been issued. */ - if (array->symtree->n.sym->error) - return NULL; - - /* Follow any component references. */ - as = array->symtree->n.sym->as; - for (ref = array->ref; ref; ref = ref->next) - { - switch (ref->type) - { - case REF_ARRAY: - type = ref->u.ar.type; - switch (ref->u.ar.type) - { - case AR_ELEMENT: - as = NULL; - continue; - - case AR_FULL: - /* We're done because 'as' has already been set in the - previous iteration. */ - goto done; - - case AR_UNKNOWN: - return NULL; - - case AR_SECTION: - as = ref->u.ar.as; - goto done; - } - - gcc_unreachable (); - - case REF_COMPONENT: - as = ref->u.c.component->as; - continue; - - case REF_SUBSTRING: - case REF_INQUIRY: - continue; - } - } - - gcc_unreachable (); - - done: - - if (as && (as->type == AS_DEFERRED || as->type == AS_ASSUMED_RANK - || (as->type == AS_ASSUMED_SHAPE && upper))) - return NULL; - - /* 'array' shall not be an unallocated allocatable variable or a pointer that - is not associated. */ - if (array->expr_type == EXPR_VARIABLE - && (gfc_expr_attr (array).allocatable || gfc_expr_attr (array).pointer)) - return NULL; - - gcc_assert (!as - || (as->type != AS_DEFERRED - && array->expr_type == EXPR_VARIABLE - && !gfc_expr_attr (array).allocatable - && !gfc_expr_attr (array).pointer)); - - if (dim == NULL) - { - /* Multi-dimensional bounds. */ - gfc_expr *bounds[GFC_MAX_DIMENSIONS]; - gfc_expr *e; - int k; - - /* UBOUND(ARRAY) is not valid for an assumed-size array. */ - if (upper && type == AR_FULL && as && as->type == AS_ASSUMED_SIZE) - { - /* An error message will be emitted in - check_assumed_size_reference (resolve.c). */ - return &gfc_bad_expr; - } - - /* Simplify the bounds for each dimension. */ - for (d = 0; d < array->rank; d++) - { - bounds[d] = simplify_bound_dim (array, kind, d + 1, upper, as, ref, - false); - if (bounds[d] == NULL || bounds[d] == &gfc_bad_expr) - { - int j; - - for (j = 0; j < d; j++) - gfc_free_expr (bounds[j]); - - if (gfc_seen_div0) - return &gfc_bad_expr; - else - return bounds[d]; - } - } - - /* Allocate the result expression. */ - k = get_kind (BT_INTEGER, kind, upper ? "UBOUND" : "LBOUND", - gfc_default_integer_kind); - if (k == -1) - return &gfc_bad_expr; - - e = gfc_get_array_expr (BT_INTEGER, k, &array->where); - - /* The result is a rank 1 array; its size is the rank of the first - argument to {L,U}BOUND. */ - e->rank = 1; - e->shape = gfc_get_shape (1); - mpz_init_set_ui (e->shape[0], array->rank); - - /* Create the constructor for this array. */ - for (d = 0; d < array->rank; d++) - gfc_constructor_append_expr (&e->value.constructor, - bounds[d], &e->where); - - return e; - } - else - { - /* A DIM argument is specified. */ - if (dim->expr_type != EXPR_CONSTANT) - return NULL; - - d = mpz_get_si (dim->value.integer); - - if ((d < 1 || d > array->rank) - || (d == array->rank && as && as->type == AS_ASSUMED_SIZE && upper)) - { - gfc_error ("DIM argument at %L is out of bounds", &dim->where); - return &gfc_bad_expr; - } - - if (as && as->type == AS_ASSUMED_RANK) - return NULL; - - return simplify_bound_dim (array, kind, d, upper, as, ref, false); - } -} - - -static gfc_expr * -simplify_cobound (gfc_expr *array, gfc_expr *dim, gfc_expr *kind, int upper) -{ - gfc_ref *ref; - gfc_array_spec *as; - int d; - - if (array->expr_type != EXPR_VARIABLE) - return NULL; - - /* Follow any component references. */ - as = (array->ts.type == BT_CLASS && array->ts.u.derived->components) - ? array->ts.u.derived->components->as - : array->symtree->n.sym->as; - for (ref = array->ref; ref; ref = ref->next) - { - switch (ref->type) - { - case REF_ARRAY: - switch (ref->u.ar.type) - { - case AR_ELEMENT: - if (ref->u.ar.as->corank > 0) - { - gcc_assert (as == ref->u.ar.as); - goto done; - } - as = NULL; - continue; - - case AR_FULL: - /* We're done because 'as' has already been set in the - previous iteration. */ - goto done; - - case AR_UNKNOWN: - return NULL; - - case AR_SECTION: - as = ref->u.ar.as; - goto done; - } - - gcc_unreachable (); - - case REF_COMPONENT: - as = ref->u.c.component->as; - continue; - - case REF_SUBSTRING: - case REF_INQUIRY: - continue; - } - } - - if (!as) - gcc_unreachable (); - - done: - - if (as->cotype == AS_DEFERRED || as->cotype == AS_ASSUMED_SHAPE) - return NULL; - - if (dim == NULL) - { - /* Multi-dimensional cobounds. */ - gfc_expr *bounds[GFC_MAX_DIMENSIONS]; - gfc_expr *e; - int k; - - /* Simplify the cobounds for each dimension. */ - for (d = 0; d < as->corank; d++) - { - bounds[d] = simplify_bound_dim (array, kind, d + 1 + as->rank, - upper, as, ref, true); - if (bounds[d] == NULL || bounds[d] == &gfc_bad_expr) - { - int j; - - for (j = 0; j < d; j++) - gfc_free_expr (bounds[j]); - return bounds[d]; - } - } - - /* Allocate the result expression. */ - e = gfc_get_expr (); - e->where = array->where; - e->expr_type = EXPR_ARRAY; - e->ts.type = BT_INTEGER; - k = get_kind (BT_INTEGER, kind, upper ? "UCOBOUND" : "LCOBOUND", - gfc_default_integer_kind); - if (k == -1) - { - gfc_free_expr (e); - return &gfc_bad_expr; - } - e->ts.kind = k; - - /* The result is a rank 1 array; its size is the rank of the first - argument to {L,U}COBOUND. */ - e->rank = 1; - e->shape = gfc_get_shape (1); - mpz_init_set_ui (e->shape[0], as->corank); - - /* Create the constructor for this array. */ - for (d = 0; d < as->corank; d++) - gfc_constructor_append_expr (&e->value.constructor, - bounds[d], &e->where); - return e; - } - else - { - /* A DIM argument is specified. */ - if (dim->expr_type != EXPR_CONSTANT) - return NULL; - - d = mpz_get_si (dim->value.integer); - - if (d < 1 || d > as->corank) - { - gfc_error ("DIM argument at %L is out of bounds", &dim->where); - return &gfc_bad_expr; - } - - return simplify_bound_dim (array, kind, d+as->rank, upper, as, ref, true); - } -} - - -gfc_expr * -gfc_simplify_lbound (gfc_expr *array, gfc_expr *dim, gfc_expr *kind) -{ - return simplify_bound (array, dim, kind, 0); -} - - -gfc_expr * -gfc_simplify_lcobound (gfc_expr *array, gfc_expr *dim, gfc_expr *kind) -{ - return simplify_cobound (array, dim, kind, 0); -} - -gfc_expr * -gfc_simplify_leadz (gfc_expr *e) -{ - unsigned long lz, bs; - int i; - - if (e->expr_type != EXPR_CONSTANT) - return NULL; - - i = gfc_validate_kind (e->ts.type, e->ts.kind, false); - bs = gfc_integer_kinds[i].bit_size; - if (mpz_cmp_si (e->value.integer, 0) == 0) - lz = bs; - else if (mpz_cmp_si (e->value.integer, 0) < 0) - lz = 0; - else - lz = bs - mpz_sizeinbase (e->value.integer, 2); - - return gfc_get_int_expr (gfc_default_integer_kind, &e->where, lz); -} - - -/* Check for constant length of a substring. */ - -static bool -substring_has_constant_len (gfc_expr *e) -{ - gfc_ref *ref; - HOST_WIDE_INT istart, iend, length; - bool equal_length = false; - - if (e->ts.type != BT_CHARACTER) - return false; - - for (ref = e->ref; ref; ref = ref->next) - if (ref->type != REF_COMPONENT && ref->type != REF_ARRAY) - break; - - if (!ref - || ref->type != REF_SUBSTRING - || !ref->u.ss.start - || ref->u.ss.start->expr_type != EXPR_CONSTANT - || !ref->u.ss.end - || ref->u.ss.end->expr_type != EXPR_CONSTANT) - return false; - - /* Basic checks on substring starting and ending indices. */ - if (!gfc_resolve_substring (ref, &equal_length)) - return false; - - istart = gfc_mpz_get_hwi (ref->u.ss.start->value.integer); - iend = gfc_mpz_get_hwi (ref->u.ss.end->value.integer); - - if (istart <= iend) - length = iend - istart + 1; - else - length = 0; - - /* Fix substring length. */ - e->value.character.length = length; - - return true; -} - - -gfc_expr * -gfc_simplify_len (gfc_expr *e, gfc_expr *kind) -{ - gfc_expr *result; - int k = get_kind (BT_INTEGER, kind, "LEN", gfc_default_integer_kind); - - if (k == -1) - return &gfc_bad_expr; - - if (e->expr_type == EXPR_CONSTANT - || substring_has_constant_len (e)) - { - result = gfc_get_constant_expr (BT_INTEGER, k, &e->where); - mpz_set_si (result->value.integer, e->value.character.length); - return range_check (result, "LEN"); - } - else if (e->ts.u.cl != NULL && e->ts.u.cl->length != NULL - && e->ts.u.cl->length->expr_type == EXPR_CONSTANT - && e->ts.u.cl->length->ts.type == BT_INTEGER) - { - result = gfc_get_constant_expr (BT_INTEGER, k, &e->where); - mpz_set (result->value.integer, e->ts.u.cl->length->value.integer); - return range_check (result, "LEN"); - } - else if (e->expr_type == EXPR_VARIABLE && e->ts.type == BT_CHARACTER - && e->symtree->n.sym - && e->symtree->n.sym->ts.type != BT_DERIVED - && e->symtree->n.sym->assoc && e->symtree->n.sym->assoc->target - && e->symtree->n.sym->assoc->target->ts.type == BT_DERIVED - && e->symtree->n.sym->assoc->target->symtree->n.sym - && UNLIMITED_POLY (e->symtree->n.sym->assoc->target->symtree->n.sym)) - - /* The expression in assoc->target points to a ref to the _data component - of the unlimited polymorphic entity. To get the _len component the last - _data ref needs to be stripped and a ref to the _len component added. */ - return gfc_get_len_component (e->symtree->n.sym->assoc->target, k); - else - return NULL; -} - - -gfc_expr * -gfc_simplify_len_trim (gfc_expr *e, gfc_expr *kind) -{ - gfc_expr *result; - size_t count, len, i; - int k = get_kind (BT_INTEGER, kind, "LEN_TRIM", gfc_default_integer_kind); - - if (k == -1) - return &gfc_bad_expr; - - if (e->expr_type != EXPR_CONSTANT) - return NULL; - - len = e->value.character.length; - for (count = 0, i = 1; i <= len; i++) - if (e->value.character.string[len - i] == ' ') - count++; - else - break; - - result = gfc_get_int_expr (k, &e->where, len - count); - return range_check (result, "LEN_TRIM"); -} - -gfc_expr * -gfc_simplify_lgamma (gfc_expr *x) -{ - gfc_expr *result; - int sg; - - if (x->expr_type != EXPR_CONSTANT) - return NULL; - - result = gfc_get_constant_expr (x->ts.type, x->ts.kind, &x->where); - mpfr_lgamma (result->value.real, &sg, x->value.real, GFC_RND_MODE); - - return range_check (result, "LGAMMA"); -} - - -gfc_expr * -gfc_simplify_lge (gfc_expr *a, gfc_expr *b) -{ - if (a->expr_type != EXPR_CONSTANT || b->expr_type != EXPR_CONSTANT) - return NULL; - - return gfc_get_logical_expr (gfc_default_logical_kind, &a->where, - gfc_compare_string (a, b) >= 0); -} - - -gfc_expr * -gfc_simplify_lgt (gfc_expr *a, gfc_expr *b) -{ - if (a->expr_type != EXPR_CONSTANT || b->expr_type != EXPR_CONSTANT) - return NULL; - - return gfc_get_logical_expr (gfc_default_logical_kind, &a->where, - gfc_compare_string (a, b) > 0); -} - - -gfc_expr * -gfc_simplify_lle (gfc_expr *a, gfc_expr *b) -{ - if (a->expr_type != EXPR_CONSTANT || b->expr_type != EXPR_CONSTANT) - return NULL; - - return gfc_get_logical_expr (gfc_default_logical_kind, &a->where, - gfc_compare_string (a, b) <= 0); -} - - -gfc_expr * -gfc_simplify_llt (gfc_expr *a, gfc_expr *b) -{ - if (a->expr_type != EXPR_CONSTANT || b->expr_type != EXPR_CONSTANT) - return NULL; - - return gfc_get_logical_expr (gfc_default_logical_kind, &a->where, - gfc_compare_string (a, b) < 0); -} - - -gfc_expr * -gfc_simplify_log (gfc_expr *x) -{ - gfc_expr *result; - - if (x->expr_type != EXPR_CONSTANT) - return NULL; - - result = gfc_get_constant_expr (x->ts.type, x->ts.kind, &x->where); - - switch (x->ts.type) - { - case BT_REAL: - if (mpfr_sgn (x->value.real) <= 0) - { - gfc_error ("Argument of LOG at %L cannot be less than or equal " - "to zero", &x->where); - gfc_free_expr (result); - return &gfc_bad_expr; - } - - mpfr_log (result->value.real, x->value.real, GFC_RND_MODE); - break; - - case BT_COMPLEX: - if (mpfr_zero_p (mpc_realref (x->value.complex)) - && mpfr_zero_p (mpc_imagref (x->value.complex))) - { - gfc_error ("Complex argument of LOG at %L cannot be zero", - &x->where); - gfc_free_expr (result); - return &gfc_bad_expr; - } - - gfc_set_model_kind (x->ts.kind); - mpc_log (result->value.complex, x->value.complex, GFC_MPC_RND_MODE); - break; - - default: - gfc_internal_error ("gfc_simplify_log: bad type"); - } - - return range_check (result, "LOG"); -} - - -gfc_expr * -gfc_simplify_log10 (gfc_expr *x) -{ - gfc_expr *result; - - if (x->expr_type != EXPR_CONSTANT) - return NULL; - - if (mpfr_sgn (x->value.real) <= 0) - { - gfc_error ("Argument of LOG10 at %L cannot be less than or equal " - "to zero", &x->where); - return &gfc_bad_expr; - } - - result = gfc_get_constant_expr (x->ts.type, x->ts.kind, &x->where); - mpfr_log10 (result->value.real, x->value.real, GFC_RND_MODE); - - return range_check (result, "LOG10"); -} - - -gfc_expr * -gfc_simplify_logical (gfc_expr *e, gfc_expr *k) -{ - int kind; - - kind = get_kind (BT_LOGICAL, k, "LOGICAL", gfc_default_logical_kind); - if (kind < 0) - return &gfc_bad_expr; - - if (e->expr_type != EXPR_CONSTANT) - return NULL; - - return gfc_get_logical_expr (kind, &e->where, e->value.logical); -} - - -gfc_expr* -gfc_simplify_matmul (gfc_expr *matrix_a, gfc_expr *matrix_b) -{ - gfc_expr *result; - int row, result_rows, col, result_columns; - int stride_a, offset_a, stride_b, offset_b; - - if (!is_constant_array_expr (matrix_a) - || !is_constant_array_expr (matrix_b)) - return NULL; - - /* MATMUL should do mixed-mode arithmetic. Set the result type. */ - if (matrix_a->ts.type != matrix_b->ts.type) - { - gfc_expr e; - e.expr_type = EXPR_OP; - gfc_clear_ts (&e.ts); - e.value.op.op = INTRINSIC_NONE; - e.value.op.op1 = matrix_a; - e.value.op.op2 = matrix_b; - gfc_type_convert_binary (&e, 1); - result = gfc_get_array_expr (e.ts.type, e.ts.kind, &matrix_a->where); - } - else - { - result = gfc_get_array_expr (matrix_a->ts.type, matrix_a->ts.kind, - &matrix_a->where); - } - - if (matrix_a->rank == 1 && matrix_b->rank == 2) - { - result_rows = 1; - result_columns = mpz_get_si (matrix_b->shape[1]); - stride_a = 1; - stride_b = mpz_get_si (matrix_b->shape[0]); - - result->rank = 1; - result->shape = gfc_get_shape (result->rank); - mpz_init_set_si (result->shape[0], result_columns); - } - else if (matrix_a->rank == 2 && matrix_b->rank == 1) - { - result_rows = mpz_get_si (matrix_a->shape[0]); - result_columns = 1; - stride_a = mpz_get_si (matrix_a->shape[0]); - stride_b = 1; - - result->rank = 1; - result->shape = gfc_get_shape (result->rank); - mpz_init_set_si (result->shape[0], result_rows); - } - else if (matrix_a->rank == 2 && matrix_b->rank == 2) - { - result_rows = mpz_get_si (matrix_a->shape[0]); - result_columns = mpz_get_si (matrix_b->shape[1]); - stride_a = mpz_get_si (matrix_a->shape[0]); - stride_b = mpz_get_si (matrix_b->shape[0]); - - result->rank = 2; - result->shape = gfc_get_shape (result->rank); - mpz_init_set_si (result->shape[0], result_rows); - mpz_init_set_si (result->shape[1], result_columns); - } - else - gcc_unreachable(); - - offset_b = 0; - for (col = 0; col < result_columns; ++col) - { - offset_a = 0; - - for (row = 0; row < result_rows; ++row) - { - gfc_expr *e = compute_dot_product (matrix_a, stride_a, offset_a, - matrix_b, 1, offset_b, false); - gfc_constructor_append_expr (&result->value.constructor, - e, NULL); - - offset_a += 1; - } - - offset_b += stride_b; - } - - return result; -} - - -gfc_expr * -gfc_simplify_maskr (gfc_expr *i, gfc_expr *kind_arg) -{ - gfc_expr *result; - int kind, arg, k; - - if (i->expr_type != EXPR_CONSTANT) - return NULL; - - kind = get_kind (BT_INTEGER, kind_arg, "MASKR", gfc_default_integer_kind); - if (kind == -1) - return &gfc_bad_expr; - k = gfc_validate_kind (BT_INTEGER, kind, false); - - bool fail = gfc_extract_int (i, &arg); - gcc_assert (!fail); - - if (!gfc_check_mask (i, kind_arg)) - return &gfc_bad_expr; - - result = gfc_get_constant_expr (BT_INTEGER, kind, &i->where); - - /* MASKR(n) = 2^n - 1 */ - mpz_set_ui (result->value.integer, 1); - mpz_mul_2exp (result->value.integer, result->value.integer, arg); - mpz_sub_ui (result->value.integer, result->value.integer, 1); - - gfc_convert_mpz_to_signed (result->value.integer, gfc_integer_kinds[k].bit_size); - - return result; -} - - -gfc_expr * -gfc_simplify_maskl (gfc_expr *i, gfc_expr *kind_arg) -{ - gfc_expr *result; - int kind, arg, k; - mpz_t z; - - if (i->expr_type != EXPR_CONSTANT) - return NULL; - - kind = get_kind (BT_INTEGER, kind_arg, "MASKL", gfc_default_integer_kind); - if (kind == -1) - return &gfc_bad_expr; - k = gfc_validate_kind (BT_INTEGER, kind, false); - - bool fail = gfc_extract_int (i, &arg); - gcc_assert (!fail); - - if (!gfc_check_mask (i, kind_arg)) - return &gfc_bad_expr; - - result = gfc_get_constant_expr (BT_INTEGER, kind, &i->where); - - /* MASKL(n) = 2^bit_size - 2^(bit_size - n) */ - mpz_init_set_ui (z, 1); - mpz_mul_2exp (z, z, gfc_integer_kinds[k].bit_size); - mpz_set_ui (result->value.integer, 1); - mpz_mul_2exp (result->value.integer, result->value.integer, - gfc_integer_kinds[k].bit_size - arg); - mpz_sub (result->value.integer, z, result->value.integer); - mpz_clear (z); - - gfc_convert_mpz_to_signed (result->value.integer, gfc_integer_kinds[k].bit_size); - - return result; -} - - -gfc_expr * -gfc_simplify_merge (gfc_expr *tsource, gfc_expr *fsource, gfc_expr *mask) -{ - gfc_expr * result; - gfc_constructor *tsource_ctor, *fsource_ctor, *mask_ctor; - - if (mask->expr_type == EXPR_CONSTANT) - { - result = gfc_copy_expr (mask->value.logical ? tsource : fsource); - /* Parenthesis is needed to get lower bounds of 1. */ - result = gfc_get_parentheses (result); - gfc_simplify_expr (result, 1); - return result; - } - - if (!mask->rank || !is_constant_array_expr (mask) - || !is_constant_array_expr (tsource) || !is_constant_array_expr (fsource)) - return NULL; - - result = gfc_get_array_expr (tsource->ts.type, tsource->ts.kind, - &tsource->where); - if (tsource->ts.type == BT_DERIVED) - result->ts.u.derived = tsource->ts.u.derived; - else if (tsource->ts.type == BT_CHARACTER) - result->ts.u.cl = tsource->ts.u.cl; - - tsource_ctor = gfc_constructor_first (tsource->value.constructor); - fsource_ctor = gfc_constructor_first (fsource->value.constructor); - mask_ctor = gfc_constructor_first (mask->value.constructor); - - while (mask_ctor) - { - if (mask_ctor->expr->value.logical) - gfc_constructor_append_expr (&result->value.constructor, - gfc_copy_expr (tsource_ctor->expr), - NULL); - else - gfc_constructor_append_expr (&result->value.constructor, - gfc_copy_expr (fsource_ctor->expr), - NULL); - tsource_ctor = gfc_constructor_next (tsource_ctor); - fsource_ctor = gfc_constructor_next (fsource_ctor); - mask_ctor = gfc_constructor_next (mask_ctor); - } - - result->shape = gfc_get_shape (1); - gfc_array_size (result, &result->shape[0]); - - return result; -} - - -gfc_expr * -gfc_simplify_merge_bits (gfc_expr *i, gfc_expr *j, gfc_expr *mask_expr) -{ - mpz_t arg1, arg2, mask; - gfc_expr *result; - - if (i->expr_type != EXPR_CONSTANT || j->expr_type != EXPR_CONSTANT - || mask_expr->expr_type != EXPR_CONSTANT) - return NULL; - - result = gfc_get_constant_expr (BT_INTEGER, i->ts.kind, &i->where); - - /* Convert all argument to unsigned. */ - mpz_init_set (arg1, i->value.integer); - mpz_init_set (arg2, j->value.integer); - mpz_init_set (mask, mask_expr->value.integer); - - /* MERGE_BITS(I,J,MASK) = IOR (IAND (I, MASK), IAND (J, NOT (MASK))). */ - mpz_and (arg1, arg1, mask); - mpz_com (mask, mask); - mpz_and (arg2, arg2, mask); - mpz_ior (result->value.integer, arg1, arg2); - - mpz_clear (arg1); - mpz_clear (arg2); - mpz_clear (mask); - - return result; -} - - -/* Selects between current value and extremum for simplify_min_max - and simplify_minval_maxval. */ -static int -min_max_choose (gfc_expr *arg, gfc_expr *extremum, int sign, bool back_val) -{ - int ret; - - switch (arg->ts.type) - { - case BT_INTEGER: - if (extremum->ts.kind < arg->ts.kind) - extremum->ts.kind = arg->ts.kind; - ret = mpz_cmp (arg->value.integer, - extremum->value.integer) * sign; - if (ret > 0) - mpz_set (extremum->value.integer, arg->value.integer); - break; - - case BT_REAL: - if (extremum->ts.kind < arg->ts.kind) - extremum->ts.kind = arg->ts.kind; - if (mpfr_nan_p (extremum->value.real)) - { - ret = 1; - mpfr_set (extremum->value.real, arg->value.real, GFC_RND_MODE); - } - else if (mpfr_nan_p (arg->value.real)) - ret = -1; - else - { - ret = mpfr_cmp (arg->value.real, extremum->value.real) * sign; - if (ret > 0) - mpfr_set (extremum->value.real, arg->value.real, GFC_RND_MODE); - } - break; - - case BT_CHARACTER: -#define LENGTH(x) ((x)->value.character.length) -#define STRING(x) ((x)->value.character.string) - if (LENGTH (extremum) < LENGTH(arg)) - { - gfc_char_t *tmp = STRING(extremum); - - STRING(extremum) = gfc_get_wide_string (LENGTH(arg) + 1); - memcpy (STRING(extremum), tmp, - LENGTH(extremum) * sizeof (gfc_char_t)); - gfc_wide_memset (&STRING(extremum)[LENGTH(extremum)], ' ', - LENGTH(arg) - LENGTH(extremum)); - STRING(extremum)[LENGTH(arg)] = '\0'; /* For debugger */ - LENGTH(extremum) = LENGTH(arg); - free (tmp); - } - ret = gfc_compare_string (arg, extremum) * sign; - if (ret > 0) - { - free (STRING(extremum)); - STRING(extremum) = gfc_get_wide_string (LENGTH(extremum) + 1); - memcpy (STRING(extremum), STRING(arg), - LENGTH(arg) * sizeof (gfc_char_t)); - gfc_wide_memset (&STRING(extremum)[LENGTH(arg)], ' ', - LENGTH(extremum) - LENGTH(arg)); - STRING(extremum)[LENGTH(extremum)] = '\0'; /* For debugger */ - } -#undef LENGTH -#undef STRING - break; - - default: - gfc_internal_error ("simplify_min_max(): Bad type in arglist"); - } - if (back_val && ret == 0) - ret = 1; - - return ret; -} - - -/* This function is special since MAX() can take any number of - arguments. The simplified expression is a rewritten version of the - argument list containing at most one constant element. Other - constant elements are deleted. Because the argument list has - already been checked, this function always succeeds. sign is 1 for - MAX(), -1 for MIN(). */ - -static gfc_expr * -simplify_min_max (gfc_expr *expr, int sign) -{ - int tmp1, tmp2; - gfc_actual_arglist *arg, *last, *extremum; - gfc_expr *tmp, *ret; - const char *fname; - - last = NULL; - extremum = NULL; - - arg = expr->value.function.actual; - - for (; arg; last = arg, arg = arg->next) - { - if (arg->expr->expr_type != EXPR_CONSTANT) - continue; - - if (extremum == NULL) - { - extremum = arg; - continue; - } - - min_max_choose (arg->expr, extremum->expr, sign); - - /* Delete the extra constant argument. */ - last->next = arg->next; - - arg->next = NULL; - gfc_free_actual_arglist (arg); - arg = last; - } - - /* If there is one value left, replace the function call with the - expression. */ - if (expr->value.function.actual->next != NULL) - return NULL; - - /* Handle special cases of specific functions (min|max)1 and - a(min|max)0. */ - - tmp = expr->value.function.actual->expr; - fname = expr->value.function.isym->name; - - if ((tmp->ts.type != BT_INTEGER || tmp->ts.kind != gfc_integer_4_kind) - && (strcmp (fname, "min1") == 0 || strcmp (fname, "max1") == 0)) - { - /* Explicit conversion, turn off -Wconversion and -Wconversion-extra - warnings. */ - tmp1 = warn_conversion; - tmp2 = warn_conversion_extra; - warn_conversion = warn_conversion_extra = 0; - - ret = gfc_convert_constant (tmp, BT_INTEGER, gfc_integer_4_kind); - - warn_conversion = tmp1; - warn_conversion_extra = tmp2; - } - else if ((tmp->ts.type != BT_REAL || tmp->ts.kind != gfc_real_4_kind) - && (strcmp (fname, "amin0") == 0 || strcmp (fname, "amax0") == 0)) - { - ret = gfc_convert_constant (tmp, BT_REAL, gfc_real_4_kind); - } - else - ret = gfc_copy_expr (tmp); - - return ret; - -} - - -gfc_expr * -gfc_simplify_min (gfc_expr *e) -{ - return simplify_min_max (e, -1); -} - - -gfc_expr * -gfc_simplify_max (gfc_expr *e) -{ - return simplify_min_max (e, 1); -} - -/* Helper function for gfc_simplify_minval. */ - -static gfc_expr * -gfc_min (gfc_expr *op1, gfc_expr *op2) -{ - min_max_choose (op1, op2, -1); - gfc_free_expr (op1); - return op2; -} - -/* Simplify minval for constant arrays. */ - -gfc_expr * -gfc_simplify_minval (gfc_expr *array, gfc_expr* dim, gfc_expr *mask) -{ - return simplify_transformation (array, dim, mask, INT_MAX, gfc_min); -} - -/* Helper function for gfc_simplify_maxval. */ - -static gfc_expr * -gfc_max (gfc_expr *op1, gfc_expr *op2) -{ - min_max_choose (op1, op2, 1); - gfc_free_expr (op1); - return op2; -} - - -/* Simplify maxval for constant arrays. */ - -gfc_expr * -gfc_simplify_maxval (gfc_expr *array, gfc_expr* dim, gfc_expr *mask) -{ - return simplify_transformation (array, dim, mask, INT_MIN, gfc_max); -} - - -/* Transform minloc or maxloc of an array, according to MASK, - to the scalar result. This code is mostly identical to - simplify_transformation_to_scalar. */ - -static gfc_expr * -simplify_minmaxloc_to_scalar (gfc_expr *result, gfc_expr *array, gfc_expr *mask, - gfc_expr *extremum, int sign, bool 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 (min_max_choose (a, extremum, sign, back_val) > 0) - mpz_set (result->value.integer, count); - } - mpz_clear (count); - gfc_free_expr (extremum); - return result; -} - -/* Simplify minloc / maxloc in the absence of a dim argument. */ - -static gfc_expr * -simplify_minmaxloc_nodim (gfc_expr *result, gfc_expr *extremum, - gfc_expr *array, gfc_expr *mask, int sign, - 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; - - if (array->shape == NULL) - 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 && min_max_choose (a, extremum, sign, back_val) > 0) - { - for (i = 0; i<array->rank; i++) - res[i] = count[i]; - } - 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: - gfc_free_expr (extremum); - 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; -} - -/* Helper function for gfc_simplify_minmaxloc - build an array - expression with n elements. */ - -static gfc_expr * -new_array (bt type, int kind, int n, locus *where) -{ - gfc_expr *result; - int i; - - result = gfc_get_array_expr (type, kind, where); - result->rank = 1; - result->shape = gfc_get_shape(1); - mpz_init_set_si (result->shape[0], n); - for (i = 0; i < n; i++) - { - gfc_constructor_append_expr (&result->value.constructor, - gfc_get_constant_expr (type, kind, where), - NULL); - } - - return result; -} - -/* Simplify minloc and maxloc. This code is mostly identical to - simplify_transformation_to_array. */ - -static gfc_expr * -simplify_minmaxloc_to_array (gfc_expr *result, gfc_expr *array, - gfc_expr *dim, gfc_expr *mask, - gfc_expr *extremum, int sign, 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) - { - gfc_expr *ex; - ex = gfc_copy_expr (extremum); - for (src = base, n = 0; n < dim_extent; src += dim_stride, ++n) - { - if (*src && min_max_choose (*src, ex, sign, back_val) > 0) - mpz_set_si ((*dest)->value.integer, n + 1); - } - - count[0]++; - base += sstride[0]; - dest += dstride[0]; - gfc_free_expr (ex); - - 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); - free (extremum); - return result; -} - -/* Simplify minloc and maxloc for constant arrays. */ - -static gfc_expr * -gfc_simplify_minmaxloc (gfc_expr *array, gfc_expr *dim, gfc_expr *mask, - gfc_expr *kind, gfc_expr *back, int sign) -{ - gfc_expr *result; - gfc_expr *extremum; - int ikind; - int init_val; - bool back_val = false; - - if (!is_constant_array_expr (array) - || !gfc_is_constant_expr (dim)) - return NULL; - - 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 (sign < 0) - init_val = INT_MAX; - else if (sign > 0) - init_val = INT_MIN; - else - gcc_unreachable(); - - extremum = gfc_get_constant_expr (array->ts.type, array->ts.kind, &array->where); - init_result_expr (extremum, init_val, array); - - if (dim) - { - result = transformational_result (array, dim, BT_INTEGER, - ikind, &array->where); - init_result_expr (result, 0, array); - - if (array->rank == 1) - return simplify_minmaxloc_to_scalar (result, array, mask, extremum, - sign, back_val); - else - return simplify_minmaxloc_to_array (result, array, dim, mask, extremum, - sign, back_val); - } - else - { - result = new_array (BT_INTEGER, ikind, array->rank, &array->where); - return simplify_minmaxloc_nodim (result, extremum, array, mask, - sign, back_val); - } -} - -gfc_expr * -gfc_simplify_minloc (gfc_expr *array, gfc_expr *dim, gfc_expr *mask, gfc_expr *kind, - gfc_expr *back) -{ - return gfc_simplify_minmaxloc (array, dim, mask, kind, back, -1); -} - -gfc_expr * -gfc_simplify_maxloc (gfc_expr *array, gfc_expr *dim, gfc_expr *mask, gfc_expr *kind, - gfc_expr *back) -{ - 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) -{ - int i = gfc_validate_kind (BT_REAL, x->ts.kind, false); - return gfc_get_int_expr (gfc_default_integer_kind, &x->where, - gfc_real_kinds[i].max_exponent); -} - - -gfc_expr * -gfc_simplify_minexponent (gfc_expr *x) -{ - int i = gfc_validate_kind (BT_REAL, x->ts.kind, false); - return gfc_get_int_expr (gfc_default_integer_kind, &x->where, - gfc_real_kinds[i].min_exponent); -} - - -gfc_expr * -gfc_simplify_mod (gfc_expr *a, gfc_expr *p) -{ - gfc_expr *result; - int kind; - - /* First check p. */ - if (p->expr_type != EXPR_CONSTANT) - return NULL; - - /* p shall not be 0. */ - switch (p->ts.type) - { - case BT_INTEGER: - if (mpz_cmp_ui (p->value.integer, 0) == 0) - { - gfc_error ("Argument %qs of MOD at %L shall not be zero", - "P", &p->where); - return &gfc_bad_expr; - } - break; - case BT_REAL: - if (mpfr_cmp_ui (p->value.real, 0) == 0) - { - gfc_error ("Argument %qs of MOD at %L shall not be zero", - "P", &p->where); - return &gfc_bad_expr; - } - break; - default: - gfc_internal_error ("gfc_simplify_mod(): Bad arguments"); - } - - if (a->expr_type != EXPR_CONSTANT) - return NULL; - - kind = a->ts.kind > p->ts.kind ? a->ts.kind : p->ts.kind; - result = gfc_get_constant_expr (a->ts.type, kind, &a->where); - - if (a->ts.type == BT_INTEGER) - mpz_tdiv_r (result->value.integer, a->value.integer, p->value.integer); - else - { - gfc_set_model_kind (kind); - mpfr_fmod (result->value.real, a->value.real, p->value.real, - GFC_RND_MODE); - } - - return range_check (result, "MOD"); -} - - -gfc_expr * -gfc_simplify_modulo (gfc_expr *a, gfc_expr *p) -{ - gfc_expr *result; - int kind; - - /* First check p. */ - if (p->expr_type != EXPR_CONSTANT) - return NULL; - - /* p shall not be 0. */ - switch (p->ts.type) - { - case BT_INTEGER: - if (mpz_cmp_ui (p->value.integer, 0) == 0) - { - gfc_error ("Argument %qs of MODULO at %L shall not be zero", - "P", &p->where); - return &gfc_bad_expr; - } - break; - case BT_REAL: - if (mpfr_cmp_ui (p->value.real, 0) == 0) - { - gfc_error ("Argument %qs of MODULO at %L shall not be zero", - "P", &p->where); - return &gfc_bad_expr; - } - break; - default: - gfc_internal_error ("gfc_simplify_modulo(): Bad arguments"); - } - - if (a->expr_type != EXPR_CONSTANT) - return NULL; - - kind = a->ts.kind > p->ts.kind ? a->ts.kind : p->ts.kind; - result = gfc_get_constant_expr (a->ts.type, kind, &a->where); - - if (a->ts.type == BT_INTEGER) - mpz_fdiv_r (result->value.integer, a->value.integer, p->value.integer); - else - { - gfc_set_model_kind (kind); - mpfr_fmod (result->value.real, a->value.real, p->value.real, - GFC_RND_MODE); - if (mpfr_cmp_ui (result->value.real, 0) != 0) - { - if (mpfr_signbit (a->value.real) != mpfr_signbit (p->value.real)) - mpfr_add (result->value.real, result->value.real, p->value.real, - GFC_RND_MODE); - } - else - mpfr_copysign (result->value.real, result->value.real, - p->value.real, GFC_RND_MODE); - } - - return range_check (result, "MODULO"); -} - - -gfc_expr * -gfc_simplify_nearest (gfc_expr *x, gfc_expr *s) -{ - gfc_expr *result; - mpfr_exp_t emin, emax; - int kind; - - if (x->expr_type != EXPR_CONSTANT || s->expr_type != EXPR_CONSTANT) - return NULL; - - result = gfc_copy_expr (x); - - /* Save current values of emin and emax. */ - emin = mpfr_get_emin (); - emax = mpfr_get_emax (); - - /* Set emin and emax for the current model number. */ - kind = gfc_validate_kind (BT_REAL, x->ts.kind, 0); - mpfr_set_emin ((mpfr_exp_t) gfc_real_kinds[kind].min_exponent - - mpfr_get_prec(result->value.real) + 1); - mpfr_set_emax ((mpfr_exp_t) gfc_real_kinds[kind].max_exponent - 1); - mpfr_check_range (result->value.real, 0, MPFR_RNDU); - - if (mpfr_sgn (s->value.real) > 0) - { - mpfr_nextabove (result->value.real); - mpfr_subnormalize (result->value.real, 0, MPFR_RNDU); - } - else - { - mpfr_nextbelow (result->value.real); - mpfr_subnormalize (result->value.real, 0, MPFR_RNDD); - } - - mpfr_set_emin (emin); - mpfr_set_emax (emax); - - /* Only NaN can occur. Do not use range check as it gives an - error for denormal numbers. */ - if (mpfr_nan_p (result->value.real) && flag_range_check) - { - gfc_error ("Result of NEAREST is NaN at %L", &result->where); - gfc_free_expr (result); - return &gfc_bad_expr; - } - - return result; -} - - -static gfc_expr * -simplify_nint (const char *name, gfc_expr *e, gfc_expr *k) -{ - gfc_expr *itrunc, *result; - int kind; - - kind = get_kind (BT_INTEGER, k, name, gfc_default_integer_kind); - if (kind == -1) - return &gfc_bad_expr; - - if (e->expr_type != EXPR_CONSTANT) - return NULL; - - itrunc = gfc_copy_expr (e); - mpfr_round (itrunc->value.real, e->value.real); - - result = gfc_get_constant_expr (BT_INTEGER, kind, &e->where); - gfc_mpfr_to_mpz (result->value.integer, itrunc->value.real, &e->where); - - gfc_free_expr (itrunc); - - return range_check (result, name); -} - - -gfc_expr * -gfc_simplify_new_line (gfc_expr *e) -{ - gfc_expr *result; - - result = gfc_get_character_expr (e->ts.kind, &e->where, NULL, 1); - result->value.character.string[0] = '\n'; - - return result; -} - - -gfc_expr * -gfc_simplify_nint (gfc_expr *e, gfc_expr *k) -{ - return simplify_nint ("NINT", e, k); -} - - -gfc_expr * -gfc_simplify_idnint (gfc_expr *e) -{ - return simplify_nint ("IDNINT", e, NULL); -} - -static int norm2_scale; - -static gfc_expr * -norm2_add_squared (gfc_expr *result, gfc_expr *e) -{ - mpfr_t tmp; - - gcc_assert (e->ts.type == BT_REAL && e->expr_type == EXPR_CONSTANT); - gcc_assert (result->ts.type == BT_REAL - && result->expr_type == EXPR_CONSTANT); - - gfc_set_model_kind (result->ts.kind); - int index = gfc_validate_kind (BT_REAL, result->ts.kind, false); - mpfr_exp_t exp; - if (mpfr_regular_p (result->value.real)) - { - exp = mpfr_get_exp (result->value.real); - /* If result is getting close to overflowing, scale down. */ - if (exp >= gfc_real_kinds[index].max_exponent - 4 - && norm2_scale <= gfc_real_kinds[index].max_exponent - 2) - { - norm2_scale += 2; - mpfr_div_ui (result->value.real, result->value.real, 16, - GFC_RND_MODE); - } - } - - mpfr_init (tmp); - if (mpfr_regular_p (e->value.real)) - { - exp = mpfr_get_exp (e->value.real); - /* If e**2 would overflow or close to overflowing, scale down. */ - if (exp - norm2_scale >= gfc_real_kinds[index].max_exponent / 2 - 2) - { - int new_scale = gfc_real_kinds[index].max_exponent / 2 + 4; - mpfr_set_ui (tmp, 1, GFC_RND_MODE); - mpfr_set_exp (tmp, new_scale - norm2_scale); - mpfr_div (result->value.real, result->value.real, tmp, GFC_RND_MODE); - mpfr_div (result->value.real, result->value.real, tmp, GFC_RND_MODE); - norm2_scale = new_scale; - } - } - if (norm2_scale) - { - mpfr_set_ui (tmp, 1, GFC_RND_MODE); - mpfr_set_exp (tmp, norm2_scale); - mpfr_div (tmp, e->value.real, tmp, GFC_RND_MODE); - } - else - mpfr_set (tmp, e->value.real, GFC_RND_MODE); - mpfr_pow_ui (tmp, tmp, 2, GFC_RND_MODE); - mpfr_add (result->value.real, result->value.real, tmp, - GFC_RND_MODE); - mpfr_clear (tmp); - - return result; -} - - -static gfc_expr * -norm2_do_sqrt (gfc_expr *result, gfc_expr *e) -{ - gcc_assert (e->ts.type == BT_REAL && e->expr_type == EXPR_CONSTANT); - gcc_assert (result->ts.type == BT_REAL - && result->expr_type == EXPR_CONSTANT); - - if (result != e) - mpfr_set (result->value.real, e->value.real, GFC_RND_MODE); - mpfr_sqrt (result->value.real, result->value.real, GFC_RND_MODE); - if (norm2_scale && mpfr_regular_p (result->value.real)) - { - mpfr_t tmp; - mpfr_init (tmp); - mpfr_set_ui (tmp, 1, GFC_RND_MODE); - mpfr_set_exp (tmp, norm2_scale); - mpfr_mul (result->value.real, result->value.real, tmp, GFC_RND_MODE); - mpfr_clear (tmp); - } - norm2_scale = 0; - - return result; -} - - -gfc_expr * -gfc_simplify_norm2 (gfc_expr *e, gfc_expr *dim) -{ - gfc_expr *result; - bool size_zero; - - size_zero = gfc_is_size_zero_array (e); - - if (!(is_constant_array_expr (e) || size_zero) - || (dim != NULL && !gfc_is_constant_expr (dim))) - return NULL; - - result = transformational_result (e, dim, e->ts.type, e->ts.kind, &e->where); - init_result_expr (result, 0, NULL); - - if (size_zero) - return result; - - norm2_scale = 0; - if (!dim || e->rank == 1) - { - result = simplify_transformation_to_scalar (result, e, NULL, - norm2_add_squared); - mpfr_sqrt (result->value.real, result->value.real, GFC_RND_MODE); - if (norm2_scale && mpfr_regular_p (result->value.real)) - { - mpfr_t tmp; - mpfr_init (tmp); - mpfr_set_ui (tmp, 1, GFC_RND_MODE); - mpfr_set_exp (tmp, norm2_scale); - mpfr_mul (result->value.real, result->value.real, tmp, GFC_RND_MODE); - mpfr_clear (tmp); - } - norm2_scale = 0; - } - else - result = simplify_transformation_to_array (result, e, dim, NULL, - norm2_add_squared, - norm2_do_sqrt); - - return result; -} - - -gfc_expr * -gfc_simplify_not (gfc_expr *e) -{ - gfc_expr *result; - - if (e->expr_type != EXPR_CONSTANT) - return NULL; - - result = gfc_get_constant_expr (e->ts.type, e->ts.kind, &e->where); - mpz_com (result->value.integer, e->value.integer); - - return range_check (result, "NOT"); -} - - -gfc_expr * -gfc_simplify_null (gfc_expr *mold) -{ - gfc_expr *result; - - if (mold) - { - result = gfc_copy_expr (mold); - result->expr_type = EXPR_NULL; - } - else - result = gfc_get_null_expr (NULL); - - return result; -} - - -gfc_expr * -gfc_simplify_num_images (gfc_expr *distance ATTRIBUTE_UNUSED, gfc_expr *failed) -{ - gfc_expr *result; - - if (flag_coarray == GFC_FCOARRAY_NONE) - { - gfc_fatal_error ("Coarrays disabled at %C, use %<-fcoarray=%> to enable"); - return &gfc_bad_expr; - } - - if (flag_coarray != GFC_FCOARRAY_SINGLE) - return NULL; - - if (failed && failed->expr_type != EXPR_CONSTANT) - return NULL; - - /* FIXME: gfc_current_locus is wrong. */ - result = gfc_get_constant_expr (BT_INTEGER, gfc_default_integer_kind, - &gfc_current_locus); - - if (failed && failed->value.logical != 0) - mpz_set_si (result->value.integer, 0); - else - mpz_set_si (result->value.integer, 1); - - return result; -} - - -gfc_expr * -gfc_simplify_or (gfc_expr *x, gfc_expr *y) -{ - gfc_expr *result; - int kind; - - if (x->expr_type != EXPR_CONSTANT || y->expr_type != EXPR_CONSTANT) - return NULL; - - kind = x->ts.kind > y->ts.kind ? x->ts.kind : y->ts.kind; - - switch (x->ts.type) - { - case BT_INTEGER: - result = gfc_get_constant_expr (BT_INTEGER, kind, &x->where); - mpz_ior (result->value.integer, x->value.integer, y->value.integer); - return range_check (result, "OR"); - - case BT_LOGICAL: - return gfc_get_logical_expr (kind, &x->where, - x->value.logical || y->value.logical); - default: - gcc_unreachable(); - } -} - - -gfc_expr * -gfc_simplify_pack (gfc_expr *array, gfc_expr *mask, gfc_expr *vector) -{ - gfc_expr *result; - gfc_constructor *array_ctor, *mask_ctor, *vector_ctor; - - if (!is_constant_array_expr (array) - || !is_constant_array_expr (vector) - || (!gfc_is_constant_expr (mask) - && !is_constant_array_expr (mask))) - return NULL; - - result = gfc_get_array_expr (array->ts.type, array->ts.kind, &array->where); - if (array->ts.type == BT_DERIVED) - result->ts.u.derived = array->ts.u.derived; - - array_ctor = gfc_constructor_first (array->value.constructor); - vector_ctor = vector - ? gfc_constructor_first (vector->value.constructor) - : NULL; - - if (mask->expr_type == EXPR_CONSTANT - && mask->value.logical) - { - /* Copy all elements of ARRAY to RESULT. */ - while (array_ctor) - { - gfc_constructor_append_expr (&result->value.constructor, - gfc_copy_expr (array_ctor->expr), - NULL); - - array_ctor = gfc_constructor_next (array_ctor); - vector_ctor = gfc_constructor_next (vector_ctor); - } - } - else if (mask->expr_type == EXPR_ARRAY) - { - /* Copy only those elements of ARRAY to RESULT whose - MASK equals .TRUE.. */ - mask_ctor = gfc_constructor_first (mask->value.constructor); - while (mask_ctor) - { - if (mask_ctor->expr->value.logical) - { - gfc_constructor_append_expr (&result->value.constructor, - gfc_copy_expr (array_ctor->expr), - NULL); - vector_ctor = gfc_constructor_next (vector_ctor); - } - - array_ctor = gfc_constructor_next (array_ctor); - mask_ctor = gfc_constructor_next (mask_ctor); - } - } - - /* Append any left-over elements from VECTOR to RESULT. */ - while (vector_ctor) - { - gfc_constructor_append_expr (&result->value.constructor, - gfc_copy_expr (vector_ctor->expr), - NULL); - vector_ctor = gfc_constructor_next (vector_ctor); - } - - result->shape = gfc_get_shape (1); - gfc_array_size (result, &result->shape[0]); - - if (array->ts.type == BT_CHARACTER) - result->ts.u.cl = array->ts.u.cl; - - return result; -} - - -static gfc_expr * -do_xor (gfc_expr *result, gfc_expr *e) -{ - gcc_assert (e->ts.type == BT_LOGICAL && e->expr_type == EXPR_CONSTANT); - gcc_assert (result->ts.type == BT_LOGICAL - && result->expr_type == EXPR_CONSTANT); - - result->value.logical = result->value.logical != e->value.logical; - return result; -} - - -gfc_expr * -gfc_simplify_is_contiguous (gfc_expr *array) -{ - if (gfc_is_simply_contiguous (array, false, true)) - return gfc_get_logical_expr (gfc_default_logical_kind, &array->where, 1); - - if (gfc_is_not_contiguous (array)) - return gfc_get_logical_expr (gfc_default_logical_kind, &array->where, 0); - - return NULL; -} - - -gfc_expr * -gfc_simplify_parity (gfc_expr *e, gfc_expr *dim) -{ - return simplify_transformation (e, dim, NULL, 0, do_xor); -} - - -gfc_expr * -gfc_simplify_popcnt (gfc_expr *e) -{ - int res, k; - mpz_t x; - - if (e->expr_type != EXPR_CONSTANT) - return NULL; - - k = gfc_validate_kind (e->ts.type, e->ts.kind, false); - - /* Convert argument to unsigned, then count the '1' bits. */ - mpz_init_set (x, e->value.integer); - convert_mpz_to_unsigned (x, gfc_integer_kinds[k].bit_size); - res = mpz_popcount (x); - mpz_clear (x); - - return gfc_get_int_expr (gfc_default_integer_kind, &e->where, res); -} - - -gfc_expr * -gfc_simplify_poppar (gfc_expr *e) -{ - gfc_expr *popcnt; - int i; - - if (e->expr_type != EXPR_CONSTANT) - return NULL; - - popcnt = gfc_simplify_popcnt (e); - gcc_assert (popcnt); - - bool fail = gfc_extract_int (popcnt, &i); - gcc_assert (!fail); - - return gfc_get_int_expr (gfc_default_integer_kind, &e->where, i % 2); -} - - -gfc_expr * -gfc_simplify_precision (gfc_expr *e) -{ - int i = gfc_validate_kind (e->ts.type, e->ts.kind, false); - return gfc_get_int_expr (gfc_default_integer_kind, &e->where, - gfc_real_kinds[i].precision); -} - - -gfc_expr * -gfc_simplify_product (gfc_expr *array, gfc_expr *dim, gfc_expr *mask) -{ - return simplify_transformation (array, dim, mask, 1, gfc_multiply); -} - - -gfc_expr * -gfc_simplify_radix (gfc_expr *e) -{ - int i; - i = gfc_validate_kind (e->ts.type, e->ts.kind, false); - - switch (e->ts.type) - { - case BT_INTEGER: - i = gfc_integer_kinds[i].radix; - break; - - case BT_REAL: - i = gfc_real_kinds[i].radix; - break; - - default: - gcc_unreachable (); - } - - return gfc_get_int_expr (gfc_default_integer_kind, &e->where, i); -} - - -gfc_expr * -gfc_simplify_range (gfc_expr *e) -{ - int i; - i = gfc_validate_kind (e->ts.type, e->ts.kind, false); - - switch (e->ts.type) - { - case BT_INTEGER: - i = gfc_integer_kinds[i].range; - break; - - case BT_REAL: - case BT_COMPLEX: - i = gfc_real_kinds[i].range; - break; - - default: - gcc_unreachable (); - } - - return gfc_get_int_expr (gfc_default_integer_kind, &e->where, i); -} - - -gfc_expr * -gfc_simplify_rank (gfc_expr *e) -{ - /* Assumed rank. */ - if (e->rank == -1) - return NULL; - - return gfc_get_int_expr (gfc_default_integer_kind, &e->where, e->rank); -} - - -gfc_expr * -gfc_simplify_real (gfc_expr *e, gfc_expr *k) -{ - gfc_expr *result = NULL; - int kind, tmp1, tmp2; - - /* Convert BOZ to real, and return without range checking. */ - if (e->ts.type == BT_BOZ) - { - /* Determine kind for conversion of the BOZ. */ - if (k) - gfc_extract_int (k, &kind); - else - kind = gfc_default_real_kind; - - if (!gfc_boz2real (e, kind)) - return NULL; - result = gfc_copy_expr (e); - return result; - } - - if (e->ts.type == BT_COMPLEX) - kind = get_kind (BT_REAL, k, "REAL", e->ts.kind); - else - kind = get_kind (BT_REAL, k, "REAL", gfc_default_real_kind); - - if (kind == -1) - return &gfc_bad_expr; - - if (e->expr_type != EXPR_CONSTANT) - return NULL; - - /* For explicit conversion, turn off -Wconversion and -Wconversion-extra - warnings. */ - tmp1 = warn_conversion; - tmp2 = warn_conversion_extra; - warn_conversion = warn_conversion_extra = 0; - - result = gfc_convert_constant (e, BT_REAL, kind); - - warn_conversion = tmp1; - warn_conversion_extra = tmp2; - - if (result == &gfc_bad_expr) - return &gfc_bad_expr; - - return range_check (result, "REAL"); -} - - -gfc_expr * -gfc_simplify_realpart (gfc_expr *e) -{ - gfc_expr *result; - - if (e->expr_type != EXPR_CONSTANT) - return NULL; - - result = gfc_get_constant_expr (BT_REAL, e->ts.kind, &e->where); - mpc_real (result->value.real, e->value.complex, GFC_RND_MODE); - - return range_check (result, "REALPART"); -} - -gfc_expr * -gfc_simplify_repeat (gfc_expr *e, gfc_expr *n) -{ - gfc_expr *result; - gfc_charlen_t len; - mpz_t ncopies; - bool have_length = false; - - /* If NCOPIES isn't a constant, there's nothing we can do. */ - if (n->expr_type != EXPR_CONSTANT) - return NULL; - - /* If NCOPIES is negative, it's an error. */ - if (mpz_sgn (n->value.integer) < 0) - { - gfc_error ("Argument NCOPIES of REPEAT intrinsic is negative at %L", - &n->where); - return &gfc_bad_expr; - } - - /* If we don't know the character length, we can do no more. */ - if (e->ts.u.cl && e->ts.u.cl->length - && e->ts.u.cl->length->expr_type == EXPR_CONSTANT) - { - len = gfc_mpz_get_hwi (e->ts.u.cl->length->value.integer); - have_length = true; - } - else if (e->expr_type == EXPR_CONSTANT - && (e->ts.u.cl == NULL || e->ts.u.cl->length == NULL)) - { - len = e->value.character.length; - } - else - return NULL; - - /* If the source length is 0, any value of NCOPIES is valid - and everything behaves as if NCOPIES == 0. */ - mpz_init (ncopies); - if (len == 0) - mpz_set_ui (ncopies, 0); - else - mpz_set (ncopies, n->value.integer); - - /* Check that NCOPIES isn't too large. */ - if (len) - { - mpz_t max, mlen; - int i; - - /* Compute the maximum value allowed for NCOPIES: huge(cl) / len. */ - mpz_init (max); - i = gfc_validate_kind (BT_INTEGER, gfc_charlen_int_kind, false); - - if (have_length) - { - mpz_tdiv_q (max, gfc_integer_kinds[i].huge, - e->ts.u.cl->length->value.integer); - } - else - { - mpz_init (mlen); - gfc_mpz_set_hwi (mlen, len); - mpz_tdiv_q (max, gfc_integer_kinds[i].huge, mlen); - mpz_clear (mlen); - } - - /* The check itself. */ - if (mpz_cmp (ncopies, max) > 0) - { - mpz_clear (max); - mpz_clear (ncopies); - gfc_error ("Argument NCOPIES of REPEAT intrinsic is too large at %L", - &n->where); - return &gfc_bad_expr; - } - - mpz_clear (max); - } - mpz_clear (ncopies); - - /* For further simplification, we need the character string to be - constant. */ - if (e->expr_type != EXPR_CONSTANT) - return NULL; - - HOST_WIDE_INT ncop; - if (len || - (e->ts.u.cl->length && - mpz_sgn (e->ts.u.cl->length->value.integer) != 0)) - { - bool fail = gfc_extract_hwi (n, &ncop); - gcc_assert (!fail); - } - else - ncop = 0; - - if (ncop == 0) - return gfc_get_character_expr (e->ts.kind, &e->where, NULL, 0); - - len = e->value.character.length; - gfc_charlen_t nlen = ncop * len; - - /* Here's a semi-arbitrary limit. If the string is longer than 1 GB - (2**28 elements * 4 bytes (wide chars) per element) defer to - runtime instead of consuming (unbounded) memory and CPU at - compile time. */ - if (nlen > 268435456) - { - gfc_warning_now (0, "Evaluation of string longer than 2**28 at %L" - " deferred to runtime, expect bugs", &e->where); - return NULL; - } - - result = gfc_get_character_expr (e->ts.kind, &e->where, NULL, nlen); - for (size_t i = 0; i < (size_t) ncop; i++) - for (size_t j = 0; j < (size_t) len; j++) - result->value.character.string[j+i*len]= e->value.character.string[j]; - - result->value.character.string[nlen] = '\0'; /* For debugger */ - return result; -} - - -/* This one is a bear, but mainly has to do with shuffling elements. */ - -gfc_expr * -gfc_simplify_reshape (gfc_expr *source, gfc_expr *shape_exp, - gfc_expr *pad, gfc_expr *order_exp) -{ - int order[GFC_MAX_DIMENSIONS], shape[GFC_MAX_DIMENSIONS]; - int i, rank, npad, x[GFC_MAX_DIMENSIONS]; - mpz_t index, size; - unsigned long j; - size_t nsource; - gfc_expr *e, *result; - bool zerosize = false; - - /* Check that argument expression types are OK. */ - if (!is_constant_array_expr (source) - || !is_constant_array_expr (shape_exp) - || !is_constant_array_expr (pad) - || !is_constant_array_expr (order_exp)) - return NULL; - - if (source->shape == NULL) - return NULL; - - /* Proceed with simplification, unpacking the array. */ - - mpz_init (index); - rank = 0; - - for (i = 0; i < GFC_MAX_DIMENSIONS; i++) - x[i] = 0; - - for (;;) - { - e = gfc_constructor_lookup_expr (shape_exp->value.constructor, rank); - if (e == NULL) - break; - - gfc_extract_int (e, &shape[rank]); - - gcc_assert (rank >= 0 && rank < GFC_MAX_DIMENSIONS); - if (shape[rank] < 0) - { - gfc_error ("The SHAPE array for the RESHAPE intrinsic at %L has a " - "negative value %d for dimension %d", - &shape_exp->where, shape[rank], rank+1); - return &gfc_bad_expr; - } - - rank++; - } - - gcc_assert (rank > 0); - - /* Now unpack the order array if present. */ - if (order_exp == NULL) - { - for (i = 0; i < rank; i++) - order[i] = i; - } - else - { - mpz_t size; - int order_size, shape_size; - - if (order_exp->rank != shape_exp->rank) - { - gfc_error ("Shapes of ORDER at %L and SHAPE at %L are different", - &order_exp->where, &shape_exp->where); - return &gfc_bad_expr; - } - - gfc_array_size (shape_exp, &size); - shape_size = mpz_get_ui (size); - mpz_clear (size); - gfc_array_size (order_exp, &size); - order_size = mpz_get_ui (size); - mpz_clear (size); - if (order_size != shape_size) - { - gfc_error ("Sizes of ORDER at %L and SHAPE at %L are different", - &order_exp->where, &shape_exp->where); - return &gfc_bad_expr; - } - - for (i = 0; i < rank; i++) - { - e = gfc_constructor_lookup_expr (order_exp->value.constructor, i); - gcc_assert (e); - - gfc_extract_int (e, &order[i]); - - if (order[i] < 1 || order[i] > rank) - { - gfc_error ("Element with a value of %d in ORDER at %L must be " - "in the range [1, ..., %d] for the RESHAPE intrinsic " - "near %L", order[i], &order_exp->where, rank, - &shape_exp->where); - return &gfc_bad_expr; - } - - order[i]--; - if (x[order[i]] != 0) - { - gfc_error ("ORDER at %L is not a permutation of the size of " - "SHAPE at %L", &order_exp->where, &shape_exp->where); - return &gfc_bad_expr; - } - x[order[i]] = 1; - } - } - - /* Count the elements in the source and padding arrays. */ - - npad = 0; - if (pad != NULL) - { - gfc_array_size (pad, &size); - npad = mpz_get_ui (size); - mpz_clear (size); - } - - gfc_array_size (source, &size); - nsource = mpz_get_ui (size); - mpz_clear (size); - - /* If it weren't for that pesky permutation we could just loop - through the source and round out any shortage with pad elements. - But no, someone just had to have the compiler do something the - user should be doing. */ - - for (i = 0; i < rank; i++) - x[i] = 0; - - result = gfc_get_array_expr (source->ts.type, source->ts.kind, - &source->where); - if (source->ts.type == BT_DERIVED) - result->ts.u.derived = source->ts.u.derived; - if (source->ts.type == BT_CHARACTER && result->ts.u.cl == NULL) - result->ts = source->ts; - result->rank = rank; - result->shape = gfc_get_shape (rank); - for (i = 0; i < rank; i++) - { - mpz_init_set_ui (result->shape[i], shape[i]); - if (shape[i] == 0) - zerosize = true; - } - - if (zerosize) - goto sizezero; - - while (nsource > 0 || npad > 0) - { - /* Figure out which element to extract. */ - mpz_set_ui (index, 0); - - for (i = rank - 1; i >= 0; i--) - { - mpz_add_ui (index, index, x[order[i]]); - if (i != 0) - mpz_mul_ui (index, index, shape[order[i - 1]]); - } - - if (mpz_cmp_ui (index, INT_MAX) > 0) - gfc_internal_error ("Reshaped array too large at %C"); - - j = mpz_get_ui (index); - - if (j < nsource) - e = gfc_constructor_lookup_expr (source->value.constructor, j); - else - { - if (npad <= 0) - { - mpz_clear (index); - return NULL; - } - j = j - nsource; - j = j % npad; - e = gfc_constructor_lookup_expr (pad->value.constructor, j); - } - gcc_assert (e); - - gfc_constructor_append_expr (&result->value.constructor, - gfc_copy_expr (e), &e->where); - - /* Calculate the next element. */ - i = 0; - -inc: - if (++x[i] < shape[i]) - continue; - x[i++] = 0; - if (i < rank) - goto inc; - - break; - } - -sizezero: - - mpz_clear (index); - - return result; -} - - -gfc_expr * -gfc_simplify_rrspacing (gfc_expr *x) -{ - gfc_expr *result; - int i; - long int e, p; - - if (x->expr_type != EXPR_CONSTANT) - return NULL; - - i = gfc_validate_kind (x->ts.type, x->ts.kind, false); - - result = gfc_get_constant_expr (BT_REAL, x->ts.kind, &x->where); - - /* RRSPACING(+/- 0.0) = 0.0 */ - if (mpfr_zero_p (x->value.real)) - { - mpfr_set_ui (result->value.real, 0, GFC_RND_MODE); - return result; - } - - /* RRSPACING(inf) = NaN */ - if (mpfr_inf_p (x->value.real)) - { - mpfr_set_nan (result->value.real); - return result; - } - - /* RRSPACING(NaN) = same NaN */ - if (mpfr_nan_p (x->value.real)) - { - mpfr_set (result->value.real, x->value.real, GFC_RND_MODE); - return result; - } - - /* | x * 2**(-e) | * 2**p. */ - mpfr_abs (result->value.real, x->value.real, GFC_RND_MODE); - e = - (long int) mpfr_get_exp (x->value.real); - mpfr_mul_2si (result->value.real, result->value.real, e, GFC_RND_MODE); - - p = (long int) gfc_real_kinds[i].digits; - mpfr_mul_2si (result->value.real, result->value.real, p, GFC_RND_MODE); - - return range_check (result, "RRSPACING"); -} - - -gfc_expr * -gfc_simplify_scale (gfc_expr *x, gfc_expr *i) -{ - int k, neg_flag, power, exp_range; - mpfr_t scale, radix; - gfc_expr *result; - - if (x->expr_type != EXPR_CONSTANT || i->expr_type != EXPR_CONSTANT) - return NULL; - - result = gfc_get_constant_expr (BT_REAL, x->ts.kind, &x->where); - - if (mpfr_zero_p (x->value.real)) - { - mpfr_set_ui (result->value.real, 0, GFC_RND_MODE); - return result; - } - - k = gfc_validate_kind (BT_REAL, x->ts.kind, false); - - exp_range = gfc_real_kinds[k].max_exponent - gfc_real_kinds[k].min_exponent; - - /* This check filters out values of i that would overflow an int. */ - if (mpz_cmp_si (i->value.integer, exp_range + 2) > 0 - || mpz_cmp_si (i->value.integer, -exp_range - 2) < 0) - { - gfc_error ("Result of SCALE overflows its kind at %L", &result->where); - gfc_free_expr (result); - return &gfc_bad_expr; - } - - /* Compute scale = radix ** power. */ - power = mpz_get_si (i->value.integer); - - if (power >= 0) - neg_flag = 0; - else - { - neg_flag = 1; - power = -power; - } - - gfc_set_model_kind (x->ts.kind); - mpfr_init (scale); - mpfr_init (radix); - mpfr_set_ui (radix, gfc_real_kinds[k].radix, GFC_RND_MODE); - mpfr_pow_ui (scale, radix, power, GFC_RND_MODE); - - if (neg_flag) - mpfr_div (result->value.real, x->value.real, scale, GFC_RND_MODE); - else - mpfr_mul (result->value.real, x->value.real, scale, GFC_RND_MODE); - - mpfr_clears (scale, radix, NULL); - - return range_check (result, "SCALE"); -} - - -/* Variants of strspn and strcspn that operate on wide characters. */ - -static size_t -wide_strspn (const gfc_char_t *s1, const gfc_char_t *s2) -{ - size_t i = 0; - const gfc_char_t *c; - - while (s1[i]) - { - for (c = s2; *c; c++) - { - if (s1[i] == *c) - break; - } - if (*c == '\0') - break; - i++; - } - - return i; -} - -static size_t -wide_strcspn (const gfc_char_t *s1, const gfc_char_t *s2) -{ - size_t i = 0; - const gfc_char_t *c; - - while (s1[i]) - { - for (c = s2; *c; c++) - { - if (s1[i] == *c) - break; - } - if (*c) - break; - i++; - } - - return i; -} - - -gfc_expr * -gfc_simplify_scan (gfc_expr *e, gfc_expr *c, gfc_expr *b, gfc_expr *kind) -{ - gfc_expr *result; - int back; - size_t i; - size_t indx, len, lenc; - int k = get_kind (BT_INTEGER, kind, "SCAN", gfc_default_integer_kind); - - if (k == -1) - return &gfc_bad_expr; - - if (e->expr_type != EXPR_CONSTANT || c->expr_type != EXPR_CONSTANT - || ( b != NULL && b->expr_type != EXPR_CONSTANT)) - return NULL; - - if (b != NULL && b->value.logical != 0) - back = 1; - else - back = 0; - - len = e->value.character.length; - lenc = c->value.character.length; - - if (len == 0 || lenc == 0) - { - indx = 0; - } - else - { - if (back == 0) - { - indx = wide_strcspn (e->value.character.string, - c->value.character.string) + 1; - if (indx > len) - indx = 0; - } - else - for (indx = len; indx > 0; indx--) - { - for (i = 0; i < lenc; i++) - { - if (c->value.character.string[i] - == e->value.character.string[indx - 1]) - break; - } - if (i < lenc) - break; - } - } - - result = gfc_get_int_expr (k, &e->where, indx); - return range_check (result, "SCAN"); -} - - -gfc_expr * -gfc_simplify_selected_char_kind (gfc_expr *e) -{ - int kind; - - if (e->expr_type != EXPR_CONSTANT) - return NULL; - - if (gfc_compare_with_Cstring (e, "ascii", false) == 0 - || gfc_compare_with_Cstring (e, "default", false) == 0) - kind = 1; - else if (gfc_compare_with_Cstring (e, "iso_10646", false) == 0) - kind = 4; - else - kind = -1; - - return gfc_get_int_expr (gfc_default_integer_kind, &e->where, kind); -} - - -gfc_expr * -gfc_simplify_selected_int_kind (gfc_expr *e) -{ - int i, kind, range; - - if (e->expr_type != EXPR_CONSTANT || gfc_extract_int (e, &range)) - return NULL; - - kind = INT_MAX; - - for (i = 0; gfc_integer_kinds[i].kind != 0; i++) - if (gfc_integer_kinds[i].range >= range - && gfc_integer_kinds[i].kind < kind) - kind = gfc_integer_kinds[i].kind; - - if (kind == INT_MAX) - kind = -1; - - return gfc_get_int_expr (gfc_default_integer_kind, &e->where, kind); -} - - -gfc_expr * -gfc_simplify_selected_real_kind (gfc_expr *p, gfc_expr *q, gfc_expr *rdx) -{ - int range, precision, radix, i, kind, found_precision, found_range, - found_radix; - locus *loc = &gfc_current_locus; - - if (p == NULL) - precision = 0; - else - { - if (p->expr_type != EXPR_CONSTANT - || gfc_extract_int (p, &precision)) - return NULL; - loc = &p->where; - } - - if (q == NULL) - range = 0; - else - { - if (q->expr_type != EXPR_CONSTANT - || gfc_extract_int (q, &range)) - return NULL; - - if (!loc) - loc = &q->where; - } - - if (rdx == NULL) - radix = 0; - else - { - if (rdx->expr_type != EXPR_CONSTANT - || gfc_extract_int (rdx, &radix)) - return NULL; - - if (!loc) - loc = &rdx->where; - } - - kind = INT_MAX; - found_precision = 0; - found_range = 0; - found_radix = 0; - - for (i = 0; gfc_real_kinds[i].kind != 0; i++) - { - if (gfc_real_kinds[i].precision >= precision) - found_precision = 1; - - if (gfc_real_kinds[i].range >= range) - found_range = 1; - - if (radix == 0 || gfc_real_kinds[i].radix == radix) - found_radix = 1; - - if (gfc_real_kinds[i].precision >= precision - && gfc_real_kinds[i].range >= range - && (radix == 0 || gfc_real_kinds[i].radix == radix) - && gfc_real_kinds[i].kind < kind) - kind = gfc_real_kinds[i].kind; - } - - if (kind == INT_MAX) - { - if (found_radix && found_range && !found_precision) - kind = -1; - else if (found_radix && found_precision && !found_range) - kind = -2; - else if (found_radix && !found_precision && !found_range) - kind = -3; - else if (found_radix) - kind = -4; - else - kind = -5; - } - - return gfc_get_int_expr (gfc_default_integer_kind, loc, kind); -} - - -gfc_expr * -gfc_simplify_set_exponent (gfc_expr *x, gfc_expr *i) -{ - gfc_expr *result; - mpfr_t exp, absv, log2, pow2, frac; - unsigned long exp2; - - if (x->expr_type != EXPR_CONSTANT || i->expr_type != EXPR_CONSTANT) - return NULL; - - result = gfc_get_constant_expr (BT_REAL, x->ts.kind, &x->where); - - /* SET_EXPONENT (+/-0.0, I) = +/- 0.0 - SET_EXPONENT (NaN) = same NaN */ - if (mpfr_zero_p (x->value.real) || mpfr_nan_p (x->value.real)) - { - mpfr_set (result->value.real, x->value.real, GFC_RND_MODE); - return result; - } - - /* SET_EXPONENT (inf) = NaN */ - if (mpfr_inf_p (x->value.real)) - { - mpfr_set_nan (result->value.real); - return result; - } - - gfc_set_model_kind (x->ts.kind); - mpfr_init (absv); - mpfr_init (log2); - mpfr_init (exp); - mpfr_init (pow2); - mpfr_init (frac); - - mpfr_abs (absv, x->value.real, GFC_RND_MODE); - mpfr_log2 (log2, absv, GFC_RND_MODE); - - mpfr_trunc (log2, log2); - mpfr_add_ui (exp, log2, 1, GFC_RND_MODE); - - /* Old exponent value, and fraction. */ - mpfr_ui_pow (pow2, 2, exp, GFC_RND_MODE); - - mpfr_div (frac, absv, pow2, GFC_RND_MODE); - - /* New exponent. */ - exp2 = (unsigned long) mpz_get_d (i->value.integer); - mpfr_mul_2exp (result->value.real, frac, exp2, GFC_RND_MODE); - - mpfr_clears (absv, log2, pow2, frac, NULL); - - return range_check (result, "SET_EXPONENT"); -} - - -gfc_expr * -gfc_simplify_shape (gfc_expr *source, gfc_expr *kind) -{ - mpz_t shape[GFC_MAX_DIMENSIONS]; - gfc_expr *result, *e, *f; - gfc_array_ref *ar; - int n; - bool t; - int k = get_kind (BT_INTEGER, kind, "SHAPE", gfc_default_integer_kind); - - if (source->rank == -1) - return NULL; - - result = gfc_get_array_expr (BT_INTEGER, k, &source->where); - result->shape = gfc_get_shape (1); - mpz_init (result->shape[0]); - - if (source->rank == 0) - return result; - - if (source->expr_type == EXPR_VARIABLE) - { - ar = gfc_find_array_ref (source); - t = gfc_array_ref_shape (ar, shape); - } - else if (source->shape) - { - t = true; - for (n = 0; n < source->rank; n++) - { - mpz_init (shape[n]); - mpz_set (shape[n], source->shape[n]); - } - } - else - t = false; - - for (n = 0; n < source->rank; n++) - { - e = gfc_get_constant_expr (BT_INTEGER, k, &source->where); - - if (t) - mpz_set (e->value.integer, shape[n]); - else - { - mpz_set_ui (e->value.integer, n + 1); - - f = simplify_size (source, e, k); - gfc_free_expr (e); - if (f == NULL) - { - gfc_free_expr (result); - return NULL; - } - else - e = f; - } - - if (e == &gfc_bad_expr || range_check (e, "SHAPE") == &gfc_bad_expr) - { - gfc_free_expr (result); - if (t) - gfc_clear_shape (shape, source->rank); - return &gfc_bad_expr; - } - - gfc_constructor_append_expr (&result->value.constructor, e, NULL); - } - - if (t) - gfc_clear_shape (shape, source->rank); - - mpz_set_si (result->shape[0], source->rank); - - return result; -} - - -static gfc_expr * -simplify_size (gfc_expr *array, gfc_expr *dim, int k) -{ - mpz_t size; - gfc_expr *return_value; - int d; - gfc_ref *ref; - - /* For unary operations, the size of the result is given by the size - of the operand. For binary ones, it's the size of the first operand - unless it is scalar, then it is the size of the second. */ - if (array->expr_type == EXPR_OP && !array->value.op.uop) - { - gfc_expr* replacement; - gfc_expr* simplified; - - switch (array->value.op.op) - { - /* Unary operations. */ - case INTRINSIC_NOT: - case INTRINSIC_UPLUS: - case INTRINSIC_UMINUS: - case INTRINSIC_PARENTHESES: - replacement = array->value.op.op1; - break; - - /* Binary operations. If any one of the operands is scalar, take - the other one's size. If both of them are arrays, it does not - matter -- try to find one with known shape, if possible. */ - default: - if (array->value.op.op1->rank == 0) - replacement = array->value.op.op2; - else if (array->value.op.op2->rank == 0) - replacement = array->value.op.op1; - else - { - simplified = simplify_size (array->value.op.op1, dim, k); - if (simplified) - return simplified; - - replacement = array->value.op.op2; - } - break; - } - - /* Try to reduce it directly if possible. */ - simplified = simplify_size (replacement, dim, k); - - /* Otherwise, we build a new SIZE call. This is hopefully at least - simpler than the original one. */ - if (!simplified) - { - gfc_expr *kind = gfc_get_int_expr (gfc_default_integer_kind, NULL, k); - simplified = gfc_build_intrinsic_call (gfc_current_ns, - GFC_ISYM_SIZE, "size", - array->where, 3, - gfc_copy_expr (replacement), - gfc_copy_expr (dim), - kind); - } - return simplified; - } - - for (ref = array->ref; ref; ref = ref->next) - if (ref->type == REF_ARRAY && ref->u.ar.as) - gfc_resolve_array_spec (ref->u.ar.as, 0); - - if (dim == NULL) - { - if (!gfc_array_size (array, &size)) - return NULL; - } - else - { - if (dim->expr_type != EXPR_CONSTANT) - return NULL; - - d = mpz_get_ui (dim->value.integer) - 1; - if (!gfc_array_dimen_size (array, d, &size)) - return NULL; - } - - return_value = gfc_get_constant_expr (BT_INTEGER, k, &array->where); - mpz_set (return_value->value.integer, size); - mpz_clear (size); - - return return_value; -} - - -gfc_expr * -gfc_simplify_size (gfc_expr *array, gfc_expr *dim, gfc_expr *kind) -{ - gfc_expr *result; - int k = get_kind (BT_INTEGER, kind, "SIZE", gfc_default_integer_kind); - - if (k == -1) - return &gfc_bad_expr; - - result = simplify_size (array, dim, k); - if (result == NULL || result == &gfc_bad_expr) - return result; - - return range_check (result, "SIZE"); -} - - -/* SIZEOF and C_SIZEOF return the size in bytes of an array element - multiplied by the array size. */ - -gfc_expr * -gfc_simplify_sizeof (gfc_expr *x) -{ - gfc_expr *result = NULL; - mpz_t array_size; - size_t res_size; - - if (x->ts.type == BT_CLASS || x->ts.deferred) - return NULL; - - if (x->ts.type == BT_CHARACTER - && (!x->ts.u.cl || !x->ts.u.cl->length - || x->ts.u.cl->length->expr_type != EXPR_CONSTANT)) - return NULL; - - if (x->rank && x->expr_type != EXPR_ARRAY - && !gfc_array_size (x, &array_size)) - return NULL; - - result = gfc_get_constant_expr (BT_INTEGER, gfc_index_integer_kind, - &x->where); - gfc_target_expr_size (x, &res_size); - mpz_set_si (result->value.integer, res_size); - - return result; -} - - -/* STORAGE_SIZE returns the size in bits of a single array element. */ - -gfc_expr * -gfc_simplify_storage_size (gfc_expr *x, - gfc_expr *kind) -{ - gfc_expr *result = NULL; - int k; - size_t siz; - - if (x->ts.type == BT_CLASS || x->ts.deferred) - return NULL; - - if (x->ts.type == BT_CHARACTER && x->expr_type != EXPR_CONSTANT - && (!x->ts.u.cl || !x->ts.u.cl->length - || x->ts.u.cl->length->expr_type != EXPR_CONSTANT)) - return NULL; - - k = get_kind (BT_INTEGER, kind, "STORAGE_SIZE", gfc_default_integer_kind); - if (k == -1) - return &gfc_bad_expr; - - result = gfc_get_constant_expr (BT_INTEGER, k, &x->where); - - gfc_element_size (x, &siz); - mpz_set_si (result->value.integer, siz); - mpz_mul_ui (result->value.integer, result->value.integer, BITS_PER_UNIT); - - return range_check (result, "STORAGE_SIZE"); -} - - -gfc_expr * -gfc_simplify_sign (gfc_expr *x, gfc_expr *y) -{ - gfc_expr *result; - - if (x->expr_type != EXPR_CONSTANT || y->expr_type != EXPR_CONSTANT) - return NULL; - - result = gfc_get_constant_expr (x->ts.type, x->ts.kind, &x->where); - - switch (x->ts.type) - { - case BT_INTEGER: - mpz_abs (result->value.integer, x->value.integer); - if (mpz_sgn (y->value.integer) < 0) - mpz_neg (result->value.integer, result->value.integer); - break; - - case BT_REAL: - if (flag_sign_zero) - mpfr_copysign (result->value.real, x->value.real, y->value.real, - GFC_RND_MODE); - else - mpfr_setsign (result->value.real, x->value.real, - mpfr_sgn (y->value.real) < 0 ? 1 : 0, GFC_RND_MODE); - break; - - default: - gfc_internal_error ("Bad type in gfc_simplify_sign"); - } - - return result; -} - - -gfc_expr * -gfc_simplify_sin (gfc_expr *x) -{ - gfc_expr *result; - - if (x->expr_type != EXPR_CONSTANT) - return NULL; - - result = gfc_get_constant_expr (x->ts.type, x->ts.kind, &x->where); - - switch (x->ts.type) - { - case BT_REAL: - mpfr_sin (result->value.real, x->value.real, GFC_RND_MODE); - break; - - case BT_COMPLEX: - gfc_set_model (x->value.real); - mpc_sin (result->value.complex, x->value.complex, GFC_MPC_RND_MODE); - break; - - default: - gfc_internal_error ("in gfc_simplify_sin(): Bad type"); - } - - return range_check (result, "SIN"); -} - - -gfc_expr * -gfc_simplify_sinh (gfc_expr *x) -{ - gfc_expr *result; - - if (x->expr_type != EXPR_CONSTANT) - return NULL; - - result = gfc_get_constant_expr (x->ts.type, x->ts.kind, &x->where); - - switch (x->ts.type) - { - case BT_REAL: - mpfr_sinh (result->value.real, x->value.real, GFC_RND_MODE); - break; - - case BT_COMPLEX: - mpc_sinh (result->value.complex, x->value.complex, GFC_MPC_RND_MODE); - break; - - default: - gcc_unreachable (); - } - - return range_check (result, "SINH"); -} - - -/* The argument is always a double precision real that is converted to - single precision. TODO: Rounding! */ - -gfc_expr * -gfc_simplify_sngl (gfc_expr *a) -{ - gfc_expr *result; - int tmp1, tmp2; - - if (a->expr_type != EXPR_CONSTANT) - return NULL; - - /* For explicit conversion, turn off -Wconversion and -Wconversion-extra - warnings. */ - tmp1 = warn_conversion; - tmp2 = warn_conversion_extra; - warn_conversion = warn_conversion_extra = 0; - - result = gfc_real2real (a, gfc_default_real_kind); - - warn_conversion = tmp1; - warn_conversion_extra = tmp2; - - return range_check (result, "SNGL"); -} - - -gfc_expr * -gfc_simplify_spacing (gfc_expr *x) -{ - gfc_expr *result; - int i; - long int en, ep; - - if (x->expr_type != EXPR_CONSTANT) - return NULL; - - i = gfc_validate_kind (x->ts.type, x->ts.kind, false); - result = gfc_get_constant_expr (BT_REAL, x->ts.kind, &x->where); - - /* SPACING(+/- 0.0) = SPACING(TINY(0.0)) = TINY(0.0) */ - if (mpfr_zero_p (x->value.real)) - { - mpfr_set (result->value.real, gfc_real_kinds[i].tiny, GFC_RND_MODE); - return result; - } - - /* SPACING(inf) = NaN */ - if (mpfr_inf_p (x->value.real)) - { - mpfr_set_nan (result->value.real); - return result; - } - - /* SPACING(NaN) = same NaN */ - if (mpfr_nan_p (x->value.real)) - { - mpfr_set (result->value.real, x->value.real, GFC_RND_MODE); - return result; - } - - /* In the Fortran 95 standard, the result is b**(e - p) where b, e, and p - are the radix, exponent of x, and precision. This excludes the - possibility of subnormal numbers. Fortran 2003 states the result is - b**max(e - p, emin - 1). */ - - ep = (long int) mpfr_get_exp (x->value.real) - gfc_real_kinds[i].digits; - en = (long int) gfc_real_kinds[i].min_exponent - 1; - en = en > ep ? en : ep; - - mpfr_set_ui (result->value.real, 1, GFC_RND_MODE); - mpfr_mul_2si (result->value.real, result->value.real, en, GFC_RND_MODE); - - return range_check (result, "SPACING"); -} - - -gfc_expr * -gfc_simplify_spread (gfc_expr *source, gfc_expr *dim_expr, gfc_expr *ncopies_expr) -{ - gfc_expr *result = NULL; - int nelem, i, j, dim, ncopies; - mpz_t size; - - if ((!gfc_is_constant_expr (source) - && !is_constant_array_expr (source)) - || !gfc_is_constant_expr (dim_expr) - || !gfc_is_constant_expr (ncopies_expr)) - return NULL; - - gcc_assert (dim_expr->ts.type == BT_INTEGER); - gfc_extract_int (dim_expr, &dim); - dim -= 1; /* zero-base DIM */ - - gcc_assert (ncopies_expr->ts.type == BT_INTEGER); - gfc_extract_int (ncopies_expr, &ncopies); - ncopies = MAX (ncopies, 0); - - /* Do not allow the array size to exceed the limit for an array - constructor. */ - if (source->expr_type == EXPR_ARRAY) - { - if (!gfc_array_size (source, &size)) - gfc_internal_error ("Failure getting length of a constant array."); - } - else - mpz_init_set_ui (size, 1); - - nelem = mpz_get_si (size) * ncopies; - if (nelem > flag_max_array_constructor) - { - if (gfc_init_expr_flag) - { - gfc_error ("The number of elements (%d) in the array constructor " - "at %L requires an increase of the allowed %d upper " - "limit. See %<-fmax-array-constructor%> option.", - nelem, &source->where, flag_max_array_constructor); - return &gfc_bad_expr; - } - else - return NULL; - } - - if (source->expr_type == EXPR_CONSTANT - || source->expr_type == EXPR_STRUCTURE) - { - gcc_assert (dim == 0); - - result = gfc_get_array_expr (source->ts.type, source->ts.kind, - &source->where); - if (source->ts.type == BT_DERIVED) - result->ts.u.derived = source->ts.u.derived; - result->rank = 1; - result->shape = gfc_get_shape (result->rank); - mpz_init_set_si (result->shape[0], ncopies); - - for (i = 0; i < ncopies; ++i) - gfc_constructor_append_expr (&result->value.constructor, - gfc_copy_expr (source), NULL); - } - else if (source->expr_type == EXPR_ARRAY) - { - int offset, rstride[GFC_MAX_DIMENSIONS], extent[GFC_MAX_DIMENSIONS]; - gfc_constructor *source_ctor; - - gcc_assert (source->rank < GFC_MAX_DIMENSIONS); - gcc_assert (dim >= 0 && dim <= source->rank); - - result = gfc_get_array_expr (source->ts.type, source->ts.kind, - &source->where); - if (source->ts.type == BT_DERIVED) - result->ts.u.derived = source->ts.u.derived; - result->rank = source->rank + 1; - result->shape = gfc_get_shape (result->rank); - - for (i = 0, j = 0; i < result->rank; ++i) - { - if (i != dim) - mpz_init_set (result->shape[i], source->shape[j++]); - else - mpz_init_set_si (result->shape[i], ncopies); - - extent[i] = mpz_get_si (result->shape[i]); - rstride[i] = (i == 0) ? 1 : rstride[i-1] * extent[i-1]; - } - - offset = 0; - for (source_ctor = gfc_constructor_first (source->value.constructor); - source_ctor; source_ctor = gfc_constructor_next (source_ctor)) - { - for (i = 0; i < ncopies; ++i) - gfc_constructor_insert_expr (&result->value.constructor, - gfc_copy_expr (source_ctor->expr), - NULL, offset + i * rstride[dim]); - - offset += (dim == 0 ? ncopies : 1); - } - } - else - { - gfc_error ("Simplification of SPREAD at %C not yet implemented"); - return &gfc_bad_expr; - } - - if (source->ts.type == BT_CHARACTER) - result->ts.u.cl = source->ts.u.cl; - - return result; -} - - -gfc_expr * -gfc_simplify_sqrt (gfc_expr *e) -{ - gfc_expr *result = NULL; - - if (e->expr_type != EXPR_CONSTANT) - return NULL; - - switch (e->ts.type) - { - case BT_REAL: - if (mpfr_cmp_si (e->value.real, 0) < 0) - { - gfc_error ("Argument of SQRT at %L has a negative value", - &e->where); - return &gfc_bad_expr; - } - result = gfc_get_constant_expr (e->ts.type, e->ts.kind, &e->where); - mpfr_sqrt (result->value.real, e->value.real, GFC_RND_MODE); - break; - - case BT_COMPLEX: - gfc_set_model (e->value.real); - - result = gfc_get_constant_expr (e->ts.type, e->ts.kind, &e->where); - mpc_sqrt (result->value.complex, e->value.complex, GFC_MPC_RND_MODE); - break; - - default: - gfc_internal_error ("invalid argument of SQRT at %L", &e->where); - } - - return range_check (result, "SQRT"); -} - - -gfc_expr * -gfc_simplify_sum (gfc_expr *array, gfc_expr *dim, gfc_expr *mask) -{ - return simplify_transformation (array, dim, mask, 0, gfc_add); -} - - -/* Simplify COTAN(X) where X has the unit of radian. */ - -gfc_expr * -gfc_simplify_cotan (gfc_expr *x) -{ - gfc_expr *result; - mpc_t swp, *val; - - if (x->expr_type != EXPR_CONSTANT) - return NULL; - - result = gfc_get_constant_expr (x->ts.type, x->ts.kind, &x->where); - - switch (x->ts.type) - { - case BT_REAL: - mpfr_cot (result->value.real, x->value.real, GFC_RND_MODE); - break; - - case BT_COMPLEX: - /* There is no builtin mpc_cot, so compute cot = cos / sin. */ - val = &result->value.complex; - mpc_init2 (swp, mpfr_get_default_prec ()); - mpc_sin_cos (*val, swp, x->value.complex, GFC_MPC_RND_MODE, - GFC_MPC_RND_MODE); - mpc_div (*val, swp, *val, GFC_MPC_RND_MODE); - mpc_clear (swp); - break; - - default: - gcc_unreachable (); - } - - return range_check (result, "COTAN"); -} - - -gfc_expr * -gfc_simplify_tan (gfc_expr *x) -{ - gfc_expr *result; - - if (x->expr_type != EXPR_CONSTANT) - return NULL; - - result = gfc_get_constant_expr (x->ts.type, x->ts.kind, &x->where); - - switch (x->ts.type) - { - case BT_REAL: - mpfr_tan (result->value.real, x->value.real, GFC_RND_MODE); - break; - - case BT_COMPLEX: - mpc_tan (result->value.complex, x->value.complex, GFC_MPC_RND_MODE); - break; - - default: - gcc_unreachable (); - } - - return range_check (result, "TAN"); -} - - -gfc_expr * -gfc_simplify_tanh (gfc_expr *x) -{ - gfc_expr *result; - - if (x->expr_type != EXPR_CONSTANT) - return NULL; - - result = gfc_get_constant_expr (x->ts.type, x->ts.kind, &x->where); - - switch (x->ts.type) - { - case BT_REAL: - mpfr_tanh (result->value.real, x->value.real, GFC_RND_MODE); - break; - - case BT_COMPLEX: - mpc_tanh (result->value.complex, x->value.complex, GFC_MPC_RND_MODE); - break; - - default: - gcc_unreachable (); - } - - return range_check (result, "TANH"); -} - - -gfc_expr * -gfc_simplify_tiny (gfc_expr *e) -{ - gfc_expr *result; - int i; - - i = gfc_validate_kind (BT_REAL, e->ts.kind, false); - - result = gfc_get_constant_expr (BT_REAL, e->ts.kind, &e->where); - mpfr_set (result->value.real, gfc_real_kinds[i].tiny, GFC_RND_MODE); - - return result; -} - - -gfc_expr * -gfc_simplify_trailz (gfc_expr *e) -{ - unsigned long tz, bs; - int i; - - if (e->expr_type != EXPR_CONSTANT) - return NULL; - - i = gfc_validate_kind (e->ts.type, e->ts.kind, false); - bs = gfc_integer_kinds[i].bit_size; - tz = mpz_scan1 (e->value.integer, 0); - - return gfc_get_int_expr (gfc_default_integer_kind, - &e->where, MIN (tz, bs)); -} - - -gfc_expr * -gfc_simplify_transfer (gfc_expr *source, gfc_expr *mold, gfc_expr *size) -{ - gfc_expr *result; - gfc_expr *mold_element; - size_t source_size; - size_t result_size; - size_t buffer_size; - mpz_t tmp; - unsigned char *buffer; - size_t result_length; - - if (!gfc_is_constant_expr (source) || !gfc_is_constant_expr (size)) - return NULL; - - if (!gfc_resolve_expr (mold)) - return NULL; - if (gfc_init_expr_flag && !gfc_is_constant_expr (mold)) - return NULL; - - if (!gfc_calculate_transfer_sizes (source, mold, size, &source_size, - &result_size, &result_length)) - return NULL; - - /* Calculate the size of the source. */ - if (source->expr_type == EXPR_ARRAY && !gfc_array_size (source, &tmp)) - gfc_internal_error ("Failure getting length of a constant array."); - - /* Create an empty new expression with the appropriate characteristics. */ - result = gfc_get_constant_expr (mold->ts.type, mold->ts.kind, - &source->where); - result->ts = mold->ts; - - mold_element = (mold->expr_type == EXPR_ARRAY && mold->value.constructor) - ? gfc_constructor_first (mold->value.constructor)->expr - : mold; - - /* Set result character length, if needed. Note that this needs to be - set even for array expressions, in order to pass this information into - gfc_target_interpret_expr. */ - if (result->ts.type == BT_CHARACTER && gfc_is_constant_expr (mold_element)) - result->value.character.length = mold_element->value.character.length; - - /* Set the number of elements in the result, and determine its size. */ - - if (mold->expr_type == EXPR_ARRAY || mold->rank || size) - { - result->expr_type = EXPR_ARRAY; - result->rank = 1; - result->shape = gfc_get_shape (1); - mpz_init_set_ui (result->shape[0], result_length); - } - else - result->rank = 0; - - /* Allocate the buffer to store the binary version of the source. */ - buffer_size = MAX (source_size, result_size); - buffer = (unsigned char*)alloca (buffer_size); - memset (buffer, 0, buffer_size); - - /* Now write source to the buffer. */ - gfc_target_encode_expr (source, buffer, buffer_size); - - /* And read the buffer back into the new expression. */ - gfc_target_interpret_expr (buffer, buffer_size, result, false); - - return result; -} - - -gfc_expr * -gfc_simplify_transpose (gfc_expr *matrix) -{ - int row, matrix_rows, col, matrix_cols; - gfc_expr *result; - - if (!is_constant_array_expr (matrix)) - return NULL; - - gcc_assert (matrix->rank == 2); - - if (matrix->shape == NULL) - return NULL; - - result = gfc_get_array_expr (matrix->ts.type, matrix->ts.kind, - &matrix->where); - result->rank = 2; - result->shape = gfc_get_shape (result->rank); - mpz_init_set (result->shape[0], matrix->shape[1]); - mpz_init_set (result->shape[1], matrix->shape[0]); - - if (matrix->ts.type == BT_CHARACTER) - result->ts.u.cl = matrix->ts.u.cl; - else if (matrix->ts.type == BT_DERIVED) - result->ts.u.derived = matrix->ts.u.derived; - - matrix_rows = mpz_get_si (matrix->shape[0]); - matrix_cols = mpz_get_si (matrix->shape[1]); - for (row = 0; row < matrix_rows; ++row) - for (col = 0; col < matrix_cols; ++col) - { - gfc_expr *e = gfc_constructor_lookup_expr (matrix->value.constructor, - col * matrix_rows + row); - gfc_constructor_insert_expr (&result->value.constructor, - gfc_copy_expr (e), &matrix->where, - row * matrix_cols + col); - } - - return result; -} - - -gfc_expr * -gfc_simplify_trim (gfc_expr *e) -{ - gfc_expr *result; - int count, i, len, lentrim; - - if (e->expr_type != EXPR_CONSTANT) - return NULL; - - len = e->value.character.length; - for (count = 0, i = 1; i <= len; ++i) - { - if (e->value.character.string[len - i] == ' ') - count++; - else - break; - } - - lentrim = len - count; - - result = gfc_get_character_expr (e->ts.kind, &e->where, NULL, lentrim); - for (i = 0; i < lentrim; i++) - result->value.character.string[i] = e->value.character.string[i]; - - return result; -} - - -gfc_expr * -gfc_simplify_image_index (gfc_expr *coarray, gfc_expr *sub) -{ - gfc_expr *result; - gfc_ref *ref; - gfc_array_spec *as; - gfc_constructor *sub_cons; - bool first_image; - int d; - - if (!is_constant_array_expr (sub)) - return NULL; - - /* Follow any component references. */ - as = coarray->symtree->n.sym->as; - for (ref = coarray->ref; ref; ref = ref->next) - if (ref->type == REF_COMPONENT) - as = ref->u.ar.as; - - if (as->type == AS_DEFERRED) - return NULL; - - /* "valid sequence of cosubscripts" are required; thus, return 0 unless - the cosubscript addresses the first image. */ - - sub_cons = gfc_constructor_first (sub->value.constructor); - first_image = true; - - for (d = 1; d <= as->corank; d++) - { - gfc_expr *ca_bound; - int cmp; - - gcc_assert (sub_cons != NULL); - - ca_bound = simplify_bound_dim (coarray, NULL, d + as->rank, 0, as, - NULL, true); - if (ca_bound == NULL) - return NULL; - - if (ca_bound == &gfc_bad_expr) - return ca_bound; - - cmp = mpz_cmp (ca_bound->value.integer, sub_cons->expr->value.integer); - - if (cmp == 0) - { - gfc_free_expr (ca_bound); - sub_cons = gfc_constructor_next (sub_cons); - continue; - } - - first_image = false; - - if (cmp > 0) - { - gfc_error ("Out of bounds in IMAGE_INDEX at %L for dimension %d, " - "SUB has %ld and COARRAY lower bound is %ld)", - &coarray->where, d, - mpz_get_si (sub_cons->expr->value.integer), - mpz_get_si (ca_bound->value.integer)); - gfc_free_expr (ca_bound); - return &gfc_bad_expr; - } - - gfc_free_expr (ca_bound); - - /* Check whether upperbound is valid for the multi-images case. */ - if (d < as->corank) - { - ca_bound = simplify_bound_dim (coarray, NULL, d + as->rank, 1, as, - NULL, true); - if (ca_bound == &gfc_bad_expr) - return ca_bound; - - if (ca_bound && ca_bound->expr_type == EXPR_CONSTANT - && mpz_cmp (ca_bound->value.integer, - sub_cons->expr->value.integer) < 0) - { - gfc_error ("Out of bounds in IMAGE_INDEX at %L for dimension %d, " - "SUB has %ld and COARRAY upper bound is %ld)", - &coarray->where, d, - mpz_get_si (sub_cons->expr->value.integer), - mpz_get_si (ca_bound->value.integer)); - gfc_free_expr (ca_bound); - return &gfc_bad_expr; - } - - if (ca_bound) - gfc_free_expr (ca_bound); - } - - sub_cons = gfc_constructor_next (sub_cons); - } - - gcc_assert (sub_cons == NULL); - - if (flag_coarray != GFC_FCOARRAY_SINGLE && !first_image) - return NULL; - - result = gfc_get_constant_expr (BT_INTEGER, gfc_default_integer_kind, - &gfc_current_locus); - if (first_image) - mpz_set_si (result->value.integer, 1); - else - mpz_set_si (result->value.integer, 0); - - return result; -} - -gfc_expr * -gfc_simplify_image_status (gfc_expr *image, gfc_expr *team ATTRIBUTE_UNUSED) -{ - if (flag_coarray == GFC_FCOARRAY_NONE) - { - gfc_current_locus = *gfc_current_intrinsic_where; - gfc_fatal_error ("Coarrays disabled at %C, use %<-fcoarray=%> to enable"); - return &gfc_bad_expr; - } - - /* Simplification is possible for fcoarray = single only. For all other modes - the result depends on runtime conditions. */ - if (flag_coarray != GFC_FCOARRAY_SINGLE) - return NULL; - - if (gfc_is_constant_expr (image)) - { - gfc_expr *result; - result = gfc_get_constant_expr (BT_INTEGER, gfc_default_integer_kind, - &image->where); - if (mpz_get_si (image->value.integer) == 1) - mpz_set_si (result->value.integer, 0); - else - mpz_set_si (result->value.integer, GFC_STAT_STOPPED_IMAGE); - return result; - } - else - return NULL; -} - - -gfc_expr * -gfc_simplify_this_image (gfc_expr *coarray, gfc_expr *dim, - gfc_expr *distance ATTRIBUTE_UNUSED) -{ - if (flag_coarray != GFC_FCOARRAY_SINGLE) - return NULL; - - /* If no coarray argument has been passed or when the first argument - is actually a distance argment. */ - if (coarray == NULL || !gfc_is_coarray (coarray)) - { - gfc_expr *result; - /* FIXME: gfc_current_locus is wrong. */ - result = gfc_get_constant_expr (BT_INTEGER, gfc_default_integer_kind, - &gfc_current_locus); - mpz_set_si (result->value.integer, 1); - return result; - } - - /* For -fcoarray=single, this_image(A) is the same as lcobound(A). */ - return simplify_cobound (coarray, dim, NULL, 0); -} - - -gfc_expr * -gfc_simplify_ubound (gfc_expr *array, gfc_expr *dim, gfc_expr *kind) -{ - return simplify_bound (array, dim, kind, 1); -} - -gfc_expr * -gfc_simplify_ucobound (gfc_expr *array, gfc_expr *dim, gfc_expr *kind) -{ - return simplify_cobound (array, dim, kind, 1); -} - - -gfc_expr * -gfc_simplify_unpack (gfc_expr *vector, gfc_expr *mask, gfc_expr *field) -{ - gfc_expr *result, *e; - gfc_constructor *vector_ctor, *mask_ctor, *field_ctor; - - if (!is_constant_array_expr (vector) - || !is_constant_array_expr (mask) - || (!gfc_is_constant_expr (field) - && !is_constant_array_expr (field))) - return NULL; - - result = gfc_get_array_expr (vector->ts.type, vector->ts.kind, - &vector->where); - if (vector->ts.type == BT_DERIVED) - result->ts.u.derived = vector->ts.u.derived; - result->rank = mask->rank; - result->shape = gfc_copy_shape (mask->shape, mask->rank); - - if (vector->ts.type == BT_CHARACTER) - result->ts.u.cl = vector->ts.u.cl; - - vector_ctor = gfc_constructor_first (vector->value.constructor); - mask_ctor = gfc_constructor_first (mask->value.constructor); - field_ctor - = field->expr_type == EXPR_ARRAY - ? gfc_constructor_first (field->value.constructor) - : NULL; - - while (mask_ctor) - { - if (mask_ctor->expr->value.logical) - { - gcc_assert (vector_ctor); - e = gfc_copy_expr (vector_ctor->expr); - vector_ctor = gfc_constructor_next (vector_ctor); - } - else if (field->expr_type == EXPR_ARRAY) - e = gfc_copy_expr (field_ctor->expr); - else - e = gfc_copy_expr (field); - - gfc_constructor_append_expr (&result->value.constructor, e, NULL); - - mask_ctor = gfc_constructor_next (mask_ctor); - field_ctor = gfc_constructor_next (field_ctor); - } - - return result; -} - - -gfc_expr * -gfc_simplify_verify (gfc_expr *s, gfc_expr *set, gfc_expr *b, gfc_expr *kind) -{ - gfc_expr *result; - int back; - size_t index, len, lenset; - size_t i; - int k = get_kind (BT_INTEGER, kind, "VERIFY", gfc_default_integer_kind); - - if (k == -1) - return &gfc_bad_expr; - - if (s->expr_type != EXPR_CONSTANT || set->expr_type != EXPR_CONSTANT - || ( b != NULL && b->expr_type != EXPR_CONSTANT)) - return NULL; - - if (b != NULL && b->value.logical != 0) - back = 1; - else - back = 0; - - result = gfc_get_constant_expr (BT_INTEGER, k, &s->where); - - len = s->value.character.length; - lenset = set->value.character.length; - - if (len == 0) - { - mpz_set_ui (result->value.integer, 0); - return result; - } - - if (back == 0) - { - if (lenset == 0) - { - mpz_set_ui (result->value.integer, 1); - return result; - } - - index = wide_strspn (s->value.character.string, - set->value.character.string) + 1; - if (index > len) - index = 0; - - } - else - { - if (lenset == 0) - { - mpz_set_ui (result->value.integer, len); - return result; - } - for (index = len; index > 0; index --) - { - for (i = 0; i < lenset; i++) - { - if (s->value.character.string[index - 1] - == set->value.character.string[i]) - break; - } - if (i == lenset) - break; - } - } - - mpz_set_ui (result->value.integer, index); - return result; -} - - -gfc_expr * -gfc_simplify_xor (gfc_expr *x, gfc_expr *y) -{ - gfc_expr *result; - int kind; - - if (x->expr_type != EXPR_CONSTANT || y->expr_type != EXPR_CONSTANT) - return NULL; - - kind = x->ts.kind > y->ts.kind ? x->ts.kind : y->ts.kind; - - switch (x->ts.type) - { - case BT_INTEGER: - result = gfc_get_constant_expr (BT_INTEGER, kind, &x->where); - mpz_xor (result->value.integer, x->value.integer, y->value.integer); - return range_check (result, "XOR"); - - case BT_LOGICAL: - return gfc_get_logical_expr (kind, &x->where, - (x->value.logical && !y->value.logical) - || (!x->value.logical && y->value.logical)); - - default: - gcc_unreachable (); - } -} - - -/****************** Constant simplification *****************/ - -/* Master function to convert one constant to another. While this is - used as a simplification function, it requires the destination type - and kind information which is supplied by a special case in - do_simplify(). */ - -gfc_expr * -gfc_convert_constant (gfc_expr *e, bt type, int kind) -{ - gfc_expr *result, *(*f) (gfc_expr *, int); - gfc_constructor *c, *t; - - switch (e->ts.type) - { - case BT_INTEGER: - switch (type) - { - case BT_INTEGER: - f = gfc_int2int; - break; - case BT_REAL: - f = gfc_int2real; - break; - case BT_COMPLEX: - f = gfc_int2complex; - break; - case BT_LOGICAL: - f = gfc_int2log; - break; - default: - goto oops; - } - break; - - case BT_REAL: - switch (type) - { - case BT_INTEGER: - f = gfc_real2int; - break; - case BT_REAL: - f = gfc_real2real; - break; - case BT_COMPLEX: - f = gfc_real2complex; - break; - default: - goto oops; - } - break; - - case BT_COMPLEX: - switch (type) - { - case BT_INTEGER: - f = gfc_complex2int; - break; - case BT_REAL: - f = gfc_complex2real; - break; - case BT_COMPLEX: - f = gfc_complex2complex; - break; - - default: - goto oops; - } - break; - - case BT_LOGICAL: - switch (type) - { - case BT_INTEGER: - f = gfc_log2int; - break; - case BT_LOGICAL: - f = gfc_log2log; - break; - default: - goto oops; - } - break; - - case BT_HOLLERITH: - switch (type) - { - case BT_INTEGER: - f = gfc_hollerith2int; - break; - - case BT_REAL: - f = gfc_hollerith2real; - break; - - case BT_COMPLEX: - f = gfc_hollerith2complex; - break; - - case BT_CHARACTER: - f = gfc_hollerith2character; - break; - - case BT_LOGICAL: - f = gfc_hollerith2logical; - break; - - default: - goto oops; - } - break; - - case BT_CHARACTER: - switch (type) - { - case BT_INTEGER: - f = gfc_character2int; - break; - - case BT_REAL: - f = gfc_character2real; - break; - - case BT_COMPLEX: - f = gfc_character2complex; - break; - - case BT_CHARACTER: - f = gfc_character2character; - break; - - case BT_LOGICAL: - f = gfc_character2logical; - break; - - default: - goto oops; - } - break; - - default: - oops: - return &gfc_bad_expr; - } - - result = NULL; - - switch (e->expr_type) - { - case EXPR_CONSTANT: - result = f (e, kind); - if (result == NULL) - return &gfc_bad_expr; - break; - - case EXPR_ARRAY: - if (!gfc_is_constant_expr (e)) - break; - - result = gfc_get_array_expr (type, kind, &e->where); - result->shape = gfc_copy_shape (e->shape, e->rank); - result->rank = e->rank; - - for (c = gfc_constructor_first (e->value.constructor); - c; c = gfc_constructor_next (c)) - { - gfc_expr *tmp; - if (c->iterator == NULL) - { - if (c->expr->expr_type == EXPR_ARRAY) - tmp = gfc_convert_constant (c->expr, type, kind); - else if (c->expr->expr_type == EXPR_OP) - { - if (!gfc_simplify_expr (c->expr, 1)) - return &gfc_bad_expr; - tmp = f (c->expr, kind); - } - else - tmp = f (c->expr, kind); - } - else - tmp = gfc_convert_constant (c->expr, type, kind); - - if (tmp == NULL || tmp == &gfc_bad_expr) - { - gfc_free_expr (result); - return NULL; - } - - t = gfc_constructor_append_expr (&result->value.constructor, - tmp, &c->where); - if (c->iterator) - t->iterator = gfc_copy_iterator (c->iterator); - } - - break; - - default: - break; - } - - return result; -} - - -/* Function for converting character constants. */ -gfc_expr * -gfc_convert_char_constant (gfc_expr *e, bt type ATTRIBUTE_UNUSED, int kind) -{ - gfc_expr *result; - int i; - - if (!gfc_is_constant_expr (e)) - return NULL; - - if (e->expr_type == EXPR_CONSTANT) - { - /* Simple case of a scalar. */ - result = gfc_get_constant_expr (BT_CHARACTER, kind, &e->where); - if (result == NULL) - return &gfc_bad_expr; - - result->value.character.length = e->value.character.length; - result->value.character.string - = gfc_get_wide_string (e->value.character.length + 1); - memcpy (result->value.character.string, e->value.character.string, - (e->value.character.length + 1) * sizeof (gfc_char_t)); - - /* Check we only have values representable in the destination kind. */ - for (i = 0; i < result->value.character.length; i++) - if (!gfc_check_character_range (result->value.character.string[i], - kind)) - { - gfc_error ("Character %qs in string at %L cannot be converted " - "into character kind %d", - gfc_print_wide_char (result->value.character.string[i]), - &e->where, kind); - gfc_free_expr (result); - return &gfc_bad_expr; - } - - return result; - } - else if (e->expr_type == EXPR_ARRAY) - { - /* For an array constructor, we convert each constructor element. */ - gfc_constructor *c; - - result = gfc_get_array_expr (type, kind, &e->where); - result->shape = gfc_copy_shape (e->shape, e->rank); - result->rank = e->rank; - result->ts.u.cl = e->ts.u.cl; - - for (c = gfc_constructor_first (e->value.constructor); - c; c = gfc_constructor_next (c)) - { - gfc_expr *tmp = gfc_convert_char_constant (c->expr, type, kind); - if (tmp == &gfc_bad_expr) - { - gfc_free_expr (result); - return &gfc_bad_expr; - } - - if (tmp == NULL) - { - gfc_free_expr (result); - return NULL; - } - - gfc_constructor_append_expr (&result->value.constructor, - tmp, &c->where); - } - - return result; - } - else - return NULL; -} - - -gfc_expr * -gfc_simplify_compiler_options (void) -{ - char *str; - gfc_expr *result; - - str = gfc_get_option_string (); - result = gfc_get_character_expr (gfc_default_character_kind, - &gfc_current_locus, str, strlen (str)); - free (str); - return result; -} - - -gfc_expr * -gfc_simplify_compiler_version (void) -{ - char *buffer; - size_t len; - - len = strlen ("GCC version ") + strlen (version_string); - buffer = XALLOCAVEC (char, len + 1); - snprintf (buffer, len + 1, "GCC version %s", version_string); - return gfc_get_character_expr (gfc_default_character_kind, - &gfc_current_locus, buffer, len); -} - -/* Simplification routines for intrinsics of IEEE modules. */ - -gfc_expr * -simplify_ieee_selected_real_kind (gfc_expr *expr) -{ - gfc_actual_arglist *arg; - gfc_expr *p = NULL, *q = NULL, *rdx = NULL; - - arg = expr->value.function.actual; - p = arg->expr; - if (arg->next) - { - q = arg->next->expr; - if (arg->next->next) - rdx = arg->next->next->expr; - } - - /* Currently, if IEEE is supported and this module is built, it means - all our floating-point types conform to IEEE. Hence, we simply handle - IEEE_SELECTED_REAL_KIND like SELECTED_REAL_KIND. */ - return gfc_simplify_selected_real_kind (p, q, rdx); -} - -gfc_expr * -simplify_ieee_support (gfc_expr *expr) -{ - /* We consider that if the IEEE modules are loaded, we have full support - for flags, halting and rounding, which are the three functions - (IEEE_SUPPORT_{FLAG,HALTING,ROUNDING}) allowed in constant - expressions. One day, we will need libgfortran to detect support and - communicate it back to us, allowing for partial support. */ - - return gfc_get_logical_expr (gfc_default_logical_kind, &expr->where, - true); -} - -bool -matches_ieee_function_name (gfc_symbol *sym, const char *name) -{ - int n = strlen(name); - - if (!strncmp(sym->name, name, n)) - return true; - - /* If a generic was used and renamed, we need more work to find out. - Compare the specific name. */ - if (sym->generic && !strncmp(sym->generic->sym->name, name, n)) - return true; - - return false; -} - -gfc_expr * -gfc_simplify_ieee_functions (gfc_expr *expr) -{ - gfc_symbol* sym = expr->symtree->n.sym; - - if (matches_ieee_function_name(sym, "ieee_selected_real_kind")) - return simplify_ieee_selected_real_kind (expr); - else if (matches_ieee_function_name(sym, "ieee_support_flag") - || matches_ieee_function_name(sym, "ieee_support_halting") - || matches_ieee_function_name(sym, "ieee_support_rounding")) - return simplify_ieee_support (expr); - else - return NULL; -} |