This is the mail archive of the mailing list for the GCC project.

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] Prune useless .debug_loc entries (PR debug/43442)


While working on PR43058, I've noticed that we emit tons of useless
.debug_loc entries.  By useless I mean locations for variable in ranges
where the variable isn't said to be in scope.  If a variable DIE is
a child of DW_TAG_lexical_block or DW_TAG_inlined_subroutine which has
DW_AT_ranges 0-10 20-30 40-50, then a .debug_loc entry that the variable
is alive in regXYZ between 12 and 18 or 30 and 40 is IMNSHO not useful
to any of the debug info consumers, the debugger will not find the variable
on insn 15 at all, as it is not in scope there.

While it would be best to prune this already at var-tracking time (and
perhaps, even avoid tracking related VALUEs that aren't used for anything
else beyond certain spot), it would be very hard.  There is some minor code
motion even after var-tracking (delayed branch scheduling) and because of
that movement, splitting blocks into fragments would be also premature.
Perhaps one day when cfg is maintained up to final var-tracking could be
taught about SEQUENCEs and dbr stuff and run after dbr, right before final.

So this patch instead does the pruning at the time when debug info is
generated.  It is done by remembering block scope change events
(each group of NOTE_INSN_BLOCK_{BEG,END} notes with no intervening real
insns is assigned an even number, odd numbers in between stand for
places in real insns between the two scope change note groups.
Each dwarf2out_var_location call remembers the scope change event counter
value at the spot where the note is present (it can be also at the
scope change note boundary if there are no insns in between it and the
NOTE_INSN_BLOCK_{BEG,END} notes, or somewhere in between - notes for
inside of a call are always considered in between the note groups)
and when we create location lists from var_loc_node chain recorded
by dwarf2out_var_location, we can skip entries which are not in the range(s)
of the containing DW_TAG_lexical_block/DW_TAG_inlined_subroutine.

The patch has big effect on the size of debug info.  Here are changes
from vanilla tree with the patch below applied but effectively disabled
(added "|| 1" in the first conditional in in_scope_var_loc_node, so
all nodes are considered to be in scope like they used to be) to
patched tree where the "|| 1" is missing.
x86_64-linux stage3 cc1plus all nodes in scope:
  [28] .debug_info       PROGBITS        0000000000000000 10eb517 149eab7 00      0   0  1
  [32] .debug_loc        PROGBITS        0000000000000000 2a6ace7 1e300ab 00      0   0  1
  [34] .debug_ranges     PROGBITS        0000000000000000 49fcab8 7b8020 00      0   0  1
x86_64-linux stage3 cc1plus with the patch:
  [28] .debug_info       PROGBITS        0000000000000000 10eb517 149af57 00      0   0  1
  [32] .debug_loc        PROGBITS        0000000000000000 2a672c4 1318257 00      0   0  1
  [34] .debug_ranges     PROGBITS        0000000000000000 3ee1241 7b7fa0 00      0   0  1
i686-linux stage3 cc1plus all nodes in scope:
  [28] .debug_info       PROGBITS        00000000 1002ada 139b6cd 00      0   0  1
  [33] .debug_loc        PROGBITS        00000000 2905694 f6b1b1 00      0   0  1
  [35] .debug_ranges     PROGBITS        00000000 39d3741 3c1400 00      0   0  1
i686-linux stage3 cc1plus with the patch:
  [28] .debug_info       PROGBITS        00000000 1002ada 1397d82 00      0   0  1
  [33] .debug_loc        PROGBITS        00000000 2901ed0 9b0f44 00      0   0  1
  [35] .debug_ranges     PROGBITS        00000000 3415d10 3c1438 00      0   0  1
This was --enable-checking=yes,rtl build btw.  Approximately 3500 variables
(mostly __t or __i from the various rtl checking macros) lost their DW_AT_location
altogether, because none of the .debug_loc entries for them overlapped with the
ranges of the containing block, and .debug_loc shrunk by ~ 37%.
cc1plus size on x86_64 decreased from 86921679 to 75274552 bytes, and on i686
from 65568300 59548797 to bytes.

Attached is a short analysis of a few randomly chosen variables that lost their
DW_AT_location resp. their location list shrunk.  Always .debug_info snippet
is followed by related .debug_ranges snippet followed by .debug_loc snippet.

Earlier version of the patch (the one attached in the PR) saved even more,
but only because it was throwing also entries which were in scope - I assumed
block fragments are sorted in order of increasing PC, but they were sorted
with smallest PC fragment coming first, then highest PC fragment, then one
before highest PC fragment, etc. down to second PC fragment.  So for one or
two fragments blocks it worked well, but for more fragmented blocks it could
think some range is not in scope when it actually was.  This got fixed by
the function.c changes - the effect is that now DW_AT_ranges lists are
sorted by increasing PC, at least within each section (hot cold partitioning
still can make the sorting appear in different order, they are sorted
by increasing assembly line number and not PC actually, but that's what
is desirable for the location list pruning anyway).

CCing some folks from the debug info consumer side to verify that we are
indeed dropping info that consumers aren't interested in.

I'd say it can be declared to fix a regression that .debug_loc size increased
by huge amount from 4.4; if it would be for something useful, that's of course
price to be paid for better debug info, but if lots of that growth accounts
for info that no debug info consumer will ever care about...

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?


Attachment: Y604g
Description: Text document

Attachment: X
Description: Text document

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]