public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
From: Simon Marchi <simark@simark.ca>
To: Andrew Burgess <andrew.burgess@embecosm.com>, gdb-patches@sourceware.org
Subject: Re: [PATCHv5 4/4] gdb/fortran: Add support for Fortran array slices at the GDB prompt
Date: Mon, 12 Oct 2020 10:10:54 -0400	[thread overview]
Message-ID: <b231b34d-7d08-48db-67f7-6e740669cce5@simark.ca> (raw)
In-Reply-To: <7832c05de858cfc8bf4b6abba4332523d0547805.1602439661.git.andrew.burgess@embecosm.com>

On 2020-10-11 2:12 p.m., Andrew Burgess wrote:
> This commit brings array slice support to GDB.
>
> WARNING: This patch contains a rather big hack which is limited to
> Fortran arrays, this can be seen in gdbtypes.c and f-lang.c.  More
> details on this below.
>
> This patch rewrites two areas of GDB's Fortran support, the code to
> extract an array slice, and the code to print an array.
>
> After this commit a user can, from the GDB prompt, ask for a slice of
> a Fortran array and should get the correct result back.  Slices can
> (optionally) have the lower bound, upper bound, and a stride
> specified.  Slices can also have a negative stride.
>
> Fortran has the concept of repacking array slices.  Within a compiled
> Fortran program if a user passes a non-contiguous array slice to a
> function then the compiler may have to repack the slice, this involves
> copying the elements of the slice to a new area of memory before the
> call, and copying the elements back to the original array after the
> call.  Whether repacking occurs will depend on which version of
> Fortran is being used, and what type of function is being called.
>
> This commit adds support for both packed, and unpacked array slicing,
> with the default being unpacked.
>
> With an unpacked array slice, when the user asks for a slice of an
> array GDB creates a new type that accurately describes where the
> elements of the slice can be found within the original array, a
> value of this type is then returned to the user.  The address of an
> element within the slice will be equal to the address of an element
> within the original array.
>
> A user can choose to selected packed array slices instead using:

"to selected"

>
>   (gdb) set fortran repack-array-slices on|off
>   (gdb) show fortran repack-array-slices
>
> With packed array slices GDB creates a new type that reflects how the
> elements of the slice would look if they were laid out in contiguous
> memory, allocates a value of this type, and then fetches the elements
> from the original array and places then into the contents buffer of
> the new value.
>
> One benefit of using packed slices over unapacked slices is the memory

"unapacked"

