/* Compiler arithmetic
- Copyright (C) 2000, 2001, 2002, 2003, 2004 Free Software Foundation,
+ Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation,
Inc.
Contributed by Andy Vaught
#include "config.h"
#include "system.h"
+#include "flags.h"
#include "gfortran.h"
#include "arith.h"
gfc_set_model (y);
mpfr_init (t);
- i = mpfr_sgn(x);
+ i = mpfr_sgn (x);
if (i > 0)
{
if (mpfr_sgn (y) < 0)
mpfr_neg (result, result, GFC_RND_MODE);
}
- else
- {
+ else
+ {
if (mpfr_sgn (y) == 0)
mpfr_set_ui (result, 0, GFC_RND_MODE);
else
case ARITH_DIV0:
p = "Division by zero";
break;
- case ARITH_0TO0:
- p = "Indeterminate form 0 ** 0";
- break;
case ARITH_INCOMMENSURATE:
p = "Array operands are incommensurate";
break;
+ case ARITH_ASYMMETRIC:
+ p = "Integer outside symmetric range implied by Standard Fortran";
+ break;
default:
gfc_internal_error ("gfc_arith_error(): Bad error code");
}
/* These are the numbers that are actually representable by the
target. For bases other than two, this needs to be changed. */
if (int_info->radix != 2)
- gfc_internal_error ("Fix min_int, max_int calculation");
+ gfc_internal_error ("Fix min_int, max_int calculation");
+
+ /* See PRs 13490 and 17912, related to integer ranges.
+ The pedantic_min_int exists for range checking when a program
+ is compiled with -pedantic, and reflects the belief that
+ Standard Fortran requires integers to be symmetrical, i.e.
+ every negative integer must have a representable positive
+ absolute value, and vice versa. */
+
+ mpz_init (int_info->pedantic_min_int);
+ mpz_neg (int_info->pedantic_min_int, int_info->huge);
mpz_init (int_info->min_int);
- mpz_neg (int_info->min_int, int_info->huge);
- /* No -1 here, because the representation is symmetric. */
+ mpz_sub_ui (int_info->min_int, int_info->pedantic_min_int, 1);
mpz_init (int_info->max_int);
mpz_add (int_info->max_int, int_info->huge, int_info->huge);
mpfr_init (real_info->tiny);
mpfr_set (real_info->tiny, b, GFC_RND_MODE);
+ /* subnormal (x) = b**(emin - digit) */
+ mpfr_set_ui (b, real_info->radix, GFC_RND_MODE);
+ mpfr_pow_si (b, b, real_info->min_exponent - real_info->digits,
+ GFC_RND_MODE);
+
+ mpfr_init (real_info->subnormal);
+ mpfr_set (real_info->subnormal, b, GFC_RND_MODE);
+
/* epsilon(x) = b**(1-p) */
mpfr_set_ui (b, real_info->radix, GFC_RND_MODE);
mpfr_pow_si (b, b, 1 - real_info->digits, GFC_RND_MODE);
/* Given an integer and a kind, make sure that the integer lies within
- the range of the kind. Returns ARITH_OK or ARITH_OVERFLOW. */
+ the range of the kind. Returns ARITH_OK, ARITH_ASYMMETRIC or
+ ARITH_OVERFLOW. */
static arith
gfc_check_integer_range (mpz_t p, int kind)
i = gfc_validate_kind (BT_INTEGER, kind, false);
result = ARITH_OK;
+ if (pedantic)
+ {
+ if (mpz_cmp (p, gfc_integer_kinds[i].pedantic_min_int) < 0)
+ result = ARITH_ASYMMETRIC;
+ }
+
if (mpz_cmp (p, gfc_integer_kinds[i].min_int) < 0
|| mpz_cmp (p, gfc_integer_kinds[i].max_int) > 0)
result = ARITH_OVERFLOW;
mpfr_init (q);
mpfr_abs (q, p, GFC_RND_MODE);
- retval = ARITH_OK;
if (mpfr_sgn (q) == 0)
- goto done;
-
- if (mpfr_cmp (q, gfc_real_kinds[i].huge) > 0)
+ retval = ARITH_OK;
+ else if (mpfr_cmp (q, gfc_real_kinds[i].huge) > 0)
+ retval = ARITH_OVERFLOW;
+ else if (mpfr_cmp (q, gfc_real_kinds[i].subnormal) < 0)
+ retval = ARITH_UNDERFLOW;
+ else if (mpfr_cmp (q, gfc_real_kinds[i].tiny) < 0)
{
- retval = ARITH_OVERFLOW;
- goto done;
- }
+ /* MPFR operates on a numbers with a given precision and enormous
+ exponential range. To represent subnormal numbers the exponent is
+ allowed to become smaller than emin, but always retains the full
+ precision. This function resets unused bits to 0 to alleviate
+ rounding problems. Note, a future version of MPFR will have a
+ mpfr_subnormalize() function, which handles this truncation in a
+ more efficient and robust way. */
+
+ int j, k;
+ char *bin, *s;
+ mp_exp_t e;
+
+ bin = mpfr_get_str (NULL, &e, gfc_real_kinds[i].radix, 0, q, GMP_RNDN);
+ k = gfc_real_kinds[i].digits - (gfc_real_kinds[i].min_exponent - e);
+ for (j = k; j < gfc_real_kinds[i].digits; j++)
+ bin[j] = '0';
+ /* Need space for '0.', bin, 'E', and e */
+ s = (char *) gfc_getmem (strlen(bin)+10);
+ sprintf (s, "0.%sE%d", bin, (int) e);
+ mpfr_set_str (q, s, gfc_real_kinds[i].radix, GMP_RNDN);
+
+ if (mpfr_sgn (p) < 0)
+ mpfr_neg (p, q, GMP_RNDN);
+ else
+ mpfr_set (p, q, GMP_RNDN);
- if (mpfr_cmp (q, gfc_real_kinds[i].tiny) < 0)
- retval = ARITH_UNDERFLOW;
+ gfc_free (s);
+ gfc_free (bin);
+
+ retval = ARITH_OK;
+ }
+ else
+ retval = ARITH_OK;
-done:
mpfr_clear (q);
return retval;
}
+/* Several of the following routines use the same set of statements to
+ check the validity of the result. Encapsulate the checking here. */
+
+static arith
+check_result (arith rc, gfc_expr * x, gfc_expr * r, gfc_expr ** rp)
+{
+ arith val = rc;
+
+ if (val == ARITH_UNDERFLOW)
+ {
+ if (gfc_option.warn_underflow)
+ gfc_warning ("%s at %L", gfc_arith_error (val), &x->where);
+ val = ARITH_OK;
+ }
+
+ if (val == ARITH_ASYMMETRIC)
+ {
+ gfc_warning ("%s at %L", gfc_arith_error (val), &x->where);
+ val = ARITH_OK;
+ }
+
+ if (val != ARITH_OK)
+ gfc_free_expr (r);
+ else
+ *rp = r;
+
+ return val;
+}
+
+
/* It may seem silly to have a subroutine that actually computes the
unary plus of a constant, but it prevents us from making exceptions
in the code elsewhere. */
static arith
gfc_arith_uplus (gfc_expr * op1, gfc_expr ** resultp)
{
-
*resultp = gfc_copy_expr (op1);
return ARITH_OK;
}
rc = gfc_range_check (result);
- if (rc == ARITH_UNDERFLOW)
- {
- if (gfc_option.warn_underflow)
- gfc_warning ("%s at %L", gfc_arith_error (rc), &op1->where);
- rc = ARITH_OK;
- *resultp = result;
- }
- else if (rc != ARITH_OK)
- gfc_free_expr (result);
- else
- *resultp = result;
-
- return rc;
+ return check_result (rc, op1, result, resultp);
}
rc = gfc_range_check (result);
- if (rc == ARITH_UNDERFLOW)
- {
- if (gfc_option.warn_underflow)
- gfc_warning ("%s at %L", gfc_arith_error (rc), &op1->where);
- rc = ARITH_OK;
- *resultp = result;
- }
- else if (rc != ARITH_OK)
- gfc_free_expr (result);
- else
- *resultp = result;
-
- return rc;
+ return check_result (rc, op1, result, resultp);
}
rc = gfc_range_check (result);
- if (rc == ARITH_UNDERFLOW)
- {
- if (gfc_option.warn_underflow)
- gfc_warning ("%s at %L", gfc_arith_error (rc), &op1->where);
- rc = ARITH_OK;
- *resultp = result;
- }
- else if (rc != ARITH_OK)
- gfc_free_expr (result);
- else
- *resultp = result;
-
- return rc;
+ return check_result (rc, op1, result, resultp);
}
rc = gfc_range_check (result);
- if (rc == ARITH_UNDERFLOW)
- {
- if (gfc_option.warn_underflow)
- gfc_warning ("%s at %L", gfc_arith_error (rc), &op1->where);
- rc = ARITH_OK;
- *resultp = result;
- }
- else if (rc != ARITH_OK)
- gfc_free_expr (result);
- else
- *resultp = result;
-
- return rc;
+ return check_result (rc, op1, result, resultp);
}
if (rc == ARITH_OK)
rc = gfc_range_check (result);
- if (rc == ARITH_UNDERFLOW)
- {
- if (gfc_option.warn_underflow)
- gfc_warning ("%s at %L", gfc_arith_error (rc), &op1->where);
- rc = ARITH_OK;
- *resultp = result;
- }
- else if (rc != ARITH_OK)
- gfc_free_expr (result);
- else
- *resultp = result;
-
- return rc;
+ return check_result (rc, op1, result, resultp);
}
result = gfc_constant_result (op1->ts.type, op1->ts.kind, &op1->where);
if (power == 0)
- { /* Handle something to the zeroth power */
+ {
+ /* Handle something to the zeroth power. Since we're dealing
+ with integral exponents, there is no ambiguity in the
+ limiting procedure used to determine the value of 0**0. */
switch (op1->ts.type)
{
case BT_INTEGER:
- if (mpz_sgn (op1->value.integer) == 0)
- rc = ARITH_0TO0;
- else
- mpz_set_ui (result->value.integer, 1);
+ mpz_set_ui (result->value.integer, 1);
break;
case BT_REAL:
- if (mpfr_sgn (op1->value.real) == 0)
- rc = ARITH_0TO0;
- else
- mpfr_set_ui (result->value.real, 1, GFC_RND_MODE);
+ mpfr_set_ui (result->value.real, 1, GFC_RND_MODE);
break;
case BT_COMPLEX:
- if (mpfr_sgn (op1->value.complex.r) == 0
- && mpfr_sgn (op1->value.complex.i) == 0)
- rc = ARITH_0TO0;
- else
- {
- mpfr_set_ui (result->value.complex.r, 1, GFC_RND_MODE);
- mpfr_set_ui (result->value.complex.i, 0, GFC_RND_MODE);
- }
-
+ mpfr_set_ui (result->value.complex.r, 1, GFC_RND_MODE);
+ mpfr_set_ui (result->value.complex.i, 0, GFC_RND_MODE);
break;
default:
if (rc == ARITH_OK)
rc = gfc_range_check (result);
- if (rc == ARITH_UNDERFLOW)
- {
- if (gfc_option.warn_underflow)
- gfc_warning ("%s at %L", gfc_arith_error (rc), &op1->where);
- rc = ARITH_OK;
- *resultp = result;
- }
- else if (rc != ARITH_OK)
- gfc_free_expr (result);
- else
- *resultp = result;
-
- return rc;
+ return check_result (rc, op1, result, resultp);
}
gfc_expr *result;
int len;
- result = gfc_constant_result (BT_CHARACTER, gfc_default_character_kind (),
+ result = gfc_constant_result (BT_CHARACTER, gfc_default_character_kind,
&op1->where);
len = op1->value.character.length + op2->value.character.length;
static int
compare_complex (gfc_expr * op1, gfc_expr * op2)
{
-
return (mpfr_cmp (op1->value.complex.r, op2->value.complex.r) == 0
&& mpfr_cmp (op1->value.complex.i, op2->value.complex.i) == 0);
}
{
gfc_expr *result;
- result = gfc_constant_result (BT_LOGICAL, gfc_default_logical_kind (),
+ result = gfc_constant_result (BT_LOGICAL, gfc_default_logical_kind,
&op1->where);
result->value.logical = (op1->ts.type == BT_COMPLEX) ?
compare_complex (op1, op2) : (gfc_compare_expr (op1, op2) == 0);
{
gfc_expr *result;
- result = gfc_constant_result (BT_LOGICAL, gfc_default_logical_kind (),
+ result = gfc_constant_result (BT_LOGICAL, gfc_default_logical_kind,
&op1->where);
result->value.logical = (op1->ts.type == BT_COMPLEX) ?
!compare_complex (op1, op2) : (gfc_compare_expr (op1, op2) != 0);
{
gfc_expr *result;
- result = gfc_constant_result (BT_LOGICAL, gfc_default_logical_kind (),
+ result = gfc_constant_result (BT_LOGICAL, gfc_default_logical_kind,
&op1->where);
result->value.logical = (gfc_compare_expr (op1, op2) > 0);
*resultp = result;
{
gfc_expr *result;
- result = gfc_constant_result (BT_LOGICAL, gfc_default_logical_kind (),
+ result = gfc_constant_result (BT_LOGICAL, gfc_default_logical_kind,
&op1->where);
result->value.logical = (gfc_compare_expr (op1, op2) >= 0);
*resultp = result;
{
gfc_expr *result;
- result = gfc_constant_result (BT_LOGICAL, gfc_default_logical_kind (),
+ result = gfc_constant_result (BT_LOGICAL, gfc_default_logical_kind,
&op1->where);
result->value.logical = (gfc_compare_expr (op1, op2) < 0);
*resultp = result;
{
gfc_expr *result;
- result = gfc_constant_result (BT_LOGICAL, gfc_default_logical_kind (),
+ result = gfc_constant_result (BT_LOGICAL, gfc_default_logical_kind,
&op1->where);
result->value.logical = (gfc_compare_expr (op1, op2) <= 0);
*resultp = result;
gfc_expr * op1, gfc_expr * op2,
gfc_expr ** result)
{
-
if (op1->expr_type == EXPR_CONSTANT && op2->expr_type == EXPR_CONSTANT)
return eval (op1, op2, result);
goto runtime;
temp.ts.type = BT_LOGICAL;
- temp.ts.kind = gfc_default_logical_kind ();
+ temp.ts.kind = gfc_default_logical_kind;
unary = 1;
break;
goto runtime;
temp.ts.type = BT_LOGICAL;
- temp.ts.kind = gfc_default_logical_kind ();
+ temp.ts.kind = gfc_default_logical_kind;
unary = 0;
break;
if (op1->ts.type == BT_COMPLEX || op2->ts.type == BT_COMPLEX)
{
temp.ts.type = BT_LOGICAL;
- temp.ts.kind = gfc_default_logical_kind();
+ temp.ts.kind = gfc_default_logical_kind;
goto runtime;
}
{
unary = 0;
temp.ts.type = BT_LOGICAL;
- temp.ts.kind = gfc_default_logical_kind();
+ temp.ts.kind = gfc_default_logical_kind;
break;
}
temp.expr_type = EXPR_OP;
gfc_clear_ts (&temp.ts);
- temp.operator = operator;
+ temp.value.op.operator = operator;
- temp.op1 = op1;
- temp.op2 = op2;
+ temp.value.op.op1 = op1;
+ temp.value.op.op2 = op2;
gfc_type_convert_binary (&temp);
|| operator == INTRINSIC_LE || operator == INTRINSIC_LT)
{
temp.ts.type = BT_LOGICAL;
- temp.ts.kind = gfc_default_logical_kind ();
+ temp.ts.kind = gfc_default_logical_kind;
}
unary = 0;
goto runtime;
temp.ts.type = BT_CHARACTER;
- temp.ts.kind = gfc_default_character_kind ();
+ temp.ts.kind = gfc_default_character_kind;
unary = 0;
break;
result->ts = temp.ts;
result->expr_type = EXPR_OP;
- result->operator = operator;
+ result->value.op.operator = operator;
- result->op1 = op1;
- result->op2 = op2;
+ result->value.op.op1 = op1;
+ result->value.op.op2 = op2;
result->where = op1->where;
eval_type_intrinsic0 (gfc_intrinsic_op operator, gfc_expr *op)
{
if (op == NULL)
- gfc_internal_error("eval_type_intrinsic0(): op NULL");
+ gfc_internal_error ("eval_type_intrinsic0(): op NULL");
- switch(operator)
+ switch (operator)
{
case INTRINSIC_GE:
case INTRINSIC_LT:
case INTRINSIC_EQ:
case INTRINSIC_NE:
op->ts.type = BT_LOGICAL;
- op->ts.kind = gfc_default_logical_kind();
+ op->ts.kind = gfc_default_logical_kind;
break;
default:
static int
gfc_zero_size_array (gfc_expr * e)
{
-
if (e->expr_type != EXPR_ARRAY)
return 0;
static gfc_expr *
reduce_binary0 (gfc_expr * op1, gfc_expr * op2)
{
-
if (gfc_zero_size_array (op1))
{
gfc_free_expr (op2);
if (op2 == NULL)
{
if (gfc_zero_size_array (op1))
- return eval_type_intrinsic0(operator, op1);
+ return eval_type_intrinsic0 (operator, op1);
}
else
{
result = reduce_binary0 (op1, op2);
if (result != NULL)
- return eval_type_intrinsic0(operator, result);
+ return eval_type_intrinsic0 (operator, result);
}
f.f2 = eval;
gfc_convert_real (const char *buffer, int kind, locus * where)
{
gfc_expr *e;
- const char *t;
e = gfc_constant_result (BT_REAL, kind, where);
- /* A leading plus is allowed in Fortran, but not by mpfr_set_str */
- if (buffer[0] == '+')
- t = buffer + 1;
- else
- t = buffer;
- mpfr_set_str (e->value.real, t, 10, GFC_RND_MODE);
+ mpfr_set_str (e->value.real, buffer, 10, GFC_RND_MODE);
return e;
}
static void
arith_error (arith rc, gfc_typespec * from, gfc_typespec * to, locus * where)
{
-
gfc_error ("%s converting %s to %s at %L", gfc_arith_error (rc),
gfc_typename (from), gfc_typename (to), where);
if ((rc = gfc_check_integer_range (result->value.integer, kind))
!= ARITH_OK)
{
- arith_error (rc, &src->ts, &result->ts, &src->where);
- gfc_free_expr (result);
- return NULL;
+ if (rc == ARITH_ASYMMETRIC)
+ {
+ gfc_warning ("%s at %L", gfc_arith_error (rc), &src->where);
+ }
+ else
+ {
+ arith_error (rc, &src->ts, &result->ts, &src->where);
+ gfc_free_expr (result);
+ return NULL;
+ }
}
return result;
{
if (gfc_option.warn_underflow)
gfc_warning ("%s at %L", gfc_arith_error (rc), &src->where);
- mpfr_set_ui(result->value.real, 0, GFC_RND_MODE);
+ mpfr_set_ui (result->value.real, 0, GFC_RND_MODE);
}
else if (rc != ARITH_OK)
{
{
if (gfc_option.warn_underflow)
gfc_warning ("%s at %L", gfc_arith_error (rc), &src->where);
- mpfr_set_ui(result->value.complex.r, 0, GFC_RND_MODE);
+ mpfr_set_ui (result->value.complex.r, 0, GFC_RND_MODE);
}
else if (rc != ARITH_OK)
{
result = gfc_constant_result (BT_INTEGER, kind, &src->where);
- gfc_mpfr_to_mpz(result->value.integer, src->value.complex.r);
+ gfc_mpfr_to_mpz (result->value.integer, src->value.complex.r);
if ((rc = gfc_check_integer_range (result->value.integer, kind))
!= ARITH_OK)
rc = gfc_check_real_range (result->value.real, kind);
- if (rc == ARITH_UNDERFLOW)
+ if (rc == ARITH_UNDERFLOW)
{
if (gfc_option.warn_underflow)
gfc_warning ("%s at %L", gfc_arith_error (rc), &src->where);
- mpfr_set_ui(result->value.real, 0, GFC_RND_MODE);
+ mpfr_set_ui (result->value.real, 0, GFC_RND_MODE);
}
if (rc != ARITH_OK)
{
{
if (gfc_option.warn_underflow)
gfc_warning ("%s at %L", gfc_arith_error (rc), &src->where);
- mpfr_set_ui(result->value.complex.r, 0, GFC_RND_MODE);
+ mpfr_set_ui (result->value.complex.r, 0, GFC_RND_MODE);
}
else if (rc != ARITH_OK)
{
gfc_free_expr (result);
return NULL;
}
-
+
rc = gfc_check_real_range (result->value.complex.i, kind);
if (rc == ARITH_UNDERFLOW)
{
if (gfc_option.warn_underflow)
gfc_warning ("%s at %L", gfc_arith_error (rc), &src->where);
- mpfr_set_ui(result->value.complex.i, 0, GFC_RND_MODE);
+ mpfr_set_ui (result->value.complex.i, 0, GFC_RND_MODE);
}
else if (rc != ARITH_OK)
{