re PR fortran/13465 (Data statement for large arrays compiles verrrry slllowwwly...
authorRichard Henderson <rth@redhat.com>
Mon, 23 Aug 2004 21:53:14 +0000 (14:53 -0700)
committerRichard Henderson <rth@gcc.gnu.org>
Mon, 23 Aug 2004 21:53:14 +0000 (14:53 -0700)
        PR 13465
        * data.c (find_con_by_offset): Search ordered list; handle
        elements with repeat counts.
        (gfc_assign_data_value_range): New.
        * gfortran.h (struct gfc_data_value): Make repeat unsigned.
        (gfc_assign_data_value_range): Declare.
        * match.c (top_val_list): Extract repeat count into a temporary.
        * resolve.c (values): Make left unsigned.
        (next_data_value): Don't decrement left.
        (check_data_variable): Use gfc_assign_data_value_range.

From-SVN: r86443

gcc/fortran/ChangeLog
gcc/fortran/data.c
gcc/fortran/gfortran.h
gcc/fortran/match.c
gcc/fortran/resolve.c

index 623a8d0916b2d1a01d3f58256c4cb2c4a21156e5..a7535db9cce236eab5b97839dbea64c5712e0287 100644 (file)
@@ -1,3 +1,16 @@
+2004-08-22  Richard Henderson  <rth@redhat.com>
+
+       PR 13465
+        * data.c (find_con_by_offset): Search ordered list; handle
+        elements with repeat counts.
+        (gfc_assign_data_value_range): New.
+        * gfortran.h (struct gfc_data_value): Make repeat unsigned.
+        (gfc_assign_data_value_range): Declare.
+        * match.c (top_val_list): Extract repeat count into a temporary.
+        * resolve.c (values): Make left unsigned.
+        (next_data_value): Don't decrement left.
+        (check_data_variable): Use gfc_assign_data_value_range.
+
 2004-08-22  Tobias Schlueter  <tobias.schlueter@physik.uni-muenchen.de>
 
        * trans-const.c, trans-decl.c, trans-expr.c: Spelling fixes.
index 4ebacd345789481873107298f69934c9e3fa652d..2999af2a8607877aa15ed3442586b0b6bab1c75f 100644 (file)
@@ -82,12 +82,40 @@ get_array_index (gfc_array_ref * ar, mpz_t * offset)
 static gfc_constructor *
 find_con_by_offset (mpz_t offset, gfc_constructor *con)
 {
+  mpz_t tmp;
+  gfc_constructor *ret = NULL;
+
+  mpz_init (tmp);
+
   for (; con; con = con->next)
     {
-      if (mpz_cmp (offset, con->n.offset) == 0)
-        return con;
+      int cmp = mpz_cmp (offset, con->n.offset);
+
+      /* We retain a sorted list, so if we're too large, we're done.  */
+      if (cmp < 0)
+       break;
+
+      /* Yaye for exact matches.  */
+      if (cmp == 0)
+       {
+          ret = con;
+         break;
+       }
+
+      /* If the constructor element is a range, match any element.  */
+      if (mpz_cmp_ui (con->repeat, 1) > 0)
+       {
+         mpz_add (tmp, con->n.offset, con->repeat);
+         if (mpz_cmp (offset, tmp) < 0)
+           {
+             ret = con;
+             break;
+           }
+       }
     }
-  return NULL;
+
+  mpz_clear (tmp);
+  return ret;
 }
 
 
@@ -236,7 +264,7 @@ gfc_assign_data_value (gfc_expr * lvalue, gfc_expr * rvalue, mpz_t index)
          if (con == NULL)
            {
              /* Create a new constructor.  */
-             con = gfc_get_constructor();
+             con = gfc_get_constructor ();
              mpz_set (con->n.offset, offset);
              gfc_insert_constructor (expr, con);
            }
@@ -272,7 +300,6 @@ gfc_assign_data_value (gfc_expr * lvalue, gfc_expr * rvalue, mpz_t index)
          abort ();
        }
 
-      
       if (init == NULL)
        {
          /* Point the container at the new expression.  */
@@ -295,7 +322,6 @@ gfc_assign_data_value (gfc_expr * lvalue, gfc_expr * rvalue, mpz_t index)
       expr = gfc_copy_expr (rvalue);
       if (!gfc_compare_types (&lvalue->ts, &expr->ts))
        gfc_convert_type (expr, &lvalue->ts, 0);
-
     }
 
   if (last_con == NULL)
@@ -304,6 +330,148 @@ gfc_assign_data_value (gfc_expr * lvalue, gfc_expr * rvalue, mpz_t index)
     last_con->expr = expr;
 }
 