> diff --git a/gdb/f-array-walker.h b/gdb/f-array-walker.h
> new file mode 100644
> index 00000000000..395c26e5350
> --- /dev/null
> +++ b/gdb/f-array-walker.h
> @@ -0,0 +1,255 @@
> +/* Copyright (C) 2020 Free Software Foundation, Inc.
> +
> +   This file is part of GDB.
> +
> +   This program is free software; you can redistribute it and/or modify
> +   it under the terms of the GNU General Public License as published by
> +   the Free Software Foundation; either version 3 of the License, or
> +   (at your option) any later version.
> +
> +   This program is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +   GNU General Public License for more details.
> +
> +   You should have received a copy of the GNU General Public License
> +   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
> +
> +/* Support classes to wrap up the process of iterating over a
> +   multi-dimensional Fortran array.  */
> +
> +#ifndef F_ARRAY_WALKER_H
> +#define F_ARRAY_WALKER_H
> +
> +#include "defs.h"
> +#include "gdbtypes.h"
> +#include "f-lang.h"
> +
> +/* Class for calculating the byte offset for elements within a single
> +   dimension of a Fortran array.  */
> +class fortran_array_offset_calculator
> +{
> +public:
> +  /* Create a new offset calculator for TYPE, which is either an array or a
> +     string.  */
> +  fortran_array_offset_calculator (struct type *type)
> +  {
> +    /* Validate the type.  */
> +    type = check_typedef (type);
> +    if (type->code () != TYPE_CODE_ARRAY
> +	&& (type->code () != TYPE_CODE_STRING))
> +      error (_("can only compute offsets for arrays and strings"));
> +
> +    /* Get the range, and extract the bounds.  */
> +    struct type *range_type = type->index_type ();
> +    if (get_discrete_bounds (range_type, &m_lowerbound, &m_upperbound) < 0)
> +      error ("unable to read array bounds");
> +
> +    /* Figure out the stride for this array.  */
> +    struct type *elt_type = check_typedef (TYPE_TARGET_TYPE (type));
> +    m_stride = type->index_type ()->bounds ()->bit_stride ();
> +    if (m_stride == 0)
> +      m_stride = type_length_units (elt_type);
> +    else
> +      {
> +	struct gdbarch *arch = get_type_arch (elt_type);
> +	int unit_size = gdbarch_addressable_memory_unit_size (arch);
> +	m_stride /= (unit_size * 8);
> +      }
> +  };
> +
> +  /* Get the byte offset for element INDEX within the type we are working
> +     on.  There is no bounds checking done on INDEX.  If the stride is
> +     negative then we still assume that the base address (for the array
> +     object) points to the element with the lowest memory address, we then
> +     calculate an offset assuming that index 0 will be the element at the
> +     highest address, index 1 the next highest, and so on.  This is not
> +     quite how Fortran works in reality; in reality the base address of
> +     the object would point at the element with the highest address, and
> +     we would index backwards from there in the "normal" way, however,
> +     GDB's current value contents model doesn't support having the base
> +     address be near to the end of the value contents, so we currently
> +     adjust the base address of Fortran arrays with negative strides so
> +     their base address points at the lowest memory address.  This code
> +     here is part of working around this weirdness.  */

I didn't quite catch this, but I think it's just because I'm missing
some knowledge about how Fortran arrays work.  But it looks well
explained enough that if I needed to fix something here, I could
understand what is happening.

> +  LONGEST index_offset (LONGEST index)
> +  {
> +    LONGEST offset;
> +    if (m_stride < 0)
> +      offset = std::abs (m_stride) * (m_upperbound - index);
> +    else
> +      offset = std::abs (m_stride) * (index - m_lowerbound);
> +    return offset;
> +  }
> +
> +private:
> +
> +  /* The stride for the type we are working with.  */
> +  LONGEST m_stride;
> +
> +  /* The upper bound for the type we are working with.  */
> +  LONGEST m_upperbound;
> +
> +  /* The lower bound for the type we are working with.  */
> +  LONGEST m_lowerbound;
> +};
> +
> +/* A base class used by fortran_array_walker.  */
> +class fortran_array_walker_base_impl
> +{
> +public:
> +  /* Constructor.  */
> +  explicit fortran_array_walker_base_impl ()
> +  { /* Nothing.  */ }
> +
> +  /* Called when iterating between the lower and upper bounds of each
> +     dimension of the array.  Return true if GDB should continue iterating,
> +     otherwise, return false.
> +
> +     SHOULD_CONTINUE indicates if GDB is going to stop anyway, and should
> +     be taken into consideration when deciding what to return.  If
> +     SHOULD_CONTINUE is false then this function must also return false,
> +     the function is still called though in case extra work needs to be
> +     done as part of the stopping process.  */
> +  bool continue_walking (bool should_continue)
> +  { return should_continue; }
> +
> +  /* Called when GDB starts iterating over a dimension of the array.  This
> +     function will be called once for each of the bounds in this dimension.
> +     DIM is the current dimension number, NDIM is the total number of
> +     dimensions, and FIRST_P is true for the first bound of this
> +     dimension, and false in all other cases.  */
> +  void start_dimension (int dim, int ndim, bool first_p)
> +  { /* Nothing.  */ }
> +
> +  /* Called when GDB finishes iterating over a dimension of the array.
> +     This function will be called once for each of the bounds in this
> +     dimension.  DIM is the current dimension number, NDIM is the total
> +     number of dimensions, and LAST_P is true for the last bound of this
> +     dimension, and false in all other cases.  */
> +  void finish_dimension (int dim, int ndim, bool last_p)
> +  { /* Nothing.  */ }
> +
> +  /* Called when processing the inner most dimension of the array, for
> +     every element in the array.  PARENT_VALUE is the value from which
> +     elements are being extracted, ELT_TYPE is the type of the element
> +     being extracted, and ELT_OFF is the offset of the element from the
> +     start of PARENT_VALUE.  */
> +  void process_element (struct value *parent_value, struct type *elt_type,
> +			LONGEST elt_off)
> +  { /* Nothing.  */ }
> +};

