OSDN Git Service

* trans-array.c (get_array_ref_dim, get_scalarizer_dim_for_array_dim):
[pf3gnuchains/gcc-fork.git] / gcc / fortran / trans-array.c
index d386a22..d918fa8 100644 (file)
@@ -688,41 +688,54 @@ void
 gfc_set_loop_bounds_from_array_spec (gfc_interface_mapping * mapping,
                                     gfc_se * se, gfc_array_spec * as)
 {
-  int n, dim;
+  int n, dim, total_dim;
   gfc_se tmpse;
+  gfc_ss *ss;
   tree lower;
   tree upper;
   tree tmp;
 
-  if (as && as->type == AS_EXPLICIT)
-    for (n = 0; n < se->loop->dimen; n++)
-      {
-       dim = se->ss->dim[n];
-       gcc_assert (dim < as->rank);
-       gcc_assert (se->loop->dimen == as->rank);
-       if (se->loop->to[n] == NULL_TREE)
-         {
-           /* Evaluate the lower bound.  */
-           gfc_init_se (&tmpse, NULL);
-           gfc_apply_interface_mapping (mapping, &tmpse, as->lower[dim]);
-           gfc_add_block_to_block (&se->pre, &tmpse.pre);
-           gfc_add_block_to_block (&se->post, &tmpse.post);
-           lower = fold_convert (gfc_array_index_type, tmpse.expr);
-
-           /* ...and the upper bound.  */
-           gfc_init_se (&tmpse, NULL);
-           gfc_apply_interface_mapping (mapping, &tmpse, as->upper[dim]);
-           gfc_add_block_to_block (&se->pre, &tmpse.pre);
-           gfc_add_block_to_block (&se->post, &tmpse.post);
-           upper = fold_convert (gfc_array_index_type, tmpse.expr);
-
-           /* Set the upper bound of the loop to UPPER - LOWER.  */
-           tmp = fold_build2_loc (input_location, MINUS_EXPR,
-                                  gfc_array_index_type, upper, lower);
-           tmp = gfc_evaluate_now (tmp, &se->pre);
-           se->loop->to[n] = tmp;
-         }
-      }
+  total_dim = 0;
+
+  if (!as || as->type != AS_EXPLICIT)
+    return;
+
+  for (ss = se->ss; ss; ss = ss->parent)
+    {
+      total_dim += ss->loop->dimen;
+      for (n = 0; n < ss->loop->dimen; n++)
+       {
+         /* The bound is known, nothing to do.  */
+         if (ss->loop->to[n] != NULL_TREE)
+           continue;
+
+         dim = ss->dim[n];
+         gcc_assert (dim < as->rank);
+         gcc_assert (ss->loop->dimen <= as->rank);
+
+         /* Evaluate the lower bound.  */
+         gfc_init_se (&tmpse, NULL);
+         gfc_apply_interface_mapping (mapping, &tmpse, as->lower[dim]);
+         gfc_add_block_to_block (&se->pre, &tmpse.pre);
+         gfc_add_block_to_block (&se->post, &tmpse.post);
+         lower = fold_convert (gfc_array_index_type, tmpse.expr);
+
+         /* ...and the upper bound.  */
+         gfc_init_se (&tmpse, NULL);
+         gfc_apply_interface_mapping (mapping, &tmpse, as->upper[dim]);
+         gfc_add_block_to_block (&se->pre, &tmpse.pre);
+         gfc_add_block_to_block (&se->post, &tmpse.post);
+         upper = fold_convert (gfc_array_index_type, tmpse.expr);
+
+         /* Set the upper bound of the loop to UPPER - LOWER.  */
+         tmp = fold_build2_loc (input_location, MINUS_EXPR,
+                                gfc_array_index_type, upper, lower);
+         tmp = gfc_evaluate_now (tmp, &se->pre);
+         ss->loop->to[n] = tmp;
+       }
+    }
+
+  gcc_assert (total_dim == as->rank);
 }
 
 
