]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
fortran: calculate elements of a subarray using a provided stride value
authorChristoph Weinmann <christoph.t.weinmann@intel.com>
Wed, 17 Aug 2016 14:05:37 +0000 (16:05 +0200)
committerBernhard Heckel <bernhard.heckel@intel.com>
Wed, 7 Sep 2016 10:08:48 +0000 (12:08 +0200)
The stride value can be a positive or negative integer, but may
not be zero.  If no stride is provided, use the default value
1 to print all elements inside the range.

1| program prog
2|   integer :: ary(10) = (/ (i, i=1, 10) /)
3| end program prog

(gdb) print ary(1:10:2)
$3 = (1, 3, 5, 7, 9)

2013-11-27  Christoph Weinmann  <christoph.t.weinmann>

* eval.c (value_f90_subarray): Add range size calculation
for stride based ranges, and evaluation of user stride
parameters.  Add check for matching user input to array
bounds.
* valops.c (value_slice): Add call parameter with default
stride value for calling value_slice_1.
* valops.c (value_slice_1): Add function parameter for
stride length in the return subarray.  Calculate array
elements based on stride value.
* value.h: Add stride parameter to declaration of
value_slice_1.

Signed-off-by: Christoph Weinmann <christoph.t.weinmann@intel.com>
gdb/eval.c
gdb/valops.c
gdb/value.h

index 3a8c3efe27455256fbbd4ab289a763dc9dc46f94..91d8a039064b1b4772f91e2e87103e69f9789baa 100644 (file)
@@ -477,7 +477,7 @@ value_f90_subarray (struct value *array, struct expression *exp,
          range = &index->U.range;
 
          *pos += 3;
-         range->f90_range_type = (enum range_type) longest_to_int (exp->elts[pc].longconst);
+         range->f90_range_type = (enum range_type) exp->elts[pc].longconst;
 
          /* If a lower bound was provided by the user, the bit has been
             set and we can assign the value from the elt stack.  Same for
@@ -499,6 +499,10 @@ value_f90_subarray (struct value *array, struct expression *exp,
          /* Assign the default stride value '1'.  */
          else
            range->stride = 1;
+
+         /* Check the provided stride value is illegal, aka '0'.  */
+         if (range->stride == 0)
+           error (_("Stride must not be 0"));
        }
       /* User input is an index.  E.g.: "p arry(5)".  */
       else
@@ -515,10 +519,8 @@ value_f90_subarray (struct value *array, struct expression *exp,
 
     }
 
-  /* Traverse the array from right to left and evaluate each corresponding
-     user input.  VALUE_SUBSCRIPT is called for every index, until a range
-     expression is evaluated.  After a range expression has been evaluated,
-     every subsequent expression is also treated as a range.  */
+  /* Traverse the array from right to left and set the high and low bounds
+     for later use.  */
   for (i = nargs - 1; i >= 0; i--)
     {
       struct subscript_store *index = &subscript_array[i];
@@ -551,6 +553,48 @@ value_f90_subarray (struct value *array, struct expression *exp,
                || range->high > TYPE_HIGH_BOUND (index_type))
              error (_("provided bound(s) outside array bound(s)"));
 
+           /* For a negative stride the lower boundary must be larger than the
+              upper boundary.
+              For a positive stride the lower boundary must be smaller than the
+              upper boundary.  */
+           if ((range->stride < 0 && range->low < range->high)
+               || (range->stride > 0 && range->low > range->high))
+             error (_("Wrong value provided for stride and boundaries"));
+
+         }
+         break;
+
+       case SUBSCRIPT_INDEX:
+         break;
+
+       }
+
+       array_type = TYPE_TARGET_TYPE (array_type);
+    }
+
+  /* Reset ARRAY_TYPE before slicing.*/
+  array_type = check_typedef (value_type (new_array));
+
+  /* Traverse the array from right to left and evaluate each corresponding
+     user input.  VALUE_SUBSCRIPT is called for every index, until a range
+     expression is evaluated.  After a range expression has been evaluated,
+     every subsequent expression is also treated as a range.  */
+  for (i = nargs - 1; i >= 0; i--)
+    {
+      struct subscript_store *index = &subscript_array[i];
+      struct type *index_type = TYPE_INDEX_TYPE (array_type);
+
+      switch (index->kind)
+       {
+       case SUBSCRIPT_RANGE:
+         {
+
+           /* When we hit the first range specified by the user, we must
+              treat any subsequent user entry as a range.  We simply
+              increment DIM_COUNT which tells us how many times we are
+              calling VALUE_SLICE_1.  */
+           subscript_range *range = &index->U.range;
+
            /* DIM_COUNT counts every user argument that is treated as a range.
               This is necessary for expressions like 'print array(7, 8:9).
               Here the first argument is a literal, but must be treated as a
@@ -558,10 +602,9 @@ value_f90_subarray (struct value *array, struct expression *exp,
            dim_count++;
 
            new_array
-             = value_slice_1 (new_array,
-                              longest_to_int (range->low),
-                              longest_to_int (range->high - range->low + 1),
-                              dim_count);
+             = value_slice_1 (new_array, range->low,
+                              range->high - range->low + 1,
+                              range->stride, dim_count);
          }
          break;
 
@@ -580,21 +623,32 @@ value_f90_subarray (struct value *array, struct expression *exp,
                                                                  (new_array)));
            else
              {
-               /* Check for valid index input.  */
+               dim_count++;
+
+               /* We might end up here, because we have to treat the provided
+                  index like a range. But now VALUE_SUBSCRIPTED_RVALUE
+                  cannot do the range checks for us. So we have to make sure
+                  ourselves that the user provided index is inside the
+                  array bounds.  Throw an error if not.  */
                if (index->U.number < TYPE_LOW_BOUND (index_type)
-                   || index->U.number > TYPE_HIGH_BOUND (index_type))
-                 error (_("error no such vector element"));
+                   && index->U.number > TYPE_HIGH_BOUND (index_type))
+                 error (_("provided bound(s) outside array bound(s)"));
+
+               if (index->U.number > TYPE_LOW_BOUND (index_type)
+                   && index->U.number > TYPE_HIGH_BOUND (index_type))
+                 error (_("provided bound(s) outside array bound(s)"));
 
-               dim_count++;
                new_array = value_slice_1 (new_array,
-                                          longest_to_int (index->U.number),
-                                          1, /* length is '1' element  */
+                                          index->U.number,
+                                          1, /* COUNT is '1' element  */
+                                          1, /* STRIDE set to '1'  */
                                           dim_count);
              }
 
          }
          break;
        }
