gfc_trans_create_temp_arrays has been using loop bounds to set array
temporary bounds; this is a sensible thing to do as gfc_conv_loop_setup
tries to set loop bounds according to the most information (especially w.r.t. 
constantness) it can find.

For plain arrays like `a(:,:)' or `b(:,1,:)', it's quite simple, as there is
a direct maping between loop bounds and temporary bounds.

Now, if we are creating a temporary for the argument of `transpose(a(:,1,1,:))'
we have to be careful as the loop has a direct mapping to
`transpose(a(:,1,1:))', while the temporary has a direct mapping to
`a(:,1,1,:)'. It is currently done (in get_array_ref_dim) by looking at the dim
array which is in the case above: {3,0}. If we want to know the bounds of the
first dimension (or zero'th as it is zero-based) of the temporary, we see that
dim[0] == 3, and that there is one element in dim that is below 3. Thus bounds
are to be taken from dimension number one (the second as it is zero-based)
of the loop.
The same function is used to retrieve the shape dimension from the loop
dimension in gfc_conv_loop_setup.

Now, let's throw sum in the mix. Now we have to generate bounds properly
when generating a temporary either for the inner or outer arrays in the
following cases: 
  sum(a(:,1,1,:), dim=1)
  transpose(sum(a(:,1,:,:), dim=1))
  sum(transpose(a(:,1,1,:)), dim=1)
For the outer array, in all cases, the current implementation can be kept as is,
as the inner loop can be completely ignored.
For the inner array, however, we have to take care of the current loop, and all
the parents ones it is in, so this patch adds a walk towards the outer array. 

With this change, the function can't be used as is anymore in
gfc_conv_loop_setup, as it is ignoring nested loops: we have to start from the
most nested array slice before calling the function. This patch also does that.

OK?
2011-10-19  Mikael Morin  <mik...@gcc.gnu.org>

        * trans-array.c (get_array_ref_dim, get_scalarizer_dim_for_array_dim): 
        Rename the former to the latter and loop over the parents.
        (innermost_ss): New function.
        (get_array_ref_dim_for_loop_dim): New function.
        (gfc_trans_create_temp_array): Use get_scalarizer_dim_for_array_dim.
        (set_loop_bounds): Use get_array_dim_for_loop_dim).
diff --git a/trans-array.c b/trans-array.c
index 25d9a37..d918fa8 100644
--- a/trans-array.c
+++ b/trans-array.c
@@ -868,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
@@ -959,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];
 
@@ -1011,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.  */
@@ -4126,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);

Reply via email to