This is the mail archive of the
fortran@gcc.gnu.org
mailing list for the GNU Fortran project.
Re: [Patch, fortran] PR16206 - array initializers
- From: Paul Thomas <paulthomas2 at wanadoo dot fr>
- To: Steve Kargl <sgk at troutmask dot apl dot washington dot edu>
- Cc: patch <gcc-patches at gcc dot gnu dot org>, "'fortran at gcc dot gnu dot org'" <fortran at gcc dot gnu dot org>
- Date: Sun, 18 Jun 2006 14:31:38 +0200
- Subject: Re: [Patch, fortran] PR16206 - array initializers
- References: <44938BAC.1070900@wanadoo.fr> <20060618034004.GA66642@troutmask.apl.washington.edu>
Steve,
The attached responds to your questions/details. It regtests on
FC5/Athlon. Is it OK with the original testcase?
I realised a few minutes ago that the submitted version of the
transformational intrinsics patch was (i) not the final version in
simplify.c and (ii) was missing a small correction in
expr.c(simplify_parameter_variable). This latter appears in the new
version of the PR16206 patch, and I have attached the correct version of
the simplify.c patch; sorry for that.
I'll wait for you to OK both before committing.
Many thanks, especially for picking up the memory leaks.
Paul
On Sat, Jun 17, 2006 at 06:57:16AM +0200, Paul Thomas wrote:
2006-06-17 Paul Thomas <pault@gcc.gnu.org>
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.
(gfc_simplify_expr): Only call gfc_expand_constructor for full
arrays.
2006-06-17 Paul Thomas <pault@gcc.gnu.org>
PR fortran/16206
* gfortran.dg/array_initializer_1.f90: New test.
There a few minor questions/details to consider see below.
!
! /* 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->upper[i]->value.integer) > 0
These mpz_cmp appear to be redundant.
! || mpz_cmp (e->value.integer,
! ar->as->lower[i]->value.integer) < 0
! || mpz_cmp (e->value.integer,
! ar->as->lower[i]->value.integer) < 0))
These mpz_cmp appear to be redundant.
*************** remove_subobject_ref (gfc_expr * p, gfc_
*** 985,990 ****
--- 1008,1225 ----
}
+ 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);
+
+ /* Build the counters to clock through the array reference. */
+ for (idx = 0; idx < rank; idx++)
+ {
+ /* Make this stretch of code easier on the eye! */
+ begin = ref->u.ar.start[idx];
+ finish = ref->u.ar.end[idx];
+ step = ref->u.ar.stride[idx];
+ lower = ref->u.ar.as->lower[idx];
+ upper = ref->u.ar.as->upper[idx];
+
+ if ((begin && begin->expr_type != EXPR_CONSTANT)
+ || (finish && finish->expr_type != EXPR_CONSTANT)
+ || (step && step->expr_type != EXPR_CONSTANT))
+ return FAILURE;
Doesn't this "return FAILURE" leak memory? Should you free at least the
mpz variables?
+ {
+ gfc_error ("index in dimension %d is out of bounds "
+ "at %L", idx + 1, &ref->u.ar.c_where[idx]);
+ return FAILURE;
Again, is memory leaked here?
Index: gcc/fortran/expr.c
===================================================================
*** gcc/fortran/expr.c (revision 114548)
--- gcc/fortran/expr.c (working copy)
*************** simplify_constructor (gfc_constructor *
*** 902,951 ****
/* Pull a single array element out of an array constructor. */
! static gfc_constructor *
! find_array_element (gfc_constructor * cons, gfc_array_ref * ar)
{
unsigned long nelemen;
int i;
mpz_t delta;
mpz_t offset;
mpz_init_set_ui (offset, 0);
mpz_init (delta);
for (i = 0; i < ar->dimen; i++)
{
! if (ar->start[i]->expr_type != EXPR_CONSTANT)
{
cons = NULL;
! break;
}
! mpz_sub (delta, ar->start[i]->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--)
{
! if (cons->iterator)
! {
! cons = NULL;
! break;
! }
! cons = cons->next;
}
}
- else
- cons = NULL;
}
mpz_clear (delta);
mpz_clear (offset);
!
! return cons;
}
--- 902,971 ----
/* Pull a single array element out of an array constructor. */
! 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++)
{
! e = gfc_copy_expr (ar->start[i]);
! if (e->expr_type != EXPR_CONSTANT)
{
cons = NULL;
! goto depart;
}
!
! /* 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)
{
! for (nelemen = mpz_get_ui (offset); nelemen > 0; nelemen--)
{
! if (cons->iterator)
{
! cons = NULL;
! goto depart;
}
+ cons = cons->next;
}
}
+ depart:
mpz_clear (delta);
mpz_clear (offset);
! if (e)
! gfc_free_expr (e);
! *rval = cons;
! return t;
}
*************** remove_subobject_ref (gfc_expr * p, gfc_
*** 985,990 ****
--- 1005,1244 ----
}
+ /* 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_init (index);
+ 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. */
*************** static try
*** 992,997 ****
--- 1246,1252 ----
simplify_const_ref (gfc_expr * p)
{
gfc_constructor *cons;
+ gfc_expr *newp;
while (p->ref)
{
*************** simplify_const_ref (gfc_expr * p)
*** 1001,1024 ****
switch (p->ref->u.ar.type)
{
case AR_ELEMENT:
! cons = find_array_element (p->value.constructor, &p->ref->u.ar);
if (!cons)
return SUCCESS;
remove_subobject_ref (p, cons);
break;
case AR_FULL:
! if (p->ref->next != NULL)
{
! /* TODO: Simplify array subobject references. */
! return SUCCESS;
}
! gfc_free_ref_list (p->ref);
! p->ref = NULL;
break;
default:
- /* TODO: Simplify array subsections. */
return SUCCESS;
}
--- 1256,1293 ----
switch (p->ref->u.ar.type)
{
case AR_ELEMENT:
! 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;
+
case AR_FULL:
! if (p->ref->next != NULL
! && (p->ts.type == BT_CHARACTER || p->ts.type == BT_DERIVED))
{
! 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;
break;
default:
return SUCCESS;
}
*************** simplify_const_ref (gfc_expr * p)
*** 1030,1037 ****
break;
case REF_SUBSTRING:
! /* TODO: Constant substrings. */
! return SUCCESS;
}
}
--- 1299,1311 ----
break;
case REF_SUBSTRING:
! if (find_substring_ref (p, &newp) == FAILURE)
! return FAILURE;
!
! gfc_replace_expr (p, newp);
! gfc_free_ref_list (p->ref);
! p->ref = NULL;
! break;
}
}
*************** simplify_ref_chain (gfc_ref * ref, int t
*** 1062,1067 ****
--- 1336,1342 ----
if (gfc_simplify_expr (ref->u.ar.stride[n], type)
== FAILURE)
return FAILURE;
+
}
break;
*************** simplify_parameter_variable (gfc_expr *
*** 1088,1093 ****
--- 1363,1371 ----
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);
*************** gfc_simplify_expr (gfc_expr * p, int typ
*** 1211,1217 ****
if (simplify_constructor (p->value.constructor, type) == FAILURE)
return FAILURE;
! if (p->expr_type == EXPR_ARRAY)
gfc_expand_constructor (p);
if (simplify_const_ref (p) == FAILURE)
--- 1489,1497 ----
if (simplify_constructor (p->value.constructor, type) == FAILURE)
return FAILURE;
! 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)
Index: gcc/fortran/simplify.c
===================================================================
*** gcc/fortran/simplify.c (revision 114548)
--- gcc/fortran/simplify.c (working copy)
*************** gfc_simplify_tiny (gfc_expr * e)
*** 3696,3701 ****
--- 3696,3714 ----
gfc_expr *
+ gfc_simplify_transfer (gfc_expr * source, gfc_expr *mold, gfc_expr * size)
+ {
+
+ /* Reference mold and size to suppress warning. */
+ if (gfc_init_expr && (mold || size))
+ gfc_error ("TRANSFER intrinsic not implemented for initialization at %L",
+ &source->where);
+
+ return NULL;
+ }
+
+
+ gfc_expr *
gfc_simplify_trim (gfc_expr * e)
{
gfc_expr *result;