diff options
author | Paul Thomas <pault@gcc.gnu.org> | 2006-06-20 04:30:48 +0000 |
---|---|---|
committer | Paul Thomas <pault@gcc.gnu.org> | 2006-06-20 04:30:48 +0000 |
commit | a4a11197f9f65c5523da3ce588d7508e47f801ab (patch) | |
tree | ac18f8deb5aff7c9354a8879e1c428d69345b10f /gcc/fortran/expr.c | |
parent | 73dab33bce6cc186f05ac0cf45e42c58f9086b3c (diff) | |
download | gcc-a4a11197f9f65c5523da3ce588d7508e47f801ab.zip gcc-a4a11197f9f65c5523da3ce588d7508e47f801ab.tar.gz gcc-a4a11197f9f65c5523da3ce588d7508e47f801ab.tar.bz2 |
re PR fortran/25049 (TRANSPOSE not allowed in initialisation expression)
2006-06-20 Paul Thomas <pault@gcc.gnu.org>
PR fortran/25049
PR fortran/25050
* check.c (non_init_transformational): New function.
(find_substring_ref): New function to signal use of disallowed
transformational intrinsic in an initialization expression.
(gfc_check_all_any): Call previous if initialization expr.
(gfc_check_count): The same.
(gfc_check_cshift): The same.
(gfc_check_dot_product): The same.
(gfc_check_eoshift): The same.
(gfc_check_minloc_maxloc): The same.
(gfc_check_minval_maxval): The same.
(gfc_check_gfc_check_product_sum): The same.
(gfc_check_pack): The same.
(gfc_check_spread): The same.
(gfc_check_transpose): The same.
(gfc_check_unpack): The same.
PR fortran/18769
*intrinsic.c (add_functions): Add gfc_simplify_transfer.
*intrinsic.h : Add prototype for gfc_simplify_transfer.
*simplify.c (gfc_simplify_transfer) : New function to act as
placeholder for eventual implementation. Emit error for now.
PR fortran/16206
* expr.c (find_array_element): Eliminate condition on length of
offset. Add bounds checking. Rearrange exit. Return try and
put gfc_constructor result as an argument.
(find_array_section): New function.
(find_substring_ref): New function.
(simplify_const_ref): Add calls to previous.
(simplify_parameter_variable): Return on NULL expr.
(gfc_simplify_expr): Only call gfc_expand_constructor for full
arrays.
PR fortran/20876
* match.c (gfc_match_forall): Add missing locus to gfc_code.
2006-06-20 Paul Thomas <pault@gcc.gnu.org>
PR libfortran/28005
* m4/matmul.m4: aystride = 1 does not uniquely detect the
presence of a temporary transpose; an array element in the
first dimension produces the same signature. Detect this
using the rank of a and add specific code.
* generated/matmul_r4.c: Regenerate.
* generated/matmul_r8.c: Regenerate.
* generated/matmul_r10.c: Regenerate.
* generated/matmul_r16.c: Regenerate.
* generated/matmul_c4.c: Regenerate.
* generated/matmul_c8.c: Regenerate.
* generated/matmul_c10.c: Regenerate.
* generated/matmul_c16.c: Regenerate.
* generated/matmul_i4.c: Regenerate.
* generated/matmul_i8.c: Regenerate.
* generated/matmul_i16.c: Regenerate.
2006-06-20 Paul Thomas <pault@gcc.gnu.org>
PR fortran/16206
* gfortran.dg/array_initializer_1.f90: New test.
PR fortran/28005
* gfortran.dg/matmul_3.f90: New test.
From-SVN: r114802
Diffstat (limited to 'gcc/fortran/expr.c')
-rw-r--r-- | gcc/fortran/expr.c | 336 |
1 files changed, 309 insertions, 27 deletions
diff --git a/gcc/fortran/expr.c b/gcc/fortran/expr.c index a163151..4b03798 100644 --- a/gcc/fortran/expr.c +++ b/gcc/fortran/expr.c @@ -902,50 +902,70 @@ simplify_constructor (gfc_constructor * c, int type) /* Pull a single array element out of an array constructor. */ -static gfc_constructor * -find_array_element (gfc_constructor * cons, gfc_array_ref * ar) +static try +find_array_element (gfc_constructor * cons, gfc_array_ref * ar, + gfc_constructor ** rval) { unsigned long nelemen; int i; mpz_t delta; mpz_t offset; + gfc_expr *e; + try t; + + t = SUCCESS; + e = NULL; mpz_init_set_ui (offset, 0); mpz_init (delta); for (i = 0; i < ar->dimen; i++) { - if (ar->start[i]->expr_type != EXPR_CONSTANT) + e = gfc_copy_expr (ar->start[i]); + if (e->expr_type != EXPR_CONSTANT) { cons = NULL; - break; + goto depart; } - mpz_sub (delta, ar->start[i]->value.integer, + + /* Check the bounds. */ + if (ar->as->upper[i] + && (mpz_cmp (e->value.integer, + ar->as->upper[i]->value.integer) > 0 + || mpz_cmp (e->value.integer, + ar->as->lower[i]->value.integer) < 0)) + { + gfc_error ("index in dimension %d is out of bounds " + "at %L", i + 1, &ar->c_where[i]); + cons = NULL; + t = FAILURE; + goto depart; + } + + mpz_sub (delta, e->value.integer, ar->as->lower[i]->value.integer); mpz_add (offset, offset, delta); } if (cons) { - if (mpz_fits_ulong_p (offset)) + for (nelemen = mpz_get_ui (offset); nelemen > 0; nelemen--) { - for (nelemen = mpz_get_ui (offset); nelemen > 0; nelemen--) + if (cons->iterator) { - if (cons->iterator) - { - cons = NULL; - break; - } - cons = cons->next; + cons = NULL; + goto depart; } + cons = cons->next; } - else - cons = NULL; } +depart: mpz_clear (delta); mpz_clear (offset); - - return cons; + if (e) + gfc_free_expr (e); + *rval = cons; + return t; } @@ -985,6 +1005,240 @@ remove_subobject_ref (gfc_expr * p, gfc_constructor * cons) } +/* Pull an array section out of an array constructor. */ + +static try +find_array_section (gfc_expr *expr, gfc_ref *ref) +{ + int idx; + int rank; + int d; + long unsigned one = 1; + mpz_t end[GFC_MAX_DIMENSIONS]; + mpz_t stride[GFC_MAX_DIMENSIONS]; + mpz_t delta[GFC_MAX_DIMENSIONS]; + mpz_t ctr[GFC_MAX_DIMENSIONS]; + mpz_t delta_mpz; + mpz_t tmp_mpz; + mpz_t nelts; + mpz_t ptr; + mpz_t stop; + mpz_t index; + gfc_constructor *cons; + gfc_constructor *base; + gfc_expr *begin; + gfc_expr *finish; + gfc_expr *step; + gfc_expr *upper; + gfc_expr *lower; + try t; + + t = SUCCESS; + + base = expr->value.constructor; + expr->value.constructor = NULL; + + rank = ref->u.ar.as->rank; + + if (expr->shape == NULL) + expr->shape = gfc_get_shape (rank); + + mpz_init_set_ui (delta_mpz, one); + mpz_init_set_ui (nelts, one); + mpz_init (tmp_mpz); + + /* Do the initialization now, so that we can cleanup without + keeping track of where we were. */ + for (d = 0; d < rank; d++) + { + mpz_init (delta[d]); + mpz_init (end[d]); + mpz_init (ctr[d]); + mpz_init (stride[d]); + } + + /* Build the counters to clock through the array reference. */ + for (d = 0; d < rank; d++) + { + /* Make this stretch of code easier on the eye! */ + begin = ref->u.ar.start[d]; + finish = ref->u.ar.end[d]; + step = ref->u.ar.stride[d]; + lower = ref->u.ar.as->lower[d]; + upper = ref->u.ar.as->upper[d]; + + if ((begin && begin->expr_type != EXPR_CONSTANT) + || (finish && finish->expr_type != EXPR_CONSTANT) + || (step && step->expr_type != EXPR_CONSTANT)) + { + t = FAILURE; + goto cleanup; + } + + /* Obtain the stride. */ + if (step) + mpz_set (stride[d], step->value.integer); + else + mpz_set_ui (stride[d], one); + + if (mpz_cmp_ui (stride[d], 0) == 0) + mpz_set_ui (stride[d], one); + + /* Obtain the start value for the index. */ + if (begin->value.integer) + mpz_set (ctr[d], begin->value.integer); + else + { + if (mpz_cmp_si (stride[d], 0) < 0) + mpz_set (ctr[d], upper->value.integer); + else + mpz_set (ctr[d], lower->value.integer); + } + + /* Obtain the end value for the index. */ + if (finish) + mpz_set (end[d], finish->value.integer); + else + { + if (mpz_cmp_si (stride[d], 0) < 0) + mpz_set (end[d], lower->value.integer); + else + mpz_set (end[d], upper->value.integer); + } + + /* Separate 'if' because elements sometimes arrive with + non-null end. */ + if (ref->u.ar.dimen_type[d] == DIMEN_ELEMENT) + mpz_set (end [d], begin->value.integer); + + /* Check the bounds. */ + if (mpz_cmp (ctr[d], upper->value.integer) > 0 + || mpz_cmp (end[d], upper->value.integer) > 0 + || mpz_cmp (ctr[d], lower->value.integer) < 0 + || mpz_cmp (end[d], lower->value.integer) < 0) + { + gfc_error ("index in dimension %d is out of bounds " + "at %L", d + 1, &ref->u.ar.c_where[d]); + t = FAILURE; + goto cleanup; + } + + /* Calculate the number of elements and the shape. */ + mpz_abs (tmp_mpz, stride[d]); + mpz_div (tmp_mpz, stride[d], tmp_mpz); + mpz_add (tmp_mpz, end[d], tmp_mpz); + mpz_sub (tmp_mpz, tmp_mpz, ctr[d]); + mpz_div (tmp_mpz, tmp_mpz, stride[d]); + mpz_mul (nelts, nelts, tmp_mpz); + + mpz_set (expr->shape[d], tmp_mpz); + + /* Calculate the 'stride' (=delta) for conversion of the + counter values into the index along the constructor. */ + mpz_set (delta[d], delta_mpz); + mpz_sub (tmp_mpz, upper->value.integer, lower->value.integer); + mpz_add_ui (tmp_mpz, tmp_mpz, one); + mpz_mul (delta_mpz, delta_mpz, tmp_mpz); + } + + mpz_init (index); + mpz_init (ptr); + mpz_init (stop); + cons = base; + + /* Now clock through the array reference, calculating the index in + the source constructor and transferring the elements to the new + constructor. */ + for (idx = 0; idx < (int)mpz_get_si (nelts); idx++) + { + if (ref->u.ar.offset) + mpz_set (ptr, ref->u.ar.offset->value.integer); + else + mpz_init_set_ui (ptr, 0); + + mpz_set_ui (stop, one); + for (d = 0; d < rank; d++) + { + mpz_set (tmp_mpz, ctr[d]); + mpz_sub_ui (tmp_mpz, tmp_mpz, one); + mpz_mul (tmp_mpz, tmp_mpz, delta[d]); + mpz_add (ptr, ptr, tmp_mpz); + + mpz_mul (tmp_mpz, stride[d], stop); + mpz_add (ctr[d], ctr[d], tmp_mpz); + + mpz_set (tmp_mpz, end[d]); + if (mpz_cmp_ui (stride[d], 0) > 0 ? + mpz_cmp (ctr[d], tmp_mpz) > 0 : + mpz_cmp (ctr[d], tmp_mpz) < 0) + mpz_set (ctr[d], ref->u.ar.start[d]->value.integer); + else + mpz_set_ui (stop, 0); + } + + /* There must be a better way of dealing with negative strides + than resetting the index and the constructor pointer! */ + if (mpz_cmp (ptr, index) < 0) + { + mpz_set_ui (index, 0); + cons = base; + } + + while (mpz_cmp (ptr, index) > 0) + { + mpz_add_ui (index, index, one); + cons = cons->next; + } + + gfc_append_constructor (expr, gfc_copy_expr (cons->expr)); + } + + mpz_clear (ptr); + mpz_clear (index); + mpz_clear (stop); + +cleanup: + + mpz_clear (delta_mpz); + mpz_clear (tmp_mpz); + mpz_clear (nelts); + for (d = 0; d < rank; d++) + { + mpz_clear (delta[d]); + mpz_clear (end[d]); + mpz_clear (ctr[d]); + mpz_clear (stride[d]); + } + gfc_free_constructor (base); + return t; +} + +/* Pull a substring out of an expression. */ + +static try +find_substring_ref (gfc_expr *p, gfc_expr **newp) +{ + int end; + int start; + char *chr; + + if (p->ref->u.ss.start->expr_type != EXPR_CONSTANT + || p->ref->u.ss.end->expr_type != EXPR_CONSTANT) + return FAILURE; + + *newp = gfc_copy_expr (p); + chr = p->value.character.string; + end = (int)mpz_get_ui (p->ref->u.ss.end->value.integer); + start = (int)mpz_get_ui (p->ref->u.ss.start->value.integer); + + (*newp)->value.character.length = end - start + 1; + strncpy ((*newp)->value.character.string, &chr[start - 1], + (*newp)->value.character.length); + return SUCCESS; +} + + + /* Simplify a subobject reference of a constructor. This occurs when parameter variable values are substituted. */ @@ -992,6 +1246,7 @@ static try simplify_const_ref (gfc_expr * p) { gfc_constructor *cons; + gfc_expr *newp; while (p->ref) { @@ -1001,24 +1256,40 @@ simplify_const_ref (gfc_expr * p) switch (p->ref->u.ar.type) { case AR_ELEMENT: - cons = find_array_element (p->value.constructor, &p->ref->u.ar); + if (find_array_element (p->value.constructor, + &p->ref->u.ar, + &cons) == FAILURE) + return FAILURE; + if (!cons) return SUCCESS; + remove_subobject_ref (p, cons); break; + case AR_SECTION: + if (find_array_section (p, p->ref) == FAILURE) + return FAILURE; + p->ref->u.ar.type = AR_FULL; + + /* FALLTHROUGH */ + case AR_FULL: - if (p->ref->next != NULL) + if (p->ref->next != NULL + && (p->ts.type == BT_CHARACTER || p->ts.type == BT_DERIVED)) { - /* TODO: Simplify array subobject references. */ - return SUCCESS; + cons = p->value.constructor; + for (; cons; cons = cons->next) + { + cons->expr->ref = copy_ref (p->ref->next); + simplify_const_ref (cons->expr); + } } - gfc_free_ref_list (p->ref); - p->ref = NULL; + gfc_free_ref_list (p->ref); + p->ref = NULL; break; default: - /* TODO: Simplify array subsections. */ return SUCCESS; } @@ -1030,8 +1301,13 @@ simplify_const_ref (gfc_expr * p) break; case REF_SUBSTRING: - /* TODO: Constant substrings. */ - return SUCCESS; + if (find_substring_ref (p, &newp) == FAILURE) + return FAILURE; + + gfc_replace_expr (p, newp); + gfc_free_ref_list (p->ref); + p->ref = NULL; + break; } } @@ -1062,6 +1338,7 @@ simplify_ref_chain (gfc_ref * ref, int type) if (gfc_simplify_expr (ref->u.ar.stride[n], type) == FAILURE) return FAILURE; + } break; @@ -1088,6 +1365,9 @@ simplify_parameter_variable (gfc_expr * p, int type) try t; e = gfc_copy_expr (p->symtree->n.sym->value); + if (e == NULL) + return FAILURE; + /* Do not copy subobject refs for constant. */ if (e->expr_type != EXPR_CONSTANT && p->ref != NULL) e->ref = copy_ref (p->ref); @@ -1211,7 +1491,9 @@ gfc_simplify_expr (gfc_expr * p, int type) if (simplify_constructor (p->value.constructor, type) == FAILURE) return FAILURE; - if (p->expr_type == EXPR_ARRAY) + if (p->expr_type == EXPR_ARRAY + && p->ref && p->ref->type == REF_ARRAY + && p->ref->u.ar.type == AR_FULL) gfc_expand_constructor (p); if (simplify_const_ref (p) == FAILURE) |