On Wed, 21 Aug 2024, Richard Biener wrote: > On Tue, 20 Aug 2024, Bernd Edlinger wrote: > > > On 8/20/24 13:00, Richard Biener wrote: > > > On Fri, Aug 16, 2024 at 12:49 PM Bernd Edlinger > > > <bernd.edlin...@hotmail.de> wrote: > > >> > > >> While this already works correctly for the case when an inlined > > >> subroutine contains only one subrange, a redundant DW_TAG_lexical_block > > >> is still emitted when the subroutine has multiple blocks. > > > > > > Huh. The point is that the inline context is a single scope block with no > > > siblings - how did that get messed up? The patch unfortunately does not > > > contain a testcase. > > > > > > > Well, I became aware of this because I am working on a gdb patch, > > which improves the debug experience of optimized C code, and to my surprise > > the test case did not work with gcc-8, while gcc-9 and following were fine. > > Initially I did not see what is wrong, therefore I started to bisect when > > this changed, and so I found your patch, which removed some lexical blocks > > in the debug info of this gdb test case: > > > > from binutils-gdb/gdb/testsuite/gdb.cp/step-and-next-inline.cc > > in case you have the binutils-gdb already downloaded you can skip this: > > $ git clone git://sourceware.org/git/binutils-gdb > > $ cd binutils-gdb/gdb/testsuite/gdb.cp > > $ gcc -g -O2 step-and-next-inline.cc > > > > when you look at the debug info with readelf -w a.out > > you will see, that the function "tree_check" > > is inlined three times, one looks like this > > <2><86b>: Abbrev Number: 40 (DW_TAG_inlined_subroutine) > > <86c> DW_AT_abstract_origin: <0x95b> > > <870> DW_AT_entry_pc : 0x1175 > > <878> DW_AT_GNU_entry_view: 0 > > <879> DW_AT_ranges : 0x21 > > <87d> DW_AT_call_file : 1 > > <87e> DW_AT_call_line : 52 > > <87f> DW_AT_call_column : 10 > > <880> DW_AT_sibling : <0x8bf> > > <3><884>: Abbrev Number: 8 (DW_TAG_formal_parameter) > > <885> DW_AT_abstract_origin: <0x974> > > <889> DW_AT_location : 0x37 (location list) > > <88d> DW_AT_GNU_locviews: 0x35 > > <3><891>: Abbrev Number: 8 (DW_TAG_formal_parameter) > > <892> DW_AT_abstract_origin: <0x96c> > > <896> DW_AT_location : 0x47 (location list) > > <89a> DW_AT_GNU_locviews: 0x45 > > <3><89e>: Abbrev Number: 41 (DW_TAG_lexical_block) > > <89f> DW_AT_ranges : 0x21 > > > > see the lexical block has the same DW_AT_ranges, as the > > inlined subroutine, but the other invocations do not > > have this lexical block, since your original fix removed > > those. > > And this lexical block triggered an unexpected issue > > in my gdb patch, which I owe you one, for helping me > > finding it :-) > > > > Before that I have never looked at these lexical blocks, > > but all I can say is that while compiling this test case, > > in the first invocation of gen_inlined_subroutine_die > > there are several SUBBLOCKS linked via BLOCK_CHAIN, > > and only the first one is used to emit the lexical_block, > > while the other siblings must be fully decoded, otherwise > > there is an internal error, that I found by try-and-error. > > I thought that is since the subroutine is split over several > > places, and therefore it appeared natural to me, that the > > subroutine is also using several SUBBLOCKS. > > OK, so the case in question looks like > > { Scope block #8 step-and-next-inline.cc:52 Originating from : static > struct tree * tree_check (struct tree *, int); Fragment chain : #16 #17 > struct tree * t; > int i; > > { Scope block #9 Originating from :#0 Fragment chain : #10 #11 > struct tree * x; > > } > > { Scope block #10 Originating from :#0 Fragment of : #9 > struct tree * x; > > } > > { Scope block #11 Originating from :#0 Fragment of : #9 > struct tree * x; > > } > > } > > so we have fragments here which we should ignore, but then fragments > are to collect multiple ranges which, when we do not emit a > lexical block for block #9 above, we will likely fail to emit and > which we instead should associate with block #8, the > DW_TAG_inlined_subroutine. > > Somehow it seems to "work" as to associate DW_AT_ranges with the > DW_TAG_inlined_subroutine. > > I've used the following - there's no need to process BLOCK_CHAIN > as fragments are ignored by gen_block_die. > > diff --git a/gcc/dwarf2out.cc b/gcc/dwarf2out.cc > index d5144714c6e..4e6ad2ab7e1 100644 > --- a/gcc/dwarf2out.cc > +++ b/gcc/dwarf2out.cc > @@ -25194,8 +25194,13 @@ gen_inlined_subroutine_die (tree stmt, dw_die_ref > context_die) > 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))) > + if (BLOCK_SUBBLOCKS (stmt)) > { > + tree subblock = BLOCK_SUBBLOCKS (stmt); > + /* We should never elide that BLOCK, but we may have multiple > fragments. > + Assert that there's only a single real inline-scope block. */ > + for (tree next = BLOCK_CHAIN (subblock); next; next = BLOCK_CHAIN > (next)) > + gcc_checking_assert (BLOCK_FRAGMENT_ORIGIN (next) == subblock); > tree origin = block_ultimate_origin (BLOCK_SUBBLOCKS (stmt)); > if (origin > && TREE_CODE (origin) == BLOCK > > I'm quite sure this will blow up, so the appropriate thing would be > to only unwrap the block if the assertion would hold.
ICEs for example c-c++-common/torture/complex-sign-mixed-div.c and gcc.dg/torture/pr50823.c. The latter has { Scope block #24 /space/rguenther/src/gcc/gcc/testsuite/gcc.dg/torture/pr50823.c:25 Originating from : static void emit_pattern_after_noloc (int (*<T3dc>) (void)); Fragment chain : #31 int (*<T3dc>) (void) make_raw; { Scope block #25 /space/rguenther/src/gcc/gcc/testsuite/gcc.dg/torture/pr50823.c:29 Originating from : static int make_insn_raw (void); Fragment chain : #28 { Scope block #26 Originating from :#0 Fragment chain : #27 } { Scope block #27 Originating from :#0 Fragment of : #26 } } { Scope block #28 /space/rguenther/src/gcc/gcc/testsuite/gcc.dg/torture/pr50823.c:29 Originating from : static int make_insn_raw (void); Fragment of : #25 } { Scope block #29 /space/rguenther/src/gcc/gcc/testsuite/gcc.dg/torture/pr50823.c:30 Originating from : static void add_insn_after (void); { Scope block #30 Originating from :#0 } } } so that's for a function without any local vars, it does seem we have to check explicitly for the case with "proper" fragments and otherwise not unwrap. Can you update your patch accordingly? Richard. > I'm testing the above. > > Richard. > > > > > Thanks > > Bernd. > > > > > Richard. > > > > > >> Fixes: ac02e5b75451 ("re PR debug/37801 (DWARF output for inlined > > >> functions > > >> doesn't always use DW_TAG_inlined_subroutine)") > > >> > > >> gcc/ChangeLog: > > >> > > >> PR debug/87440 > > >> * dwarf2out.cc (gen_inlined_subroutine_die): Handle the case > > >> of multiple subranges correctly. > > >> --- > > >> some more context is here: > > >> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87440#c5 > > >> Bootstrapped and regression-tested on x86_64-pc-linux-gnu, OK for trunk? > > >> > > >> gcc/dwarf2out.cc | 11 ++++++++--- > > >> 1 file changed, 8 insertions(+), 3 deletions(-) > > >> > > >> diff --git a/gcc/dwarf2out.cc b/gcc/dwarf2out.cc > > >> index 357efaa5990..346feeb53c8 100644 > > >> --- a/gcc/dwarf2out.cc > > >> +++ b/gcc/dwarf2out.cc > > >> @@ -25171,9 +25171,10 @@ gen_inlined_subroutine_die (tree stmt, > > >> dw_die_ref context_die) > > >> 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 sub = BLOCK_SUBBLOCKS (stmt); > > >> + if (sub) > > >> { > > >> - tree origin = block_ultimate_origin (BLOCK_SUBBLOCKS (stmt)); > > >> + tree origin = block_ultimate_origin (sub); > > >> if (origin > > >> && TREE_CODE (origin) == BLOCK > > >> && BLOCK_SUPERCONTEXT (origin) == decl) > > >> @@ -25181,7 +25182,11 @@ gen_inlined_subroutine_die (tree stmt, > > >> dw_die_ref context_die) > > >> } > > >> decls_for_scope (stmt, subr_die, !unwrap_one); > > >> if (unwrap_one) > > >> - decls_for_scope (BLOCK_SUBBLOCKS (stmt), subr_die); > > >> + { > > >> + decls_for_scope (sub, subr_die); > > >> + for (sub = BLOCK_CHAIN (sub); sub; sub = BLOCK_CHAIN (sub)) > > >> + gen_block_die (sub, subr_die); > > >> + } > > >> } > > >> > > >> /* Generate a DIE for a field in a record, or structure. CTX is > > >> required: see > > >> -- > > >> 2.39.2 > > >> > > > > -- Richard Biener <rguent...@suse.de> SUSE Software Solutions Germany GmbH, Frankenstrasse 146, 90461 Nuernberg, Germany; GF: Ivo Totev, Andrew McDonald, Werner Knoblich; (HRB 36809, AG Nuernberg)