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


Document various BLOCK macros.

gcc/ChangeLog:

	* doc/generic.texi (Function Basics): Mention BLOCK_SUBBLOCKS,
	BLOCK_VARS, BLOCK_SUPERCONTEXT, and BLOCK_ABSTRACT_ORIGIN.
	* doc/gimple.texi (GIMPLE): Update.  Mention free_lang_data pass.
	* tree.h (BLOCK_VARS): Add comment.
	(BLOCK_SUBBLOCKS): Same.
	(BLOCK_SUPERCONTEXT): Same.
	(BLOCK_ABSTRACT_ORIGIN): Same.
	(inlined_function_outer_scope_p): Same.

diff --git a/gcc/tree.h b/gcc/tree.h
index 02b03d1f68e..0dd2196008b 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -1912,18 +1912,29 @@ class auto_suppress_location_wrappers
 #define OMP_CLAUSE_OPERAND(NODE, I)				\
 	OMP_CLAUSE_ELT_CHECK (NODE, I)
 
-/* In a BLOCK node.  */
+/* In a BLOCK (scope) node:
+   Variables declared in the scope NODE.  */
 #define BLOCK_VARS(NODE) (BLOCK_CHECK (NODE)->block.vars)
 #define BLOCK_NONLOCALIZED_VARS(NODE) \
   (BLOCK_CHECK (NODE)->block.nonlocalized_vars)
 #define BLOCK_NUM_NONLOCALIZED_VARS(NODE) \
   vec_safe_length (BLOCK_NONLOCALIZED_VARS (NODE))
 #define BLOCK_NONLOCALIZED_VAR(NODE,N) (*BLOCK_NONLOCALIZED_VARS (NODE))[N]
+/* A chain of BLOCKs (scopes) nested within the scope NODE.  */
 #define BLOCK_SUBBLOCKS(NODE) (BLOCK_CHECK (NODE)->block.subblocks)
+/* 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.   */
 #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.  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). */
 #define BLOCK_ABSTRACT_ORIGIN(NODE) (BLOCK_CHECK (NODE)->block.abstract_origin)
-#define BLOCK_ORIGIN(NODE) \
+#define BLOCK_ORIGIN(NODE)						\
   (BLOCK_ABSTRACT_ORIGIN(NODE) ? BLOCK_ABSTRACT_ORIGIN(NODE) : (NODE))
 #define BLOCK_DIE(NODE) (BLOCK_CHECK (NODE)->block.die)
 
@@ -5078,7 +5089,10 @@ function_args_iter_next (function_args_iterator *i)
   i->next = TREE_CHAIN (i->next);
 }
 
-/* We set BLOCK_SOURCE_LOCATION only to inlined function entry points.  */
+/* Returns true if a BLOCK has a source location.
+   BLOCK_SOURCE_LOCATION is set only to inlined function entry points,
+   so the function returns true for all but the innermost and outermost
+   blocks into which an expression has been inlined.  */
 
 static inline bool
 inlined_function_outer_scope_p (const_tree block)
diff --git a/gcc/doc/generic.texi b/gcc/doc/generic.texi
index 642cbc83fe4..6be5e4c16ab 100644
--- a/gcc/doc/generic.texi
+++ b/gcc/doc/generic.texi
@@ -2570,12 +2570,17 @@ A function that has a definition in the current translation unit will
 have a non-@code{NULL} @code{DECL_INITIAL}.  However, back ends should not make
 use of the particular value given by @code{DECL_INITIAL}.
 
-It should contain a tree of @code{BLOCK} nodes that mirrors the scopes
-that variables are bound in the function.  Each block contains a list
-of decls declared in a basic block, a pointer to a chain of blocks at
-the next lower scope level, then a pointer to the next block at the
-same level and a backpointer to the parent @code{BLOCK} or
-@code{FUNCTION_DECL}.  So given a function as follows:
+@code{DECL_INITIAL} is a @code{BLOCK} tree node corresponding to
+the outermost scope of the function definition.  A @code{BLOCK} may contain
+other blocks accessible by @code{BLOCK_SUBBLOCKS} and corresponding to
+the scopes nested within it, a list of decls declared in a basic block
+and accessible as @code{BLOCK_VARS}, a pointer to a chain of blocks at
+the next lower scope level accessible as @code{BLOCK_SUBBLOCKS}, and
+a pointer to the next block at the same level accessible as
+@code{BLOCK_CHAIN}.  Any of these trees may be null.  In addition,
+each @code{BLOCK} has a nonnull backpointer to the parent @code{BLOCK}
+or @code{FUNCTION_DECL} (@code{BLOCK_SUPERCONTEXT}).  For example, given
+a function as follows:
 
 @smallexample
 void foo()
@@ -2609,6 +2614,82 @@ BLOCK_SUPERCONTEXT(block_c) = foo;
 DECL_INITIAL(foo) = block_a;
 @end smallexample
 