@@ -855,28 +868,62 @@ gfc_trans_allocate_array_storage (stmtblock_t * pre, stmtblock_t * post,
 }
 
 
-/* Get the array reference dimension corresponding to the given loop dimension.
-   It is different from the true array dimension given by the dim array in
-   the case of a partial array reference
-   It is different from the loop dimension in the case of a transposed array.
-   */
+/* Get the scalarizer array dimension corresponding to actual array dimension
+   given by ARRAY_DIM.
+
+   For example, if SS represents the array ref a(1,:,:,1), it is a
+   bidimensional scalarizer array, and the result would be 0 for ARRAY_DIM=1,
+   and 1 for ARRAY_DIM=2.
+   If SS represents transpose(a(:,1,1,:)), it is again a bidimensional
+   scalarizer array, and the result would be 1 for ARRAY_DIM=0 and 0 for
+   ARRAY_DIM=3.
+   If SS represents sum(a(:,:,:,1), dim=1), it is a 2+1-dimensional scalarizer
+   array.  If called on the inner ss, the result would be respectively 0,1,2 for
+   ARRAY_DIM=0,1,2.  If called on the outer ss, the result would be 0,1
+   for ARRAY_DIM=1,2.  */
 
 static int
-get_array_ref_dim (gfc_ss *ss, int loop_dim)
+get_scalarizer_dim_for_array_dim (gfc_ss *ss, int array_dim)
 {
-  int n, array_dim, array_ref_dim;
+  int array_ref_dim;
+  int n;
 
   array_ref_dim = 0;
-  array_dim = ss->dim[loop_dim];
 
-  for (n = 0; n < ss->dimen; n++)
-    if (ss->dim[n] < array_dim)
-      array_ref_dim++;
+  for (; ss; ss = ss->parent)
+    for (n = 0; n < ss->dimen; n++)
+      if (ss->dim[n] < array_dim)
+       array_ref_dim++;
 
   return array_ref_dim;
 }
 
 
+static gfc_ss *
+innermost_ss (gfc_ss *ss)
+{
+  while (ss->nested_ss != NULL)
+    ss = ss->nested_ss;
+
+  return ss;
+}
+
+
+
+/* Get the array reference dimension corresponding to the given loop dimension.
+   It is different from the true array dimension given by the dim array in
+   the case of a partial array reference (i.e. a(:,:,1,:) for example)
+   It is different from the loop dimension in the case of a transposed array.
+   */
+
+static int
+get_array_ref_dim_for_loop_dim (gfc_ss *ss, int loop_dim)
+{
+  return get_scalarizer_dim_for_array_dim (innermost_ss (ss),
+                                          ss->dim[loop_dim]);
+}
+
+
 /* Generate code to create and initialize the descriptor for a temporary
    array.  This is used for both temporaries needed by the scalarizer, and
    functions returning arrays.  Adjusts the loop variables to be
@@ -946,7 +993,7 @@ gfc_trans_create_temp_array (stmtblock_t * pre, stmtblock_t * post, gfc_ss * ss,
         to the n'th dimension of the array. We need to reconstruct loop infos
         in the right order before using it to set the descriptor
         bounds.  */
-      tmp_dim = get_array_ref_dim (ss, n);
+      tmp_dim = get_scalarizer_dim_for_array_dim (ss, dim);
       from[tmp_dim] = loop->from[n];
       to[tmp_dim] = loop->to[n];
 
