aboutsummaryrefslogtreecommitdiff
path: root/gcc/fortran/simplify.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/fortran/simplify.cc')
-rw-r--r--gcc/fortran/simplify.cc208
1 files changed, 208 insertions, 0 deletions
diff --git a/gcc/fortran/simplify.cc b/gcc/fortran/simplify.cc
index e7a7e21..92ab17b 100644
--- a/gcc/fortran/simplify.cc
+++ b/gcc/fortran/simplify.cc
@@ -6784,6 +6784,214 @@ gfc_simplify_or (gfc_expr *x, gfc_expr *y)
gfc_expr *
+gfc_simplify_out_of_range (gfc_expr *x, gfc_expr *mold, gfc_expr *round)
+{
+ gfc_expr *result;
+ mpfr_t a;
+ mpz_t b;
+ int i, k;
+ bool res = false;
+ bool rnd = false;
+
+ i = gfc_validate_kind (x->ts.type, x->ts.kind, false);
+ k = gfc_validate_kind (mold->ts.type, mold->ts.kind, false);
+
+ mpfr_init (a);
+
+ switch (x->ts.type)
+ {
+ case BT_REAL:
+ if (mold->ts.type == BT_REAL)
+ {
+ if (mpfr_cmp (gfc_real_kinds[i].huge,
+ gfc_real_kinds[k].huge) <= 0)
+ {
+ /* Range of MOLD is always sufficient. */
+ res = false;
+ goto done;
+ }
+ else if (x->expr_type == EXPR_CONSTANT)
+ {
+ mpfr_neg (a, gfc_real_kinds[k].huge, GFC_RND_MODE);
+ res = (mpfr_cmp (x->value.real, a) < 0
+ || mpfr_cmp (x->value.real, gfc_real_kinds[k].huge) > 0);
+ goto done;
+ }
+ }
+ else if (mold->ts.type == BT_INTEGER)
+ {
+ if (x->expr_type == EXPR_CONSTANT)
+ {
+ res = mpfr_inf_p (x->value.real) || mpfr_nan_p (x->value.real);
+ if (res)
+ goto done;
+
+ if (round && round->expr_type != EXPR_CONSTANT)
+ break;
+
+ if (round && round->expr_type == EXPR_CONSTANT)
+ rnd = round->value.logical;
+
+ if (rnd)
+ mpfr_round (a, x->value.real);
+ else
+ mpfr_trunc (a, x->value.real);
+
+ mpz_init (b);
+ mpfr_get_z (b, a, GFC_RND_MODE);
+ res = (mpz_cmp (b, gfc_integer_kinds[k].min_int) < 0
+ || mpz_cmp (b, gfc_integer_kinds[k].huge) > 0);
+ mpz_clear (b);
+ goto done;
+ }
+ }
+ else if (mold->ts.type == BT_UNSIGNED)
+ {
+ if (x->expr_type == EXPR_CONSTANT)
+ {
+ res = mpfr_inf_p (x->value.real) || mpfr_nan_p (x->value.real);
+ if (res)
+ goto done;
+
+ if (round && round->expr_type != EXPR_CONSTANT)
+ break;
+
+ if (round && round->expr_type == EXPR_CONSTANT)
+ rnd = round->value.logical;
+
+ if (rnd)
+ mpfr_round (a, x->value.real);
+ else
+ mpfr_trunc (a, x->value.real);
+
+ mpz_init (b);
+ mpfr_get_z (b, a, GFC_RND_MODE);
+ res = (mpz_cmp (b, gfc_unsigned_kinds[k].huge) > 0
+ || mpz_cmp_si (b, 0) < 0);
+ mpz_clear (b);
+ goto done;
+ }
+ }
+ break;
+
+ case BT_INTEGER:
+ gcc_assert (round == NULL);
+ if (mold->ts.type == BT_INTEGER)
+ {
+ if (mpz_cmp (gfc_integer_kinds[i].huge,
+ gfc_integer_kinds[k].huge) <= 0)
+ {
+ /* Range of MOLD is always sufficient. */
+ res = false;
+ goto done;
+ }
+ else if (x->expr_type == EXPR_CONSTANT)
+ {
+ res = (mpz_cmp (x->value.integer,
+ gfc_integer_kinds[k].min_int) < 0
+ || mpz_cmp (x->value.integer,
+ gfc_integer_kinds[k].huge) > 0);
+ goto done;
+ }
+ }
+ else if (mold->ts.type == BT_UNSIGNED)
+ {
+ if (x->expr_type == EXPR_CONSTANT)
+ {
+ res = (mpz_cmp_si (x->value.integer, 0) < 0
+ || mpz_cmp (x->value.integer,
+ gfc_unsigned_kinds[k].huge) > 0);
+ goto done;
+ }
+ }
+ else if (mold->ts.type == BT_REAL)
+ {
+ mpfr_set_z (a, gfc_integer_kinds[i].min_int, GFC_RND_MODE);
+ mpfr_neg (a, a, GFC_RND_MODE);
+ res = mpfr_cmp (a, gfc_real_kinds[k].huge) > 0;
+ /* When false, range of MOLD is always sufficient. */
+ if (!res)
+ goto done;
+
+ if (x->expr_type == EXPR_CONSTANT)
+ {
+ mpfr_set_z (a, x->value.integer, GFC_RND_MODE);
+ mpfr_abs (a, a, GFC_RND_MODE);
+ res = mpfr_cmp (a, gfc_real_kinds[k].huge) > 0;
+ goto done;
+ }
+ }
+ break;
+
+ case BT_UNSIGNED:
+ gcc_assert (round == NULL);
+ if (mold->ts.type == BT_UNSIGNED)
+ {
+ if (mpz_cmp (gfc_unsigned_kinds[i].huge,
+ gfc_unsigned_kinds[k].huge) <= 0)
+ {
+ /* Range of MOLD is always sufficient. */
+ res = false;
+ goto done;
+ }
+ else if (x->expr_type == EXPR_CONSTANT)
+ {
+ res = mpz_cmp (x->value.integer,
+ gfc_unsigned_kinds[k].huge) > 0;
+ goto done;
+ }
+ }
+ else if (mold->ts.type == BT_INTEGER)
+ {
+ if (mpz_cmp (gfc_unsigned_kinds[i].huge,
+ gfc_integer_kinds[k].huge) <= 0)
+ {
+ /* Range of MOLD is always sufficient. */
+ res = false;
+ goto done;
+ }
+ else if (x->expr_type == EXPR_CONSTANT)
+ {
+ res = mpz_cmp (x->value.integer,
+ gfc_integer_kinds[k].huge) > 0;
+ goto done;
+ }
+ }
+ else if (mold->ts.type == BT_REAL)
+ {
+ mpfr_set_z (a, gfc_unsigned_kinds[i].huge, GFC_RND_MODE);
+ res = mpfr_cmp (a, gfc_real_kinds[k].huge) > 0;
+ /* When false, range of MOLD is always sufficient. */
+ if (!res)
+ goto done;
+
+ if (x->expr_type == EXPR_CONSTANT)
+ {
+ mpfr_set_z (a, x->value.integer, GFC_RND_MODE);
+ res = mpfr_cmp (a, gfc_real_kinds[k].huge) > 0;
+ goto done;
+ }
+ }
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ mpfr_clear (a);
+
+ return NULL;
+
+done:
+ result = gfc_get_logical_expr (gfc_default_logical_kind, &x->where, res);
+
+ mpfr_clear (a);
+
+ return result;
+}
+
+
+gfc_expr *
gfc_simplify_pack (gfc_expr *array, gfc_expr *mask, gfc_expr *vector)
{
gfc_expr *result;