+      array_type = TYPE_TARGET_TYPE (array_type);
     }
 
   /* With DIM_COUNT > 1 we currently have a one dimensional array, but expect
@@ -620,7 +674,9 @@ value_f90_subarray (struct value *array, struct expression *exp,
         the output array.  So we traverse the SUBSCRIPT_ARRAY again, looking
         for a range entry.  When we find one, we use the range info to create
         an additional range_type to set the correct bounds and dimensions for
-        the output array.  */
+        the output array.  In addition, we may have a stride value that is not
+        '1', forcing us to adjust the number of elements in a range, according
+        to the stride value.  */
       for (i = 0; i < nargs; i++)
        {
          struct subscript_store *index = &subscript_array[i];
@@ -629,12 +685,20 @@ value_f90_subarray (struct value *array, struct expression *exp,
            {
              struct type *range_type, *interim_array_type;
 
+             int new_length;
+
+             /* The length of a sub-dimension with all elements between the
+                bounds plus the start element itself.  It may be modified by
+                a user provided stride value.  */
+             new_length = index->U.range.high - index->U.range.low;
+
+             new_length /= index->U.range.stride;
+
              range_type
                = create_static_range_type (NULL,
                                            elt_type,
-                                           1,
-                                           index->U.range.high
-                                             - index->U.range.low + 1);
+                                           index->U.range.low,
+                                           index->U.range.low + new_length);
 
              interim_array_type = create_array_type (NULL,
                                                      elt_type,
index 479cf8d644cb18f9165f4b0c84fb8c9448bf36f1..24ffacb9bf3e0759f96bb83b98c1813cc7bdc577 100644 (file)
@@ -3775,10 +3775,13 @@ value_of_this_silent (const struct language_defn *lang)
 struct value *
 value_slice (struct value *array, int lowbound, int length)
 {
-  /* Pass unaltered arguments to VALUE_SLICE_1, plus a CALL_COUNT of '1' as we
-     are only considering the highest dimension, or we are working on a one
-     dimensional array.  So we call VALUE_SLICE_1 exactly once.  */
-  return value_slice_1 (array, lowbound, length, 1);
+  /* Pass unaltered arguments to VALUE_SLICE_1, plus a default stride
+     value of '1', which returns every element between LOWBOUND and
+     (LOWBOUND + LENGTH).  We also provide a default CALL_COUNT of '1'
+     as we are only considering the highest dimension, or we are
+     working on a one dimensional array.  So we call VALUE_SLICE_1
+     exactly once.  */
+  return value_slice_1 (array, lowbound, length, 1, 1);
 }
 
 /* VALUE_SLICE_1 is called for each array dimension to calculate the number
@@ -3794,7 +3797,8 @@ value_slice (struct value *array, int lowbound, int length)
    ranges in the calling function.  */
 
 struct value *
-value_slice_1 (struct value *array, int lowbound, int length, int call_count)
+value_slice_1 (struct value *array, int lowbound, int length,
+              int stride_length, int call_count)
 {
   struct type *slice_range_type, *slice_type, *range_type;
   struct type *array_type = check_typedef (value_type (array));
@@ -3817,14 +3821,24 @@ value_slice_1 (struct value *array, int lowbound, int length, int call_count)
      attributes of the underlying type.  */
   if (call_count > 1)
     {
+      ary_low_bound = TYPE_LOW_BOUND (TYPE_INDEX_TYPE (elt_type));
+      ary_high_bound = TYPE_HIGH_BOUND (TYPE_INDEX_TYPE (elt_type));
       elt_type = check_typedef (TYPE_TARGET_TYPE (elt_type));
       row_count = TYPE_LENGTH (array_type)
                    / TYPE_LENGTH (TYPE_TARGET_TYPE (array_type));
     }
 
-  elem_count = length;
+  /* With a stride of '1', the number of elements per result row is equal to
+     the LENGTH of the subarray.  With non-default stride values, we skip
+     elements, but have to add the start element to the total number of
+     elements per row.  */
+  if (stride_length == 1)
+    elem_count = length;
+  else
+    elem_count = ((length - 1) / stride_length) + 1;
+
   elt_size = TYPE_LENGTH (elt_type);
-  elt_offs = longest_to_int (lowbound - ary_low_bound);
+  elt_offs = lowbound - ary_low_bound;
 
   elt_offs *= elt_size;
 
@@ -3866,8 +3880,9 @@ value_slice_1 (struct value *array, int lowbound, int length, int call_count)
   {
     struct type *element_type;
 
-    /* When CALL_COUNT equals 1 we can use the legacy code for subarrays.  */
-    if (call_count == 1)
+    /* When both CALL_COUNT and STRIDE_LENGTH equal 1, we can use the legacy
+       code for subarrays.  */
+    if (call_count == 1 && stride_length == 1)
       {
        element_type = TYPE_TARGET_TYPE (array_type);
 
@@ -3888,29 +3903,53 @@ value_slice_1 (struct value *array, int lowbound, int length, int call_count)
          }
 
       }
-    /* When CALL_COUNT is larger than 1 we are working on a range of ranges.
-       So we copy the relevant elements into the new array we return.  */
+    /* With a CALL_COUNT or STRIDE_LENGTH are greater than 1 we are working
+       on a range of ranges.  So we copy the relevant elements into the
+       new array we return.  */
     else
       {
+       int j, offs_store = elt_offs;
        LONGEST dst_offset = 0;
        LONGEST src_row_length = TYPE_LENGTH (TYPE_TARGET_TYPE (array_type));
 
-       element_type = TYPE_TARGET_TYPE (TYPE_TARGET_TYPE (array_type));
+       if (call_count == 1)
+         {
+           /* When CALL_COUNT is equal to 1 we are working on the current range
+              and use these elements directly.  */
+           element_type = TYPE_TARGET_TYPE (array_type);
+         }
+       else
+         {
+           /* Working on an array of arrays, the type of the elements is the type
+              of the subarrays' type.  */
+           element_type = TYPE_TARGET_TYPE (TYPE_TARGET_TYPE (array_type));
+         }
+
        slice_type = create_array_type (NULL, element_type, slice_range_type);
 
-       TYPE_CODE (slice_type) = TYPE_CODE (TYPE_TARGET_TYPE (array_type));
+        /* If we have a one dimensional array, we copy its TYPE_CODE.  For a
+           multi dimensional array we copy the embedded type's TYPE_CODE.  */
+       if (call_count == 1)
+         TYPE_CODE (slice_type) = TYPE_CODE (array_type);
+       else
+         TYPE_CODE (slice_type) = TYPE_CODE (TYPE_TARGET_TYPE (array_type));
 
        v = allocate_value (slice_type);
-       for (i = 0; i < longest_to_int (row_count); i++)
+
+       /* Iterate through the rows of the outer array and set the new offset
+          for each row.  */
+       for (i = 0; i < row_count; i++)
          {
-           /* Fetches the contents of ARRAY and copies them into V.  */
-           value_contents_copy (v,
-                                dst_offset,
-                                array,
-                                elt_offs,
-                                elt_size * elem_count);
-           elt_offs += src_row_length;
-           dst_offset += elt_size * elem_count;
+           elt_offs = offs_store + i * src_row_length;
+
+           /* Iterate through the elements in each row to copy only those.  */
+           for (j = 1; j <= elem_count; j++)
+             {
+               /* Fetches the contents of ARRAY and copies them into V.  */
+               value_contents_copy (v, dst_offset, array, elt_offs, elt_size);
+               elt_offs += elt_size * stride_length;
+               dst_offset += elt_size;
+             }
          }
       }
 
index 4086a77d1fc062078874d4af6f9e516aac52b610..9c37713239249e0e2f720c0525c652106c093977 100644 (file)
@@ -1057,7 +1057,7 @@ extern struct value *varying_to_slice (struct value *);
 
 extern struct value *value_slice (struct value *, int, int);
 
-extern struct value *value_slice_1 (struct value *, int, int, int);
+extern struct value *value_slice_1 (struct value *, int, int, int, int);
 
 extern struct value *value_literal_complex (struct value *, struct value *,
                                            struct type *);