@@ -998,7 +1045,7 @@ gfc_trans_create_temp_array (stmtblock_t * pre, stmtblock_t * post, gfc_ss * ss,
     {
       for (n = 0; n < loop->dimen; n++)
        {
-         dim = ss->dim[n];
+         dim = get_scalarizer_dim_for_array_dim (ss, ss->dim[n]);
 
          /* For a callee allocated array express the loop bounds in terms
             of the descriptor fields.  */
@@ -1940,6 +1987,7 @@ trans_constant_array_constructor (gfc_ss * ss, tree type)
     }
 }
 
+
 /* Helper routine of gfc_trans_array_constructor to determine if the
    bounds of the loop specified by LOOP are constant and simple enough
    to use with trans_constant_array_constructor.  Returns the
@@ -1997,6 +2045,7 @@ trans_array_constructor (gfc_ss * ss, locus * where)
   gfc_loopinfo *loop;
   gfc_ss_info *ss_info;
   gfc_expr *expr;
+  gfc_ss *s;
 
   /* Save the old values for nested checking.  */
   old_first_len = first_len;
@@ -2065,16 +2114,20 @@ trans_array_constructor (gfc_ss * ss, locus * where)
   if (expr->shape && loop->dimen > 1 && loop->to[0] == NULL_TREE)
     {
       /* We have a multidimensional parameter.  */
-      int n;
-      for (n = 0; n < expr->rank; n++)
-      {
-       loop->from[n] = gfc_index_zero_node;
-       loop->to[n] = gfc_conv_mpz_to_tree (expr->shape [n],
-                                           gfc_index_integer_kind);
-       loop->to[n] = fold_build2_loc (input_location, MINUS_EXPR,
-                                      gfc_array_index_type,
-                                      loop->to[n], gfc_index_one_node);
-      }
+      for (s = ss; s; s = s->parent)
+       {
+         int n;
+         for (n = 0; n < s->loop->dimen; n++)
+           {
+             s->loop->from[n] = gfc_index_zero_node;
+             s->loop->to[n] = gfc_conv_mpz_to_tree (expr->shape[s->dim[n]],
+                                                    gfc_index_integer_kind);
+             s->loop->to[n] = fold_build2_loc (input_location, MINUS_EXPR,
+                                               gfc_array_index_type,
+                                               s->loop->to[n],
+                                               gfc_index_one_node);
+           }
+       }
     }
 
   if (loop->to[0] == NULL_TREE)
@@ -2178,14 +2231,18 @@ set_vector_loop_bounds (gfc_ss * ss)
   int dim;
 
   info = &ss->info->data.array;
-  loop = ss->loop;
 
-  for (n = 0; n < loop->dimen; n++)
+  for (; ss; ss = ss->parent)
     {
-      dim = ss->dim[n];
-      if (info->ref->u.ar.dimen_type[dim] == DIMEN_VECTOR
-         && loop->to[n] == NULL)
+      loop = ss->loop;
+
+      for (n = 0; n < loop->dimen; n++)
        {
+         dim = ss->dim[n];
+         if (info->ref->u.ar.dimen_type[dim] != DIMEN_VECTOR
+             || loop->to[n] != NULL)
+           continue;
+
          /* Loop variable N indexes vector dimension DIM, and we don't
             yet know the upper bound of loop variable N.  Set it to the
             difference between the vector's upper and lower bounds.  */
@@ -3193,7 +3250,8 @@ gfc_trans_scalarizing_loops (gfc_loopinfo * loop, stmtblock_t * body)
 
   /* Clear all the used flags.  */
   for (ss = loop->ss; ss != gfc_ss_terminator; ss = ss->loop_chain)
-    ss->info->useflags = 0;
+    if (ss->parent == NULL)
+      ss->info->useflags = 0;
 }
 
 
@@ -4102,7 +4160,7 @@ set_loop_bounds (gfc_loopinfo *loop)
          && INTEGER_CST_P (info->stride[dim]))
        {
          loop->from[n] = info->start[dim];
-         mpz_set (i, cshape[get_array_ref_dim (loopspec[n], n)]);
+         mpz_set (i, cshape[get_array_ref_dim_for_loop_dim (loopspec[n], n)]);
          mpz_sub_ui (i, i, 1);
          /* To = from + (size - 1) * stride.  */
          tmp = gfc_conv_mpz_to_tree (i, gfc_index_integer_kind);