I don't understand when start_dimension and finish_dimension get called
exactly.  Looking at the implementation, it looks like it will be
something like this:

  start_dimension(1, 3, true)
    start_dimension(2, 3, true)
      start_dimension(3, 3, true)
	process_element(element at (1,1,1))
      finish_dimension(3, 3, false)
      start_dimension(3, 3, false)
        process_element(element (1,1,2))
      finish_dimension(3, 3, true)
    finish_dimension(2, 3, false)
    start_dimension(2, 3, false)
      start_dimension(3, 3, true)
	process_element(element at (1,2,1))
      finish_dimension(3, 3, false)
      start_dimension(3, 3, false)
        process_element(element (1,2,2))
      finish_dimension(3, 3, true)
    finish_dimension(2, 3, false)
  finish_dimension(1, 3, false)
  start_dimension(1, 3, false)
    start_dimension(2, 3, true)
      start_dimension(3, 3, true)
	process_element(element at (2,1,1))
      finish_dimension(3, 3, false)
      start_dimension(3, 3, false)
        process_element(element (2,1,2))
      finish_dimension(3, 3, true)
    finish_dimension(2, 3, false)
    start_dimension(2, 3, false)
      start_dimension(3, 3, true)
	process_element(element at (2,2,1))
      finish_dimension(3, 3, false)
      start_dimension(3, 3, false)
        process_element(element (2,2,2))
      finish_dimension(3, 3, true)
    finish_dimension(2, 3, false)
  finish_dimension(1, 3, false)

Essentially for the inner dimention, walk_1 calls start_dimension and
finish_dimension around each single element.  That's more than I
expected to given my understanding of start_dimension and
finish_dimension.  I expected them to be called just once around once
"scan" of the inner dimension, so every two elements.  For the outer
dimension, I would expect a single call to start and finish, as there is
a single "scan" in this dimension.  I would expect basically this:

  start_dimension(1, 3, ?)
    start_dimension(2, 3, ?)
      start_dimension(3, 3, ?)
	process_element(element at (1,1,1))
        process_element(element (1,1,2))
      finish_dimension(3, 3, ?)
      start_dimension(3, 3, ?)
	process_element(element at (1,2,1))
        process_element(element (1,2,2))
      finish_dimension(3, 3, ?)
    finish_dimension(2, 3, ?)
    start_dimension(2, 3, ?)
      start_dimension(3, 3, ?)
	process_element(element at (2,1,1))
        process_element(element (2,1,2))
      finish_dimension(3, 3, ?)
      start_dimension(3, 3, ?)
	process_element(element at (2,2,1))
        process_element(element (2,2,2))
      finish_dimension(3, 3, ?)
    finish_dimension(2, 3, ?)
  finish_dimension(1, 3, ?)

I omitted the first_p/last_p values, because I am not sure what they
would be.  Did I understand the meaning of
start_dimension/finish_dimension wrong?

I don't have time to look at the rest of the patch now, so that is all
for now :).

Simon

  reply	other threads:[~2020-10-12 14:10 UTC|newest]

