On Sat, Feb 6, 2021 at 8:11 PM Martin Sebor <mse...@gmail.com> wrote:
>
> On 2/4/21 1:48 AM, Richard Biener wrote:
> > On Wed, Feb 3, 2021 at 6:12 PM Martin Sebor <mse...@gmail.com> wrote:
> >>
> >> On 2/3/21 5:01 AM, Richard Biener wrote:
> >>> On Mon, Feb 1, 2021 at 5:20 PM Martin Sebor <mse...@gmail.com> wrote:
> >>>>
> >>>> I have pushed the tree.h comments in g:6a2053773b8.  I will wait
> >>>> for an approval of the changes to the manual.
> >>>
> >>> Sorry for not looking earlier.
> >>
> >> Sorry, I thought you were fine with the text after your first review.
> >> I'll adjust the tree.h comments when we're done, though I'd like to
> >> think the example in the manual will do a lot more to help make it
> >> clear than the comments in tree.h can.
> >>
> >>>
> >>> +/* The scope enclosing the scope NODE, or FUNCTION_DECL for the 
> >>> "outermost"
> >>> +   function scope.  Inlined functions are chained by this so that given
> >>> +   expression E and its TREE_BLOCK(E) B, BLOCK_SUPERCONTEXT(B) is the 
> >>> scope
> >>> +   in which E has been made or into which E has been inlined.   */
> >>>
> >>> I can't really understand what you are trying to say with the second
> >>> sentence.  There's
> >>> nothing really special about BLOCK_SUPERCONTEXT and inlines so I believe 
> >>> this
> >>> sentence only adds confusion.
> >>
> >> The sentence explains how SUPERCONTEXT chains inlined blocks.  In
> >> the manual diff I show an example:
> >>
> >>           void f0 (char *p, int n) { memset (p, 1, n); }
> >>
> >>         void f1 (char *p, int n) { f0 (p + 1, n + 1); }
> >>
> >>       void f2 (char *p, int n) { f1 (p + 1, n + 1); }
> >>
> >>     int a[6];
> >>     void f3 (char *p, int n) { f2 (a, 3); }
> >>
> >> The blocks for all calls inlined into f3 are chained like so:
> >>
> >>         CALL_EXPR: memset              E
> >>
> >>         BLOCK #13             <--+     TREE_BLOCK (E)
> >>     +-- SUPERCONTEXT: BLOCK #12  |
> >>     |     ABSTRACT_ORIGIN: BLOCK #0 --+
> >>     |                            |    |
> >>     +-> BLOCK #12 (f1)        <--|-+  |
> >>     +-- SUPERCONTEXT: BLOCK #10  | |  |
> >>     |     SUBBLOCKS: BLOCK #13 --|-|  |
> >>     |     ABSTRACT_ORIGIN: f0 ---+ |  |
> >>     |                              |  |
> >>     +-> BLOCK #10 (f2)         <-+ |  |
> >>     +--- SUPERCONTEXT: BLOCK #8  | |  |
> >>     |    SUBBLOCKS: BLOCK #12 ---|-|  |
> >>     |    ABSTRACT_ORIGIN: f1 ------+  |
> >>     |                            |    |
> >>     +-> BLOCK #8 (f3)            |    |
> >>     +---- SUPERCONTEXT: BLOCK #0 |    |
> >>     |     SUBBLOCKS: BLOCK #10 --|    |
> >>     |     ABSTRACT_ORIGIN: f2 ---+    |
> >>     |                                 |
> >>     +-> BLOCK #0 (f3) <---------------+
> >>           SUPERCONTEXT: f3
> >>           SUBBLOCKS: BLOCK #8
> >>
> >> Does the following sound better? (Dropping the "in which E has been
> >> made.")
> >>
> >>     Inlined functions are chained by this so that given expression E
> >>     and its TREE_BLOCK(E) B, BLOCK_SUPERCONTEXT(B) is the scope into
> >>     which E has been inlined.
> >
> > Oh, I see what you mean.  But this is misleading for the case where f0
> > has any blocks:
> >
> >   f0 (..) { { int tem; { memset (..); } } if () { }... }
> >
> > because BLOCK_SUPERCONTEXT is simply the parent scope ( { int tem; ... } ) 
> > and
> > not yet the artifical scope we generate to wrap f0.
>
> I haven't seen those scopes in my (admittedly simplistic) tests and
> based on the internals manual have been assuming most lexical scopes
> are removed during gimplification:
>
>    Additionally, all the control structures used in GENERIC are lowered
>    into conditional jumps, lexical scopes are removed and exception
>    regions are converted into an on the side exception region tree.
>
> Is the above wrong or inaccurate?  Do all nested scope not get removed?

The scopes are not present in the GIMPLE IL but the lexical scope tree
is still there in a function decls DECL_INITIAL.  What happens is that
scopes are gone semantically since all automatic vars get promoted to function
scope by GIMPLE but we preserve (some) out-of-scope going by inserting
CLOBBER instructions into the IL (there's nothing similar at the point
the vars originally went live - liveness analysis has to be done for this
and the compiler can freely move defs outside of the original scope).

> > To figure the
> > scope a block was
> > inlined to you'd have to do sth like
> >
> >    b = TREE_BLOCK (E);
> >    gcc_assert (BLOCK_ABSTRACT_ORIGIN (b)); // it was inlined
> >    while (!inlined_function_outer_scope_p (b))
> >      b = BLOCK_SUPERCONTEXT (b);
> >    now BLOCK_SUPERCONTEXT (b) is the block the function containing E was
> >    inlined to.
> >
> > So again, I think tree.h is not the place to document this.  There
> > BLOCK_SUPERCONTEXT
> > should simply say it's pointing  to the parent BLOCK.
>
> I can simplify the text but want to make it clear it doesn't
> necessarily point to a BLOCK but can also point to a FUNCTION_DECL.
> So how about:
>
>    BLOCK_SUPERCONTEXT
>    Either a BLOCK of the enclosing scope or FUNCTION_DECL for
>    the "outermost" function scope.  In the middle end used to chain
>    scopes of functions inlined into their callers.  */

Please remove the last sentence.  There's nothing different in FE vs.
middle-end about BLOCK_SUPERCONTEXT.  It's BLOCK_ABSTRACT_ORIGIN
where inlining comes into play.

> >
> > In the texi documentation I'd separate out the representation of
> > inlines and clones,
> > eventually put it on the BLOCK_ABSTRACT_ORIGIN documentation.
> >
> > [I did not review the texi part yet - I mainly want to avoid people
> > being even more
> > confused about the tree.h comments]
>
> I take your point that sometimes less is more.  But from my personal
> experience with these macros, I'd be surprised if the text that's
> there now could be worse than having no comments at all.

But wrong or misleading comments are worse than no comments.

> >
> >>>    #define BLOCK_SUPERCONTEXT(NODE) (BLOCK_CHECK 
> >>> (NODE)->block.supercontext)
> >>> +/* Points to the next scope at the same level of nesting as scope NODE.  
> >>> */
> >>>    #define BLOCK_CHAIN(NODE) (BLOCK_CHECK (NODE)->block.chain)
> >>> +/* A BLOCK, or FUNCTION_DECL of the function from which a block has been
> >>> +   inlined.
> >>>
> >>> ... from which a block has been ultimatively copied for example by 
> >>> inlining.
> >>>
> >>> [clones also will have abstract origins]
>
> Okay, how's this:
>
> /* A BLOCK, or FUNCTION_DECL of the function from which a block has been
>     copied by inlining or cloning. */
> #define BLOCK_ABSTRACT_ORIGIN(NODE) (BLOCK_CHECK
> (NODE)->block.abstract_origin)

