Re: [DWARF] mark partial fn versions and OMP frags as partial in dwarf2+ debug info

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

Re: [DWARF] mark partial fn versions and OMP frags as partial in dwarf2+ debug info

Jakub Jelinek
On Wed, Nov 22, 2017 at 02:40:39AM -0200, Alexandre Oliva wrote:

> On Nov 21, 2017, Jakub Jelinek <[hidden email]> wrote:
>
> > On Wed, Nov 15, 2017 at 05:05:36AM -0200, Alexandre Oliva wrote:
>
> >> This patch introduces a new DWARF attribute to indicate that a function
> >> is a partial copy of its abstract origin, specifically, that its entry
> >> point does not correspond to the entry point of the abstract origin.
> >> This attribute can then be used to mark the out-of-line portion of
> >> partial inlines, and OpenMP blocks split out into artificial functions.
>
> > I'm not sure I like the attribute name too much, and more importantly,
> > as I said before, I think the attribute should not be a flag, but a number
> > which tells not just that it is an outlined portion of the original
> > subprogram, but also what kind of outlining it is and its purpose.
>
> I suppose you don't like it because it means something other than what
> you suggested.  I'd taken note of your suggestion, and even asked for
> more details back then, but none of the debug info consumers seemed to
> have changed their mind to the initial assessment that a single boolean
> flag would suffice for the purposes of telling whether or not the entry
> point of a given (implementation) subprogram should be covered by a
> breakpoint at a given (source-level) subprogram.

Let's take them into a loop again.

> We could supply a lot more detail about how functions are split, and
> why, but if debug info consumers have no way to make use of the info, or
> have no interest in doing so, I don't see that makes sense to waste
> compiler resources preserving and generating such additional
> information.

The thing is, the different kinds of outlined regions work very differently.
Say you have:

int bar (int);
static inline int foo (int x, int y)
{
  int z = x + 9 * y;
  if (x < 20)
    return y;
  return bar (bar (bar (bar (x + y * 7))));
}
as an example of possibly partially inlined function and
void
baz (int x, int y)
{
  int z = x + 9 * y;
  #pragma omp parallel for
  for (int i = 0; i < 60; i++)
    bar (i);
}
as an example of OpenMP parallel region.  Now, if inside of the outlined
regions (bar (bar (bar (bar (x + y * 7)))); in the first case and the
#pragma omp for in the second case) you want in the debugger to query
the value of z, which isn't used in those outlined regions and thus there
is likely no DW_TAG_variable for it in the outlined region, you need to do
something quite different.  In the first case just look up the caller,
and if the innermost inlined region has the same abstract origin as the
outlined region, query the z variable there.
In the OpenMP region, it isn't a parent that you need to look up though.
In the master thread, it is a grand+ parent, where you need to skip up all
the frames that belong to the OpenMP runtime library, in other threads you
need to talk to the runtime library to find what the parent thread is and
unwind there to some frame above the frames that belong to the OpenMP
runtime library.
OpenMP task region is again quite different from this, in that the parent
might still exist but might not, the task can be invoked after the function
spawning it returned if there is no thread synchronization before that (or
might at least leave some lexical scopes).
If we have an attribute like I'm proposing, you can easily test it even as a
boolean if there is some handling common to all the outlined region kinds
(just compare the value against 0).

> This flag serves a simple purpose that doesn't require debug info
> consumers to understand the implications of such relationships as a
> function having multiple openmp blocks split out of it, before being
> further split into inline and out-of-line, and then have the out-of-line
> portion further versioned and then split into inline and out-of-line.
> A debug info consumer can deal with that regardless of our providing
> additional detail about the purpose of the splits elsewhere.
>
> Now consider that we mark both inline and out-of-line functions with the
> same attribute and different nonzero values, and that we assign
> different values for the various kinds of split-out blocks, some of
> which a debug info consumer doesn't know about.  Should it then stop at
> the entry point of that fragment when a breakpoint is set on a function,
> or should it not?  (if there's more than one nonzero value for which the
> fragment encompasses the entry point, a conservative debug info consumer
> won't know what to do)

If we have a value for the partial inlining inlined outer part, then yes,
the debugger would need to check for two values (if we use 1 for the inlined
outer part, then <= 1 check), it is unlikely further outlined regions of
that kind would be needed.  If we don't mark the partial inlining inlined
outer part, then just != 0.  My point is when we are adding a new attribute,
we shouldn't look just for a single consumer purpose when we actually
already now know about multiple other uses where we'll need to know more
details, and we don't want to have dozens of attributes just for this
purpose.  Furthermore, in DWARF5 one can use DW_FORM_implicit_const and can
have the enum occupy no space in the DIE like a flag would in DWARF4.
Otherwise your flag attribute would have to be always coupled with an enum
attribute telling the reason.  The cost of .debug_abbrev entries isn't
negligible.

        Jakub