diff mbox series

Fix PR87440, extra lexical block in inline instances

Message ID alpine.LSU.2.20.1809261531040.16707@zhemvz.fhfr.qr
State New
Headers show
Series Fix PR87440, extra lexical block in inline instances | expand

Commit Message

Richard Biener Sept. 26, 2018, 1:35 p.m. UTC
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  <rguenther@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.

Comments

Jason Merrill Sept. 26, 2018, 2:47 p.m. UTC | #1
On Wed, Sep 26, 2018 at 9:35 AM, Richard Biener <rguenther@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  <rguenther@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?

Jason
Richard Biener Sept. 27, 2018, 7:28 a.m. UTC | #2
On Wed, 26 Sep 2018, Jason Merrill wrote:

> On Wed, Sep 26, 2018 at 9:35 AM, Richard Biener <rguenther@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  <rguenther@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  <rguenther@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;
+}
Jason Merrill Sept. 27, 2018, 1:41 p.m. UTC | #3
On Thu, Sep 27, 2018 at 3:28 AM, Richard Biener <rguenther@suse.de> wrote:
> On Wed, 26 Sep 2018, Jason Merrill wrote:
>
>> On Wed, Sep 26, 2018 at 9:35 AM, Richard Biener <rguenther@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  <rguenther@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  <rguenther@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.

This sentence is no longer accurate; OK with it removed.

Jason
diff mbox series

Patch

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))
+	    unwrap_one = true;
+	}
+      decls_for_scope (stmt, subr_die, !unwrap_one);
+      if (unwrap_one)
+	decls_for_scope (BLOCK_SUBBLOCKS (stmt), subr_die);
     }
 }
 
@@ -25777,7 +25800,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;
@@ -25820,10 +25843,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?  */