+Besides nesting lexical scopes, @code{BLOCK}s may be chained by
+@code{BLOCK_ORIGIN} and @code{BLOCK_ABSTRACT_ORIGIN} during function
+inlining to provide context in middle end diagnostic messages.
+
+@code{BLOCK_ABSTRACT_ORIGIN} is either a @code{BLOCK}, or
+a @code{FUNCTION_DECL} of the function from which a block has been inlined.
+In a scope immediately enclosing an inlined leaf expression, it points to
+the outermost scope into which it has been inlined (thus bypassing all
+intermediate @code{BLOCK_SUPERCONTEXT}s).  For example, when all the calls
+to the following functions are inlined
+
+@smallexample
+void f0 (char *p, int n) @{
+  memset (p, 1, n);           // a.c:2:3
+@}
+
+void f1 (char *p, int n) @{
+  f0 (p + 1, n + 1);          // a.c:6:3
+@}
+
+void f2 (char *p, int n) @{
+  f1 (p + 1, n + 1);          // a.c:10:3
+@}
+
+char a[6];
+
+void f3 (void) @{
+  f2 (a, 3);                  // a.c:16:3
+@}
+@end smallexample
+
+the result is the following output showing the inlining context
+
+@smallexample
+In function 'f0',
+    inlined from 'f2' at a.c:6:3,
+    inlined from 'f3' at a.c:16:3:
+a.c:2:3: warning: 'memset' writing 5 bytes into a region of size 4 overflows the destination [-Wstringop-overflow=]
+    2 |   memset (p, 1, n);
+      |   ^~~~~~~~~~~~~~~~
+a.c: In function 'f3':
+a.c:13:6: note: at offset 2 into destination object 'a' of size 6
+   13 | char a[6];
+      |      ^
+@end smallexample
+
+The context is made possible by the following arrangement of blocks.
+
+@smallexample
+        CALL_EXPR
+  	  memset (p, 1, n);             | f0:2:3
+
+        BLOCK #13                       | f0
+          SUPERCONTEXT: BLOCK #12
+          ABSTRACT_ORIGIN: BLOCK #0
+
+      BLOCK #12 [/build/tmp/a.c:6:3]    | f1
+        SUPERCONTEXT: BLOCK #10
+        SUBBLOCKS: BLOCK #13
+        ABSTRACT_ORIGIN: f0
+
+    BLOCK #10 [/build/tmp/a.c:10:3]     | f2
+      SUPERCONTEXT: BLOCK #8
+      SUBBLOCKS: BLOCK #12
+      ABSTRACT_ORIGIN: f1
+
+  BLOCK #8 [/build/tmp/a.c:16:3]        | f3
+    SUPERCONTEXT: BLOCK #0
+    SUBBLOCKS: BLOCK #10
+    ABSTRACT_ORIGIN: f2
+
+BLOCK #0                                | f3
+  SUPERCONTEXT: f3
+  SUBBLOCKS: BLOCK #8
+@end smallexample
+
 @end ftable
 
 @c ---------------------------------------------------------------------
diff --git a/gcc/doc/gimple.texi b/gcc/doc/gimple.texi
index 4b3d7d7452e..02cd4e65727 100644
--- a/gcc/doc/gimple.texi
+++ b/gcc/doc/gimple.texi
@@ -17,8 +17,11 @@ choices.  For one thing, SIMPLE doesn't support @code{goto}.
 Temporaries are introduced to hold intermediate values needed to
 compute complex expressions. 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.
+lexical scopes other than at the function definition level are
+removed, and exception regions are converted into an on the side
+exception region tree.  Nested scopes may be retained independently
+of the GIMPLE representation.  They are accessible as @code{BLOCK}s
+via @code{DECL_INITIAL} of each function definition.
 
 The compiler pass which converts GENERIC into GIMPLE is referred to as
 the @samp{gimplifier}.  The gimplifier works recursively, generating
@@ -33,7 +36,7 @@ representation than abstract syntax trees (AST), therefore it
 does not require the full structural complexity provided by the
 main tree data structure.
 
-The GENERIC representation of a function is stored in the
+The GENERIC representation of a function definition is stored in the
 @code{DECL_SAVED_TREE} field of the associated @code{FUNCTION_DECL}
 tree node.  It is converted to GIMPLE by a call to
 @code{gimplify_function_tree}.
@@ -45,6 +48,8 @@ convert the front end trees to GIMPLE@.  Usually such a hook will involve
 much of the same code for expanding front end trees to RTL@.  This function
 can return fully lowered GIMPLE, or it can return GENERIC trees and let the
 main gimplifier lower them the rest of the way; this is often simpler.
+Other language-specific tree codes should be removed by each front end
+before gimplification no later than by the @code{free_lang_data} pass.
 GIMPLE that is not fully lowered is known as ``High GIMPLE'' and
 consists of the IL before the pass @code{pass_lower_cf}.  High GIMPLE
 contains some container statements like lexical scopes

Reply via email to