diff options
author | Diego Novillo <dnovillo@gcc.gnu.org> | 2004-05-13 02:41:07 -0400 |
---|---|---|
committer | Diego Novillo <dnovillo@gcc.gnu.org> | 2004-05-13 02:41:07 -0400 |
commit | 6de9cd9a886ea695aa892c3c7c07818a7b7e9e6f (patch) | |
tree | a2568888a519c077427b133de9ece5879a8484a5 /gcc/fortran/simplify.c | |
parent | ac1a20aec53364d77f3bdff94a2a0a06840e0fe9 (diff) | |
download | gcc-6de9cd9a886ea695aa892c3c7c07818a7b7e9e6f.zip gcc-6de9cd9a886ea695aa892c3c7c07818a7b7e9e6f.tar.gz gcc-6de9cd9a886ea695aa892c3c7c07818a7b7e9e6f.tar.bz2 |
Merge tree-ssa-20020619-branch into mainline.
From-SVN: r81764
Diffstat (limited to 'gcc/fortran/simplify.c')
-rw-r--r-- | gcc/fortran/simplify.c | 4008 |
1 files changed, 4008 insertions, 0 deletions
diff --git a/gcc/fortran/simplify.c b/gcc/fortran/simplify.c new file mode 100644 index 0000000..876eb2f --- /dev/null +++ b/gcc/fortran/simplify.c @@ -0,0 +1,4008 @@ +/* Simplify intrinsic functions at compile-time. + Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc. + Contributed by Andy Vaught & Katherine Holcomb + +This file is part of GNU G95. + +GNU G95 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 2, or (at your option) +any later version. + +GNU G95 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 GNU G95; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include "system.h" +#include "flags.h" + +#include <string.h> + +#include "gfortran.h" +#include "arith.h" +#include "intrinsic.h" + +static mpf_t mpf_zero, mpf_half, mpf_one; +static mpz_t mpz_zero; + +gfc_expr gfc_bad_expr; + + +/* 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. If the + simplification function sets the type and/or the function name + via the pointer gfc_simple_expression, then this type is + retained. + + An expression pointer to gfc_bad_expr (a static placeholder) + indicating that some error has prevented simplification. For + example, sqrt(-1.0). 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 never passed to these subroutines. + + 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. */ + +/* Static table for converting non-ascii character sets to ascii. + The xascii_table[] is the inverse table. */ + +static int ascii_table[256] = { + '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', + '\b', '\t', '\n', '\v', '\0', '\r', '\0', '\0', + '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', + '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', + ' ', '!', '\'', '#', '$', '%', '&', '\'', + '(', ')', '*', '+', ',', '-', '.', '/', + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', ':', ';', '<', '=', '>', '?', + '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', + 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', + 'X', 'Y', 'Z', '[', '\\', ']', '^', '_', + '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', + 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', + 'x', 'y', 'z', '{', '|', '}', '~', '\?' +}; + +static int xascii_table[256]; + + +/* 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 (gfc_range_check (result) == ARITH_OK) + return result; + + gfc_error ("Result of %s overflows its kind at %L", name, &result->where); + 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) != NULL + || gfc_validate_kind (type, kind) == -1) + { + + gfc_error ("Invalid KIND parameter of %s at %L", name, &k->where); + return -1; + } + + return kind; +} + + +/********************** Simplification functions *****************************/ + +gfc_expr * +gfc_simplify_abs (gfc_expr * e) +{ + gfc_expr *result; + mpf_t a, b; + + if (e->expr_type != EXPR_CONSTANT) + return NULL; + + switch (e->ts.type) + { + case BT_INTEGER: + result = gfc_constant_result (BT_INTEGER, e->ts.kind, &e->where); + + mpz_abs (result->value.integer, e->value.integer); + + result = range_check (result, "IABS"); + break; + + case BT_REAL: + result = gfc_constant_result (BT_REAL, e->ts.kind, &e->where); + + mpf_abs (result->value.real, e->value.real); + + result = range_check (result, "ABS"); + break; + + case BT_COMPLEX: + result = gfc_constant_result (BT_REAL, e->ts.kind, &e->where); + + mpf_init (a); + mpf_mul (a, e->value.complex.r, e->value.complex.r); + + mpf_init (b); + mpf_mul (b, e->value.complex.i, e->value.complex.i); + + mpf_add (a, a, b); + mpf_sqrt (result->value.real, a); + + mpf_clear (a); + mpf_clear (b); + + result = range_check (result, "CABS"); + break; + + default: + gfc_internal_error ("gfc_simplify_abs(): Bad type"); + } + + return result; +} + + +gfc_expr * +gfc_simplify_achar (gfc_expr * e) +{ + gfc_expr *result; + int index; + + if (e->expr_type != EXPR_CONSTANT) + return NULL; + + /* We cannot assume that the native character set is ASCII in this + function. */ + if (gfc_extract_int (e, &index) != NULL || index < 0 || index > 127) + { + gfc_error ("Extended ASCII not implemented: argument of ACHAR at %L " + "must be between 0 and 127", &e->where); + return &gfc_bad_expr; + } + + result = gfc_constant_result (BT_CHARACTER, gfc_default_character_kind (), + &e->where); + + result->value.character.string = gfc_getmem (2); + + result->value.character.length = 1; + result->value.character.string[0] = ascii_table[index]; + result->value.character.string[1] = '\0'; /* For debugger */ + return result; +} + + +gfc_expr * +gfc_simplify_acos (gfc_expr * x) +{ + gfc_expr *result; + mpf_t negative, square, term; + + if (x->expr_type != EXPR_CONSTANT) + return NULL; + + if (mpf_cmp_si (x->value.real, 1) > 0 || mpf_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_constant_result (x->ts.type, x->ts.kind, &x->where); + + if (mpf_cmp_si (x->value.real, 1) == 0) + { + mpf_set_ui (result->value.real, 0); + return range_check (result, "ACOS"); + } + + if (mpf_cmp_si (x->value.real, -1) == 0) + { + mpf_set (result->value.real, pi); + return range_check (result, "ACOS"); + } + + mpf_init (negative); + mpf_init (square); + mpf_init (term); + + mpf_pow_ui (square, x->value.real, 2); + mpf_ui_sub (term, 1, square); + mpf_sqrt (term, term); + mpf_div (term, x->value.real, term); + mpf_neg (term, term); + arctangent (&term, &negative); + mpf_add (result->value.real, half_pi, negative); + + mpf_clear (negative); + mpf_clear (square); + mpf_clear (term); + + return range_check (result, "ACOS"); +} + + +gfc_expr * +gfc_simplify_adjustl (gfc_expr * e) +{ + gfc_expr *result; + int count, i, len; + char ch; + + if (e->expr_type != EXPR_CONSTANT) + return NULL; + + len = e->value.character.length; + + result = gfc_constant_result (BT_CHARACTER, e->ts.kind, &e->where); + + result->value.character.length = len; + result->value.character.string = gfc_getmem (len + 1); + + for (count = 0, i = 0; i < len; ++i) + { + ch = e->value.character.string[i]; + if (ch != ' ') + break; + ++count; + } + + for (i = 0; i < len - count; ++i) + { + result->value.character.string[i] = + e->value.character.string[count + i]; + } + + for (i = len - count; i < len; ++i) + { + result->value.character.string[i] = ' '; + } + + result->value.character.string[len] = '\0'; /* For debugger */ + + return result; +} + + +gfc_expr * +gfc_simplify_adjustr (gfc_expr * e) +{ + gfc_expr *result; + int count, i, len; + char ch; + + if (e->expr_type != EXPR_CONSTANT) + return NULL; + + len = e->value.character.length; + + result = gfc_constant_result (BT_CHARACTER, e->ts.kind, &e->where); + + result->value.character.length = len; + result->value.character.string = gfc_getmem (len + 1); + + for (count = 0, i = len - 1; i >= 0; --i) + { + ch = e->value.character.string[i]; + if (ch != ' ') + break; + ++count; + } + + 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]; + } + + result->value.character.string[len] = '\0'; /* For debugger */ + + return result; +} + + +gfc_expr * +gfc_simplify_aimag (gfc_expr * e) +{ + gfc_expr *result; + + if (e->expr_type != EXPR_CONSTANT) + return NULL; + + result = gfc_constant_result (BT_REAL, e->ts.kind, &e->where); + mpf_set (result->value.real, e->value.complex.i); + + 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); + + mpf_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_dint (gfc_expr * e) +{ + gfc_expr *rtrunc, *result; + + if (e->expr_type != EXPR_CONSTANT) + return NULL; + + rtrunc = gfc_copy_expr (e); + + mpf_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_anint (gfc_expr * e, gfc_expr * k) +{ + gfc_expr *rtrunc, *result; + int kind, cmp; + + 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_constant_result (e->ts.type, kind, &e->where); + + rtrunc = gfc_copy_expr (e); + + cmp = mpf_cmp_ui (e->value.real, 0); + + if (cmp > 0) + { + mpf_add (rtrunc->value.real, e->value.real, mpf_half); + mpf_trunc (result->value.real, rtrunc->value.real); + } + else if (cmp < 0) + { + mpf_sub (rtrunc->value.real, e->value.real, mpf_half); + mpf_trunc (result->value.real, rtrunc->value.real); + } + else + mpf_set_ui (result->value.real, 0); + + gfc_free_expr (rtrunc); + + return range_check (result, "ANINT"); +} + + +gfc_expr * +gfc_simplify_dnint (gfc_expr * e) +{ + gfc_expr *rtrunc, *result; + int cmp; + + if (e->expr_type != EXPR_CONSTANT) + return NULL; + + result = + gfc_constant_result (BT_REAL, gfc_default_double_kind (), &e->where); + + rtrunc = gfc_copy_expr (e); + + cmp = mpf_cmp_ui (e->value.real, 0); + + if (cmp > 0) + { + mpf_add (rtrunc->value.real, e->value.real, mpf_half); + mpf_trunc (result->value.real, rtrunc->value.real); + } + else if (cmp < 0) + { + mpf_sub (rtrunc->value.real, e->value.real, mpf_half); + mpf_trunc (result->value.real, rtrunc->value.real); + } + else + mpf_set_ui (result->value.real, 0); + + gfc_free_expr (rtrunc); + + return range_check (result, "DNINT"); +} + + +gfc_expr * +gfc_simplify_asin (gfc_expr * x) +{ + gfc_expr *result; + mpf_t negative, square, term; + + if (x->expr_type != EXPR_CONSTANT) + return NULL; + + if (mpf_cmp_si (x->value.real, 1) > 0 || mpf_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_constant_result (x->ts.type, x->ts.kind, &x->where); + + if (mpf_cmp_si (x->value.real, 1) == 0) + { + mpf_set (result->value.real, half_pi); + return range_check (result, "ASIN"); + } + + if (mpf_cmp_si (x->value.real, -1) == 0) + { + mpf_init (negative); + mpf_neg (negative, half_pi); + mpf_set (result->value.real, negative); + mpf_clear (negative); + return range_check (result, "ASIN"); + } + + mpf_init (square); + mpf_init (term); + + mpf_pow_ui (square, x->value.real, 2); + mpf_ui_sub (term, 1, square); + mpf_sqrt (term, term); + mpf_div (term, x->value.real, term); + arctangent (&term, &result->value.real); + + mpf_clear (square); + mpf_clear (term); + + return range_check (result, "ASIN"); +} + + +gfc_expr * +gfc_simplify_atan (gfc_expr * x) +{ + gfc_expr *result; + + if (x->expr_type != EXPR_CONSTANT) + return NULL; + + result = gfc_constant_result (x->ts.type, x->ts.kind, &x->where); + + arctangent (&x->value.real, &result->value.real); + + return range_check (result, "ATAN"); + +} + + +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; + + result = gfc_constant_result (x->ts.type, x->ts.kind, &x->where); + + + if (mpf_sgn (y->value.real) == 0 && mpf_sgn (x->value.real) == 0) + { + gfc_error + ("If first argument of ATAN2 %L is zero, the second argument " + "must not be zero", &x->where); + gfc_free_expr (result); + return &gfc_bad_expr; + } + + arctangent2 (&y->value.real, &x->value.real, &result->value.real); + + return range_check (result, "ATAN2"); + +} + + +gfc_expr * +gfc_simplify_bit_size (gfc_expr * e) +{ + gfc_expr *result; + int i; + + i = gfc_validate_kind (e->ts.type, e->ts.kind); + if (i == -1) + gfc_internal_error ("In gfc_simplify_bit_size(): Bad kind"); + + result = gfc_constant_result (BT_INTEGER, e->ts.kind, &e->where); + mpz_set_ui (result->value.integer, gfc_integer_kinds[i].bit_size); + + return result; +} + + +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) != NULL || b < 0) + return gfc_logical_expr (0, &e->where); + + return gfc_logical_expr (mpz_tstbit (e->value.integer, b), &e->where); +} + + +gfc_expr * +gfc_simplify_ceiling (gfc_expr * e, gfc_expr * k) +{ + gfc_expr *ceil, *result; + int kind; + + kind = get_kind (BT_REAL, k, "CEILING", gfc_default_real_kind ()); + if (kind == -1) + return &gfc_bad_expr; + + if (e->expr_type != EXPR_CONSTANT) + return NULL; + + result = gfc_constant_result (BT_INTEGER, kind, &e->where); + + ceil = gfc_copy_expr (e); + + mpf_ceil (ceil->value.real, e->value.real); + mpz_set_f (result->value.integer, ceil->value.real); + + gfc_free_expr (ceil); + + return range_check (result, "CEILING"); +} + + +gfc_expr * +gfc_simplify_char (gfc_expr * e, gfc_expr * k) +{ + gfc_expr *result; + int c, kind; + + kind = get_kind (BT_CHARACTER, k, "CHAR", gfc_default_character_kind ()); + if (kind == -1) + return &gfc_bad_expr; + + if (e->expr_type != EXPR_CONSTANT) + return NULL; + + if (gfc_extract_int (e, &c) != NULL || c < 0 || c > 255) + { + gfc_error ("Bad character in CHAR function at %L", &e->where); + return &gfc_bad_expr; + } + + result = gfc_constant_result (BT_CHARACTER, kind, &e->where); + + result->value.character.length = 1; + result->value.character.string = gfc_getmem (2); + + result->value.character.string[0] = c; + result->value.character.string[1] = '\0'; /* For debugger */ + + return result; +} + + +/* Common subroutine for simplifying CMPLX and DCMPLX. */ + +static gfc_expr * +simplify_cmplx (const char *name, gfc_expr * x, gfc_expr * y, int kind) +{ + gfc_expr *result; + + result = gfc_constant_result (BT_COMPLEX, kind, &x->where); + + mpf_set_ui (result->value.complex.i, 0); + + switch (x->ts.type) + { + case BT_INTEGER: + mpf_set_z (result->value.complex.r, x->value.integer); + break; + + case BT_REAL: + mpf_set (result->value.complex.r, x->value.real); + break; + + case BT_COMPLEX: + mpf_set (result->value.complex.r, x->value.complex.r); + mpf_set (result->value.complex.i, x->value.complex.i); + break; + + default: + gfc_internal_error ("gfc_simplify_dcmplx(): Bad type (x)"); + } + + if (y != NULL) + { + switch (y->ts.type) + { + case BT_INTEGER: + mpf_set_z (result->value.complex.i, y->value.integer); + break; + + case BT_REAL: + mpf_set (result->value.complex.i, y->value.real); + 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; + + if (x->expr_type != EXPR_CONSTANT + || (y != NULL && y->expr_type != EXPR_CONSTANT)) + return NULL; + + kind = get_kind (BT_REAL, k, "CMPLX", gfc_default_real_kind ()); + if (kind == -1) + return &gfc_bad_expr; + + return simplify_cmplx ("CMPLX", 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); + mpf_neg (result->value.complex.i, result->value.complex.i); + + return range_check (result, "CONJG"); +} + + +gfc_expr * +gfc_simplify_cos (gfc_expr * x) +{ + gfc_expr *result; + mpf_t xp, xq; + + if (x->expr_type != EXPR_CONSTANT) + return NULL; + + result = gfc_constant_result (x->ts.type, x->ts.kind, &x->where); + + switch (x->ts.type) + { + case BT_REAL: + cosine (&x->value.real, &result->value.real); + break; + case BT_COMPLEX: + mpf_init (xp); + mpf_init (xq); + + cosine (&x->value.complex.r, &xp); + hypercos (&x->value.complex.i, &xq); + mpf_mul (result->value.complex.r, xp, xq); + + sine (&x->value.complex.r, &xp); + hypersine (&x->value.complex.i, &xq); + mpf_mul (xp, xp, xq); + mpf_neg (result->value.complex.i, xp); + + mpf_clear (xp); + mpf_clear (xq); + break; + default: + gfc_internal_error ("in gfc_simplify_cos(): Bad type"); + } + + return range_check (result, "COS"); + +} + + +gfc_expr * +gfc_simplify_cosh (gfc_expr * x) +{ + gfc_expr *result; + + if (x->expr_type != EXPR_CONSTANT) + return NULL; + + result = gfc_constant_result (x->ts.type, x->ts.kind, &x->where); + + hypercos (&x->value.real, &result->value.real); + + return range_check (result, "COSH"); +} + + +gfc_expr * +gfc_simplify_dcmplx (gfc_expr * x, gfc_expr * y) +{ + + if (x->expr_type != EXPR_CONSTANT + || (y != NULL && y->expr_type != EXPR_CONSTANT)) + return NULL; + + return simplify_cmplx ("DCMPLX", x, y, gfc_default_double_kind ()); +} + + +gfc_expr * +gfc_simplify_dble (gfc_expr * e) +{ + gfc_expr *result; + + if (e->expr_type != EXPR_CONSTANT) + return NULL; + + switch (e->ts.type) + { + case BT_INTEGER: + result = gfc_int2real (e, gfc_default_double_kind ()); + break; + + case BT_REAL: + result = gfc_real2real (e, gfc_default_double_kind ()); + break; + + case BT_COMPLEX: + result = gfc_complex2real (e, gfc_default_double_kind ()); + break; + + default: + gfc_internal_error ("gfc_simplify_dble(): bad type at %L", &e->where); + } + + 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); + if (i == -1) + goto bad; + + 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: + bad: + gfc_internal_error ("gfc_simplify_digits(): Bad type"); + } + + return gfc_int_expr (digits); +} + + +gfc_expr * +gfc_simplify_dim (gfc_expr * x, gfc_expr * y) +{ + gfc_expr *result; + + if (x->expr_type != EXPR_CONSTANT || y->expr_type != EXPR_CONSTANT) + return NULL; + + result = gfc_constant_result (x->ts.type, x->ts.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 (result->value.integer, mpz_zero); + + break; + + case BT_REAL: + if (mpf_cmp (x->value.real, y->value.real) > 0) + mpf_sub (result->value.real, x->value.real, y->value.real); + else + mpf_set (result->value.real, mpf_zero); + + break; + + default: + gfc_internal_error ("gfc_simplify_dim(): Bad type"); + } + + return range_check (result, "DIM"); +} + + +gfc_expr * +gfc_simplify_dprod (gfc_expr * x, gfc_expr * y) +{ + gfc_expr *mult1, *mult2, *result; + + if (x->expr_type != EXPR_CONSTANT || y->expr_type != EXPR_CONSTANT) + return NULL; + + result = + gfc_constant_result (BT_REAL, gfc_default_double_kind (), &x->where); + + mult1 = gfc_real2real (x, gfc_default_double_kind ()); + mult2 = gfc_real2real (y, gfc_default_double_kind ()); + + mpf_mul (result->value.real, mult1->value.real, mult2->value.real); + + gfc_free_expr (mult1); + gfc_free_expr (mult2); + + return range_check (result, "DPROD"); +} + + +gfc_expr * +gfc_simplify_epsilon (gfc_expr * e) +{ + gfc_expr *result; + int i; + + i = gfc_validate_kind (e->ts.type, e->ts.kind); + if (i == -1) + gfc_internal_error ("gfc_simplify_epsilon(): Bad kind"); + + result = gfc_constant_result (BT_REAL, e->ts.kind, &e->where); + + mpf_set (result->value.real, gfc_real_kinds[i].epsilon); + + return range_check (result, "EPSILON"); +} + + +gfc_expr * +gfc_simplify_exp (gfc_expr * x) +{ + gfc_expr *result; + mpf_t xp, xq; + double ln2, absval, rhuge; + + if (x->expr_type != EXPR_CONSTANT) + return NULL; + + result = gfc_constant_result (x->ts.type, x->ts.kind, &x->where); + + /* Exactitude doesn't matter here */ + ln2 = .6931472; + rhuge = ln2 * mpz_get_d (gfc_integer_kinds[0].huge); + + switch (x->ts.type) + { + case BT_REAL: + absval = mpf_get_d (x->value.real); + if (absval < 0) + absval = -absval; + if (absval > rhuge) + { + /* Underflow (set arg to zero) if x is negative and its + magnitude is greater than the maximum C long int times + ln2, because the exponential method in arith.c will fail + for such values. */ + if (mpf_cmp_ui (x->value.real, 0) < 0) + { + if (pedantic == 1) + gfc_warning_now + ("Argument of EXP at %L is negative and too large, " + "setting result to zero", &x->where); + mpf_set_ui (result->value.real, 0); + return range_check (result, "EXP"); + } + /* Overflow if magnitude of x is greater than C long int + huge times ln2. */ + else + { + gfc_error ("Argument of EXP at %L too large", &x->where); + gfc_free_expr (result); + return &gfc_bad_expr; + } + } + exponential (&x->value.real, &result->value.real); + break; + + case BT_COMPLEX: + /* Using Euler's formula. */ + absval = mpf_get_d (x->value.complex.r); + if (absval < 0) + absval = -absval; + if (absval > rhuge) + { + if (mpf_cmp_ui (x->value.complex.r, 0) < 0) + { + if (pedantic == 1) + gfc_warning_now + ("Real part of argument of EXP at %L is negative " + "and too large, setting result to zero", &x->where); + + mpf_set_ui (result->value.complex.r, 0); + mpf_set_ui (result->value.complex.i, 0); + return range_check (result, "EXP"); + } + else + { + gfc_error ("Real part of argument of EXP at %L too large", + &x->where); + gfc_free_expr (result); + return &gfc_bad_expr; + } + } + mpf_init (xp); + mpf_init (xq); + exponential (&x->value.complex.r, &xq); + cosine (&x->value.complex.i, &xp); + mpf_mul (result->value.complex.r, xq, xp); + sine (&x->value.complex.i, &xp); + mpf_mul (result->value.complex.i, xq, xp); + mpf_clear (xp); + mpf_clear (xq); + break; + + default: + gfc_internal_error ("in gfc_simplify_exp(): Bad type"); + } + + return range_check (result, "EXP"); +} + + +gfc_expr * +gfc_simplify_exponent (gfc_expr * x) +{ + mpf_t i2, absv, ln2, lnx; + gfc_expr *result; + + if (x->expr_type != EXPR_CONSTANT) + return NULL; + + result = gfc_constant_result (BT_INTEGER, gfc_default_integer_kind (), + &x->where); + + if (mpf_cmp (x->value.real, mpf_zero) == 0) + { + mpz_set_ui (result->value.integer, 0); + return result; + } + + mpf_init_set_ui (i2, 2); + mpf_init (absv); + mpf_init (ln2); + mpf_init (lnx); + + natural_logarithm (&i2, &ln2); + + mpf_abs (absv, x->value.real); + natural_logarithm (&absv, &lnx); + + mpf_div (lnx, lnx, ln2); + mpf_trunc (lnx, lnx); + mpf_add_ui (lnx, lnx, 1); + mpz_set_f (result->value.integer, lnx); + + mpf_clear (i2); + mpf_clear (ln2); + mpf_clear (lnx); + mpf_clear (absv); + + return range_check (result, "EXPONENT"); +} + + +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"); +} + + +gfc_expr * +gfc_simplify_floor (gfc_expr * e, gfc_expr * k) +{ + gfc_expr *result; + mpf_t floor; + int kind; + + kind = get_kind (BT_REAL, k, "FLOOR", gfc_default_real_kind ()); + if (kind == -1) + gfc_internal_error ("gfc_simplify_floor(): Bad kind"); + + if (e->expr_type != EXPR_CONSTANT) + return NULL; + + result = gfc_constant_result (BT_INTEGER, kind, &e->where); + + mpf_init (floor); + mpf_floor (floor, e->value.real); + mpz_set_f (result->value.integer, floor); + mpf_clear (floor); + + return range_check (result, "FLOOR"); +} + + +gfc_expr * +gfc_simplify_fraction (gfc_expr * x) +{ + gfc_expr *result; + mpf_t i2, absv, ln2, lnx, pow2; + unsigned long exp2; + + if (x->expr_type != EXPR_CONSTANT) + return NULL; + + result = gfc_constant_result (BT_REAL, x->ts.kind, &x->where); + + if (mpf_cmp (x->value.real, mpf_zero) == 0) + { + mpf_set (result->value.real, mpf_zero); + return result; + } + + mpf_init_set_ui (i2, 2); + mpf_init (absv); + mpf_init (ln2); + mpf_init (lnx); + mpf_init (pow2); + + natural_logarithm (&i2, &ln2); + + mpf_abs (absv, x->value.real); + natural_logarithm (&absv, &lnx); + + mpf_div (lnx, lnx, ln2); + mpf_trunc (lnx, lnx); + mpf_add_ui (lnx, lnx, 1); + + exp2 = (unsigned long) mpf_get_d (lnx); + mpf_pow_ui (pow2, i2, exp2); + + mpf_div (result->value.real, absv, pow2); + + mpf_clear (i2); + mpf_clear (ln2); + mpf_clear (absv); + mpf_clear (lnx); + mpf_clear (pow2); + + return range_check (result, "FRACTION"); +} + + +gfc_expr * +gfc_simplify_huge (gfc_expr * e) +{ + gfc_expr *result; + int i; + + i = gfc_validate_kind (e->ts.type, e->ts.kind); + if (i == -1) + goto bad_type; + + result = gfc_constant_result (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: + mpf_set (result->value.real, gfc_real_kinds[i].huge); + break; + + bad_type: + default: + gfc_internal_error ("gfc_simplify_huge(): Bad type"); + } + + return result; +} + + +gfc_expr * +gfc_simplify_iachar (gfc_expr * e) +{ + gfc_expr *result; + int index; + + 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 = xascii_table[(int) e->value.character.string[0] & 0xFF]; + + result = gfc_int_expr (index); + result->where = e->where; + + return range_check (result, "IACHAR"); +} + + +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_constant_result (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; + + if (gfc_extract_int (y, &pos) != NULL || pos < 0) + { + gfc_error ("Invalid second argument of IBCLR at %L", &y->where); + return &gfc_bad_expr; + } + + k = gfc_validate_kind (x->ts.type, x->ts.kind); + if (k == -1) + gfc_internal_error ("gfc_simplify_ibclr(): Bad kind"); + + if (pos > gfc_integer_kinds[k].bit_size) + { + gfc_error ("Second argument of IBCLR exceeds bit size at %L", + &y->where); + return &gfc_bad_expr; + } + + result = gfc_copy_expr (x); + + mpz_clrbit (result->value.integer, pos); + return range_check (result, "IBCLR"); +} + + +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; + + if (gfc_extract_int (y, &pos) != NULL || pos < 0) + { + gfc_error ("Invalid second argument of IBITS at %L", &y->where); + return &gfc_bad_expr; + } + + if (gfc_extract_int (z, &len) != NULL || len < 0) + { + gfc_error ("Invalid third argument of IBITS at %L", &z->where); + return &gfc_bad_expr; + } + + k = gfc_validate_kind (BT_INTEGER, x->ts.kind); + if (k == -1) + gfc_internal_error ("gfc_simplify_ibits(): Bad kind"); + + 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_constant_result (x->ts.type, x->ts.kind, &x->where); + + bits = gfc_getmem (bitsize * sizeof (int)); + + 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"); + } + } + + gfc_free (bits); + + return range_check (result, "IBITS"); +} + + +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; + + if (gfc_extract_int (y, &pos) != NULL || pos < 0) + { + gfc_error ("Invalid second argument of IBSET at %L", &y->where); + return &gfc_bad_expr; + } + + k = gfc_validate_kind (x->ts.type, x->ts.kind); + if (k == -1) + gfc_internal_error ("gfc_simplify_ibset(): Bad kind"); + + if (pos > gfc_integer_kinds[k].bit_size) + { + gfc_error ("Second argument of IBSET exceeds bit size at %L", + &y->where); + return &gfc_bad_expr; + } + + result = gfc_copy_expr (x); + + mpz_setbit (result->value.integer, pos); + return range_check (result, "IBSET"); +} + + +gfc_expr * +gfc_simplify_ichar (gfc_expr * e) +{ + gfc_expr *result; + int index; + + 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 = (int) e->value.character.string[0]; + + if (index < CHAR_MIN || index > CHAR_MAX) + { + gfc_error ("Argument of ICHAR at %L out of range of this processor", + &e->where); + return &gfc_bad_expr; + } + + result = gfc_int_expr (index); + result->where = e->where; + 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_constant_result (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 *result; + int back, len, lensub; + int i, j, k, count, index = 0, start; + + if (x->expr_type != EXPR_CONSTANT || y->expr_type != EXPR_CONSTANT) + return NULL; + + if (b != NULL && b->value.logical != 0) + back = 1; + else + back = 0; + + result = gfc_constant_result (BT_INTEGER, gfc_default_integer_kind (), + &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"); +} + + +gfc_expr * +gfc_simplify_int (gfc_expr * e, gfc_expr * k) +{ + gfc_expr *rpart, *rtrunc, *result; + int kind; + + kind = get_kind (BT_REAL, k, "INT", gfc_default_real_kind ()); + if (kind == -1) + return &gfc_bad_expr; + + if (e->expr_type != EXPR_CONSTANT) + return NULL; + + result = gfc_constant_result (BT_INTEGER, kind, &e->where); + + switch (e->ts.type) + { + case BT_INTEGER: + mpz_set (result->value.integer, e->value.integer); + break; + + case BT_REAL: + rtrunc = gfc_copy_expr (e); + mpf_trunc (rtrunc->value.real, e->value.real); + mpz_set_f (result->value.integer, rtrunc->value.real); + gfc_free_expr (rtrunc); + break; + + case BT_COMPLEX: + rpart = gfc_complex2real (e, kind); + rtrunc = gfc_copy_expr (rpart); + mpf_trunc (rtrunc->value.real, rpart->value.real); + mpz_set_f (result->value.integer, rtrunc->value.real); + gfc_free_expr (rpart); + gfc_free_expr (rtrunc); + break; + + default: + gfc_error ("Argument of INT at %L is not a valid type", &e->where); + gfc_free_expr (result); + return &gfc_bad_expr; + } + + return range_check (result, "INT"); +} + + +gfc_expr * +gfc_simplify_ifix (gfc_expr * e) +{ + gfc_expr *rtrunc, *result; + + if (e->expr_type != EXPR_CONSTANT) + return NULL; + + result = gfc_constant_result (BT_INTEGER, gfc_default_integer_kind (), + &e->where); + + rtrunc = gfc_copy_expr (e); + + mpf_trunc (rtrunc->value.real, e->value.real); + mpz_set_f (result->value.integer, rtrunc->value.real); + + 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; + + result = gfc_constant_result (BT_INTEGER, gfc_default_integer_kind (), + &e->where); + + rtrunc = gfc_copy_expr (e); + + mpf_trunc (rtrunc->value.real, e->value.real); + mpz_set_f (result->value.integer, rtrunc->value.real); + + 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_constant_result (BT_INTEGER, x->ts.kind, &x->where); + + mpz_ior (result->value.integer, x->value.integer, y->value.integer); + return range_check (result, "IOR"); +} + + +gfc_expr * +gfc_simplify_ishft (gfc_expr * e, gfc_expr * s) +{ + gfc_expr *result; + int shift, ashift, isize, k; + long e_int; + + if (e->expr_type != EXPR_CONSTANT || s->expr_type != EXPR_CONSTANT) + return NULL; + + if (gfc_extract_int (s, &shift) != NULL) + { + gfc_error ("Invalid second argument of ISHFT at %L", &s->where); + return &gfc_bad_expr; + } + + k = gfc_validate_kind (BT_INTEGER, e->ts.kind); + if (k == -1) + gfc_internal_error ("gfc_simplify_ishft(): Bad kind"); + + isize = gfc_integer_kinds[k].bit_size; + + if (shift >= 0) + ashift = shift; + else + ashift = -shift; + + if (ashift > isize) + { + gfc_error + ("Magnitude of second argument of ISHFT exceeds bit size at %L", + &s->where); + return &gfc_bad_expr; + } + + e_int = mpz_get_si (e->value.integer); + if (e_int > INT_MAX || e_int < INT_MIN) + gfc_internal_error ("ISHFT: unable to extract integer"); + + result = gfc_constant_result (e->ts.type, e->ts.kind, &e->where); + + if (shift == 0) + { + mpz_set (result->value.integer, e->value.integer); + return range_check (result, "ISHFT"); + } + + if (shift > 0) + mpz_set_si (result->value.integer, e_int << shift); + else + mpz_set_si (result->value.integer, e_int >> ashift); + + return range_check (result, "ISHFT"); +} + + +gfc_expr * +gfc_simplify_ishftc (gfc_expr * e, gfc_expr * s, gfc_expr * sz) +{ + gfc_expr *result; + int shift, ashift, isize, delta, k; + int i, *bits; + + if (e->expr_type != EXPR_CONSTANT || s->expr_type != EXPR_CONSTANT) + return NULL; + + if (gfc_extract_int (s, &shift) != NULL) + { + gfc_error ("Invalid second argument of ISHFTC at %L", &s->where); + return &gfc_bad_expr; + } + + k = gfc_validate_kind (e->ts.type, e->ts.kind); + if (k == -1) + gfc_internal_error ("gfc_simplify_ishftc(): Bad kind"); + + if (sz != NULL) + { + if (gfc_extract_int (sz, &isize) != NULL || isize < 0) + { + gfc_error ("Invalid third argument of ISHFTC at %L", &sz->where); + return &gfc_bad_expr; + } + } + else + isize = gfc_integer_kinds[k].bit_size; + + if (shift >= 0) + ashift = shift; + else + ashift = -shift; + + if (ashift > isize) + { + gfc_error + ("Magnitude of second argument of ISHFTC exceeds third argument " + "at %L", &s->where); + return &gfc_bad_expr; + } + + result = gfc_constant_result (e->ts.type, e->ts.kind, &e->where); + + bits = gfc_getmem (isize * sizeof (int)); + + for (i = 0; i < isize; i++) + bits[i] = mpz_tstbit (e->value.integer, i); + + delta = isize - ashift; + + if (shift == 0) + { + mpz_set (result->value.integer, e->value.integer); + gfc_free (bits); + return range_check (result, "ISHFTC"); + } + + else if (shift > 0) + { + for (i = 0; i < delta; i++) + { + if (bits[i] == 0) + mpz_clrbit (result->value.integer, i + shift); + if (bits[i] == 1) + mpz_setbit (result->value.integer, i + shift); + } + + for (i = delta; i < isize; i++) + { + if (bits[i] == 0) + mpz_clrbit (result->value.integer, i - delta); + if (bits[i] == 1) + mpz_setbit (result->value.integer, i - delta); + } + + gfc_free (bits); + return range_check (result, "ISHFTC"); + } + else + { + for (i = 0; i < ashift; i++) + { + if (bits[i] == 0) + mpz_clrbit (result->value.integer, i + delta); + if (bits[i] == 1) + mpz_setbit (result->value.integer, i + delta); + } + + for (i = ashift; i < isize; i++) + { + if (bits[i] == 0) + mpz_clrbit (result->value.integer, i + shift); + if (bits[i] == 1) + mpz_setbit (result->value.integer, i + shift); + } + + gfc_free (bits); + return range_check (result, "ISHFTC"); + } +} + + +gfc_expr * +gfc_simplify_kind (gfc_expr * e) +{ + + if (e->ts.type == BT_DERIVED) + { + gfc_error ("Argument of KIND at %L is a DERIVED type", &e->where); + return &gfc_bad_expr; + } + + return gfc_int_expr (e->ts.kind); +} + + +static gfc_expr * +gfc_simplify_bound (gfc_expr * array, gfc_expr * dim, int upper) +{ + gfc_ref *ref; + gfc_array_spec *as; + int i; + + if (array->expr_type != EXPR_VARIABLE) + return NULL; + + if (dim == NULL) + return NULL; + + if (dim->expr_type != EXPR_CONSTANT) + return NULL; + + /* Follow any component references. */ + as = array->symtree->n.sym->as; + ref = array->ref; + while (ref->next != NULL) + { + if (ref->type == REF_COMPONENT) + as = ref->u.c.sym->as; + ref = ref->next; + } + + if (ref->type != REF_ARRAY || ref->u.ar.type != AR_FULL) + return NULL; + + i = mpz_get_si (dim->value.integer); + if (upper) + return as->upper[i-1]; + else + return as->lower[i-1]; +} + + +gfc_expr * +gfc_simplify_lbound (gfc_expr * array, gfc_expr * dim) +{ + return gfc_simplify_bound (array, dim, 0); +} + + +gfc_expr * +gfc_simplify_len (gfc_expr * e) +{ + gfc_expr *result; + + if (e->expr_type != EXPR_CONSTANT) + return NULL; + + result = gfc_constant_result (BT_INTEGER, gfc_default_integer_kind (), + &e->where); + + mpz_set_si (result->value.integer, e->value.character.length); + return range_check (result, "LEN"); +} + + +gfc_expr * +gfc_simplify_len_trim (gfc_expr * e) +{ + gfc_expr *result; + int count, len, lentrim, i; + + if (e->expr_type != EXPR_CONSTANT) + return NULL; + + result = gfc_constant_result (BT_INTEGER, gfc_default_integer_kind (), + &e->where); + + 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; + + mpz_set_si (result->value.integer, lentrim); + return range_check (result, "LEN_TRIM"); +} + + +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_logical_expr (gfc_compare_string (a, b, xascii_table) >= 0, + &a->where); +} + + +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_logical_expr (gfc_compare_string (a, b, xascii_table) > 0, + &a->where); +} + + +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_logical_expr (gfc_compare_string (a, b, xascii_table) <= 0, + &a->where); +} + + +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_logical_expr (gfc_compare_string (a, b, xascii_table) < 0, + &a->where); +} + + +gfc_expr * +gfc_simplify_log (gfc_expr * x) +{ + gfc_expr *result; + mpf_t xr, xi; + + if (x->expr_type != EXPR_CONSTANT) + return NULL; + + result = gfc_constant_result (x->ts.type, x->ts.kind, &x->where); + + switch (x->ts.type) + { + case BT_REAL: + if (mpf_cmp (x->value.real, mpf_zero) <= 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; + } + + natural_logarithm (&x->value.real, &result->value.real); + break; + + case BT_COMPLEX: + if ((mpf_cmp (x->value.complex.r, mpf_zero) == 0) + && (mpf_cmp (x->value.complex.i, mpf_zero) == 0)) + { + gfc_error ("Complex argument of LOG at %L cannot be zero", + &x->where); + gfc_free_expr (result); + return &gfc_bad_expr; + } + + mpf_init (xr); + mpf_init (xi); + + mpf_div (xr, x->value.complex.i, x->value.complex.r); + arctangent2 (&x->value.complex.i, &x->value.complex.r, + &result->value.complex.i); + + mpf_mul (xr, x->value.complex.r, x->value.complex.r); + mpf_mul (xi, x->value.complex.i, x->value.complex.i); + mpf_add (xr, xr, xi); + mpf_sqrt (xr, xr); + natural_logarithm (&xr, &result->value.complex.r); + + mpf_clear (xr); + mpf_clear (xi); + + 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 (mpf_cmp (x->value.real, mpf_zero) <= 0) + { + gfc_error + ("Argument of LOG10 at %L cannot be less than or equal to zero", + &x->where); + return &gfc_bad_expr; + } + + result = gfc_constant_result (x->ts.type, x->ts.kind, &x->where); + + common_logarithm (&x->value.real, &result->value.real); + + return range_check (result, "LOG10"); +} + + +gfc_expr * +gfc_simplify_logical (gfc_expr * e, gfc_expr * k) +{ + gfc_expr *result; + 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; + + result = gfc_constant_result (BT_LOGICAL, kind, &e->where); + + result->value.logical = e->value.logical; + + return result; +} + + +/* 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) +{ + gfc_actual_arglist *arg, *last, *extremum; + gfc_intrinsic_sym * specific; + + last = NULL; + extremum = NULL; + specific = expr->value.function.isym; + + 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; + } + + switch (arg->expr->ts.type) + { + case BT_INTEGER: + if (mpz_cmp (arg->expr->value.integer, + extremum->expr->value.integer) * sign > 0) + mpz_set (extremum->expr->value.integer, arg->expr->value.integer); + + break; + + case BT_REAL: + if (mpf_cmp (arg->expr->value.real, extremum->expr->value.real) * + sign > 0) + mpf_set (extremum->expr->value.real, arg->expr->value.real); + + break; + + default: + gfc_internal_error ("gfc_simplify_max(): Bad type in arglist"); + } + + /* Delete the extra constant argument. */ + if (last == NULL) + expr->value.function.actual = arg->next; + else + 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; + + /* Convert to the correct type and kind. */ + if (expr->ts.type != BT_UNKNOWN) + return gfc_convert_constant (expr->value.function.actual->expr, + expr->ts.type, expr->ts.kind); + + if (specific->ts.type != BT_UNKNOWN) + return gfc_convert_constant (expr->value.function.actual->expr, + specific->ts.type, specific->ts.kind); + + return gfc_copy_expr (expr->value.function.actual->expr); +} + + +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); +} + + +gfc_expr * +gfc_simplify_maxexponent (gfc_expr * x) +{ + gfc_expr *result; + int i; + + i = gfc_validate_kind (BT_REAL, x->ts.kind); + if (i == -1) + gfc_internal_error ("gfc_simplify_maxexponent(): Bad kind"); + + result = gfc_int_expr (gfc_real_kinds[i].max_exponent); + result->where = x->where; + + return result; +} + + +gfc_expr * +gfc_simplify_minexponent (gfc_expr * x) +{ + gfc_expr *result; + int i; + + i = gfc_validate_kind (BT_REAL, x->ts.kind); + if (i == -1) + gfc_internal_error ("gfc_simplify_minexponent(): Bad kind"); + + result = gfc_int_expr (gfc_real_kinds[i].min_exponent); + result->where = x->where; + + return result; +} + + +gfc_expr * +gfc_simplify_mod (gfc_expr * a, gfc_expr * p) +{ + gfc_expr *result; + mpf_t quot, iquot, term; + + if (a->expr_type != EXPR_CONSTANT || p->expr_type != EXPR_CONSTANT) + return NULL; + + result = gfc_constant_result (a->ts.type, a->ts.kind, &a->where); + + switch (a->ts.type) + { + case BT_INTEGER: + if (mpz_cmp_ui (p->value.integer, 0) == 0) + { + /* Result is processor-dependent. */ + gfc_error ("Second argument MOD at %L is zero", &a->where); + gfc_free_expr (result); + return &gfc_bad_expr; + } + mpz_tdiv_r (result->value.integer, a->value.integer, p->value.integer); + break; + + case BT_REAL: + if (mpf_cmp_ui (p->value.real, 0) == 0) + { + /* Result is processor-dependent. */ + gfc_error ("Second argument of MOD at %L is zero", &p->where); + gfc_free_expr (result); + return &gfc_bad_expr; + } + + mpf_init (quot); + mpf_init (iquot); + mpf_init (term); + + mpf_div (quot, a->value.real, p->value.real); + mpf_trunc (iquot, quot); + mpf_mul (term, iquot, p->value.real); + mpf_sub (result->value.real, a->value.real, term); + + mpf_clear (quot); + mpf_clear (iquot); + mpf_clear (term); + break; + + default: + gfc_internal_error ("gfc_simplify_mod(): Bad arguments"); + } + + return range_check (result, "MOD"); +} + + +gfc_expr * +gfc_simplify_modulo (gfc_expr * a, gfc_expr * p) +{ + gfc_expr *result; + mpf_t quot, iquot, term; + + if (a->expr_type != EXPR_CONSTANT || p->expr_type != EXPR_CONSTANT) + return NULL; + + result = gfc_constant_result (a->ts.type, a->ts.kind, &a->where); + + switch (a->ts.type) + { + case BT_INTEGER: + if (mpz_cmp_ui (p->value.integer, 0) == 0) + { + /* Result is processor-dependent. This processor just opts + to not handle it at all. */ + gfc_error ("Second argument of MODULO at %L is zero", &a->where); + gfc_free_expr (result); + return &gfc_bad_expr; + } + mpz_fdiv_r (result->value.integer, a->value.integer, p->value.integer); + + break; + + case BT_REAL: + if (mpf_cmp_ui (p->value.real, 0) == 0) + { + /* Result is processor-dependent. */ + gfc_error ("Second argument of MODULO at %L is zero", &p->where); + gfc_free_expr (result); + return &gfc_bad_expr; + } + + mpf_init (quot); + mpf_init (iquot); + mpf_init (term); + + mpf_div (quot, a->value.real, p->value.real); + mpf_floor (iquot, quot); + mpf_mul (term, iquot, p->value.real); + + mpf_clear (quot); + mpf_clear (iquot); + mpf_clear (term); + + mpf_sub (result->value.real, a->value.real, term); + break; + + default: + gfc_internal_error ("gfc_simplify_modulo(): Bad arguments"); + } + + return range_check (result, "MODULO"); +} + + +/* Exists for the sole purpose of consistency with other intrinsics. */ +gfc_expr * +gfc_simplify_mvbits (gfc_expr * f ATTRIBUTE_UNUSED, + gfc_expr * fp ATTRIBUTE_UNUSED, + gfc_expr * l ATTRIBUTE_UNUSED, + gfc_expr * to ATTRIBUTE_UNUSED, + gfc_expr * tp ATTRIBUTE_UNUSED) +{ + return NULL; +} + + +gfc_expr * +gfc_simplify_nearest (gfc_expr * x, gfc_expr * s) +{ + gfc_expr *result; + float rval; + double val, eps; + int p, i, k, match_float; + + /* FIXME: This implementation is dopey and probably not quite right, + but it's a start. */ + + if (x->expr_type != EXPR_CONSTANT) + return NULL; + + k = gfc_validate_kind (x->ts.type, x->ts.kind); + if (k == -1) + gfc_internal_error ("gfc_simplify_precision(): Bad kind"); + + result = gfc_constant_result (x->ts.type, x->ts.kind, &x->where); + + val = mpf_get_d (x->value.real); + p = gfc_real_kinds[k].digits; + + eps = 1.; + for (i = 1; i < p; ++i) + { + eps = eps / 2.; + } + + /* TODO we should make sure that 'float' matches kind 4 */ + match_float = gfc_real_kinds[k].kind == 4; + if (mpf_cmp_ui (s->value.real, 0) > 0) + { + if (match_float) + { + rval = (float) val; + rval = rval + eps; + mpf_set_d (result->value.real, rval); + } + else + { + val = val + eps; + mpf_set_d (result->value.real, val); + } + } + else if (mpf_cmp_ui (s->value.real, 0) < 0) + { + if (match_float) + { + rval = (float) val; + rval = rval - eps; + mpf_set_d (result->value.real, rval); + } + else + { + val = val - eps; + mpf_set_d (result->value.real, val); + } + } + else + { + gfc_error ("Invalid second argument of NEAREST at %L", &s->where); + gfc_free (result); + return &gfc_bad_expr; + } + + return range_check (result, "NEAREST"); + +} + + +static gfc_expr * +simplify_nint (const char *name, gfc_expr * e, gfc_expr * k) +{ + gfc_expr *rtrunc, *itrunc, *result; + int kind, cmp; + + 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; + + result = gfc_constant_result (BT_INTEGER, kind, &e->where); + + rtrunc = gfc_copy_expr (e); + itrunc = gfc_copy_expr (e); + + cmp = mpf_cmp_ui (e->value.real, 0); + + if (cmp > 0) + { + mpf_add (rtrunc->value.real, e->value.real, mpf_half); + mpf_trunc (itrunc->value.real, rtrunc->value.real); + } + else if (cmp < 0) + { + mpf_sub (rtrunc->value.real, e->value.real, mpf_half); + mpf_trunc (itrunc->value.real, rtrunc->value.real); + } + else + mpf_set_ui (itrunc->value.real, 0); + + mpz_set_f (result->value.integer, itrunc->value.real); + + gfc_free_expr (itrunc); + gfc_free_expr (rtrunc); + + return range_check (result, name); +} + + +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); +} + + +gfc_expr * +gfc_simplify_not (gfc_expr * e) +{ + gfc_expr *result; + int i; + + if (e->expr_type != EXPR_CONSTANT) + return NULL; + + result = gfc_constant_result (e->ts.type, e->ts.kind, &e->where); + + mpz_com (result->value.integer, e->value.integer); + + /* Because of how GMP handles numbers, the result must be ANDed with + the max_int mask. For radices <> 2, this will require change. */ + + i = gfc_validate_kind (BT_INTEGER, e->ts.kind); + if (i == -1) + gfc_internal_error ("gfc_simplify_not(): Bad kind"); + + mpz_and (result->value.integer, result->value.integer, + gfc_integer_kinds[i].max_int); + + return range_check (result, "NOT"); +} + + +gfc_expr * +gfc_simplify_null (gfc_expr * mold) +{ + gfc_expr *result; + + result = gfc_get_expr (); + result->expr_type = EXPR_NULL; + + if (mold == NULL) + result->ts.type = BT_UNKNOWN; + else + { + result->ts = mold->ts; + result->where = mold->where; + } + + return result; +} + + +gfc_expr * +gfc_simplify_precision (gfc_expr * e) +{ + gfc_expr *result; + int i; + + i = gfc_validate_kind (e->ts.type, e->ts.kind); + if (i == -1) + gfc_internal_error ("gfc_simplify_precision(): Bad kind"); + + result = gfc_int_expr (gfc_real_kinds[i].precision); + result->where = e->where; + + return result; +} + + +gfc_expr * +gfc_simplify_radix (gfc_expr * e) +{ + gfc_expr *result; + int i; + + i = gfc_validate_kind (e->ts.type, e->ts.kind); + if (i == -1) + goto bad; + + 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: + bad: + gfc_internal_error ("gfc_simplify_radix(): Bad type"); + } + + result = gfc_int_expr (i); + result->where = e->where; + + return result; +} + + +gfc_expr * +gfc_simplify_range (gfc_expr * e) +{ + gfc_expr *result; + int i; + long j; + + i = gfc_validate_kind (e->ts.type, e->ts.kind); + if (i == -1) + goto bad_type; + + switch (e->ts.type) + { + case BT_INTEGER: + j = gfc_integer_kinds[i].range; + break; + + case BT_REAL: + case BT_COMPLEX: + j = gfc_real_kinds[i].range; + break; + + bad_type: + default: + gfc_internal_error ("gfc_simplify_range(): Bad kind"); + } + + result = gfc_int_expr (j); + result->where = e->where; + + return result; +} + + +gfc_expr * +gfc_simplify_real (gfc_expr * e, gfc_expr * k) +{ + gfc_expr *result; + int kind; + + 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; + + switch (e->ts.type) + { + case BT_INTEGER: + result = gfc_int2real (e, kind); + break; + + case BT_REAL: + result = gfc_real2real (e, kind); + break; + + case BT_COMPLEX: + result = gfc_complex2real (e, kind); + break; + + default: + gfc_internal_error ("bad type in REAL"); + /* Not reached */ + } + + return range_check (result, "REAL"); +} + +gfc_expr * +gfc_simplify_repeat (gfc_expr * e, gfc_expr * n) +{ + gfc_expr *result; + int i, j, len, ncopies, nlen; + + if (e->expr_type != EXPR_CONSTANT || n->expr_type != EXPR_CONSTANT) + return NULL; + + if (n != NULL && (gfc_extract_int (n, &ncopies) != NULL || ncopies < 0)) + { + gfc_error ("Invalid second argument of REPEAT at %L", &n->where); + return &gfc_bad_expr; + } + + len = e->value.character.length; + nlen = ncopies * len; + + result = gfc_constant_result (BT_CHARACTER, e->ts.kind, &e->where); + + if (ncopies == 0) + { + result->value.character.string = gfc_getmem (1); + result->value.character.length = 0; + result->value.character.string[0] = '\0'; + return result; + } + + result->value.character.length = nlen; + result->value.character.string = gfc_getmem (nlen + 1); + + for (i = 0; i < ncopies; i++) + for (j = 0; j < 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]; + gfc_constructor *head, *tail; + mpz_t index, size; + unsigned long j; + size_t nsource; + gfc_expr *e; + + /* Unpack the shape array. */ + if (source->expr_type != EXPR_ARRAY || !gfc_is_constant_expr (source)) + return NULL; + + if (shape_exp->expr_type != EXPR_ARRAY || !gfc_is_constant_expr (shape_exp)) + return NULL; + + if (pad != NULL + && (pad->expr_type != EXPR_ARRAY + || !gfc_is_constant_expr (pad))) + return NULL; + + if (order_exp != NULL + && (order_exp->expr_type != EXPR_ARRAY + || !gfc_is_constant_expr (order_exp))) + return NULL; + + mpz_init (index); + rank = 0; + head = tail = NULL; + + for (;;) + { + e = gfc_get_array_element (shape_exp, rank); + if (e == NULL) + break; + + if (gfc_extract_int (e, &shape[rank]) != NULL) + { + gfc_error ("Integer too large in shape specification at %L", + &e->where); + gfc_free_expr (e); + goto bad_reshape; + } + + gfc_free_expr (e); + + if (rank >= GFC_MAX_DIMENSIONS) + { + gfc_error ("Too many dimensions in shape specification for RESHAPE " + "at %L", &e->where); + + goto bad_reshape; + } + + if (shape[rank] < 0) + { + gfc_error ("Shape specification at %L cannot be negative", + &e->where); + goto bad_reshape; + } + + rank++; + } + + if (rank == 0) + { + gfc_error ("Shape specification at %L cannot be the null array", + &shape_exp->where); + goto bad_reshape; + } + + /* Now unpack the order array if present. */ + if (order_exp == NULL) + { + for (i = 0; i < rank; i++) + order[i] = i; + + } + else + { + + for (i = 0; i < rank; i++) + x[i] = 0; + + for (i = 0; i < rank; i++) + { + e = gfc_get_array_element (order_exp, i); + if (e == NULL) + { + gfc_error + ("ORDER parameter of RESHAPE at %L is not the same size " + "as SHAPE parameter", &order_exp->where); + goto bad_reshape; + } + + if (gfc_extract_int (e, &order[i]) != NULL) + { + gfc_error ("Error in ORDER parameter of RESHAPE at %L", + &e->where); + gfc_free_expr (e); + goto bad_reshape; + } + + gfc_free_expr (e); + + if (order[i] < 1 || order[i] > rank) + { + gfc_error ("ORDER parameter of RESHAPE at %L is out of range", + &e->where); + goto bad_reshape; + } + + order[i]--; + + if (x[order[i]]) + { + gfc_error ("Invalid permutation in ORDER parameter at %L", + &e->where); + goto bad_reshape; + } + + 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; + + for (;;) + { + /* 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 %L", &e->where); + + j = mpz_get_ui (index); + + if (j < nsource) + e = gfc_get_array_element (source, j); + else + { + j = j - nsource; + + if (npad == 0) + { + gfc_error + ("PAD parameter required for short SOURCE parameter at %L", + &source->where); + goto bad_reshape; + } + + j = j % npad; + e = gfc_get_array_element (pad, j); + } + + if (head == NULL) + head = tail = gfc_get_constructor (); + else + { + tail->next = gfc_get_constructor (); + tail = tail->next; + } + + if (e == NULL) + goto bad_reshape; + + tail->where = e->where; + tail->expr = e; + + /* Calculate the next element. */ + i = 0; + +inc: + if (++x[i] < shape[i]) + continue; + x[i++] = 0; + if (i < rank) + goto inc; + + break; + } + + mpz_clear (index); + + e = gfc_get_expr (); + e->where = source->where; + e->expr_type = EXPR_ARRAY; + e->value.constructor = head; + e->shape = gfc_get_shape (rank); + + for (i = 0; i < rank; i++) + mpz_init_set_ui (e->shape[i], shape[order[i]]); + + e->ts = head->expr->ts; + e->rank = rank; + + return e; + +bad_reshape: + gfc_free_constructor (head); + mpz_clear (index); + return &gfc_bad_expr; +} + + +gfc_expr * +gfc_simplify_rrspacing (gfc_expr * x) +{ + gfc_expr *result; + mpf_t i2, absv, ln2, lnx, frac, pow2; + unsigned long exp2; + int i, p; + + if (x->expr_type != EXPR_CONSTANT) + return NULL; + + i = gfc_validate_kind (x->ts.type, x->ts.kind); + if (i == -1) + gfc_internal_error ("gfc_simplify_rrspacing(): Bad kind"); + + result = gfc_constant_result (BT_REAL, x->ts.kind, &x->where); + + p = gfc_real_kinds[i].digits; + + if (mpf_cmp (x->value.real, mpf_zero) == 0) + { + mpf_ui_div (result->value.real, 1, gfc_real_kinds[i].tiny); + return result; + } + + mpf_init_set_ui (i2, 2); + mpf_init (ln2); + mpf_init (absv); + mpf_init (lnx); + mpf_init (frac); + mpf_init (pow2); + + natural_logarithm (&i2, &ln2); + + mpf_abs (absv, x->value.real); + natural_logarithm (&absv, &lnx); + + mpf_div (lnx, lnx, ln2); + mpf_trunc (lnx, lnx); + mpf_add_ui (lnx, lnx, 1); + + exp2 = (unsigned long) mpf_get_d (lnx); + mpf_pow_ui (pow2, i2, exp2); + mpf_div (frac, absv, pow2); + + exp2 = (unsigned long) p; + mpf_mul_2exp (result->value.real, frac, exp2); + + mpf_clear (i2); + mpf_clear (ln2); + mpf_clear (absv); + mpf_clear (lnx); + mpf_clear (frac); + mpf_clear (pow2); + + return range_check (result, "RRSPACING"); +} + + +gfc_expr * +gfc_simplify_scale (gfc_expr * x, gfc_expr * i) +{ + int k, neg_flag, power, exp_range; + mpf_t scale, radix; + gfc_expr *result; + + if (x->expr_type != EXPR_CONSTANT || i->expr_type != EXPR_CONSTANT) + return NULL; + + result = gfc_constant_result (BT_REAL, x->ts.kind, &x->where); + + if (mpf_sgn (x->value.real) == 0) + { + mpf_set_ui (result->value.real, 0); + return result; + } + + k = gfc_validate_kind (BT_REAL, x->ts.kind); + if (k == -1) + gfc_internal_error ("gfc_simplify_scale(): Bad kind"); + + 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); + 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; + } + + mpf_init_set_ui (radix, gfc_real_kinds[k].radix); + mpf_init (scale); + mpf_pow_ui (scale, radix, power); + + if (neg_flag) + mpf_div (result->value.real, x->value.real, scale); + else + mpf_mul (result->value.real, x->value.real, scale); + + mpf_clear (scale); + mpf_clear (radix); + + return range_check (result, "SCALE"); +} + + +gfc_expr * +gfc_simplify_scan (gfc_expr * e, gfc_expr * c, gfc_expr * b) +{ + gfc_expr *result; + int back; + size_t i; + size_t indx, len, lenc; + + if (e->expr_type != EXPR_CONSTANT || c->expr_type != EXPR_CONSTANT) + return NULL; + + if (b != NULL && b->value.logical != 0) + back = 1; + else + back = 0; + + result = gfc_constant_result (BT_INTEGER, gfc_default_integer_kind (), + &e->where); + + len = e->value.character.length; + lenc = c->value.character.length; + + if (len == 0 || lenc == 0) + { + indx = 0; + } + else + { + if (back == 0) + { + indx = + strcspn (e->value.character.string, c->value.character.string) + 1; + if (indx > len) + indx = 0; + } + else + { + i = 0; + 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; + } + } + } + mpz_set_ui (result->value.integer, indx); + return range_check (result, "SCAN"); +} + + +gfc_expr * +gfc_simplify_selected_int_kind (gfc_expr * e) +{ + int i, kind, range; + gfc_expr *result; + + if (e->expr_type != EXPR_CONSTANT || gfc_extract_int (e, &range) != NULL) + 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; + + result = gfc_int_expr (kind); + result->where = e->where; + + return result; +} + + +gfc_expr * +gfc_simplify_selected_real_kind (gfc_expr * p, gfc_expr * q) +{ + int range, precision, i, kind, found_precision, found_range; + gfc_expr *result; + + if (p == NULL) + precision = 0; + else + { + if (p->expr_type != EXPR_CONSTANT + || gfc_extract_int (p, &precision) != NULL) + return NULL; + } + + if (q == NULL) + range = 0; + else + { + if (q->expr_type != EXPR_CONSTANT + || gfc_extract_int (q, &range) != NULL) + return NULL; + } + + kind = INT_MAX; + found_precision = 0; + found_range = 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 (gfc_real_kinds[i].precision >= precision + && gfc_real_kinds[i].range >= range && gfc_real_kinds[i].kind < kind) + kind = gfc_real_kinds[i].kind; + } + + if (kind == INT_MAX) + { + kind = 0; + + if (!found_precision) + kind = -1; + if (!found_range) + kind -= 2; + } + + result = gfc_int_expr (kind); + result->where = (p != NULL) ? p->where : q->where; + + return result; +} + + +gfc_expr * +gfc_simplify_set_exponent (gfc_expr * x, gfc_expr * i) +{ + gfc_expr *result; + mpf_t i2, ln2, absv, lnx, pow2, frac; + unsigned long exp2; + + if (x->expr_type != EXPR_CONSTANT || i->expr_type != EXPR_CONSTANT) + return NULL; + + result = gfc_constant_result (BT_REAL, x->ts.kind, &x->where); + + if (mpf_cmp (x->value.real, mpf_zero) == 0) + { + mpf_set (result->value.real, mpf_zero); + return result; + } + + mpf_init_set_ui (i2, 2); + mpf_init (ln2); + mpf_init (absv); + mpf_init (lnx); + mpf_init (pow2); + mpf_init (frac); + + natural_logarithm (&i2, &ln2); + + mpf_abs (absv, x->value.real); + natural_logarithm (&absv, &lnx); + + mpf_div (lnx, lnx, ln2); + mpf_trunc (lnx, lnx); + mpf_add_ui (lnx, lnx, 1); + + /* Old exponent value, and fraction. */ + exp2 = (unsigned long) mpf_get_d (lnx); + mpf_pow_ui (pow2, i2, exp2); + + mpf_div (frac, absv, pow2); + + /* New exponent. */ + exp2 = (unsigned long) mpz_get_d (i->value.integer); + mpf_mul_2exp (result->value.real, frac, exp2); + + mpf_clear (i2); + mpf_clear (ln2); + mpf_clear (absv); + mpf_clear (lnx); + mpf_clear (pow2); + mpf_clear (frac); + + return range_check (result, "SET_EXPONENT"); +} + + +gfc_expr * +gfc_simplify_shape (gfc_expr * source) +{ + mpz_t shape[GFC_MAX_DIMENSIONS]; + gfc_expr *result, *e, *f; + gfc_array_ref *ar; + int n; + try t; + + result = gfc_start_constructor (BT_INTEGER, gfc_default_integer_kind (), + &source->where); + + if (source->rank == 0 || source->expr_type != EXPR_VARIABLE) + return result; + + ar = gfc_find_array_ref (source); + + t = gfc_array_ref_shape (ar, shape); + + for (n = 0; n < source->rank; n++) + { + e = gfc_constant_result (BT_INTEGER, gfc_default_integer_kind (), + &source->where); + + if (t == SUCCESS) + { + mpz_set (e->value.integer, shape[n]); + mpz_clear (shape[n]); + } + else + { + mpz_set_ui (e->value.integer, n + 1); + + f = gfc_simplify_size (source, e); + gfc_free_expr (e); + if (f == NULL) + { + gfc_free_expr (result); + return NULL; + } + else + { + e = f; + } + } + + gfc_append_constructor (result, e); + } + + return result; +} + + +gfc_expr * +gfc_simplify_size (gfc_expr * array, gfc_expr * dim) +{ + mpz_t size; + gfc_expr *result; + int d; + + if (dim == NULL) + { + if (gfc_array_size (array, &size) == FAILURE) + 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) == FAILURE) + return NULL; + } + + result = gfc_constant_result (BT_INTEGER, gfc_default_integer_kind (), + &array->where); + + mpz_set (result->value.integer, size); + + return result; +} + + +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_constant_result (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: + /* TODO: Handle -0.0 and +0.0 correctly on machines that support + it. */ + mpf_abs (result->value.real, x->value.real); + if (mpf_sgn (y->value.integer) < 0) + mpf_neg (result->value.real, result->value.real); + + break; + + default: + gfc_internal_error ("Bad type in gfc_simplify_sign"); + } + + return result; +} + + +gfc_expr * +gfc_simplify_sin (gfc_expr * x) +{ + gfc_expr *result; + mpf_t xp, xq; + + if (x->expr_type != EXPR_CONSTANT) + return NULL; + + result = gfc_constant_result (x->ts.type, x->ts.kind, &x->where); + + switch (x->ts.type) + { + case BT_REAL: + sine (&x->value.real, &result->value.real); + break; + + case BT_COMPLEX: + mpf_init (xp); + mpf_init (xq); + + sine (&x->value.complex.r, &xp); + hypercos (&x->value.complex.i, &xq); + mpf_mul (result->value.complex.r, xp, xq); + + cosine (&x->value.complex.r, &xp); + hypersine (&x->value.complex.i, &xq); + mpf_mul (result->value.complex.i, xp, xq); + + mpf_clear (xp); + mpf_clear (xq); + 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_constant_result (x->ts.type, x->ts.kind, &x->where); + + hypersine (&x->value.real, &result->value.real); + + 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; + + if (a->expr_type != EXPR_CONSTANT) + return NULL; + + result = gfc_real2real (a, gfc_default_real_kind ()); + return range_check (result, "SNGL"); +} + + +gfc_expr * +gfc_simplify_spacing (gfc_expr * x) +{ + gfc_expr *result; + mpf_t i1, i2, ln2, absv, lnx; + long diff; + unsigned long exp2; + int i, p; + + if (x->expr_type != EXPR_CONSTANT) + return NULL; + + i = gfc_validate_kind (x->ts.type, x->ts.kind); + if (i == -1) + gfc_internal_error ("gfc_simplify_spacing(): Bad kind"); + + p = gfc_real_kinds[i].digits; + + result = gfc_constant_result (BT_REAL, x->ts.kind, &x->where); + + if (mpf_cmp (x->value.real, mpf_zero) == 0) + { + mpf_set (result->value.real, gfc_real_kinds[i].tiny); + return result; + } + + mpf_init_set_ui (i1, 1); + mpf_init_set_ui (i2, 2); + mpf_init (ln2); + mpf_init (absv); + mpf_init (lnx); + + natural_logarithm (&i2, &ln2); + + mpf_abs (absv, x->value.real); + natural_logarithm (&absv, &lnx); + + mpf_div (lnx, lnx, ln2); + mpf_trunc (lnx, lnx); + mpf_add_ui (lnx, lnx, 1); + + diff = (long) mpf_get_d (lnx) - (long) p; + if (diff >= 0) + { + exp2 = (unsigned) diff; + mpf_mul_2exp (result->value.real, i1, exp2); + } + else + { + diff = -diff; + exp2 = (unsigned) diff; + mpf_div_2exp (result->value.real, i1, exp2); + } + + mpf_clear (i1); + mpf_clear (i2); + mpf_clear (ln2); + mpf_clear (absv); + mpf_clear (lnx); + + if (mpf_cmp (result->value.real, gfc_real_kinds[i].tiny) < 0) + mpf_set (result->value.real, gfc_real_kinds[i].tiny); + + return range_check (result, "SPACING"); +} + + +gfc_expr * +gfc_simplify_sqrt (gfc_expr * e) +{ + gfc_expr *result; + mpf_t ac, ad, s, t, w; + + if (e->expr_type != EXPR_CONSTANT) + return NULL; + + result = gfc_constant_result (e->ts.type, e->ts.kind, &e->where); + + switch (e->ts.type) + { + case BT_REAL: + if (mpf_cmp_si (e->value.real, 0) < 0) + goto negative_arg; + mpf_sqrt (result->value.real, e->value.real); + + break; + + case BT_COMPLEX: + /* Formula taken from Numerical Recipes to avoid over- and + underflow. */ + + mpf_init (ac); + mpf_init (ad); + mpf_init (s); + mpf_init (t); + mpf_init (w); + + if (mpf_cmp_ui (e->value.complex.r, 0) == 0 + && mpf_cmp_ui (e->value.complex.i, 0) == 0) + { + + mpf_set_ui (result->value.complex.r, 0); + mpf_set_ui (result->value.complex.i, 0); + break; + } + + mpf_abs (ac, e->value.complex.r); + mpf_abs (ad, e->value.complex.i); + + if (mpf_cmp (ac, ad) >= 0) + { + mpf_div (t, e->value.complex.i, e->value.complex.r); + mpf_mul (t, t, t); + mpf_add_ui (t, t, 1); + mpf_sqrt (t, t); + mpf_add_ui (t, t, 1); + mpf_div_ui (t, t, 2); + mpf_sqrt (t, t); + mpf_sqrt (s, ac); + mpf_mul (w, s, t); + } + else + { + mpf_div (s, e->value.complex.r, e->value.complex.i); + mpf_mul (t, s, s); + mpf_add_ui (t, t, 1); + mpf_sqrt (t, t); + mpf_abs (s, s); + mpf_add (t, t, s); + mpf_div_ui (t, t, 2); + mpf_sqrt (t, t); + mpf_sqrt (s, ad); + mpf_mul (w, s, t); + } + + if (mpf_cmp_ui (w, 0) != 0 && mpf_cmp_ui (e->value.complex.r, 0) >= 0) + { + mpf_mul_ui (t, w, 2); + mpf_div (result->value.complex.i, e->value.complex.i, t); + mpf_set (result->value.complex.r, w); + } + else if (mpf_cmp_ui (w, 0) != 0 + && mpf_cmp_ui (e->value.complex.r, 0) < 0 + && mpf_cmp_ui (e->value.complex.i, 0) >= 0) + { + mpf_mul_ui (t, w, 2); + mpf_div (result->value.complex.r, e->value.complex.i, t); + mpf_set (result->value.complex.i, w); + } + else if (mpf_cmp_ui (w, 0) != 0 + && mpf_cmp_ui (e->value.complex.r, 0) < 0 + && mpf_cmp_ui (e->value.complex.i, 0) < 0) + { + mpf_mul_ui (t, w, 2); + mpf_div (result->value.complex.r, ad, t); + mpf_neg (w, w); + mpf_set (result->value.complex.i, w); + } + else + gfc_internal_error ("invalid complex argument of SQRT at %L", + &e->where); + + mpf_clear (s); + mpf_clear (t); + mpf_clear (ac); + mpf_clear (ad); + mpf_clear (w); + + break; + + default: + gfc_internal_error ("invalid argument of SQRT at %L", &e->where); + } + + return range_check (result, "SQRT"); + +negative_arg: + gfc_free_expr (result); + gfc_error ("Argument of SQRT at %L has a negative value", &e->where); + return &gfc_bad_expr; +} + + +gfc_expr * +gfc_simplify_tan (gfc_expr * x) +{ + gfc_expr *result; + mpf_t mpf_sin, mpf_cos, mag_cos; + int i; + + if (x->expr_type != EXPR_CONSTANT) + return NULL; + + i = gfc_validate_kind (BT_REAL, x->ts.kind); + if (i == -1) + gfc_internal_error ("gfc_simplify_tan(): Bad kind"); + + result = gfc_constant_result (x->ts.type, x->ts.kind, &x->where); + + mpf_init (mpf_sin); + mpf_init (mpf_cos); + mpf_init (mag_cos); + sine (&x->value.real, &mpf_sin); + cosine (&x->value.real, &mpf_cos); + mpf_abs (mag_cos, mpf_cos); + if (mpf_cmp_ui (mag_cos, 0) == 0) + { + gfc_error ("Tangent undefined at %L", &x->where); + mpf_clear (mpf_sin); + mpf_clear (mpf_cos); + mpf_clear (mag_cos); + gfc_free_expr (result); + return &gfc_bad_expr; + } + else if (mpf_cmp (mag_cos, gfc_real_kinds[i].tiny) < 0) + { + gfc_error ("Tangent cannot be accurately evaluated at %L", &x->where); + mpf_clear (mpf_sin); + mpf_clear (mpf_cos); + mpf_clear (mag_cos); + gfc_free_expr (result); + return &gfc_bad_expr; + } + else + { + mpf_div (result->value.real, mpf_sin, mpf_cos); + mpf_clear (mpf_sin); + mpf_clear (mpf_cos); + mpf_clear (mag_cos); + } + + return range_check (result, "TAN"); +} + + +gfc_expr * +gfc_simplify_tanh (gfc_expr * x) +{ + gfc_expr *result; + mpf_t xp, xq; + + if (x->expr_type != EXPR_CONSTANT) + return NULL; + + result = gfc_constant_result (x->ts.type, x->ts.kind, &x->where); + + mpf_init (xp); + mpf_init (xq); + + hypersine (&x->value.real, &xq); + hypercos (&x->value.real, &xp); + + mpf_div (result->value.real, xq, xp); + + mpf_clear (xp); + mpf_clear (xq); + + 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); + if (i == -1) + gfc_internal_error ("gfc_simplify_error(): Bad kind"); + + result = gfc_constant_result (BT_REAL, e->ts.kind, &e->where); + mpf_set (result->value.real, gfc_real_kinds[i].tiny); + + 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; + + result = gfc_constant_result (BT_CHARACTER, e->ts.kind, &e->where); + + for (count = 0, i = 1; i <= len; ++i) + { + if (e->value.character.string[len - i] == ' ') + count++; + else + break; + } + + lentrim = len - count; + + result->value.character.length = lentrim; + result->value.character.string = gfc_getmem (lentrim + 1); + + for (i = 0; i < lentrim; i++) + result->value.character.string[i] = e->value.character.string[i]; + + result->value.character.string[lentrim] = '\0'; /* For debugger */ + + return result; +} + + +gfc_expr * +gfc_simplify_ubound (gfc_expr * array, gfc_expr * dim) +{ + return gfc_simplify_bound (array, dim, 1); +} + + +gfc_expr * +gfc_simplify_verify (gfc_expr * s, gfc_expr * set, gfc_expr * b) +{ + gfc_expr *result; + int back; + size_t index, len, lenset; + size_t i; + + if (s->expr_type != EXPR_CONSTANT || set->expr_type != EXPR_CONSTANT) + return NULL; + + if (b != NULL && b->value.logical != 0) + back = 1; + else + back = 0; + + result = gfc_constant_result (BT_INTEGER, gfc_default_integer_kind (), + &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, len); + return result; + } + + index = + 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, 1); + 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; +} + +/****************** 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 *g, *result, *(*f) (gfc_expr *, int); + gfc_constructor *head, *c, *tail = NULL; + + 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; + 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: + if (type != BT_LOGICAL) + goto oops; + f = gfc_log2log; + break; + + default: + oops: + gfc_internal_error ("gfc_convert_constant(): Unexpected type"); + } + + 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; + + head = NULL; + + for (c = e->value.constructor; c; c = c->next) + { + if (head == NULL) + head = tail = gfc_get_constructor (); + else + { + tail->next = gfc_get_constructor (); + tail = tail->next; + } + + tail->where = c->where; + + if (c->iterator == NULL) + tail->expr = f (c->expr, kind); + else + { + g = gfc_convert_constant (c->expr, type, kind); + if (g == &gfc_bad_expr) + return g; + tail->expr = g; + } + + if (tail->expr == NULL) + { + gfc_free_constructor (head); + return NULL; + } + } + + result = gfc_get_expr (); + result->ts.type = type; + result->ts.kind = kind; + result->expr_type = EXPR_ARRAY; + result->value.constructor = head; + result->shape = gfc_copy_shape (e->shape, e->rank); + result->where = e->where; + result->rank = e->rank; + break; + + default: + break; + } + + return result; +} + + +/****************** Helper functions ***********************/ + +/* Given a collating table, create the inverse table. */ + +static void +invert_table (const int *table, int *xtable) +{ + int i; + + for (i = 0; i < 256; i++) + xtable[i] = 0; + + for (i = 0; i < 256; i++) + xtable[table[i]] = i; +} + + +void +gfc_simplify_init_1 (void) +{ + + mpf_init_set_str (mpf_zero, "0.0", 10); + mpf_init_set_str (mpf_half, "0.5", 10); + mpf_init_set_str (mpf_one, "1.0", 10); + mpz_init_set_str (mpz_zero, "0", 10); + + invert_table (ascii_table, xascii_table); +} + + +void +gfc_simplify_done_1 (void) +{ + + mpf_clear (mpf_zero); + mpf_clear (mpf_half); + mpf_clear (mpf_one); + mpz_clear (mpz_zero); +} |