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 |
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
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; +}
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
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? */