Sounds good.

> >>>
> >>>     In a scope immediately enclosing an inlined leaf expression,
> >>> +   points to the outermost scope into which it has been inlined (thus
> >>> +   bypassing all intermediate BLOCK_SUPERCONTEXTs). */
> >>>
> >>> ?
> >>
> >> This describes the long arrow on the right, pointing Block #13's
> >> ABSTRACT_ORIGIN down to Block #0.  All the other AO's point down
> >> to the next/enclosing block (arrows on the left).  I didn't expect
> >> this when I first worked with the blocks so it seemed like
> >> an important detail to mention.
> >>
> >>>
> >>> Maybe:  An inlined function is represented by a scope with
> >>> BLOCK_ABSTRACT_ORIGIN being the FUNCTION_DECL of the inlined function
> >>> containing the inlined functions scope tree as children.  All abstract 
> >>> origins
> >>> are ultimate, that is BLOCK_ABSTRACT_ORIGIN(NODE)
> >>> == BLOCK_ABSTRACT_ORIGIN(BLOCK_ABSTRACT_ORIGIN (NODE)).
> >>
> >> The first sentence sounds good to me as far as it goes but it
> >> doesn't capture the long arrow above.  (By children I assume you
> >> mean SUBBLOCKS, correct?)
> >>
> >> I don't follow what you're trying to say in the second sentence.
> >> The equality isn't true for Block #0 whose AO is null.  It also
> >> isn't true for Block #12 and the others whose AO is a DECL, not
> >> a block.
> >>
> >> What do you mean by "ultimate" in plain English?
> >
> > Ultimate in the sense dwarf2out uses it.  DWARF wants to refer to
> > the abstract copy.  Originally (I think till GCC 9) BLOCK_ABSTRACT_ORIGIN
> > of a function inlined that had functions inlined into it pointed to the
> > inlined block of the inner inline but now it points to the original
> > outline copy BLOCK of the inner inline (uh, can you parse that?).
> > That simplifies things and is all we need.
>
> I *think* I understand what you're saying about how it's set up now,
> but I had to refer to the diagram above to help.  You're referring
> to the arrow below, f2's AO pointing to f1's block (and
> the corresponding arrow from f3's AO to f2's block:
>
>             BLOCK #12 (f1)        <----+
>               SUPERCONTEXT: BLOCK #10  |
>               SUBBLOCKS: BLOCK #13     |
>               ABSTRACT_ORIGIN: f0      |
>                                        |
>             BLOCK #10 (f2)             |
>               SUPERCONTEXT: BLOCK #8   |
>               SUBBLOCKS: BLOCK #12     |
>               ABSTRACT_ORIGIN: f1 -----+
>
> FWIW, a relationship between two interior parts of a larger whole
> is not something I would understand by the word ultimate.  A couple
> of synonyms for "ultimate" are "last" and "final" and f1 is neither.
> I would call f3 the ultimate origin the three inlined calls, and
> that matches AO only in Block #13, but not in any others.

But the diagram is only correct until GCC 9 (if I remembered correctly
the point I changed it).  Currently f2 abstract origin refers to the
abstract origin of f1 (so f0).  Otherwise the invariant I gave doesn't hold.

Abstract origins are best understood in the context of generated
DWARF for DW_TAG_lexical_block DW_AT_abstract_origins and
the way you'd expect those for DW_TAG_inlined_subroutine
DIEs (those we generate for the inlined_function_outer_scope_p
blocks - the BLOCKs with FUNCTION_DECL abstract origin).

> >> FWIW, if I were to try to explain it using the example I'd say
> >> only Block #13's AO is "ultimate:" it points down in the diagram
> >> to the block of the function into which the expression has
> >> ultimately been inlined.  The AO's of all the other intervening
> >> inlined blocks are the DECLs of the inlined callees (up-pointing
> >> arrows); they don't look ultimate to me in this sense.
> >>
> >> But however this is phrased I suspect it won't be perfectly clear
> >> without an example or a picture.
> >
> > Which means giving partial info in tree.h isn't useful but confusing.
>
> I don't think that's true.  Most comments in tree.h are only partial
> and don't fully describe every fine detail of whatever they document.
> They may not be enough for using the thing they describe properly
> and safely in every instance but they're often good enough to read
> the code and what what it does.  BLOCK_ABSTRACT_ORIGIN or
> BLOC_SUPERCONTEXT without any comment at all isn't good enough
> for even that.

But wrong info gives people the idea they can use it wrongly without
investigating or asking.

Richard.

> Anyway, thanks for continuing to help with this.  Attached are
> the tweaks to tree.h.  I'll post an update to the manual separately.
>
> Martin
>
> >
> > Richard.
> >
> >>
> >> Martin
> >>
> >>>
> >>>    #define BLOCK_ABSTRACT_ORIGIN(NODE) (BLOCK_CHECK 
> >>> (NODE)->block.abstract_origin)
> >>>
> >>>
> >>>> On 1/27/21 5:54 PM, Martin Sebor wrote:
> >>>>> Attached is an updated patch for both tree.h and the internals manual
> >>>>> documenting the most important BLOCK_ macros and what they represent.
> >>>>>
> >>>>> On 1/21/21 2:52 PM, Martin Sebor wrote:
> >>>>>> On 1/18/21 6:25 AM, Richard Biener wrote:
> >>>>>>>> PS Here are my notes on the macros and the two related functions:
> >>>>>>>>
> >>>>>>>> BLOCK: Denotes a lexical scope.  Contains BLOCK_VARS of variables
> >>>>>>>> declared in it, BLOCK_SUBBLOCKS of scopes nested in it, and
> >>>>>>>> BLOCK_CHAIN pointing to the next BLOCK.  Its BLOCK_SUPERCONTEXT
> >>>>>>>> point to the BLOCK of the enclosing scope.  May have
> >>>>>>>> a BLOCK_ABSTRACT_ORIGIN and a BLOCK_SOURCE_LOCATION.
> >>>>>>>>
> >>>>>>>> BLOCK_SUPERCONTEXT: The scope of the enclosing block, or 
> >>>>>>>> FUNCTION_DECL
> >>>>>>>> for the "outermost" function scope.  Inlined functions are chained by
> >>>>>>>> this so that given expression E and its TREE_BLOCK(E) B,
> >>>>>>>> BLOCK_SUPERCONTEXT(B) is the scope (BLOCK) in which E has been made
> >>>>>>>> or into which E has been inlined.  In the latter case,
> >>>>>>>>
> >>>>>>>> BLOCK_ORIGIN(B) evaluates either to the enclosing BLOCK or to
> >>>>>>>> the enclosing function DECL.  It's never null.
> >>>>>>>>
> >>>>>>>> BLOCK_ABSTRACT_ORIGIN(B) is the FUNCTION_DECL of the function into
> >>>>>>>> which it has been inlined, or null if B is not inlined.
> >>>>>>>
> >>>>>>> It's the BLOCK or FUNCTION it was inlined _from_, not were it was
> >>>>>>> inlined to.
> >>>>>>> It's the "ultimate" source, thus the abstract copy of the block or
> >>>>>>> function decl
> >>>>>>> (for the outermost scope, aka inlined_function_outer_scope_p).  It
> >>>>>>> corresponds
> >>>>>>> to what you'd expect for the DWARF abstract origin.
> >>>>>>
> >>>>>> Thanks for the correction!  It's just the "innermost" block that
> >>>>>> points to the "ultimate" destination into which it's been inlined.
> >>>>>>
> >>>>>>>
> >>>>>>> BLOCK_ABSTRACT_ORIGIN can be NULL (in case it isn't an inline 
> >>>>>>> instance).
> >>>>>>>
> >>>>>>>> BLOCK_ABSTRACT_ORIGIN: A BLOCK, or FUNCTION_DECL of the function
> >>>>>>>> into which a block has been inlined.  In a BLOCK immediately 
> >>>>>>>> enclosing
> >>>>>>>> an inlined leaf expression points to the outermost BLOCK into which 
> >>>>>>>> it
> >>>>>>>> has been inlined (thus bypassing all intermediate 
> >>>>>>>> BLOCK_SUPERCONTEXTs).
> >>>>>>>>
> >>>>>>>> BLOCK_FRAGMENT_ORIGIN: ???
> >>>>>>>> BLOCK_FRAGMENT_CHAIN: ???
> >>>>>>>
> >>>>>>> that's for scope blocks split by hot/cold partitioning and only
> >>>>>>> temporarily
> >>>>>>> populated.
> >>>>>>
> >>>>>> Thanks, I now see these documented in detail in tree.h.
> >>>>>>
> >>>>>>>
> >>>>>>>> bool inlined_function_outer_scope_p(BLOCK)   [tree.h]
> >>>>>>>>       Returns true if a BLOCK has a source location.
> >>>>>>>>       True for all but the innermost (no SUBBLOCKs?) and outermost 
> >>>>>>>> blocks
> >>>>>>>>       into which an expression has been inlined. (Is this always 
> >>>>>>>> true?)
> >>>>>>>>
> >>>>>>>> tree block_ultimate_origin(BLOCK)   [tree.c]
> >>>>>>>>       Returns BLOCK_ABSTRACT_ORIGIN(BLOCK), AO, after asserting that
> >>>>>>>>       (DECL_P(AO) && DECL_ORIGIN(AO) == AO) || BLOCK_ORIGIN(AO) == 
> >>>>>>>> AO).
> >>>>>>
> >>>>>> The attached diff adds the comments above to tree.h.
> >>>>>>
> >>>>>> I looked for a good place in the manual to add the same text but I'm
> >>>>>> not sure.  Would the Blocks @subsection in generic.texi be appropriate?
> >>>>>>
> >>>>>> Martin
> >>>>>
> >>>>>
> >>>>
> >>
>

Reply via email to