Thread overview: 62+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-08-13 12:58 [PATCH 0/8] Fortran Array Slicing and Striding Support Andrew Burgess
2020-08-13 12:58 ` [PATCH 1/8] gdbsupport: Provide global operators |=, &=, and ^= for enum bit flags Andrew Burgess
2020-08-15 17:16   ` Tom Tromey
2020-08-16  9:13     ` Andrew Burgess
2020-08-17 10:40     ` Andrew Burgess
2020-08-20 16:00       ` Pedro Alves
2020-08-21 14:49       ` Pedro Alves
2020-08-21 15:57         ` Andrew Burgess
2020-08-21 18:10           ` Pedro Alves
2020-08-13 12:58 ` [PATCH 2/8] gdbsupport: Make function arguments constant in enum-flags.h Andrew Burgess
2020-08-15 19:45   ` Tom Tromey
2020-08-16  9:08     ` Andrew Burgess
2020-08-13 12:58 ` [PATCH 3/8] gdb/fortran: Clean up array/string expression evaluation Andrew Burgess
2020-08-13 12:58 ` [PATCH 4/8] gdb/fortran: Move Fortran expression handling into f-lang.c Andrew Burgess
2020-08-13 12:58 ` [PATCH 5/8] gdb/fortran: Change whitespace when printing arrays Andrew Burgess
2020-08-13 12:58 ` [PATCH 6/8] gdb: Convert enum range_type to a bit field enum Andrew Burgess
2020-08-13 12:58 ` [PATCH 7/8] gdb/testsuite: Add missing expected results Andrew Burgess
2020-08-13 12:58 ` [PATCH 8/8] gdb/fortran: Add support for Fortran array slices at the GDB prompt Andrew Burgess
2020-08-13 13:31   ` Eli Zaretskii
2020-08-26 14:49 ` [PATCHv2 00/10] Fortran Array Slicing and Striding Support Andrew Burgess
2020-08-26 14:49   ` [PATCHv2 01/10] Rewrite valid-expr.h's internals in terms of the detection idiom (C++17/N4502) Andrew Burgess
2020-08-26 14:49   ` [PATCHv2 02/10] Use type_instance_flags more throughout Andrew Burgess
2020-08-26 14:49   ` [PATCHv2 03/10] Rewrite enum_flags, add unit tests, fix problems Andrew Burgess
2020-08-26 14:49   ` [PATCHv2 04/10] gdb: additional changes to make use of type_instance_flags more Andrew Burgess
2020-08-26 14:49   ` [PATCHv2 05/10] gdb/fortran: Clean up array/string expression evaluation Andrew Burgess
2020-09-19  8:53     ` Andrew Burgess
2020-08-26 14:49   ` [PATCHv2 06/10] gdb/fortran: Move Fortran expression handling into f-lang.c Andrew Burgess
2020-09-19  8:53     ` Andrew Burgess
2020-08-26 14:49   ` [PATCHv2 07/10] gdb/fortran: Change whitespace when printing arrays Andrew Burgess
2020-09-19  8:54     ` Andrew Burgess
2020-08-26 14:49   ` [PATCHv2 08/10] gdb: Convert enum range_type to a bit field enum Andrew Burgess
2020-08-26 14:49   ` [PATCHv2 09/10] gdb/testsuite: Add missing expected results Andrew Burgess
2020-09-18  9:53     ` Andrew Burgess
2020-08-26 14:49   ` [PATCHv2 10/10] gdb/fortran: Add support for Fortran array slices at the GDB prompt Andrew Burgess
2020-08-26 17:02     ` Eli Zaretskii
2020-09-19  9:47   ` [PATCHv3 0/2] Fortran Array Slicing and Striding Support Andrew Burgess
2020-09-19  9:48     ` [PATCHv3 1/2] gdb: Convert enum range_type to a bit field enum Andrew Burgess
2020-09-19 13:50       ` Simon Marchi
2020-09-19  9:48     ` [PATCHv3 2/2] gdb/fortran: Add support for Fortran array slices at the GDB prompt Andrew Burgess
2020-09-19 10:03       ` Eli Zaretskii
2020-09-28  9:40     ` [PATCHv4 0/3] Fortran Array Slicing and Striding Support Andrew Burgess
2020-09-28  9:40       ` [PATCHv4 1/3] gdb: Convert enum range_type to a bit field enum Andrew Burgess
2020-09-28  9:40       ` [PATCHv4 2/3] gdb: rename 'enum range_type' to 'enum range_flag' Andrew Burgess
2020-09-28  9:40       ` [PATCHv4 3/3] gdb/fortran: Add support for Fortran array slices at the GDB prompt Andrew Burgess
2020-09-28  9:52         ` Eli Zaretskii
2020-10-11 18:12       ` [PATCHv5 0/4] Fortran Array Slicing and Striding Support Andrew Burgess
2020-10-11 18:12         ` [PATCHv5 1/4] gdb: Convert enum range_type to a bit field enum Andrew Burgess
2020-10-20 20:16           ` Tom Tromey
2020-10-11 18:12         ` [PATCHv5 2/4] gdb: rename 'enum range_type' to 'enum range_flag' Andrew Burgess
2020-10-20 20:16           ` Tom Tromey
2020-10-11 18:12         ` [PATCHv5 3/4] gdb/fortran: add support for parsing array strides in expressions Andrew Burgess
2020-10-12 13:21           ` Simon Marchi
2020-10-20 20:17           ` Tom Tromey
2020-10-22 10:42           ` Andrew Burgess
2020-10-11 18:12         ` [PATCHv5 4/4] gdb/fortran: Add support for Fortran array slices at the GDB prompt Andrew Burgess
2020-10-12 14:10           ` Simon Marchi [this message]
2020-10-20 20:45           ` Tom Tromey
2020-10-29 11:08             ` Andrew Burgess
2020-10-31 22:16           ` [PATCHv6] " Andrew Burgess
2020-11-12 12:09             ` Andrew Burgess
2020-11-12 18:58             ` Tom Tromey
2020-11-19 11:56             ` Andrew Burgess

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=b231b34d-7d08-48db-67f7-6e740669cce5@simark.ca \
    --to=simark@simark.ca \
    --cc=andrew.burgess@embecosm.com \
    --cc=gdb-patches@sourceware.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).