Hi! As discussed in the PR and can be seen on the first testcase, the removal of repeat field for ctors resulted in huge memory consumption of the fortran FE on some real-world testcases (the first testcase needs several GB of memory to compile).
This patch reintroduces the repeat field and handles the cases where a range ctor is replacing some other ctors in that range or some ctor is being replacing a part of a range ctor. It should result in no change in the generated code, just use much less memory in larger testcases. Bootstrapped/regtested on x86_64-linux and i686-linux. Ok for trunk and after a while for 4.6 too? OT, the results before as well as after the patch for the second testcases are unexpected, it seems the DATA stmts are processed in reverse order, so that the first one wins instead of last one, unlike e.g. ifort or gfortran 4.1. I guess we should change that, but independently of this patch. 2011-06-27 Jakub Jelinek <ja...@redhat.com> PR fortran/49540 * gfortran.h (gfc_constructor): Add repeat field. * trans-array.c (gfc_conv_array_initializer): Handle repeat > 1. * array.c (current_expand): Add repeat field. (expand_constructor): Copy repeat. * constructor.c (node_free, node_copy, gfc_constructor_get, gfc_constructor_lookup): Handle repeat field. (gfc_constructor_lookup_next, gfc_constructor_remove): New functions. * data.h (gfc_assign_data_value): Add mpz_t * argument. (gfc_assign_data_value_range): Removed. * constructor.h (gfc_constructor_advance): Removed. (gfc_constructor_lookup_next, gfc_constructor_remove): New prototypes. * data.c (gfc_assign_data_value): Add REPEAT argument, handle it and also handle overwriting a range with a single entry. (gfc_assign_data_value_range): Removed. * resolve.c (check_data_variable): Adjust gfc_assign_data_value call. Use gfc_assign_data_value instead of gfc_assign_data_value_expr. * gfortran.dg/pr49540-1.f90: New test. * gfortran.dg/pr49540-2.f90: New test. --- gcc/fortran/gfortran.h.jj 2011-06-21 16:45:54.000000000 +0200 +++ gcc/fortran/gfortran.h 2011-06-27 18:37:45.000000000 +0200 @@ -2271,6 +2271,8 @@ typedef struct gfc_constructor gfc_component *component; /* Record the component being initialized. */ } n; + mpz_t repeat; /* Record the repeat number of initial values in data + statement like "data a/5*10/". */ } gfc_constructor; --- gcc/fortran/trans-array.c.jj 2011-06-17 11:02:01.000000000 +0200 +++ gcc/fortran/trans-array.c 2011-06-29 15:15:04.000000000 +0200 @@ -4555,7 +4555,7 @@ gfc_conv_array_initializer (tree type, g gfc_se se; HOST_WIDE_INT hi; unsigned HOST_WIDE_INT lo; - tree index; + tree index, range; VEC(constructor_elt,gc) *v = NULL; switch (expr->expr_type) @@ -4608,29 +4608,56 @@ gfc_conv_array_initializer (tree type, g index = gfc_conv_mpz_to_tree (c->offset, gfc_index_integer_kind); else index = NULL_TREE; + if (mpz_cmp_si (c->repeat, 1) > 0) + { + tree tmp1, tmp2; + mpz_t maxval; + + mpz_init (maxval); + mpz_add (maxval, c->offset, c->repeat); + mpz_sub_ui (maxval, maxval, 1); + tmp2 = gfc_conv_mpz_to_tree (maxval, gfc_index_integer_kind); + if (mpz_cmp_si (c->offset, 0) != 0) + { + mpz_add_ui (maxval, c->offset, 1); + tmp1 = gfc_conv_mpz_to_tree (maxval, gfc_index_integer_kind); + } + else + tmp1 = gfc_conv_mpz_to_tree (c->offset, gfc_index_integer_kind); + + range = fold_build2 (RANGE_EXPR, integer_type_node, tmp1, tmp2); + mpz_clear (maxval); + } + else + range = NULL; gfc_init_se (&se, NULL); switch (c->expr->expr_type) { case EXPR_CONSTANT: gfc_conv_constant (&se, c->expr); - CONSTRUCTOR_APPEND_ELT (v, index, se.expr); break; case EXPR_STRUCTURE: gfc_conv_structure (&se, c->expr, 1); - CONSTRUCTOR_APPEND_ELT (v, index, se.expr); break; - default: /* Catch those occasional beasts that do not simplify for one reason or another, assuming that if they are standard defying the frontend will catch them. */ gfc_conv_expr (&se, c->expr); - CONSTRUCTOR_APPEND_ELT (v, index, se.expr); break; } + + if (range == NULL_TREE) + CONSTRUCTOR_APPEND_ELT (v, index, se.expr); + else + { + if (index != NULL_TREE) + CONSTRUCTOR_APPEND_ELT (v, index, se.expr); + CONSTRUCTOR_APPEND_ELT (v, range, se.expr); + } } break; --- gcc/fortran/array.c.jj 2011-05-02 18:39:17.000000000 +0200 +++ gcc/fortran/array.c 2011-06-27 18:37:45.000000000 +0200 @@ -1322,6 +1322,7 @@ typedef struct mpz_t *offset; gfc_component *component; + mpz_t *repeat; gfc_try (*expand_work_function) (gfc_expr *); } @@ -1556,6 +1557,7 @@ expand_constructor (gfc_constructor_base return FAILURE; } current_expand.offset = &c->offset; + current_expand.repeat = &c->repeat; current_expand.component = c->n.component; if (current_expand.expand_work_function (e) == FAILURE) return FAILURE; --- gcc/fortran/constructor.c.jj 2011-05-02 18:39:17.000000000 +0200 +++ gcc/fortran/constructor.c 2011-06-29 18:31:44.000000000 +0200 @@ -1,5 +1,5 @@ /* Array and structure constructors - Copyright (C) 2009, 2010 + Copyright (C) 2009, 2010, 2011 Free Software Foundation, Inc. This file is part of GCC. @@ -36,6 +36,7 @@ node_free (splay_tree_value value) gfc_free_iterator (c->iterator, 1); mpz_clear (c->offset); + mpz_clear (c->repeat); free (c); } @@ -54,6 +55,7 @@ node_copy (splay_tree_node node, void *b c->n.component = src->n.component; mpz_init_set (c->offset, src->offset); + mpz_init_set (c->repeat, src->repeat); return c; } @@ -78,6 +80,7 @@ gfc_constructor_get (void) c->iterator = NULL; mpz_init_set_si (c->offset, 0); + mpz_init_set_si (c->repeat, 1); return c; } @@ -169,6 +172,7 @@ gfc_constructor_insert_expr (gfc_constru gfc_constructor * gfc_constructor_lookup (gfc_constructor_base base, int offset) { + gfc_constructor *c; splay_tree_node node; if (!base) @@ -176,9 +180,24 @@ gfc_constructor_lookup (gfc_constructor_ node = splay_tree_lookup (base, (splay_tree_key) offset); if (node) - return (gfc_constructor*) node->value; + return (gfc_constructor *) node->value; - return NULL; + /* Check if the previous node has a repeat count big enough to + cover the offset looked for. */ + node = splay_tree_predecessor (base, (splay_tree_key) offset); + if (!node) + return NULL; + + c = (gfc_constructor *) node->value; + if (mpz_cmp_si (c->repeat, 1) > 0) + { + if (mpz_get_si (c->offset) + mpz_get_si (c->repeat) <= offset) + c = NULL; + } + else + c = NULL; + + return c; } @@ -232,3 +251,27 @@ gfc_constructor_next (gfc_constructor *c else return NULL; } + + +void +gfc_constructor_remove (gfc_constructor *ctor) +{ + if (ctor) + splay_tree_remove (ctor->base, mpz_get_si (ctor->offset)); +} + + +gfc_constructor * +gfc_constructor_lookup_next (gfc_constructor_base base, int offset) +{ + splay_tree_node node; + + if (!base) + return NULL; + + node = splay_tree_successor (base, (splay_tree_key) offset); + if (!node) + return NULL; + + return (gfc_constructor *) node->value; +} --- gcc/fortran/data.h.jj 2011-01-06 10:21:41.000000000 +0100 +++ gcc/fortran/data.h 2011-06-29 15:19:31.000000000 +0200 @@ -1,5 +1,5 @@ /* Header for functions resolving DATA statements. - Copyright (C) 2007, 2008, 2010 Free Software Foundation, Inc. + Copyright (C) 2007, 2008, 2010, 2011 Free Software Foundation, Inc. This file is part of GCC. @@ -19,6 +19,5 @@ along with GCC; see the file COPYING3. void gfc_formalize_init_value (gfc_symbol *); void gfc_get_section_index (gfc_array_ref *, mpz_t *, mpz_t *); -gfc_try gfc_assign_data_value (gfc_expr *, gfc_expr *, mpz_t); -gfc_try gfc_assign_data_value_range (gfc_expr *, gfc_expr *, mpz_t, mpz_t); +gfc_try gfc_assign_data_value (gfc_expr *, gfc_expr *, mpz_t, mpz_t *); void gfc_advance_section (mpz_t *, gfc_array_ref *, mpz_t *); --- gcc/fortran/constructor.h.jj 2010-05-25 11:27:34.000000000 +0200 +++ gcc/fortran/constructor.h 2011-06-29 15:46:17.000000000 +0200 @@ -1,5 +1,5 @@ /* Array and structure constructors - Copyright (C) 2009, 2010 + Copyright (C) 2009, 2010, 2011 Free Software Foundation, Inc. This file is part of GCC. @@ -81,6 +81,10 @@ gfc_constructor *gfc_constructor_first ( Returns NULL if there is no next expression. */ gfc_constructor *gfc_constructor_next (gfc_constructor *ctor); -gfc_constructor *gfc_constructor_advance (gfc_constructor *ctor, int n); +/* Remove the gfc_constructor node from the splay tree. */ +void gfc_constructor_remove (gfc_constructor *); + +/* Return first constructor node after offset. */ +gfc_constructor *gfc_constructor_lookup_next (gfc_constructor_base, int); #endif /* GFC_CONSTRUCTOR_H */ --- gcc/fortran/data.c.jj 2011-05-02 18:39:17.000000000 +0200 +++ gcc/fortran/data.c 2011-06-29 18:28:24.000000000 +0200 @@ -1,5 +1,5 @@ /* Supporting functions for resolving DATA statement. - Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 + Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc. Contributed by Lifang Zeng <zlf...@hotmail.com> @@ -189,10 +189,13 @@ create_character_initializer (gfc_expr * /* Assign the initial value RVALUE to LVALUE's symbol->value. If the LVALUE already has an initialization, we extend this, otherwise we - create a new one. */ + create a new one. If REPEAT is non-NULL, initialize *REPEAT + consecutive values in LVALUE the same value in RVALUE. In that case, + LVALUE must refer to a full array, not an array section. */ gfc_try -gfc_assign_data_value (gfc_expr *lvalue, gfc_expr *rvalue, mpz_t index) +gfc_assign_data_value (gfc_expr *lvalue, gfc_expr *rvalue, mpz_t index, + mpz_t *repeat) { gfc_ref *ref; gfc_expr *init; @@ -269,6 +272,100 @@ gfc_assign_data_value (gfc_expr *lvalue, &lvalue->where); goto abort; } + else if (repeat != NULL + && ref->u.ar.type != AR_ELEMENT) + { + mpz_t size, end; + gcc_assert (ref->u.ar.type == AR_FULL + && ref->next == NULL); + mpz_init_set (end, offset); + mpz_add (end, end, *repeat); + if (spec_size (ref->u.ar.as, &size) == SUCCESS) + { + if (mpz_cmp (end, size) > 0) + { + mpz_clear (size); + gfc_error ("Data element above array upper bound at %L", + &lvalue->where); + goto abort; + } + mpz_clear (size); + } + + con = gfc_constructor_lookup (expr->value.constructor, + mpz_get_si (offset)); + if (!con) + { + con = gfc_constructor_lookup_next (expr->value.constructor, + mpz_get_si (offset)); + if (con != NULL && mpz_cmp (con->offset, end) >= 0) + con = NULL; + } + + /* Overwriting an existing initializer is non-standard but + usually only provokes a warning from other compilers. */ + if (con != NULL && con->expr != NULL) + { + /* Order in which the expressions arrive here depends on + whether they are from data statements or F95 style + declarations. Therefore, check which is the most + recent. */ + gfc_expr *exprd; + exprd = (LOCATION_LINE (con->expr->where.lb->location) + > LOCATION_LINE (rvalue->where.lb->location)) + ? con->expr : rvalue; + if (gfc_notify_std (GFC_STD_GNU,"Extension: " + "re-initialization of '%s' at %L", + symbol->name, &exprd->where) == FAILURE) + return FAILURE; + } + + while (con != NULL) + { + gfc_constructor *next_con = gfc_constructor_next (con); + + if (mpz_cmp (con->offset, end) >= 0) + break; + if (mpz_cmp (con->offset, offset) < 0) + { + gcc_assert (mpz_cmp_si (con->repeat, 1) > 0); + mpz_sub (con->repeat, offset, con->offset); + } + else if (mpz_cmp_si (con->repeat, 1) > 0 + && mpz_get_si (con->offset) + + mpz_get_si (con->repeat) > mpz_get_si (end)) + { + int endi; + splay_tree_node node + = splay_tree_lookup (con->base, + mpz_get_si (con->offset)); + gcc_assert (node + && con == (gfc_constructor *) node->value + && node->key == (splay_tree_key) + mpz_get_si (con->offset)); + endi = mpz_get_si (con->offset) + + mpz_get_si (con->repeat); + if (endi > mpz_get_si (end) + 1) + mpz_set_si (con->repeat, endi - mpz_get_si (end)); + else + mpz_set_si (con->repeat, 1); + mpz_set (con->offset, end); + node->key = (splay_tree_key) mpz_get_si (end); + break; + } + else + gfc_constructor_remove (con); + con = next_con; + } + + con = gfc_constructor_insert_expr (&expr->value.constructor, + NULL, &rvalue->where, + mpz_get_si (offset)); + mpz_set (con->repeat, *repeat); + repeat = NULL; + mpz_clear (end); + break; + } else { mpz_t size; @@ -293,6 +390,32 @@ gfc_assign_data_value (gfc_expr *lvalue, NULL, &rvalue->where, mpz_get_si (offset)); } + else if (mpz_cmp_si (con->repeat, 1) > 0) + { + /* Need to split a range. */ + if (mpz_cmp (con->offset, offset) < 0) + { + gfc_constructor *pred_con = con; + con = gfc_constructor_insert_expr (&expr->value.constructor, + NULL, &con->where, + mpz_get_si (offset)); + con->expr = gfc_copy_expr (pred_con->expr); + mpz_add (con->repeat, pred_con->offset, pred_con->repeat); + mpz_sub (con->repeat, con->repeat, offset); + mpz_sub (pred_con->repeat, offset, pred_con->offset); + } + if (mpz_cmp_si (con->repeat, 1) > 0) + { + gfc_constructor *succ_con; + succ_con + = gfc_constructor_insert_expr (&expr->value.constructor, + NULL, &con->where, + mpz_get_si (offset) + 1); + succ_con->expr = gfc_copy_expr (con->expr); + mpz_sub_ui (succ_con->repeat, con->repeat, 1); + mpz_set_si (con->repeat, 1); + } + } break; case REF_COMPONENT: @@ -337,6 +460,7 @@ gfc_assign_data_value (gfc_expr *lvalue, } mpz_clear (offset); + gcc_assert (repeat == NULL); if (ref || last_ts->type == BT_CHARACTER) { @@ -380,36 +504,6 @@ abort: } -/* Similarly, but initialize REPEAT consecutive values in LVALUE the same - value in RVALUE. */ - -gfc_try -gfc_assign_data_value_range (gfc_expr *lvalue, gfc_expr *rvalue, - mpz_t index, mpz_t repeat) -{ - mpz_t offset, last_offset; - gfc_try t; - - mpz_init (offset); - mpz_init (last_offset); - mpz_add (last_offset, index, repeat); - - t = SUCCESS; - for (mpz_set(offset, index) ; mpz_cmp(offset, last_offset) < 0; - mpz_add_ui (offset, offset, 1)) - if (gfc_assign_data_value (lvalue, rvalue, offset) == FAILURE) - { - t = FAILURE; - break; - } - - mpz_clear (offset); - mpz_clear (last_offset); - - return t; -} - - /* Modify the index of array section and re-calculate the array offset. */ void --- gcc/fortran/resolve.c.jj 2011-06-21 16:45:54.000000000 +0200 +++ gcc/fortran/resolve.c 2011-06-29 11:52:20.000000000 +0200 @@ -12752,8 +12752,8 @@ check_data_variable (gfc_data_variable * mpz_set_ui (size, 0); } - t = gfc_assign_data_value_range (var->expr, values.vnode->expr, - offset, range); + t = gfc_assign_data_value (var->expr, values.vnode->expr, + offset, &range); mpz_add (offset, offset, range); mpz_clear (range); @@ -12768,7 +12768,8 @@ check_data_variable (gfc_data_variable * mpz_sub_ui (values.left, values.left, 1); mpz_sub_ui (size, size, 1); - t = gfc_assign_data_value (var->expr, values.vnode->expr, offset); + t = gfc_assign_data_value (var->expr, values.vnode->expr, + offset, NULL); if (t == FAILURE) break; --- gcc/testsuite/gfortran.dg/pr49540-1.f90.jj 2011-06-29 18:35:36.000000000 +0200 +++ gcc/testsuite/gfortran.dg/pr49540-1.f90 2011-06-29 17:08:57.000000000 +0200 @@ -0,0 +1,6 @@ +! PR fortran/49540 +! { dg-do compile } +block data + common /a/ b(100000,100) + data b /10000000 * 0.0/ +end block data --- gcc/testsuite/gfortran.dg/pr49540-2.f90.jj 2011-06-29 18:35:48.000000000 +0200 +++ gcc/testsuite/gfortran.dg/pr49540-2.f90 2011-06-29 18:36:43.000000000 +0200 @@ -0,0 +1,17 @@ +! PR fortran/49540 +! { dg-do compile } +! { dg-options "" } +block data + common /a/ i(5,5) + data i /4, 23 * 5, 6/ + data i(:,2) /1, 3 * 2, 3/ + common /b/ j(5,5) + data j(2,:) /1, 3 * 2, 3/ + data j /4, 23 * 5, 6/ + common /c/ k(5,5) + data k(:,2) /1, 3 * 2, 3/ + data k /4, 23 * 5, 6/ + common /d/ l(5,5) + data l /4, 23 * 5, 6/ + data l(2,:) /1, 3 * 2, 3/ +end block data Jakub