+/* Similarly, but initialize REPEAT consectutive values in LVALUE the same
+   value in RVALUE.  For the nonce, LVALUE must refer to a full array, not
+   an array section.  */
+
+void
+gfc_assign_data_value_range (gfc_expr * lvalue, gfc_expr * rvalue,
+                            mpz_t index, mpz_t repeat)
+{
+  gfc_ref *ref;
+  gfc_expr *init, *expr;
+  gfc_constructor *con, *last_con;
+  gfc_symbol *symbol;
+  gfc_typespec *last_ts;
+  mpz_t offset;
+
+  symbol = lvalue->symtree->n.sym;
+  init = symbol->value;
+  last_ts = &symbol->ts;
+  last_con = NULL;
+  mpz_init_set_si (offset, 0);
+
+  /* Find/create the parent expressions for subobject references.  */
+  for (ref = lvalue->ref; ref; ref = ref->next)
+    {
+      /* Use the existing initializer expression if it exists.
+        Otherwise create a new one.  */
+      if (init == NULL)
+       expr = gfc_get_expr ();
+      else
+       expr = init;
+
+      /* Find or create this element.  */
+      switch (ref->type)
+       {
+       case REF_ARRAY:
+         if (init == NULL)
+           {
+             /* The element typespec will be the same as the array
+                typespec.  */
+             expr->ts = *last_ts;
+             /* Setup the expression to hold the constructor.  */
+             expr->expr_type = EXPR_ARRAY;
+             expr->rank = ref->u.ar.as->rank;
+           }
+         else
+           assert (expr->expr_type == EXPR_ARRAY);
+
+         if (ref->u.ar.type == AR_ELEMENT)
+           {
+             get_array_index (&ref->u.ar, &offset);
+
+             /* This had better not be the bottom of the reference.
+                We can still get to a full array via a component.  */
+             assert (ref->next != NULL);
+           }
+         else
+           {
+             mpz_set (offset, index);
+
+             /* We're at a full array or an array section.  This means
+                that we've better have found a full array, and that we're
+                at the bottom of the reference.  */
+             assert (ref->u.ar.type == AR_FULL);
+             assert (ref->next == NULL);
+           }
+
+         /* Find the same element in the existing constructor.  */
+         con = expr->value.constructor;
+         con = find_con_by_offset (offset, con);
+
+         /* Create a new constructor.  */
+         if (con == NULL)
+           {
+             con = gfc_get_constructor ();
+             mpz_set (con->n.offset, offset);
+             if (ref->next == NULL)
+               mpz_set (con->repeat, repeat);
+             gfc_insert_constructor (expr, con);
+           }
+         else
+           assert (ref->next != NULL);
+         break;
+
+       case REF_COMPONENT:
+         if (init == NULL)
+           {
+             /* Setup the expression to hold the constructor.  */
+             expr->expr_type = EXPR_STRUCTURE;
+             expr->ts.type = BT_DERIVED;
+             expr->ts.derived = ref->u.c.sym;
+           }
+         else
+           assert (expr->expr_type == EXPR_STRUCTURE);
+         last_ts = &ref->u.c.component->ts;
+
+         /* Find the same element in the existing constructor.  */
+         con = expr->value.constructor;
+         con = find_con_by_component (ref->u.c.component, con);
+
+         if (con == NULL)
+           {
+             /* Create a new constructor.  */
+             con = gfc_get_constructor ();
+             con->n.component = ref->u.c.component;
+             con->next = expr->value.constructor;
+             expr->value.constructor = con;
+           }
+
+         /* Since we're only intending to initialize arrays here,
+            there better be an inner reference.  */
+         assert (ref->next != NULL);
+         break;
+
+       case REF_SUBSTRING:
+       default:
+         abort ();
+       }
+
+      if (init == NULL)
+       {
+         /* Point the container at the new expression.  */
+         if (last_con == NULL)
+           symbol->value = expr;
+         else
+           last_con->expr = expr;
+       }
+      init = con->expr;
+      last_con = con;
+    }
+
+  /* We should never be overwriting an existing initializer.  */
+  assert (!init);
+
+  expr = gfc_copy_expr (rvalue);
+  if (!gfc_compare_types (&lvalue->ts, &expr->ts))
+    gfc_convert_type (expr, &lvalue->ts, 0);
+
+  if (last_con == NULL)
+    symbol->value = expr;
+  else
+    last_con->expr = expr;
+}
 
 /* Modify the index of array section and re-calculate the array offset.  */
 
index 697f662bc1a338cc416e7f0300ae274f9430c028..e33a0aac7108c8c1f890fcbf490b8ed4010fd4a4 100644 (file)
@@ -1304,9 +1304,8 @@ gfc_data_variable;
 
 typedef struct gfc_data_value
 {
-  int repeat;
+  unsigned int repeat;
   gfc_expr *expr;
-
   struct gfc_data_value *next;
 }
 gfc_data_value;
@@ -1402,6 +1401,7 @@ extern iterator_stack *iter_stack;
 void gfc_formalize_init_value (gfc_symbol *);
 void gfc_get_section_index (gfc_array_ref *, mpz_t *, mpz_t *);
 void gfc_assign_data_value (gfc_expr *, gfc_expr *, mpz_t);
