Index: gcc/gcc/fortran/simplify.c |
diff --git a/gcc/gcc/fortran/simplify.c b/gcc/gcc/fortran/simplify.c |
index 8b84d65f8e877c5871b66a7fe9c765c929fe4705..8768cb64de2894b6e0900da3fa781447b5eeaf75 100644 |
--- a/gcc/gcc/fortran/simplify.c |
+++ b/gcc/gcc/fortran/simplify.c |
@@ -27,6 +27,10 @@ along with GCC; see the file COPYING3. If not see |
#include "intrinsic.h" |
#include "target-memory.h" |
+/* Savely advance an array constructor by 'n' elements. |
+ Mainly used by simplifiers of transformational intrinsics. */ |
+#define ADVANCE(ctor, n) do { int i; for (i = 0; i < n && ctor; ++i) ctor = ctor->next; } while (0) |
+ |
gfc_expr gfc_bad_expr; |
@@ -210,6 +214,397 @@ convert_mpz_to_signed (mpz_t x, int bitsize) |
} |
} |
+/* Test that the expression is an constant array. */ |
+ |
+static bool |
+is_constant_array_expr (gfc_expr *e) |
+{ |
+ gfc_constructor *c; |
+ |
+ if (e == NULL) |
+ return true; |
+ |
+ if (e->expr_type != EXPR_ARRAY || !gfc_is_constant_expr (e)) |
+ return false; |
+ |
+ for (c = e->value.constructor; c; c = c->next) |
+ if (c->expr->expr_type != EXPR_CONSTANT) |
+ return false; |
+ |
+ return true; |
+} |
+ |
+ |
+/* Initialize a transformational result expression with a given value. */ |
+ |
+static void |
+init_result_expr (gfc_expr *e, int init, gfc_expr *array) |
+{ |
+ if (e && e->expr_type == EXPR_ARRAY) |
+ { |
+ gfc_constructor *ctor = e->value.constructor; |
+ while (ctor) |
+ { |
+ init_result_expr (ctor->expr, init, array); |
+ ctor = ctor->next; |
+ } |
+ } |
+ else if (e && e->expr_type == EXPR_CONSTANT) |
+ { |
+ int i = gfc_validate_kind (e->ts.type, e->ts.kind, false); |
+ int length; |
+ gfc_char_t *string; |
+ |
+ switch (e->ts.type) |
+ { |
+ case BT_LOGICAL: |
+ e->value.logical = (init ? 1 : 0); |
+ break; |
+ |
+ case BT_INTEGER: |
+ if (init == INT_MIN) |
+ mpz_set (e->value.integer, gfc_integer_kinds[i].min_int); |
+ else if (init == INT_MAX) |
+ mpz_set (e->value.integer, gfc_integer_kinds[i].huge); |
+ else |
+ mpz_set_si (e->value.integer, init); |
+ break; |
+ |
+ case BT_REAL: |
+ if (init == INT_MIN) |
+ { |
+ mpfr_set (e->value.real, gfc_real_kinds[i].huge, GFC_RND_MODE); |
+ mpfr_neg (e->value.real, e->value.real, GFC_RND_MODE); |
+ } |
+ else if (init == INT_MAX) |
+ mpfr_set (e->value.real, gfc_real_kinds[i].huge, GFC_RND_MODE); |
+ else |
+ mpfr_set_si (e->value.real, init, GFC_RND_MODE); |
+ break; |
+ |
+ case BT_COMPLEX: |
+ mpc_set_si (e->value.complex, init, GFC_MPC_RND_MODE); |
+ break; |
+ |
+ case BT_CHARACTER: |
+ if (init == INT_MIN) |
+ { |
+ gfc_expr *len = gfc_simplify_len (array, NULL); |
+ gfc_extract_int (len, &length); |
+ string = gfc_get_wide_string (length + 1); |
+ gfc_wide_memset (string, 0, length); |
+ } |
+ else if (init == INT_MAX) |
+ { |
+ gfc_expr *len = gfc_simplify_len (array, NULL); |
+ gfc_extract_int (len, &length); |
+ string = gfc_get_wide_string (length + 1); |
+ gfc_wide_memset (string, 255, length); |
+ } |
+ else |
+ { |
+ length = 0; |
+ string = gfc_get_wide_string (1); |
+ } |
+ |
+ string[length] = '\0'; |
+ e->value.character.length = length; |
+ e->value.character.string = string; |
+ break; |
+ |
+ default: |
+ gcc_unreachable(); |
+ } |
+ } |
+ else |
+ gcc_unreachable(); |
+} |
+ |
+ |
+/* Helper function for gfc_simplify_dot_product() and gfc_simplify_matmul. */ |
+ |
+static gfc_expr * |
+compute_dot_product (gfc_constructor *ctor_a, int stride_a, |
+ gfc_constructor *ctor_b, int stride_b) |
+{ |
+ gfc_expr *result; |
+ gfc_expr *a = ctor_a->expr, *b = ctor_b->expr; |
+ |
+ gcc_assert (gfc_compare_types (&a->ts, &b->ts)); |
+ |
+ result = gfc_constant_result (a->ts.type, a->ts.kind, &a->where); |
+ init_result_expr (result, 0, NULL); |
+ |
+ while (ctor_a && ctor_b) |
+ { |
+ /* Copying of expressions is required as operands are free'd |
+ by the gfc_arith routines. */ |
+ switch (result->ts.type) |
+ { |
+ case BT_LOGICAL: |
+ result = gfc_or (result, |
+ gfc_and (gfc_copy_expr (ctor_a->expr), |
+ gfc_copy_expr (ctor_b->expr))); |
+ break; |
+ |
+ case BT_INTEGER: |
+ case BT_REAL: |
+ case BT_COMPLEX: |
+ result = gfc_add (result, |
+ gfc_multiply (gfc_copy_expr (ctor_a->expr), |
+ gfc_copy_expr (ctor_b->expr))); |
+ break; |
+ |
+ default: |
+ gcc_unreachable(); |
+ } |
+ |
+ ADVANCE (ctor_a, stride_a); |
+ ADVANCE (ctor_b, stride_b); |
+ } |
+ |
+ return result; |
+} |
+ |
+ |
+/* Build a result expression for transformational intrinsics, |
+ depending on DIM. */ |
+ |
+static gfc_expr * |
+transformational_result (gfc_expr *array, gfc_expr *dim, bt type, |
+ int kind, locus* where) |
+{ |
+ gfc_expr *result; |
+ int i, nelem; |
+ |
+ if (!dim || array->rank == 1) |
+ return gfc_constant_result (type, kind, where); |
+ |
+ result = gfc_start_constructor (type, kind, where); |
+ result->shape = gfc_copy_shape_excluding (array->shape, array->rank, dim); |
+ result->rank = array->rank - 1; |
+ |
+ /* gfc_array_size() would count the number of elements in the constructor, |
+ we have not built those yet. */ |
+ nelem = 1; |
+ for (i = 0; i < result->rank; ++i) |
+ nelem *= mpz_get_ui (result->shape[i]); |
+ |
+ for (i = 0; i < nelem; ++i) |
+ { |
+ gfc_expr *e = gfc_constant_result (type, kind, where); |
+ gfc_append_constructor (result, e); |
+ } |
+ |
+ return result; |
+} |
+ |
+ |
+typedef gfc_expr* (*transformational_op)(gfc_expr*, gfc_expr*); |
+ |
+/* Wrapper function, implements 'op1 += 1'. Only called if MASK |
+ of COUNT intrinsic is .TRUE.. |
+ |
+ Interface and implimentation mimics arith functions as |
+ gfc_add, gfc_multiply, etc. */ |
+ |
+static gfc_expr* gfc_count (gfc_expr *op1, gfc_expr *op2) |
+{ |
+ gfc_expr *result; |
+ |
+ gcc_assert (op1->ts.type == BT_INTEGER); |
+ gcc_assert (op2->ts.type == BT_LOGICAL); |
+ gcc_assert (op2->value.logical); |
+ |
+ result = gfc_copy_expr (op1); |
+ mpz_add_ui (result->value.integer, result->value.integer, 1); |
+ |
+ gfc_free_expr (op1); |
+ gfc_free_expr (op2); |
+ return result; |
+} |
+ |
+ |
+/* Transforms an ARRAY with operation OP, according to MASK, to a |
+ scalar RESULT. E.g. called if |
+ |
+ REAL, PARAMETER :: array(n, m) = ... |
+ REAL, PARAMETER :: s = SUM(array) |
+ |
+ where OP == gfc_add(). */ |
+ |
+static gfc_expr * |
+simplify_transformation_to_scalar (gfc_expr *result, gfc_expr *array, gfc_expr *mask, |
+ transformational_op op) |
+{ |
+ gfc_expr *a, *m; |
+ gfc_constructor *array_ctor, *mask_ctor; |
+ |
+ /* Shortcut for constant .FALSE. MASK. */ |
+ if (mask |
+ && mask->expr_type == EXPR_CONSTANT |
+ && !mask->value.logical) |
+ return result; |
+ |
+ array_ctor = array->value.constructor; |
+ mask_ctor = NULL; |
+ if (mask && mask->expr_type == EXPR_ARRAY) |
+ mask_ctor = mask->value.constructor; |
+ |
+ while (array_ctor) |
+ { |
+ a = array_ctor->expr; |
+ array_ctor = array_ctor->next; |
+ |
+ /* A constant MASK equals .TRUE. here and can be ignored. */ |
+ if (mask_ctor) |
+ { |
+ m = mask_ctor->expr; |
+ mask_ctor = mask_ctor->next; |
+ if (!m->value.logical) |
+ continue; |
+ } |
+ |
+ result = op (result, gfc_copy_expr (a)); |
+ } |
+ |
+ return result; |
+} |
+ |
+/* Transforms an ARRAY with operation OP, according to MASK, to an |
+ array RESULT. E.g. called if |
+ |
+ REAL, PARAMETER :: array(n, m) = ... |
+ REAL, PARAMETER :: s(n) = PROD(array, DIM=1) |
+ |
+ where OP == gfc_multiply(). */ |
+ |
+static gfc_expr * |
+simplify_transformation_to_array (gfc_expr *result, gfc_expr *array, gfc_expr *dim, |
+ gfc_expr *mask, transformational_op op) |
+{ |
+ mpz_t size; |
+ int done, i, n, arraysize, resultsize, dim_index, dim_extent, dim_stride; |
+ gfc_expr **arrayvec, **resultvec, **base, **src, **dest; |
+ gfc_constructor *array_ctor, *mask_ctor, *result_ctor; |
+ |
+ int count[GFC_MAX_DIMENSIONS], extent[GFC_MAX_DIMENSIONS], |
+ sstride[GFC_MAX_DIMENSIONS], dstride[GFC_MAX_DIMENSIONS], |
+ tmpstride[GFC_MAX_DIMENSIONS]; |
+ |
+ /* Shortcut for constant .FALSE. MASK. */ |
+ if (mask |
+ && mask->expr_type == EXPR_CONSTANT |
+ && !mask->value.logical) |
+ return result; |
+ |
+ /* Build an indexed table for array element expressions to minimize |
+ linked-list traversal. Masked elements are set to NULL. */ |
+ gfc_array_size (array, &size); |
+ arraysize = mpz_get_ui (size); |
+ |
+ arrayvec = (gfc_expr**) gfc_getmem (sizeof (gfc_expr*) * arraysize); |
+ |
+ array_ctor = array->value.constructor; |
+ mask_ctor = NULL; |
+ if (mask && mask->expr_type == EXPR_ARRAY) |
+ mask_ctor = mask->value.constructor; |
+ |
+ for (i = 0; i < arraysize; ++i) |
+ { |
+ arrayvec[i] = array_ctor->expr; |
+ array_ctor = array_ctor->next; |
+ |
+ if (mask_ctor) |
+ { |
+ if (!mask_ctor->expr->value.logical) |
+ arrayvec[i] = NULL; |
+ |
+ mask_ctor = mask_ctor->next; |
+ } |
+ } |
+ |
+ /* Same for the result expression. */ |
+ gfc_array_size (result, &size); |
+ resultsize = mpz_get_ui (size); |
+ mpz_clear (size); |
+ |
+ resultvec = (gfc_expr**) gfc_getmem (sizeof (gfc_expr*) * resultsize); |
+ result_ctor = result->value.constructor; |
+ for (i = 0; i < resultsize; ++i) |
+ { |
+ resultvec[i] = result_ctor->expr; |
+ result_ctor = result_ctor->next; |
+ } |
+ |
+ gfc_extract_int (dim, &dim_index); |
+ dim_index -= 1; /* zero-base index */ |
+ dim_extent = 0; |
+ dim_stride = 0; |
+ |
+ for (i = 0, n = 0; i < array->rank; ++i) |
+ { |
+ count[i] = 0; |
+ tmpstride[i] = (i == 0) ? 1 : tmpstride[i-1] * mpz_get_si (array->shape[i-1]); |
+ if (i == dim_index) |
+ { |
+ dim_extent = mpz_get_si (array->shape[i]); |
+ dim_stride = tmpstride[i]; |
+ continue; |
+ } |
+ |
+ extent[n] = mpz_get_si (array->shape[i]); |
+ sstride[n] = tmpstride[i]; |
+ dstride[n] = (n == 0) ? 1 : dstride[n-1] * extent[n-1]; |
+ n += 1; |
+ } |
+ |
+ done = false; |
+ base = arrayvec; |
+ dest = resultvec; |
+ while (!done) |
+ { |
+ for (src = base, n = 0; n < dim_extent; src += dim_stride, ++n) |
+ if (*src) |
+ *dest = op (*dest, gfc_copy_expr (*src)); |
+ |
+ count[0]++; |
+ base += sstride[0]; |
+ dest += dstride[0]; |
+ |
+ n = 0; |
+ while (!done && count[n] == extent[n]) |
+ { |
+ count[n] = 0; |
+ base -= sstride[n] * extent[n]; |
+ dest -= dstride[n] * extent[n]; |
+ |
+ n++; |
+ if (n < result->rank) |
+ { |
+ count [n]++; |
+ base += sstride[n]; |
+ dest += dstride[n]; |
+ } |
+ else |
+ done = true; |
+ } |
+ } |
+ |
+ /* Place updated expression in result constructor. */ |
+ result_ctor = result->value.constructor; |
+ for (i = 0; i < resultsize; ++i) |
+ { |
+ result_ctor->expr = resultvec[i]; |
+ result_ctor = result_ctor->next; |
+ } |
+ |
+ gfc_free (arrayvec); |
+ gfc_free (resultvec); |
+ return result; |
+} |
+ |
+ |
/********************** Simplification functions *****************************/ |
@@ -244,8 +639,7 @@ gfc_simplify_abs (gfc_expr *e) |
gfc_set_model_kind (e->ts.kind); |
- mpfr_hypot (result->value.real, e->value.complex.r, |
- e->value.complex.i, GFC_RND_MODE); |
+ mpc_abs (result->value.real, e->value.complex, GFC_RND_MODE); |
result = range_check (result, "CABS"); |
break; |
@@ -331,17 +725,27 @@ gfc_simplify_acos (gfc_expr *x) |
if (x->expr_type != EXPR_CONSTANT) |
return NULL; |
- if (mpfr_cmp_si (x->value.real, 1) > 0 |
- || mpfr_cmp_si (x->value.real, -1) < 0) |
+ switch (x->ts.type) |
{ |
- gfc_error ("Argument of ACOS at %L must be between -1 and 1", |
- &x->where); |
- return &gfc_bad_expr; |
+ case BT_REAL: |
+ if (mpfr_cmp_si (x->value.real, 1) > 0 |
+ || mpfr_cmp_si (x->value.real, -1) < 0) |
+ { |
+ gfc_error ("Argument of ACOS at %L must be between -1 and 1", |
+ &x->where); |
+ return &gfc_bad_expr; |
+ } |
+ result = gfc_constant_result (x->ts.type, x->ts.kind, &x->where); |
+ mpfr_acos (result->value.real, x->value.real, GFC_RND_MODE); |
+ break; |
+ case BT_COMPLEX: |
+ result = gfc_constant_result (x->ts.type, x->ts.kind, &x->where); |
+ mpc_acos (result->value.complex, x->value.complex, GFC_MPC_RND_MODE); |
+ break; |
+ default: |
+ gfc_internal_error ("in gfc_simplify_acos(): Bad type"); |
} |
- result = gfc_constant_result (x->ts.type, x->ts.kind, &x->where); |
- |
- mpfr_acos (result->value.real, x->value.real, GFC_RND_MODE); |
return range_check (result, "ACOS"); |
} |
@@ -354,16 +758,26 @@ gfc_simplify_acosh (gfc_expr *x) |
if (x->expr_type != EXPR_CONSTANT) |
return NULL; |
- if (mpfr_cmp_si (x->value.real, 1) < 0) |
+ switch (x->ts.type) |
{ |
- gfc_error ("Argument of ACOSH at %L must not be less than 1", |
- &x->where); |
- return &gfc_bad_expr; |
- } |
- |
- result = gfc_constant_result (x->ts.type, x->ts.kind, &x->where); |
+ case BT_REAL: |
+ if (mpfr_cmp_si (x->value.real, 1) < 0) |
+ { |
+ gfc_error ("Argument of ACOSH at %L must not be less than 1", |
+ &x->where); |
+ return &gfc_bad_expr; |
+ } |
- mpfr_acosh (result->value.real, x->value.real, GFC_RND_MODE); |
+ result = gfc_constant_result (x->ts.type, x->ts.kind, &x->where); |
+ mpfr_acosh (result->value.real, x->value.real, GFC_RND_MODE); |
+ break; |
+ case BT_COMPLEX: |
+ result = gfc_constant_result (x->ts.type, x->ts.kind, &x->where); |
+ mpc_acosh (result->value.complex, x->value.complex, GFC_MPC_RND_MODE); |
+ break; |
+ default: |
+ gfc_internal_error ("in gfc_simplify_acosh(): Bad type"); |
+ } |
return range_check (result, "ACOSH"); |
} |
@@ -451,7 +865,7 @@ gfc_simplify_aimag (gfc_expr *e) |
return NULL; |
result = gfc_constant_result (BT_REAL, e->ts.kind, &e->where); |
- mpfr_set (result->value.real, e->value.complex.i, GFC_RND_MODE); |
+ mpfr_set (result->value.real, mpc_imagref (e->value.complex), GFC_RND_MODE); |
return range_check (result, "AIMAG"); |
} |
@@ -482,6 +896,25 @@ gfc_simplify_aint (gfc_expr *e, gfc_expr *k) |
gfc_expr * |
+gfc_simplify_all (gfc_expr *mask, gfc_expr *dim) |
+{ |
+ gfc_expr *result; |
+ |
+ if (!is_constant_array_expr (mask) |
+ || !gfc_is_constant_expr (dim)) |
+ return NULL; |
+ |
+ result = transformational_result (mask, dim, mask->ts.type, |
+ mask->ts.kind, &mask->where); |
+ init_result_expr (result, true, NULL); |
+ |
+ return !dim || mask->rank == 1 ? |
+ simplify_transformation_to_scalar (result, mask, NULL, gfc_and) : |
+ simplify_transformation_to_array (result, mask, dim, NULL, gfc_and); |
+} |
+ |
+ |
+gfc_expr * |
gfc_simplify_dint (gfc_expr *e) |
{ |
gfc_expr *rtrunc, *result; |
@@ -547,6 +980,25 @@ gfc_simplify_and (gfc_expr *x, gfc_expr *y) |
gfc_expr * |
+gfc_simplify_any (gfc_expr *mask, gfc_expr *dim) |
+{ |
+ gfc_expr *result; |
+ |
+ if (!is_constant_array_expr (mask) |
+ || !gfc_is_constant_expr (dim)) |
+ return NULL; |
+ |
+ result = transformational_result (mask, dim, mask->ts.type, |
+ mask->ts.kind, &mask->where); |
+ init_result_expr (result, false, NULL); |
+ |
+ return !dim || mask->rank == 1 ? |
+ simplify_transformation_to_scalar (result, mask, NULL, gfc_or) : |
+ simplify_transformation_to_array (result, mask, dim, NULL, gfc_or); |
+} |
+ |
+ |
+gfc_expr * |
gfc_simplify_dnint (gfc_expr *e) |
{ |
gfc_expr *result; |
@@ -570,18 +1022,27 @@ gfc_simplify_asin (gfc_expr *x) |
if (x->expr_type != EXPR_CONSTANT) |
return NULL; |
- if (mpfr_cmp_si (x->value.real, 1) > 0 |
- || mpfr_cmp_si (x->value.real, -1) < 0) |
+ switch (x->ts.type) |
{ |
- gfc_error ("Argument of ASIN at %L must be between -1 and 1", |
- &x->where); |
- return &gfc_bad_expr; |
+ case BT_REAL: |
+ if (mpfr_cmp_si (x->value.real, 1) > 0 |
+ || mpfr_cmp_si (x->value.real, -1) < 0) |
+ { |
+ gfc_error ("Argument of ASIN at %L must be between -1 and 1", |
+ &x->where); |
+ return &gfc_bad_expr; |
+ } |
+ result = gfc_constant_result (x->ts.type, x->ts.kind, &x->where); |
+ mpfr_asin (result->value.real, x->value.real, GFC_RND_MODE); |
+ break; |
+ case BT_COMPLEX: |
+ result = gfc_constant_result (x->ts.type, x->ts.kind, &x->where); |
+ mpc_asin (result->value.complex, x->value.complex, GFC_MPC_RND_MODE); |
+ break; |
+ default: |
+ gfc_internal_error ("in gfc_simplify_asin(): Bad type"); |
} |
- result = gfc_constant_result (x->ts.type, x->ts.kind, &x->where); |
- |
- mpfr_asin (result->value.real, x->value.real, GFC_RND_MODE); |
- |
return range_check (result, "ASIN"); |
} |
@@ -594,9 +1055,19 @@ gfc_simplify_asinh (gfc_expr *x) |
if (x->expr_type != EXPR_CONSTANT) |
return NULL; |
- result = gfc_constant_result (x->ts.type, x->ts.kind, &x->where); |
- |
- mpfr_asinh (result->value.real, x->value.real, GFC_RND_MODE); |
+ switch (x->ts.type) |
+ { |
+ case BT_REAL: |
+ result = gfc_constant_result (x->ts.type, x->ts.kind, &x->where); |
+ mpfr_asinh (result->value.real, x->value.real, GFC_RND_MODE); |
+ break; |
+ case BT_COMPLEX: |
+ result = gfc_constant_result (x->ts.type, x->ts.kind, &x->where); |
+ mpc_asinh (result->value.complex, x->value.complex, GFC_MPC_RND_MODE); |
+ break; |
+ default: |
+ gfc_internal_error ("in gfc_simplify_asinh(): Bad type"); |
+ } |
return range_check (result, "ASINH"); |
} |
@@ -610,9 +1081,19 @@ gfc_simplify_atan (gfc_expr *x) |
if (x->expr_type != EXPR_CONSTANT) |
return NULL; |
- result = gfc_constant_result (x->ts.type, x->ts.kind, &x->where); |
- |
- mpfr_atan (result->value.real, x->value.real, GFC_RND_MODE); |
+ switch (x->ts.type) |
+ { |
+ case BT_REAL: |
+ result = gfc_constant_result (x->ts.type, x->ts.kind, &x->where); |
+ mpfr_atan (result->value.real, x->value.real, GFC_RND_MODE); |
+ break; |
+ case BT_COMPLEX: |
+ result = gfc_constant_result (x->ts.type, x->ts.kind, &x->where); |
+ mpc_atan (result->value.complex, x->value.complex, GFC_MPC_RND_MODE); |
+ break; |
+ default: |
+ gfc_internal_error ("in gfc_simplify_atan(): Bad type"); |
+ } |
return range_check (result, "ATAN"); |
} |
@@ -626,17 +1107,27 @@ gfc_simplify_atanh (gfc_expr *x) |
if (x->expr_type != EXPR_CONSTANT) |
return NULL; |
- if (mpfr_cmp_si (x->value.real, 1) >= 0 |
- || mpfr_cmp_si (x->value.real, -1) <= 0) |
+ switch (x->ts.type) |
{ |
- gfc_error ("Argument of ATANH at %L must be inside the range -1 to 1", |
- &x->where); |
- return &gfc_bad_expr; |
- } |
- |
- result = gfc_constant_result (x->ts.type, x->ts.kind, &x->where); |
+ case BT_REAL: |
+ if (mpfr_cmp_si (x->value.real, 1) >= 0 |
+ || mpfr_cmp_si (x->value.real, -1) <= 0) |
+ { |
+ gfc_error ("Argument of ATANH at %L must be inside the range -1 " |
+ "to 1", &x->where); |
+ return &gfc_bad_expr; |
+ } |
- mpfr_atanh (result->value.real, x->value.real, GFC_RND_MODE); |
+ result = gfc_constant_result (x->ts.type, x->ts.kind, &x->where); |
+ mpfr_atanh (result->value.real, x->value.real, GFC_RND_MODE); |
+ break; |
+ case BT_COMPLEX: |
+ result = gfc_constant_result (x->ts.type, x->ts.kind, &x->where); |
+ mpc_atanh (result->value.complex, x->value.complex, GFC_MPC_RND_MODE); |
+ break; |
+ default: |
+ gfc_internal_error ("in gfc_simplify_atanh(): Bad type"); |
+ } |
return range_check (result, "ATANH"); |
} |
@@ -832,22 +1323,19 @@ simplify_cmplx (const char *name, gfc_expr *x, gfc_expr *y, int kind) |
result = gfc_constant_result (BT_COMPLEX, kind, &x->where); |
- mpfr_set_ui (result->value.complex.i, 0, GFC_RND_MODE); |
- |
switch (x->ts.type) |
{ |
case BT_INTEGER: |
if (!x->is_boz) |
- mpfr_set_z (result->value.complex.r, x->value.integer, GFC_RND_MODE); |
+ mpc_set_z (result->value.complex, x->value.integer, GFC_MPC_RND_MODE); |
break; |
case BT_REAL: |
- mpfr_set (result->value.complex.r, x->value.real, GFC_RND_MODE); |
+ mpc_set_fr (result->value.complex, x->value.real, GFC_RND_MODE); |
break; |
case BT_COMPLEX: |
- mpfr_set (result->value.complex.r, x->value.complex.r, GFC_RND_MODE); |
- mpfr_set (result->value.complex.i, x->value.complex.i, GFC_RND_MODE); |
+ mpc_set (result->value.complex, x->value.complex, GFC_MPC_RND_MODE); |
break; |
default: |
@@ -860,12 +1348,13 @@ simplify_cmplx (const char *name, gfc_expr *x, gfc_expr *y, int kind) |
{ |
case BT_INTEGER: |
if (!y->is_boz) |
- mpfr_set_z (result->value.complex.i, y->value.integer, |
- GFC_RND_MODE); |
+ mpfr_set_z (mpc_imagref (result->value.complex), |
+ y->value.integer, GFC_RND_MODE); |
break; |
case BT_REAL: |
- mpfr_set (result->value.complex.i, y->value.real, GFC_RND_MODE); |
+ mpfr_set (mpc_imagref (result->value.complex), |
+ y->value.real, GFC_RND_MODE); |
break; |
default: |
@@ -882,7 +1371,8 @@ simplify_cmplx (const char *name, gfc_expr *x, gfc_expr *y, int kind) |
ts.type = BT_REAL; |
if (!gfc_convert_boz (x, &ts)) |
return &gfc_bad_expr; |
- mpfr_set (result->value.complex.r, x->value.real, GFC_RND_MODE); |
+ mpfr_set (mpc_realref (result->value.complex), |
+ x->value.real, GFC_RND_MODE); |
} |
if (y && y->is_boz) |
@@ -893,7 +1383,8 @@ simplify_cmplx (const char *name, gfc_expr *x, gfc_expr *y, int kind) |
ts.type = BT_REAL; |
if (!gfc_convert_boz (y, &ts)) |
return &gfc_bad_expr; |
- mpfr_set (result->value.complex.i, y->value.real, GFC_RND_MODE); |
+ mpfr_set (mpc_imagref (result->value.complex), |
+ y->value.real, GFC_RND_MODE); |
} |
return range_check (result, name); |
@@ -975,8 +1466,7 @@ gfc_simplify_conjg (gfc_expr *e) |
return NULL; |
result = gfc_copy_expr (e); |
- mpfr_neg (result->value.complex.i, result->value.complex.i, GFC_RND_MODE); |
- |
+ mpc_conj (result->value.complex, result->value.complex, GFC_MPC_RND_MODE); |
return range_check (result, "CONJG"); |
} |
@@ -985,7 +1475,6 @@ gfc_expr * |
gfc_simplify_cos (gfc_expr *x) |
{ |
gfc_expr *result; |
- mpfr_t xp, xq; |
if (x->expr_type != EXPR_CONSTANT) |
return NULL; |
@@ -999,19 +1488,7 @@ gfc_simplify_cos (gfc_expr *x) |
break; |
case BT_COMPLEX: |
gfc_set_model_kind (x->ts.kind); |
- mpfr_init (xp); |
- mpfr_init (xq); |
- |
- mpfr_cos (xp, x->value.complex.r, GFC_RND_MODE); |
- mpfr_cosh (xq, x->value.complex.i, GFC_RND_MODE); |
- mpfr_mul (result->value.complex.r, xp, xq, GFC_RND_MODE); |
- |
- mpfr_sin (xp, x->value.complex.r, GFC_RND_MODE); |
- mpfr_sinh (xq, x->value.complex.i, GFC_RND_MODE); |
- mpfr_mul (xp, xp, xq, GFC_RND_MODE); |
- mpfr_neg (result->value.complex.i, xp, GFC_RND_MODE ); |
- |
- mpfr_clears (xp, xq, NULL); |
+ mpc_cos (result->value.complex, x->value.complex, GFC_MPC_RND_MODE); |
break; |
default: |
gfc_internal_error ("in gfc_simplify_cos(): Bad type"); |
@@ -1032,13 +1509,44 @@ gfc_simplify_cosh (gfc_expr *x) |
result = gfc_constant_result (x->ts.type, x->ts.kind, &x->where); |
- mpfr_cosh (result->value.real, x->value.real, GFC_RND_MODE); |
+ if (x->ts.type == BT_REAL) |
+ mpfr_cosh (result->value.real, x->value.real, GFC_RND_MODE); |
+ else if (x->ts.type == BT_COMPLEX) |
+ mpc_cosh (result->value.complex, x->value.complex, GFC_MPC_RND_MODE); |
+ else |
+ gcc_unreachable (); |
return range_check (result, "COSH"); |
} |
gfc_expr * |
+gfc_simplify_count (gfc_expr *mask, gfc_expr *dim, gfc_expr *kind) |
+{ |
+ gfc_expr *result; |
+ |
+ if (!is_constant_array_expr (mask) |
+ || !gfc_is_constant_expr (dim) |
+ || !gfc_is_constant_expr (kind)) |
+ return NULL; |
+ |
+ result = transformational_result (mask, dim, |
+ BT_INTEGER, |
+ get_kind (BT_INTEGER, kind, "COUNT", |
+ gfc_default_integer_kind), |
+ &mask->where); |
+ |
+ init_result_expr (result, 0, NULL); |
+ |
+ /* Passing MASK twice, once as data array, once as mask. |
+ Whenever gfc_count is called, '1' is added to the result. */ |
+ return !dim || mask->rank == 1 ? |
+ simplify_transformation_to_scalar (result, mask, mask, gfc_count) : |
+ simplify_transformation_to_array (result, mask, dim, mask, gfc_count); |
+} |
+ |
+ |
+gfc_expr * |
gfc_simplify_dcmplx (gfc_expr *x, gfc_expr *y) |
{ |
@@ -1159,6 +1667,32 @@ gfc_simplify_dim (gfc_expr *x, gfc_expr *y) |
} |
+gfc_expr* |
+gfc_simplify_dot_product (gfc_expr *vector_a, gfc_expr *vector_b) |
+{ |
+ gfc_expr *result; |
+ |
+ if (!is_constant_array_expr (vector_a) |
+ || !is_constant_array_expr (vector_b)) |
+ return NULL; |
+ |
+ gcc_assert (vector_a->rank == 1); |
+ gcc_assert (vector_b->rank == 1); |
+ gcc_assert (gfc_compare_types (&vector_a->ts, &vector_b->ts)); |
+ |
+ if (vector_a->value.constructor && vector_b->value.constructor) |
+ return compute_dot_product (vector_a->value.constructor, 1, |
+ vector_b->value.constructor, 1); |
+ |
+ /* Zero sized array ... */ |
+ result = gfc_constant_result (vector_a->ts.type, |
+ vector_a->ts.kind, |
+ &vector_a->where); |
+ init_result_expr (result, 0, NULL); |
+ return result; |
+} |
+ |
+ |
gfc_expr * |
gfc_simplify_dprod (gfc_expr *x, gfc_expr *y) |
{ |
@@ -1213,6 +1747,143 @@ gfc_simplify_erfc (gfc_expr *x) |
} |
+/* Helper functions to simplify ERFC_SCALED(x) = ERFC(x) * EXP(X**2). */ |
+ |
+#define MAX_ITER 200 |
+#define ARG_LIMIT 12 |
+ |
+/* Calculate ERFC_SCALED directly by its definition: |
+ |
+ ERFC_SCALED(x) = ERFC(x) * EXP(X**2) |
+ |
+ using a large precision for intermediate results. This is used for all |
+ but large values of the argument. */ |
+static void |
+fullprec_erfc_scaled (mpfr_t res, mpfr_t arg) |
+{ |
+ mp_prec_t prec; |
+ mpfr_t a, b; |
+ |
+ prec = mpfr_get_default_prec (); |
+ mpfr_set_default_prec (10 * prec); |
+ |
+ mpfr_init (a); |
+ mpfr_init (b); |
+ |
+ mpfr_set (a, arg, GFC_RND_MODE); |
+ mpfr_sqr (b, a, GFC_RND_MODE); |
+ mpfr_exp (b, b, GFC_RND_MODE); |
+ mpfr_erfc (a, a, GFC_RND_MODE); |
+ mpfr_mul (a, a, b, GFC_RND_MODE); |
+ |
+ mpfr_set (res, a, GFC_RND_MODE); |
+ mpfr_set_default_prec (prec); |
+ |
+ mpfr_clear (a); |
+ mpfr_clear (b); |
+} |
+ |
+/* Calculate ERFC_SCALED using a power series expansion in 1/arg: |
+ |
+ ERFC_SCALED(x) = 1 / (x * sqrt(pi)) |
+ * (1 + Sum_n (-1)**n * (1 * 3 * 5 * ... * (2n-1)) |
+ / (2 * x**2)**n) |
+ |
+ This is used for large values of the argument. Intermediate calculations |
+ are performed with twice the precision. We don't do a fixed number of |
+ iterations of the sum, but stop when it has converged to the required |
+ precision. */ |
+static void |
+asympt_erfc_scaled (mpfr_t res, mpfr_t arg) |
+{ |
+ mpfr_t sum, x, u, v, w, oldsum, sumtrunc; |
+ mpz_t num; |
+ mp_prec_t prec; |
+ unsigned i; |
+ |
+ prec = mpfr_get_default_prec (); |
+ mpfr_set_default_prec (2 * prec); |
+ |
+ mpfr_init (sum); |
+ mpfr_init (x); |
+ mpfr_init (u); |
+ mpfr_init (v); |
+ mpfr_init (w); |
+ mpz_init (num); |
+ |
+ mpfr_init (oldsum); |
+ mpfr_init (sumtrunc); |
+ mpfr_set_prec (oldsum, prec); |
+ mpfr_set_prec (sumtrunc, prec); |
+ |
+ mpfr_set (x, arg, GFC_RND_MODE); |
+ mpfr_set_ui (sum, 1, GFC_RND_MODE); |
+ mpz_set_ui (num, 1); |
+ |
+ mpfr_set (u, x, GFC_RND_MODE); |
+ mpfr_sqr (u, u, GFC_RND_MODE); |
+ mpfr_mul_ui (u, u, 2, GFC_RND_MODE); |
+ mpfr_pow_si (u, u, -1, GFC_RND_MODE); |
+ |
+ for (i = 1; i < MAX_ITER; i++) |
+ { |
+ mpfr_set (oldsum, sum, GFC_RND_MODE); |
+ |
+ mpz_mul_ui (num, num, 2 * i - 1); |
+ mpz_neg (num, num); |
+ |
+ mpfr_set (w, u, GFC_RND_MODE); |
+ mpfr_pow_ui (w, w, i, GFC_RND_MODE); |
+ |
+ mpfr_set_z (v, num, GFC_RND_MODE); |
+ mpfr_mul (v, v, w, GFC_RND_MODE); |
+ |
+ mpfr_add (sum, sum, v, GFC_RND_MODE); |
+ |
+ mpfr_set (sumtrunc, sum, GFC_RND_MODE); |
+ if (mpfr_cmp (sumtrunc, oldsum) == 0) |
+ break; |
+ } |
+ |
+ /* We should have converged by now; otherwise, ARG_LIMIT is probably |
+ set too low. */ |
+ gcc_assert (i < MAX_ITER); |
+ |
+ /* Divide by x * sqrt(Pi). */ |
+ mpfr_const_pi (u, GFC_RND_MODE); |
+ mpfr_sqrt (u, u, GFC_RND_MODE); |
+ mpfr_mul (u, u, x, GFC_RND_MODE); |
+ mpfr_div (sum, sum, u, GFC_RND_MODE); |
+ |
+ mpfr_set (res, sum, GFC_RND_MODE); |
+ mpfr_set_default_prec (prec); |
+ |
+ mpfr_clears (sum, x, u, v, w, oldsum, sumtrunc, NULL); |
+ mpz_clear (num); |
+} |
+ |
+ |
+gfc_expr * |
+gfc_simplify_erfc_scaled (gfc_expr *x) |
+{ |
+ gfc_expr *result; |
+ |
+ if (x->expr_type != EXPR_CONSTANT) |
+ return NULL; |
+ |
+ result = gfc_constant_result (x->ts.type, x->ts.kind, &x->where); |
+ if (mpfr_cmp_d (x->value.real, ARG_LIMIT) >= 0) |
+ asympt_erfc_scaled (result->value.real, x->value.real); |
+ else |
+ fullprec_erfc_scaled (result->value.real, x->value.real); |
+ |
+ return range_check (result, "ERFC_SCALED"); |
+} |
+ |
+#undef MAX_ITER |
+#undef ARG_LIMIT |
+ |
+ |
gfc_expr * |
gfc_simplify_epsilon (gfc_expr *e) |
{ |
@@ -1233,7 +1904,6 @@ gfc_expr * |
gfc_simplify_exp (gfc_expr *x) |
{ |
gfc_expr *result; |
- mpfr_t xp, xq; |
if (x->expr_type != EXPR_CONSTANT) |
return NULL; |
@@ -1248,14 +1918,7 @@ gfc_simplify_exp (gfc_expr *x) |
case BT_COMPLEX: |
gfc_set_model_kind (x->ts.kind); |
- mpfr_init (xp); |
- mpfr_init (xq); |
- mpfr_exp (xq, x->value.complex.r, GFC_RND_MODE); |
- mpfr_cos (xp, x->value.complex.i, GFC_RND_MODE); |
- mpfr_mul (result->value.complex.r, xq, xp, GFC_RND_MODE); |
- mpfr_sin (xp, x->value.complex.i, GFC_RND_MODE); |
- mpfr_mul (result->value.complex.i, xq, xp, GFC_RND_MODE); |
- mpfr_clears (xp, xq, NULL); |
+ mpc_exp (result->value.complex, x->value.complex, GFC_MPC_RND_MODE); |
break; |
default: |
@@ -1969,6 +2632,54 @@ gfc_simplify_ior (gfc_expr *x, gfc_expr *y) |
gfc_expr * |
+gfc_simplify_is_iostat_end (gfc_expr *x) |
+{ |
+ gfc_expr *result; |
+ |
+ if (x->expr_type != EXPR_CONSTANT) |
+ return NULL; |
+ |
+ result = gfc_constant_result (BT_LOGICAL, gfc_default_logical_kind, |
+ &x->where); |
+ result->value.logical = (mpz_cmp_si (x->value.integer, LIBERROR_END) == 0); |
+ |
+ return result; |
+} |
+ |
+ |
+gfc_expr * |
+gfc_simplify_is_iostat_eor (gfc_expr *x) |
+{ |
+ gfc_expr *result; |
+ |
+ if (x->expr_type != EXPR_CONSTANT) |
+ return NULL; |
+ |
+ result = gfc_constant_result (BT_LOGICAL, gfc_default_logical_kind, |
+ &x->where); |
+ result->value.logical = (mpz_cmp_si (x->value.integer, LIBERROR_EOR) == 0); |
+ |
+ return result; |
+} |
+ |
+ |
+gfc_expr * |
+gfc_simplify_isnan (gfc_expr *x) |
+{ |
+ gfc_expr *result; |
+ |
+ if (x->expr_type != EXPR_CONSTANT) |
+ return NULL; |
+ |
+ result = gfc_constant_result (BT_LOGICAL, gfc_default_logical_kind, |
+ &x->where); |
+ result->value.logical = mpfr_nan_p (x->value.real); |
+ |
+ return result; |
+} |
+ |
+ |
+gfc_expr * |
gfc_simplify_ishft (gfc_expr *e, gfc_expr *s) |
{ |
gfc_expr *result; |
@@ -2436,16 +3147,28 @@ gfc_simplify_len (gfc_expr *e, gfc_expr *kind) |
{ |
result = gfc_constant_result (BT_INTEGER, k, &e->where); |
mpz_set_si (result->value.integer, e->value.character.length); |
- return range_check (result, "LEN"); |
+ if (gfc_range_check (result) == ARITH_OK) |
+ return result; |
+ else |
+ { |
+ gfc_free_expr (result); |
+ return NULL; |
+ } |
} |
- if (e->ts.cl != NULL && e->ts.cl->length != NULL |
- && e->ts.cl->length->expr_type == EXPR_CONSTANT |
- && e->ts.cl->length->ts.type == BT_INTEGER) |
+ if (e->ts.u.cl != NULL && e->ts.u.cl->length != NULL |
+ && e->ts.u.cl->length->expr_type == EXPR_CONSTANT |
+ && e->ts.u.cl->length->ts.type == BT_INTEGER) |
{ |
result = gfc_constant_result (BT_INTEGER, k, &e->where); |
- mpz_set (result->value.integer, e->ts.cl->length->value.integer); |
- return range_check (result, "LEN"); |
+ mpz_set (result->value.integer, e->ts.u.cl->length->value.integer); |
+ if (gfc_range_check (result) == ARITH_OK) |
+ return result; |
+ else |
+ { |
+ gfc_free_expr (result); |
+ return NULL; |
+ } |
} |
return NULL; |
@@ -2542,7 +3265,6 @@ gfc_expr * |
gfc_simplify_log (gfc_expr *x) |
{ |
gfc_expr *result; |
- mpfr_t xr, xi; |
if (x->expr_type != EXPR_CONSTANT) |
return NULL; |
@@ -2565,8 +3287,8 @@ gfc_simplify_log (gfc_expr *x) |
break; |
case BT_COMPLEX: |
- if ((mpfr_sgn (x->value.complex.r) == 0) |
- && (mpfr_sgn (x->value.complex.i) == 0)) |
+ if ((mpfr_sgn (mpc_realref (x->value.complex)) == 0) |
+ && (mpfr_sgn (mpc_imagref (x->value.complex)) == 0)) |
{ |
gfc_error ("Complex argument of LOG at %L cannot be zero", |
&x->where); |
@@ -2575,20 +3297,7 @@ gfc_simplify_log (gfc_expr *x) |
} |
gfc_set_model_kind (x->ts.kind); |
- mpfr_init (xr); |
- mpfr_init (xi); |
- |
- mpfr_atan2 (result->value.complex.i, x->value.complex.i, |
- x->value.complex.r, GFC_RND_MODE); |
- |
- mpfr_mul (xr, x->value.complex.r, x->value.complex.r, GFC_RND_MODE); |
- mpfr_mul (xi, x->value.complex.i, x->value.complex.i, GFC_RND_MODE); |
- mpfr_add (xr, xr, xi, GFC_RND_MODE); |
- mpfr_sqrt (xr, xr, GFC_RND_MODE); |
- mpfr_log (result->value.complex.r, xr, GFC_RND_MODE); |
- |
- mpfr_clears (xr, xi, NULL); |
- |
+ mpc_log (result->value.complex, x->value.complex, GFC_MPC_RND_MODE); |
break; |
default: |
@@ -2643,6 +3352,84 @@ gfc_simplify_logical (gfc_expr *e, gfc_expr *k) |
} |
+gfc_expr* |
+gfc_simplify_matmul (gfc_expr *matrix_a, gfc_expr *matrix_b) |
+{ |
+ gfc_expr *result; |
+ gfc_constructor *ma_ctor, *mb_ctor; |
+ int row, result_rows, col, result_columns, stride_a, stride_b; |
+ |
+ if (!is_constant_array_expr (matrix_a) |
+ || !is_constant_array_expr (matrix_b)) |
+ return NULL; |
+ |
+ gcc_assert (gfc_compare_types (&matrix_a->ts, &matrix_b->ts)); |
+ result = gfc_start_constructor (matrix_a->ts.type, |
+ matrix_a->ts.kind, |
+ &matrix_a->where); |
+ |
+ if (matrix_a->rank == 1 && matrix_b->rank == 2) |
+ { |
+ result_rows = 1; |
+ result_columns = mpz_get_si (matrix_b->shape[0]); |
+ stride_a = 1; |
+ stride_b = mpz_get_si (matrix_b->shape[0]); |
+ |
+ result->rank = 1; |
+ result->shape = gfc_get_shape (result->rank); |
+ mpz_init_set_si (result->shape[0], result_columns); |
+ } |
+ else if (matrix_a->rank == 2 && matrix_b->rank == 1) |
+ { |
+ result_rows = mpz_get_si (matrix_b->shape[0]); |
+ result_columns = 1; |
+ stride_a = mpz_get_si (matrix_a->shape[0]); |
+ stride_b = 1; |
+ |
+ result->rank = 1; |
+ result->shape = gfc_get_shape (result->rank); |
+ mpz_init_set_si (result->shape[0], result_rows); |
+ } |
+ else if (matrix_a->rank == 2 && matrix_b->rank == 2) |
+ { |
+ result_rows = mpz_get_si (matrix_a->shape[0]); |
+ result_columns = mpz_get_si (matrix_b->shape[1]); |
+ stride_a = mpz_get_si (matrix_a->shape[1]); |
+ stride_b = mpz_get_si (matrix_b->shape[0]); |
+ |
+ result->rank = 2; |
+ result->shape = gfc_get_shape (result->rank); |
+ mpz_init_set_si (result->shape[0], result_rows); |
+ mpz_init_set_si (result->shape[1], result_columns); |
+ } |
+ else |
+ gcc_unreachable(); |
+ |
+ ma_ctor = matrix_a->value.constructor; |
+ mb_ctor = matrix_b->value.constructor; |
+ |
+ for (col = 0; col < result_columns; ++col) |
+ { |
+ ma_ctor = matrix_a->value.constructor; |
+ |
+ for (row = 0; row < result_rows; ++row) |
+ { |
+ gfc_expr *e; |
+ e = compute_dot_product (ma_ctor, stride_a, |
+ mb_ctor, 1); |
+ |
+ gfc_append_constructor (result, e); |
+ |
+ ADVANCE (ma_ctor, 1); |
+ } |
+ |
+ ADVANCE (mb_ctor, stride_b); |
+ } |
+ |
+ return result; |
+} |
+ |
+ |
gfc_expr * |
gfc_simplify_merge (gfc_expr *tsource, gfc_expr *fsource, gfc_expr *mask) |
{ |
@@ -3173,6 +3960,75 @@ gfc_simplify_or (gfc_expr *x, gfc_expr *y) |
gfc_expr * |
+gfc_simplify_pack (gfc_expr *array, gfc_expr *mask, gfc_expr *vector) |
+{ |
+ gfc_expr *result; |
+ gfc_constructor *array_ctor, *mask_ctor, *vector_ctor; |
+ |
+ if (!is_constant_array_expr(array) |
+ || !is_constant_array_expr(vector) |
+ || (!gfc_is_constant_expr (mask) |
+ && !is_constant_array_expr(mask))) |
+ return NULL; |
+ |
+ result = gfc_start_constructor (array->ts.type, |
+ array->ts.kind, |
+ &array->where); |
+ |
+ array_ctor = array->value.constructor; |
+ vector_ctor = vector ? vector->value.constructor : NULL; |
+ |
+ if (mask->expr_type == EXPR_CONSTANT |
+ && mask->value.logical) |
+ { |
+ /* Copy all elements of ARRAY to RESULT. */ |
+ while (array_ctor) |
+ { |
+ gfc_append_constructor (result, |
+ gfc_copy_expr (array_ctor->expr)); |
+ |
+ ADVANCE (array_ctor, 1); |
+ ADVANCE (vector_ctor, 1); |
+ } |
+ } |
+ else if (mask->expr_type == EXPR_ARRAY) |
+ { |
+ /* Copy only those elements of ARRAY to RESULT whose |
+ MASK equals .TRUE.. */ |
+ mask_ctor = mask->value.constructor; |
+ while (mask_ctor) |
+ { |
+ if (mask_ctor->expr->value.logical) |
+ { |
+ gfc_append_constructor (result, |
+ gfc_copy_expr (array_ctor->expr)); |
+ ADVANCE (vector_ctor, 1); |
+ } |
+ |
+ ADVANCE (array_ctor, 1); |
+ ADVANCE (mask_ctor, 1); |
+ } |
+ } |
+ |
+ /* Append any left-over elements from VECTOR to RESULT. */ |
+ while (vector_ctor) |
+ { |
+ gfc_append_constructor (result, |
+ gfc_copy_expr (vector_ctor->expr)); |
+ ADVANCE (vector_ctor, 1); |
+ } |
+ |
+ result->shape = gfc_get_shape (1); |
+ gfc_array_size (result, &result->shape[0]); |
+ |
+ if (array->ts.type == BT_CHARACTER) |
+ result->ts.u.cl = array->ts.u.cl; |
+ |
+ return result; |
+} |
+ |
+ |
+gfc_expr * |
gfc_simplify_precision (gfc_expr *e) |
{ |
gfc_expr *result; |
@@ -3188,6 +4044,30 @@ gfc_simplify_precision (gfc_expr *e) |
gfc_expr * |
+gfc_simplify_product (gfc_expr *array, gfc_expr *dim, gfc_expr *mask) |
+{ |
+ gfc_expr *result; |
+ |
+ if (!is_constant_array_expr (array) |
+ || !gfc_is_constant_expr (dim)) |
+ return NULL; |
+ |
+ if (mask |
+ && !is_constant_array_expr (mask) |
+ && mask->expr_type != EXPR_CONSTANT) |
+ return NULL; |
+ |
+ result = transformational_result (array, dim, array->ts.type, |
+ array->ts.kind, &array->where); |
+ init_result_expr (result, 1, NULL); |
+ |
+ return !dim || array->rank == 1 ? |
+ simplify_transformation_to_scalar (result, array, mask, gfc_multiply) : |
+ simplify_transformation_to_array (result, array, dim, mask, gfc_multiply); |
+} |
+ |
+ |
+gfc_expr * |
gfc_simplify_radix (gfc_expr *e) |
{ |
gfc_expr *result; |
@@ -3310,8 +4190,7 @@ gfc_simplify_realpart (gfc_expr *e) |
return NULL; |
result = gfc_constant_result (BT_REAL, e->ts.kind, &e->where); |
- mpfr_set (result->value.real, e->value.complex.r, GFC_RND_MODE); |
- |
+ mpc_real (result->value.real, e->value.complex, GFC_RND_MODE); |
return range_check (result, "REALPART"); |
} |
@@ -3336,14 +4215,14 @@ gfc_simplify_repeat (gfc_expr *e, gfc_expr *n) |
} |
/* If we don't know the character length, we can do no more. */ |
- if (e->ts.cl && e->ts.cl->length |
- && e->ts.cl->length->expr_type == EXPR_CONSTANT) |
+ if (e->ts.u.cl && e->ts.u.cl->length |
+ && e->ts.u.cl->length->expr_type == EXPR_CONSTANT) |
{ |
- len = mpz_get_si (e->ts.cl->length->value.integer); |
+ len = mpz_get_si (e->ts.u.cl->length->value.integer); |
have_length = true; |
} |
else if (e->expr_type == EXPR_CONSTANT |
- && (e->ts.cl == NULL || e->ts.cl->length == NULL)) |
+ && (e->ts.u.cl == NULL || e->ts.u.cl->length == NULL)) |
{ |
len = e->value.character.length; |
} |
@@ -3371,7 +4250,7 @@ gfc_simplify_repeat (gfc_expr *e, gfc_expr *n) |
if (have_length) |
{ |
mpz_tdiv_q (max, gfc_integer_kinds[i].huge, |
- e->ts.cl->length->value.integer); |
+ e->ts.u.cl->length->value.integer); |
} |
else |
{ |
@@ -3400,8 +4279,8 @@ gfc_simplify_repeat (gfc_expr *e, gfc_expr *n) |
return NULL; |
if (len || |
- (e->ts.cl->length && |
- mpz_sgn (e->ts.cl->length->value.integer)) != 0) |
+ (e->ts.u.cl->length && |
+ mpz_sgn (e->ts.u.cl->length->value.integer)) != 0) |
{ |
const char *res = gfc_extract_int (n, &ncop); |
gcc_assert (res == NULL); |
@@ -3434,27 +4313,6 @@ gfc_simplify_repeat (gfc_expr *e, gfc_expr *n) |
} |
-/* Test that the expression is an constant array. */ |
- |
-static bool |
-is_constant_array_expr (gfc_expr *e) |
-{ |
- gfc_constructor *c; |
- |
- if (e == NULL) |
- return true; |
- |
- if (e->expr_type != EXPR_ARRAY || !gfc_is_constant_expr (e)) |
- return false; |
- |
- for (c = e->value.constructor; c; c = c->next) |
- if (c->expr->expr_type != EXPR_CONSTANT) |
- return false; |
- |
- return true; |
-} |
- |
- |
/* This one is a bear, but mainly has to do with shuffling elements. */ |
gfc_expr * |
@@ -3470,16 +4328,10 @@ gfc_simplify_reshape (gfc_expr *source, gfc_expr *shape_exp, |
gfc_expr *e; |
/* Check that argument expression types are OK. */ |
- if (!is_constant_array_expr (source)) |
- return NULL; |
- |
- if (!is_constant_array_expr (shape_exp)) |
- return NULL; |
- |
- if (!is_constant_array_expr (pad)) |
- return NULL; |
- |
- if (!is_constant_array_expr (order_exp)) |
+ if (!is_constant_array_expr (source) |
+ || !is_constant_array_expr (shape_exp) |
+ || !is_constant_array_expr (pad) |
+ || !is_constant_array_expr (order_exp)) |
return NULL; |
/* Proceed with simplification, unpacking the array. */ |
@@ -3494,40 +4346,16 @@ gfc_simplify_reshape (gfc_expr *source, gfc_expr *shape_exp, |
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; |
- } |
- |
- if (rank >= GFC_MAX_DIMENSIONS) |
- { |
- gfc_error ("Too many dimensions in shape specification for RESHAPE " |
- "at %L", &e->where); |
- gfc_free_expr (e); |
- goto bad_reshape; |
- } |
+ gfc_extract_int (e, &shape[rank]); |
- if (shape[rank] < 0) |
- { |
- gfc_error ("Shape specification at %L cannot be negative", |
- &e->where); |
- gfc_free_expr (e); |
- goto bad_reshape; |
- } |
+ gcc_assert (rank >= 0 && rank < GFC_MAX_DIMENSIONS); |
+ gcc_assert (shape[rank] >= 0); |
gfc_free_expr (e); |
rank++; |
} |
- if (rank == 0) |
- { |
- gfc_error ("Shape specification at %L cannot be the null array", |
- &shape_exp->where); |
- goto bad_reshape; |
- } |
+ gcc_assert (rank > 0); |
/* Now unpack the order array if present. */ |
if (order_exp == NULL) |
@@ -3543,41 +4371,14 @@ gfc_simplify_reshape (gfc_expr *source, gfc_expr *shape_exp, |
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; |
- } |
- |
- if (order[i] < 1 || order[i] > rank) |
- { |
- gfc_error ("ORDER parameter of RESHAPE at %L is out of range", |
- &e->where); |
- gfc_free_expr (e); |
- goto bad_reshape; |
- } |
- |
- order[i]--; |
- |
- if (x[order[i]]) |
- { |
- gfc_error ("Invalid permutation in ORDER parameter at %L", |
- &e->where); |
- gfc_free_expr (e); |
- goto bad_reshape; |
- } |
+ gcc_assert (e); |
+ gfc_extract_int (e, &order[i]); |
gfc_free_expr (e); |
+ gcc_assert (order[i] >= 1 && order[i] <= rank); |
+ order[i]--; |
+ gcc_assert (x[order[i]] == 0); |
x[order[i]] = 1; |
} |
} |
@@ -3604,7 +4405,7 @@ gfc_simplify_reshape (gfc_expr *source, gfc_expr *shape_exp, |
for (i = 0; i < rank; i++) |
x[i] = 0; |
- for (;;) |
+ while (nsource > 0 || npad > 0) |
{ |
/* Figure out which element to extract. */ |
mpz_set_ui (index, 0); |
@@ -3625,18 +4426,13 @@ gfc_simplify_reshape (gfc_expr *source, gfc_expr *shape_exp, |
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; |
- } |
+ gcc_assert (npad > 0); |
+ j = j - nsource; |
j = j % npad; |
e = gfc_get_array_element (pad, j); |
} |
+ gcc_assert (e); |
if (head == NULL) |
head = tail = gfc_get_constructor (); |
@@ -3646,9 +4442,6 @@ gfc_simplify_reshape (gfc_expr *source, gfc_expr *shape_exp, |
tail = tail->next; |
} |
- if (e == NULL) |
- goto bad_reshape; |
- |
tail->where = e->where; |
tail->expr = e; |
@@ -3680,11 +4473,6 @@ inc: |
e->rank = rank; |
return e; |
- |
-bad_reshape: |
- gfc_free_constructor (head); |
- mpz_clear (index); |
- return &gfc_bad_expr; |
} |
@@ -4144,16 +4932,15 @@ gfc_simplify_sign (gfc_expr *x, gfc_expr *y) |
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. */ |
- mpfr_abs (result->value.real, x->value.real, GFC_RND_MODE); |
- if (mpfr_sgn (y->value.real) < 0) |
- mpfr_neg (result->value.real, result->value.real, GFC_RND_MODE); |
- |
+ if (gfc_option.flag_sign_zero) |
+ mpfr_copysign (result->value.real, x->value.real, y->value.real, |
+ GFC_RND_MODE); |
+ else |
+ mpfr_setsign (result->value.real, x->value.real, |
+ mpfr_sgn (y->value.real) < 0 ? 1 : 0, GFC_RND_MODE); |
break; |
default: |
@@ -4168,7 +4955,6 @@ gfc_expr * |
gfc_simplify_sin (gfc_expr *x) |
{ |
gfc_expr *result; |
- mpfr_t xp, xq; |
if (x->expr_type != EXPR_CONSTANT) |
return NULL; |
@@ -4183,18 +4969,7 @@ gfc_simplify_sin (gfc_expr *x) |
case BT_COMPLEX: |
gfc_set_model (x->value.real); |
- mpfr_init (xp); |
- mpfr_init (xq); |
- |
- mpfr_sin (xp, x->value.complex.r, GFC_RND_MODE); |
- mpfr_cosh (xq, x->value.complex.i, GFC_RND_MODE); |
- mpfr_mul (result->value.complex.r, xp, xq, GFC_RND_MODE); |
- |
- mpfr_cos (xp, x->value.complex.r, GFC_RND_MODE); |
- mpfr_sinh (xq, x->value.complex.i, GFC_RND_MODE); |
- mpfr_mul (result->value.complex.i, xp, xq, GFC_RND_MODE); |
- |
- mpfr_clears (xp, xq, NULL); |
+ mpc_sin (result->value.complex, x->value.complex, GFC_MPC_RND_MODE); |
break; |
default: |
@@ -4215,7 +4990,13 @@ gfc_simplify_sinh (gfc_expr *x) |
result = gfc_constant_result (x->ts.type, x->ts.kind, &x->where); |
- mpfr_sinh (result->value.real, x->value.real, GFC_RND_MODE); |
+ if (x->ts.type == BT_REAL) |
+ mpfr_sinh (result->value.real, x->value.real, GFC_RND_MODE); |
+ else if (x->ts.type == BT_COMPLEX) |
+ mpc_sinh (result->value.complex, x->value.complex, GFC_MPC_RND_MODE); |
+ else |
+ gcc_unreachable (); |
+ |
return range_check (result, "SINH"); |
} |
@@ -4276,10 +5057,116 @@ gfc_simplify_spacing (gfc_expr *x) |
gfc_expr * |
+gfc_simplify_spread (gfc_expr *source, gfc_expr *dim_expr, gfc_expr *ncopies_expr) |
+{ |
+ gfc_expr *result = 0L; |
+ int i, j, dim, ncopies; |
+ mpz_t size; |
+ |
+ if ((!gfc_is_constant_expr (source) |
+ && !is_constant_array_expr (source)) |
+ || !gfc_is_constant_expr (dim_expr) |
+ || !gfc_is_constant_expr (ncopies_expr)) |
+ return NULL; |
+ |
+ gcc_assert (dim_expr->ts.type == BT_INTEGER); |
+ gfc_extract_int (dim_expr, &dim); |
+ dim -= 1; /* zero-base DIM */ |
+ |
+ gcc_assert (ncopies_expr->ts.type == BT_INTEGER); |
+ gfc_extract_int (ncopies_expr, &ncopies); |
+ ncopies = MAX (ncopies, 0); |
+ |
+ /* Do not allow the array size to exceed the limit for an array |
+ constructor. */ |
+ if (source->expr_type == EXPR_ARRAY) |
+ { |
+ if (gfc_array_size (source, &size) == FAILURE) |
+ gfc_internal_error ("Failure getting length of a constant array."); |
+ } |
+ else |
+ mpz_init_set_ui (size, 1); |
+ |
+ if (mpz_get_si (size)*ncopies > gfc_option.flag_max_array_constructor) |
+ return NULL; |
+ |
+ if (source->expr_type == EXPR_CONSTANT) |
+ { |
+ gcc_assert (dim == 0); |
+ |
+ result = gfc_start_constructor (source->ts.type, |
+ source->ts.kind, |
+ &source->where); |
+ result->rank = 1; |
+ result->shape = gfc_get_shape (result->rank); |
+ mpz_init_set_si (result->shape[0], ncopies); |
+ |
+ for (i = 0; i < ncopies; ++i) |
+ gfc_append_constructor (result, gfc_copy_expr (source)); |
+ } |
+ else if (source->expr_type == EXPR_ARRAY) |
+ { |
+ int result_size, rstride[GFC_MAX_DIMENSIONS], extent[GFC_MAX_DIMENSIONS]; |
+ gfc_constructor *ctor, *source_ctor, *result_ctor; |
+ |
+ gcc_assert (source->rank < GFC_MAX_DIMENSIONS); |
+ gcc_assert (dim >= 0 && dim <= source->rank); |
+ |
+ result = gfc_start_constructor (source->ts.type, |
+ source->ts.kind, |
+ &source->where); |
+ result->rank = source->rank + 1; |
+ result->shape = gfc_get_shape (result->rank); |
+ |
+ result_size = 1; |
+ for (i = 0, j = 0; i < result->rank; ++i) |
+ { |
+ if (i != dim) |
+ mpz_init_set (result->shape[i], source->shape[j++]); |
+ else |
+ mpz_init_set_si (result->shape[i], ncopies); |
+ |
+ extent[i] = mpz_get_si (result->shape[i]); |
+ rstride[i] = (i == 0) ? 1 : rstride[i-1] * extent[i-1]; |
+ result_size *= extent[i]; |
+ } |
+ |
+ for (i = 0; i < result_size; ++i) |
+ gfc_append_constructor (result, NULL); |
+ |
+ source_ctor = source->value.constructor; |
+ result_ctor = result->value.constructor; |
+ while (source_ctor) |
+ { |
+ ctor = result_ctor; |
+ |
+ for (i = 0; i < ncopies; ++i) |
+ { |
+ ctor->expr = gfc_copy_expr (source_ctor->expr); |
+ ADVANCE (ctor, rstride[dim]); |
+ } |
+ |
+ ADVANCE (result_ctor, (dim == 0 ? ncopies : 1)); |
+ ADVANCE (source_ctor, 1); |
+ } |
+ } |
+ else |
+ /* FIXME: Returning here avoids a regression in array_simplify_1.f90. |
+ Replace NULL with gcc_unreachable() after implementing |
+ gfc_simplify_cshift(). */ |
+ return NULL; |
+ |
+ if (source->ts.type == BT_CHARACTER) |
+ result->ts.u.cl = source->ts.u.cl; |
+ |
+ return result; |
+} |
+ |
+ |
+gfc_expr * |
gfc_simplify_sqrt (gfc_expr *e) |
{ |
gfc_expr *result; |
- mpfr_t ac, ad, s, t, w; |
if (e->expr_type != EXPR_CONSTANT) |
return NULL; |
@@ -4296,82 +5183,8 @@ gfc_simplify_sqrt (gfc_expr *e) |
break; |
case BT_COMPLEX: |
- /* Formula taken from Numerical Recipes to avoid over- and |
- underflow. */ |
- |
gfc_set_model (e->value.real); |
- mpfr_init (ac); |
- mpfr_init (ad); |
- mpfr_init (s); |
- mpfr_init (t); |
- mpfr_init (w); |
- |
- if (mpfr_cmp_ui (e->value.complex.r, 0) == 0 |
- && mpfr_cmp_ui (e->value.complex.i, 0) == 0) |
- { |
- mpfr_set_ui (result->value.complex.r, 0, GFC_RND_MODE); |
- mpfr_set_ui (result->value.complex.i, 0, GFC_RND_MODE); |
- break; |
- } |
- |
- mpfr_abs (ac, e->value.complex.r, GFC_RND_MODE); |
- mpfr_abs (ad, e->value.complex.i, GFC_RND_MODE); |
- |
- if (mpfr_cmp (ac, ad) >= 0) |
- { |
- mpfr_div (t, e->value.complex.i, e->value.complex.r, GFC_RND_MODE); |
- mpfr_mul (t, t, t, GFC_RND_MODE); |
- mpfr_add_ui (t, t, 1, GFC_RND_MODE); |
- mpfr_sqrt (t, t, GFC_RND_MODE); |
- mpfr_add_ui (t, t, 1, GFC_RND_MODE); |
- mpfr_div_ui (t, t, 2, GFC_RND_MODE); |
- mpfr_sqrt (t, t, GFC_RND_MODE); |
- mpfr_sqrt (s, ac, GFC_RND_MODE); |
- mpfr_mul (w, s, t, GFC_RND_MODE); |
- } |
- else |
- { |
- mpfr_div (s, e->value.complex.r, e->value.complex.i, GFC_RND_MODE); |
- mpfr_mul (t, s, s, GFC_RND_MODE); |
- mpfr_add_ui (t, t, 1, GFC_RND_MODE); |
- mpfr_sqrt (t, t, GFC_RND_MODE); |
- mpfr_abs (s, s, GFC_RND_MODE); |
- mpfr_add (t, t, s, GFC_RND_MODE); |
- mpfr_div_ui (t, t, 2, GFC_RND_MODE); |
- mpfr_sqrt (t, t, GFC_RND_MODE); |
- mpfr_sqrt (s, ad, GFC_RND_MODE); |
- mpfr_mul (w, s, t, GFC_RND_MODE); |
- } |
- |
- if (mpfr_cmp_ui (w, 0) != 0 && mpfr_cmp_ui (e->value.complex.r, 0) >= 0) |
- { |
- mpfr_mul_ui (t, w, 2, GFC_RND_MODE); |
- mpfr_div (result->value.complex.i, e->value.complex.i, t, GFC_RND_MODE); |
- mpfr_set (result->value.complex.r, w, GFC_RND_MODE); |
- } |
- else if (mpfr_cmp_ui (w, 0) != 0 |
- && mpfr_cmp_ui (e->value.complex.r, 0) < 0 |
- && mpfr_cmp_ui (e->value.complex.i, 0) >= 0) |
- { |
- mpfr_mul_ui (t, w, 2, GFC_RND_MODE); |
- mpfr_div (result->value.complex.r, e->value.complex.i, t, GFC_RND_MODE); |
- mpfr_set (result->value.complex.i, w, GFC_RND_MODE); |
- } |
- else if (mpfr_cmp_ui (w, 0) != 0 |
- && mpfr_cmp_ui (e->value.complex.r, 0) < 0 |
- && mpfr_cmp_ui (e->value.complex.i, 0) < 0) |
- { |
- mpfr_mul_ui (t, w, 2, GFC_RND_MODE); |
- mpfr_div (result->value.complex.r, ad, t, GFC_RND_MODE); |
- mpfr_neg (w, w, GFC_RND_MODE); |
- mpfr_set (result->value.complex.i, w, GFC_RND_MODE); |
- } |
- else |
- gfc_internal_error ("invalid complex argument of SQRT at %L", |
- &e->where); |
- |
- mpfr_clears (s, t, ac, ad, w, NULL); |
- |
+ mpc_sqrt (result->value.complex, e->value.complex, GFC_MPC_RND_MODE); |
break; |
default: |
@@ -4388,19 +5201,45 @@ negative_arg: |
gfc_expr * |
+gfc_simplify_sum (gfc_expr *array, gfc_expr *dim, gfc_expr *mask) |
+{ |
+ gfc_expr *result; |
+ |
+ if (!is_constant_array_expr (array) |
+ || !gfc_is_constant_expr (dim)) |
+ return NULL; |
+ |
+ if (mask |
+ && !is_constant_array_expr (mask) |
+ && mask->expr_type != EXPR_CONSTANT) |
+ return NULL; |
+ |
+ result = transformational_result (array, dim, array->ts.type, |
+ array->ts.kind, &array->where); |
+ init_result_expr (result, 0, NULL); |
+ |
+ return !dim || array->rank == 1 ? |
+ simplify_transformation_to_scalar (result, array, mask, gfc_add) : |
+ simplify_transformation_to_array (result, array, dim, mask, gfc_add); |
+} |
+ |
+ |
+gfc_expr * |
gfc_simplify_tan (gfc_expr *x) |
{ |
- int i; |
gfc_expr *result; |
if (x->expr_type != EXPR_CONSTANT) |
return NULL; |
- i = gfc_validate_kind (BT_REAL, x->ts.kind, false); |
- |
result = gfc_constant_result (x->ts.type, x->ts.kind, &x->where); |
- mpfr_tan (result->value.real, x->value.real, GFC_RND_MODE); |
+ if (x->ts.type == BT_REAL) |
+ mpfr_tan (result->value.real, x->value.real, GFC_RND_MODE); |
+ else if (x->ts.type == BT_COMPLEX) |
+ mpc_tan (result->value.complex, x->value.complex, GFC_MPC_RND_MODE); |
+ else |
+ gcc_unreachable (); |
return range_check (result, "TAN"); |
} |
@@ -4416,7 +5255,12 @@ gfc_simplify_tanh (gfc_expr *x) |
result = gfc_constant_result (x->ts.type, x->ts.kind, &x->where); |
- mpfr_tanh (result->value.real, x->value.real, GFC_RND_MODE); |
+ if (x->ts.type == BT_REAL) |
+ mpfr_tanh (result->value.real, x->value.real, GFC_RND_MODE); |
+ else if (x->ts.type == BT_COMPLEX) |
+ mpc_tanh (result->value.complex, x->value.complex, GFC_MPC_RND_MODE); |
+ else |
+ gcc_unreachable (); |
return range_check (result, "TANH"); |
@@ -4557,6 +5401,47 @@ gfc_simplify_transfer (gfc_expr *source, gfc_expr *mold, gfc_expr *size) |
gfc_expr * |
+gfc_simplify_transpose (gfc_expr *matrix) |
+{ |
+ int i, matrix_rows; |
+ gfc_expr *result; |
+ gfc_constructor *matrix_ctor; |
+ |
+ if (!is_constant_array_expr (matrix)) |
+ return NULL; |
+ |
+ gcc_assert (matrix->rank == 2); |
+ |
+ result = gfc_start_constructor (matrix->ts.type, matrix->ts.kind, &matrix->where); |
+ result->rank = 2; |
+ result->shape = gfc_get_shape (result->rank); |
+ mpz_set (result->shape[0], matrix->shape[1]); |
+ mpz_set (result->shape[1], matrix->shape[0]); |
+ |
+ if (matrix->ts.type == BT_CHARACTER) |
+ result->ts.u.cl = matrix->ts.u.cl; |
+ |
+ matrix_rows = mpz_get_si (matrix->shape[0]); |
+ matrix_ctor = matrix->value.constructor; |
+ for (i = 0; i < matrix_rows; ++i) |
+ { |
+ gfc_constructor *column_ctor = matrix_ctor; |
+ while (column_ctor) |
+ { |
+ gfc_append_constructor (result, |
+ gfc_copy_expr (column_ctor->expr)); |
+ |
+ ADVANCE (column_ctor, matrix_rows); |
+ } |
+ |
+ ADVANCE (matrix_ctor, 1); |
+ } |
+ |
+ return result; |
+} |
+ |
+ |
+gfc_expr * |
gfc_simplify_trim (gfc_expr *e) |
{ |
gfc_expr *result; |
@@ -4599,6 +5484,54 @@ gfc_simplify_ubound (gfc_expr *array, gfc_expr *dim, gfc_expr *kind) |
gfc_expr * |
+gfc_simplify_unpack (gfc_expr *vector, gfc_expr *mask, gfc_expr *field) |
+{ |
+ gfc_expr *result, *e; |
+ gfc_constructor *vector_ctor, *mask_ctor, *field_ctor; |
+ |
+ if (!is_constant_array_expr (vector) |
+ || !is_constant_array_expr (mask) |
+ || (!gfc_is_constant_expr (field) |
+ && !is_constant_array_expr(field))) |
+ return NULL; |
+ |
+ result = gfc_start_constructor (vector->ts.type, |
+ vector->ts.kind, |
+ &vector->where); |
+ result->rank = mask->rank; |
+ result->shape = gfc_copy_shape (mask->shape, mask->rank); |
+ |
+ if (vector->ts.type == BT_CHARACTER) |
+ result->ts.u.cl = vector->ts.u.cl; |
+ |
+ vector_ctor = vector->value.constructor; |
+ mask_ctor = mask->value.constructor; |
+ field_ctor = field->expr_type == EXPR_ARRAY ? field->value.constructor : NULL; |
+ |
+ while (mask_ctor) |
+ { |
+ if (mask_ctor->expr->value.logical) |
+ { |
+ gcc_assert (vector_ctor); |
+ e = gfc_copy_expr (vector_ctor->expr); |
+ ADVANCE (vector_ctor, 1); |
+ } |
+ else if (field->expr_type == EXPR_ARRAY) |
+ e = gfc_copy_expr (field_ctor->expr); |
+ else |
+ e = gfc_copy_expr (field); |
+ |
+ gfc_append_constructor (result, e); |
+ |
+ ADVANCE (mask_ctor, 1); |
+ ADVANCE (field_ctor, 1); |
+ } |
+ |
+ return result; |
+} |
+ |
+ |
+gfc_expr * |
gfc_simplify_verify (gfc_expr *s, gfc_expr *set, gfc_expr *b, gfc_expr *kind) |
{ |
gfc_expr *result; |
@@ -4950,7 +5883,7 @@ gfc_convert_char_constant (gfc_expr *e, bt type ATTRIBUTE_UNUSED, int kind) |
result->shape = gfc_copy_shape (e->shape, e->rank); |
result->where = e->where; |
result->rank = e->rank; |
- result->ts.cl = e->ts.cl; |
+ result->ts.u.cl = e->ts.u.cl; |
return result; |
} |