On Wed, 26 Sep 2018, Jason Merrill wrote:

> On Wed, Sep 26, 2018 at 9:35 AM, Richard Biener <rguent...@suse.de> wrote:
> >
> > We do not create a DW_AT_lexical_block for the outermost block in
> > functions but we do for DW_AT_inlined_subroutines.  That makes
> > debuginfo look like if there were two of each local, the outer
> > one (from the abstract instance) optimized out (visible via
> > info locals in gdb).
> >
> > The following elides the outermost block also from inline instances.
> > It's a bit tricky to reliably track that block given we remove unused
> > blocks here and there.  The trick is to have the block in the abstract
> > instance _not_ point to itself (given we do not output it it isn't
> > the abstract origin for itself).
> >
> > Bootstrapped on x86_64-unkown-linux-gnu, testing in progress.
> >
> > Again with some scan-assembler testcase, guality cannot do 'info locals'.
> >
> > OK?
> >
> > Thanks,
> > Richard.
> >
> > 2018-09-26  Richard Biener  <rguent...@suse.de>
> >
> >         PR debug/87440
> >         * dwarf2out.c (set_block_origin_self): Do not mark outermost
> >         block as we do not output that.
> >         (gen_inlined_subroutine_die): Elide the originally outermost
> >         block, matching what we do for concrete instances.
> >         (decls_for_scope): Add parameter specifying whether to recurse
> >         to subblocks.
> >
> >         * gcc.dg/debug/dwarf2/inline4.c: New testcase.
> >
> > Index: gcc/testsuite/gcc.dg/debug/dwarf2/inline4.c
> > ===================================================================
> > --- gcc/testsuite/gcc.dg/debug/dwarf2/inline4.c (nonexistent)
> > +++ gcc/testsuite/gcc.dg/debug/dwarf2/inline4.c (working copy)
> > @@ -0,0 +1,17 @@
> > +/* Verify that the inline instance has no extra DW_TAG_lexical_block 
> > between
> > +   the DW_TAG_inlined_subroutine and the DW_TAG_variable for the local.  */
> > +/* { dg-options "-O -gdwarf -dA" } */
> > +/* { dg-do compile } */
> > +/* { dg-final { scan-assembler 
> > "DW_TAG_inlined_subroutine\[^\\(\]*\\(\[^\\)\]*\\)\[^\\(\]*\\(DIE 
> > \\(0x\[0-9a-f\]*\\) DW_TAG_formal_parameter\[^\\(\]*\\(DIE 
> > \\(0x\[0-9a-f\]*\\) DW_TAG_variable" } } */
> > +/* { dg-final { scan-assembler-times "DW_TAG_inlined_subroutine" 2 } } */
> > +
> > +static int foo (int i)
> > +{
> > +  volatile int j = i + 3;
> > +  return j - 2;
> > +}
> > +int main()
> > +{
> > +  volatile int z = foo (-1);
> > +  return z;
> > +}
> > Index: gcc/dwarf2out.c
> > ===================================================================
> > --- gcc/dwarf2out.c     (revision 264640)
> > +++ gcc/dwarf2out.c     (working copy)
> > @@ -3867,7 +3867,7 @@ static void gen_subroutine_type_die (tre
> >  static void gen_typedef_die (tree, dw_die_ref);
> >  static void gen_type_die (tree, dw_die_ref);
> >  static void gen_block_die (tree, dw_die_ref);
> > -static void decls_for_scope (tree, dw_die_ref);
> > +static void decls_for_scope (tree, dw_die_ref, bool = true);
> >  static bool is_naming_typedef_decl (const_tree);
> >  static inline dw_die_ref get_context_die (tree);
> >  static void gen_namespace_die (tree, dw_die_ref);
> > @@ -22389,7 +22389,13 @@ set_block_origin_self (tree stmt)
> >  {
> >    if (BLOCK_ABSTRACT_ORIGIN (stmt) == NULL_TREE)
> >      {
> > -      BLOCK_ABSTRACT_ORIGIN (stmt) = stmt;
> > +      /* We do not mark the outermost block as we are not outputting it.
> > +        This is then a reliable way of determining whether we should
> > +        do the same for an inline instance.  */
> > +      if (TREE_CODE (BLOCK_SUPERCONTEXT (stmt)) != FUNCTION_DECL)
> > +       BLOCK_ABSTRACT_ORIGIN (stmt) = stmt;
> > +      else
> > +       gcc_assert (DECL_INITIAL (BLOCK_SUPERCONTEXT (stmt)) == stmt);
> >
> >        {
> >         tree local_decl;
> > @@ -24149,7 +24155,24 @@ gen_inlined_subroutine_die (tree stmt, d
> >          add_high_low_attributes (stmt, subr_die);
> >        add_call_src_coords_attributes (stmt, subr_die);
> >
> > -      decls_for_scope (stmt, subr_die);
> > +      /* The inliner creates an extra BLOCK for the parameter setup,
> > +         we want to merge that with the actual outermost BLOCK of the
> > +        inlined function to avoid duplicate locals in consumers.  Note
> > +        we specially mark that not as origin-self.
> > +        Do that by doing the recursion to subblocks on the single subblock
> > +        of STMT.  */
> > +      bool unwrap_one = false;
> > +      if (BLOCK_SUBBLOCKS (stmt) && !BLOCK_CHAIN (BLOCK_SUBBLOCKS (stmt)))
> > +       {
> > +         tree origin = block_ultimate_origin (BLOCK_SUBBLOCKS (stmt));
> > +         if (origin
> > +             && TREE_CODE (origin) == BLOCK
> > +             && !BLOCK_ABSTRACT_ORIGIN (origin))
> 
> Can we look at BLOCK_SUPERCONTEXT here rather than above?

Ah, yes.  It could be simply

+             && BLOCK_SUPERCONTEXT (origin) == decl)

I guess.  I also noticed that the very same bug was noticed in
the fixed PP37801 in comment #4 by you but the fix that was installed
didn't fix that part thus with the fix we now regress
gcc.dg/debug/dwarf2/inline2.c which explicitely looks for the bogus
DW_TAG_lexical_blocks.  I have adjusted that testcase now.

Re-bootstrap & regtest in progress on x86_64-unknown-linux-gnu, OK?

Thanks,
Richard.

2018-09-27  Richard Biener  <rguent...@suse.de>

        PR debug/37801
        PR debug/87440
        * dwarf2out.c (set_block_origin_self): Do not mark outermost
        block as we do not output that.
        (gen_inlined_subroutine_die): Elide the originally outermost
        block, matching what we do for concrete instances.
        (decls_for_scope): Add parameter specifying whether to recurse
        to subblocks.

        * gcc.dg/debug/dwarf2/inline2.c: Adjust.
        * gcc.dg/debug/dwarf2/inline4.c: New testcase.

Index: gcc/dwarf2out.c
===================================================================
--- gcc/dwarf2out.c     (revision 264662)
+++ gcc/dwarf2out.c     (working copy)
@@ -3867,7 +3867,7 @@ static void gen_subroutine_type_die (tre
 static void gen_typedef_die (tree, dw_die_ref);
 static void gen_type_die (tree, dw_die_ref);
 static void gen_block_die (tree, dw_die_ref);
-static void decls_for_scope (tree, dw_die_ref);
+static void decls_for_scope (tree, dw_die_ref, bool = true);
 static bool is_naming_typedef_decl (const_tree);
 static inline dw_die_ref get_context_die (tree);
 static void gen_namespace_die (tree, dw_die_ref);
@@ -24147,7 +24147,24 @@ gen_inlined_subroutine_die (tree stmt, d
         add_high_low_attributes (stmt, subr_die);
       add_call_src_coords_attributes (stmt, subr_die);
 
-      decls_for_scope (stmt, subr_die);
+      /* The inliner creates an extra BLOCK for the parameter setup,
+         we want to merge that with the actual outermost BLOCK of the
+        inlined function to avoid duplicate locals in consumers.  Note
+        we specially mark that not as origin-self.
+        Do that by doing the recursion to subblocks on the single subblock
+        of STMT.  */
+      bool unwrap_one = false;
+      if (BLOCK_SUBBLOCKS (stmt) && !BLOCK_CHAIN (BLOCK_SUBBLOCKS (stmt)))
+       {
+         tree origin = block_ultimate_origin (BLOCK_SUBBLOCKS (stmt));
+         if (origin
+             && TREE_CODE (origin) == BLOCK
+             && BLOCK_SUPERCONTEXT (origin) == decl)
+           unwrap_one = true;
+       }
+      decls_for_scope (stmt, subr_die, !unwrap_one);
+      if (unwrap_one)
+       decls_for_scope (BLOCK_SUBBLOCKS (stmt), subr_die);
     }
 }
 
@@ -25775,7 +25792,7 @@ process_scope_var (tree stmt, tree decl,
    all of its sub-blocks.  */
 
 static void
-decls_for_scope (tree stmt, dw_die_ref context_die)
+decls_for_scope (tree stmt, dw_die_ref context_die, bool recurse)
 {
   tree decl;
   unsigned int i;
@@ -25818,10 +25835,11 @@ decls_for_scope (tree stmt, dw_die_ref c
 
   /* Output the DIEs to represent all sub-blocks (and the items declared
      therein) of this block.  */
-  for (subblocks = BLOCK_SUBBLOCKS (stmt);
-       subblocks != NULL;
-       subblocks = BLOCK_CHAIN (subblocks))
-    gen_block_die (subblocks, context_die);
+  if (recurse)
+    for (subblocks = BLOCK_SUBBLOCKS (stmt);
+        subblocks != NULL;
+        subblocks = BLOCK_CHAIN (subblocks))
+      gen_block_die (subblocks, context_die);
 }
 
 /* Is this a typedef we can avoid emitting?  */
Index: gcc/testsuite/gcc.dg/debug/dwarf2/inline2.c
===================================================================
--- gcc/testsuite/gcc.dg/debug/dwarf2/inline2.c (revision 264662)
+++ gcc/testsuite/gcc.dg/debug/dwarf2/inline2.c (working copy)
@@ -23,12 +23,10 @@
      of third, second and first.  */
 /* { dg-final { scan-assembler-times "\\(DIE \\(\[^\n\]*\\) 
DW_TAG_inlined_subroutine" 6 } } */
 
-/* Likewise we should have 6 DW_TAG_lexical_block DIEs:
-   - One for each subroutine inlined into main, so that's 3.
-   - One for each subroutine inlined in the out of line instances
-     of third, second and first, that's 3.
-*/
-/* { dg-final { scan-assembler-times "\\(DIE \\(\[^\n\]*\\) 
DW_TAG_lexical_block" 6 } } */
+/* We should have no DW_TAG_lexical_block DIEs, all inline instances
+   should have the first subblock elided to match the abstract instance
+   layout.  */
+/* { dg-final { scan-assembler-times "\\(DIE \\(\[^\n\]*\\) 
DW_TAG_lexical_block" 0 } } */
 
 
 /* There are 3 DW_AT_inline attributes: one per abstract inline instance.
Index: gcc/testsuite/gcc.dg/debug/dwarf2/inline4.c
===================================================================
--- gcc/testsuite/gcc.dg/debug/dwarf2/inline4.c (nonexistent)
+++ gcc/testsuite/gcc.dg/debug/dwarf2/inline4.c (working copy)
@@ -0,0 +1,17 @@
+/* Verify that the inline instance has no extra DW_TAG_lexical_block between
+   the DW_TAG_inlined_subroutine and the DW_TAG_variable for the local.  */
+/* { dg-options "-O -gdwarf -dA" } */
+/* { dg-do compile } */
+/* { dg-final { scan-assembler 
"DW_TAG_inlined_subroutine\[^\\(\]*\\(\[^\\)\]*\\)\[^\\(\]*\\(DIE 
\\(0x\[0-9a-f\]*\\) DW_TAG_formal_parameter\[^\\(\]*\\(DIE \\(0x\[0-9a-f\]*\\) 
DW_TAG_variable" } } */
+/* { dg-final { scan-assembler-times "DW_TAG_inlined_subroutine" 2 } } */
+
+static int foo (int i)
+{
+  volatile int j = i + 3;
+  return j - 2;
+}
+int main()
+{
+  volatile int z = foo (-1);
+  return z;
+}

Reply via email to