+void gfc_assign_data_value_range (gfc_expr *, gfc_expr *, mpz_t, mpz_t);
 void gfc_advance_section (mpz_t *, gfc_array_ref *, mpz_t *);
 
 /* scanner.c */
index 65af46ad779fff9cd7fbbf8efa052b25e7f800db..a42fd7f66ab2e1011821ed7ce760fb8deab50d89 100644 (file)
@@ -2894,13 +2894,15 @@ top_val_list (gfc_data * data)
        }
       else
        {
-         msg = gfc_extract_int (expr, &tail->repeat);
+         signed int tmp;
+         msg = gfc_extract_int (expr, &tmp);
          gfc_free_expr (expr);
          if (msg != NULL)
            {
              gfc_error (msg);
              return MATCH_ERROR;
            }
+         tail->repeat = tmp;
 
          m = match_data_constant (&tail->expr);
          if (m == MATCH_NO)
index 1dc4db8a35d7b4e480c2e866b41519854160f8d8..dfca4abff013a611d10b5920bbe5967644517f4d 100644 (file)
@@ -4037,7 +4037,7 @@ resolve_symbol (gfc_symbol * sym)
 static struct
 {
   gfc_data_value *vnode;
-  int left;
+  unsigned int left;
 }
 values;
 
@@ -4047,7 +4047,6 @@ values;
 static try
 next_data_value (void)
 {
-
   while (values.left == 0)
     {
       if (values.vnode->next == NULL)
@@ -4057,7 +4056,6 @@ next_data_value (void)
       values.left = values.vnode->repeat;
     }
 
-  values.left--;
   return SUCCESS;
 }
 
@@ -4086,7 +4084,10 @@ check_data_variable (gfc_data_variable * var, locus * where)
     gfc_internal_error ("check_data_variable(): Bad expression");
 
   if (e->rank == 0)
-    mpz_init_set_ui (size, 1);
+    {
+      mpz_init_set_ui (size, 1);
+      ref = NULL;
+    }
   else
     {
       ref = e->ref;
@@ -4145,19 +4146,54 @@ check_data_variable (gfc_data_variable * var, locus * where)
       if (t == FAILURE)
        break;
 
+      /* If we have more than one element left in the repeat count,
+        and we have more than one element left in the target variable,
+        then create a range assignment.  */
+      /* ??? Only done for full arrays for now, since array sections
+        seem tricky.  */
+      if (mark == AR_FULL && ref && ref->next == NULL
+         && values.left > 1 && mpz_cmp_ui (size, 1) > 0)
+       {
+         mpz_t range;
+
+         if (mpz_cmp_ui (size, values.left) >= 0)
+           {
+             mpz_init_set_ui (range, values.left);
+             mpz_sub_ui (size, size, values.left);
+             values.left = 0;
+           }
+         else
+           {
+             mpz_init_set (range, size);
+             values.left -= mpz_get_ui (size);
+             mpz_set_ui (size, 0);
+           }
+
+         gfc_assign_data_value_range (var->expr, values.vnode->expr,
+                                      offset, range);
+
+         mpz_add (offset, offset, range);
+         mpz_clear (range);
+       }
+
       /* Assign initial value to symbol.  */
-      gfc_assign_data_value (var->expr, values.vnode->expr, offset);
+      else
+       {
+         values.left -= 1;
+         mpz_sub_ui (size, size, 1);
 
-      if (mark == AR_FULL)
-        mpz_add_ui (offset, offset, 1);
+         gfc_assign_data_value (var->expr, values.vnode->expr, offset);
 
-      /* Modify the array section indexes and recalculate the offset for
-         next element.  */
-      else if (mark == AR_SECTION)
-        gfc_advance_section (section_index, ar, &offset);
+         if (mark == AR_FULL)
+           mpz_add_ui (offset, offset, 1);
 
-      mpz_sub_ui (size, size, 1);
+         /* Modify the array section indexes and recalculate the offset
+            for next element.  */
+         else if (mark == AR_SECTION)
+           gfc_advance_section (section_index, ar, &offset);
+       }
     }
+
   if (mark == AR_SECTION)
     {
       for (i = 0; i < ar->dimen; i++)
@@ -4253,7 +4289,6 @@ traverse_data_var (gfc_data_variable * var, locus * where)
 static try
 resolve_data_variables (gfc_data_variable * d)
 {
-
   for (; d; d = d->next)
     {
       if (d->list == NULL)
@@ -4287,7 +4322,6 @@ resolve_data_variables (gfc_data_variable * d)
 static void
 resolve_data (gfc_data * d)
 {
-
   if (resolve_data_variables (d->var) == FAILURE)
     return;
 
@@ -4312,7 +4346,6 @@ resolve_data (gfc_data * d)
 int
 gfc_impure_variable (gfc_symbol * sym)
 {
-
   if (sym->attr.use_assoc || sym->attr.in_common)
     return 1;
 
@@ -4606,4 +4639,3 @@ gfc_resolve (gfc_namespace * ns)
 
   gfc_current_ns = old_ns;
 }
-