On the https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94495#c5 testcase GCC emits worse debug info after the PR92264 cselib.c changes. The difference at -O2 -g -dA in the assembly is (when ignoring debug info): # DEBUG g => [argp] # DEBUG k => [argp+0x20] # DEBUG j => [argp+0x18] # DEBUG a => di # DEBUG b => si # DEBUG c => dx # DEBUG d => cx # DEBUG h => [argp+0x8] # DEBUG e => r8 # DEBUG i => [argp+0x10] # DEBUG f => r9 ... .LVL4: + # DEBUG h => [sp+0x10] + # DEBUG i => [sp+0x18] + # DEBUG j => [sp+0x20] + # DEBUG k => [sp+0x28] # DEBUG c => entry_value # SUCC: EXIT [always] count:1073741824 (estimated locally) ret .LVL5: + # DEBUG k => [argp+0x20] # DEBUG a => bx # DEBUG b => si # DEBUG c => dx # DEBUG d => cx # DEBUG e => r8 # DEBUG f => r9 + # DEBUG h => [argp+0x8] + # DEBUG i => [argp+0x10] + # DEBUG j => [argp+0x18] This means that before the changes, h, i, j, k could be all expressed in DW_AT_location directly with DW_OP_fbreg <some_offset>, but now we need to use a location list, where in the first part of the function and last part of the function (everything except the ret instruction) we use that DW_OP_fbreg <some_offset>, but for the single ret instruction we instead say those values live in something pointed by stack pointer + offset. It is true, but only because stack pointer + offset is equal to DW_OP_fbreg <some_offset> at that point. The var-tracking pass has for !frame_pointer_needed functions code to canonicalize stack pointer uses in the insns before it hands it over to cselib to cfa_base_rtx + offset depending on the stack depth at each point. The problem is that on the last epilogue pop insn (the one right before ret) the canonicalization is sp = argp - 8 and add_stores records a MO_VAL_SET operation for that argp - 8 value (which is the SP_DERIVED_VALUE_P VALUE the cselib changes canonicalize sp based accesses on) and thus var-tracking from that point onwards tracks that that VALUE (2:2) now lives in sp. At the end of function it of course needs to forget it again (or it would need on any changes to sp). But when processing that uop, we note that the VALUE has changed and anything based on it changed too, so emit changes for everything. Before that var-tracking itself doesn't track it in any register, so uses cselib and cselib knows through the permanent equivs how to compute it using argp (i.e. what will be DW_OP_fbreg). The following fix has two parts. One is it detects if cselib can compute a certain VALUE using the cfa_base_rtx and for such VALUEs doesn't add the MO_VAL_SET operation, as it is better to express them using cfa_base_rtx rather than temporarily through something else. And the other is make sure we reuse in !frame_pointer_needed the single SP_DERIVED_VALUE_P VALUE in other extended basic blocks too (and other VALUEs) too. This can be done because we have computed the stack depths at the start of each basic block in vt_stack_adjustments and while cselib_reset_table is called at the end of each extended bb, which throws away all hard registers (but the magic cfa_base_rtx) and so can hint cselib.c at the start of the ebb what VALUE the sp hard reg has. That means fewer VALUEs during var-tracking and more importantly that they will all have the cfa_base_rtx + offset equivalency. I have performed 4 bootstraps+regtests (x86_64-linux and i686-linux, each with this patch (that is the new cselib + var-tracking variant) and once with that patch reverted as well as all other cselib.c changes from this month; once that bootstrapped, I've reapplied the cselib.c changes and this patch and rebuilt cc1plus, so that the content is comparable, but built with the pre-Apr 2 cselib.c+var-tracking.c (that is the old cselib one)). Below are readelf -WS cc1plus | grep debug_ filtered to only have debug sections whose size actually changed, followed by dwlocstat results on cc1plus. This shows that there was about 3% shrink in those .debug* sections for 32-bit and 1% shrink for 64-bit, with minor variable coverage changes one or the other way that are IMHO insignificant. 32-bit old cselib [33] .debug_info PROGBITS 00000000 29139c0 710e5fa 00 0 0 1 [34] .debug_abbrev PROGBITS 00000000 9a21fba 21ad6d 00 0 0 1 [35] .debug_line PROGBITS 00000000 9c3cd27 1a05e56 00 0 0 1 [36] .debug_str PROGBITS 00000000 b642b7d 7cad09 01 MS 0 0 1 [37] .debug_loc PROGBITS 00000000 be0d886 5792627 00 0 0 1 [38] .debug_ranges PROGBITS 00000000 1159fead e57218 00 0 0 1 sum 263075589B 32-bit new cselib + var-tracking [33] .debug_info PROGBITS 00000000 29129c0 71065d1 00 0 0 1 [34] .debug_abbrev PROGBITS 00000000 9a18f91 21af28 00 0 0 1 [35] .debug_line PROGBITS 00000000 9c33eb9 195dffc 00 0 0 1 [36] .debug_str PROGBITS 00000000 b591eb5 7cace0 01 MS 0 0 1 [37] .debug_loc PROGBITS 00000000 bd5cb95 50185bf 00 0 0 1 [38] .debug_ranges PROGBITS 00000000 10d75154 e57068 00 0 0 1 sum 254515196B (8560393B smaller) 64-bit old cselib [33] .debug_info PROGBITS 0000000000000000 25e64b0 84d7cc9 00 0 0 1 [34] .debug_abbrev PROGBITS 0000000000000000 aabe179 225e2d 00 0 0 1 [35] .debug_line PROGBITS 0000000000000000 ace3fa6 19a3505 00 0 0 1 [37] .debug_loc PROGBITS 0000000000000000 ce6e960 89707bc 00 0 0 1 [38] .debug_ranges PROGBITS 0000000000000000 157df11c 1c59a70 00 0 0 1 sum 342274599B 64-bit new cselib + var-tracking [33] .debug_info PROGBITS 0000000000000000 25e64b0 84d8e86 00 0 0 1 [34] .debug_abbrev PROGBITS 0000000000000000 aabf336 225e8d 00 0 0 1 [35] .debug_line PROGBITS 0000000000000000 ace51c3 199ded5 00 0 0 1 [37] .debug_loc PROGBITS 0000000000000000 ce6a54d 85f62da 00 0 0 1 [38] .debug_ranges PROGBITS 0000000000000000 15460827 1c59a20 00 0 0 1 sum 338610402B (3664197B smaller) 32-bit old cselib cov% samples cumul 0..10 1231599/48% 1231599/48% 11..20 31017/1% 1262616/49% 21..30 36495/1% 1299111/51% 31..40 35846/1% 1334957/52% 41..50 47179/1% 1382136/54% 51..60 41203/1% 1423339/56% 61..70 65504/2% 1488843/58% 71..80 59656/2% 1548499/61% 81..90 104399/4% 1652898/65% 91..100 882231/34% 2535129/100% 32-bit new cselib + var-tracking cov% samples cumul 0..10 1230542/48% 1230542/48% 11..20 30385/1% 1260927/49% 21..30 36393/1% 1297320/51% 31..40 36053/1% 1333373/52% 41..50 47670/1% 1381043/54% 51..60 41599/1% 1422642/56% 61..70 65902/2% 1488544/58% 71..80 59911/2% 1548455/61% 81..90 104607/4% 1653062/65% 91..100 882067/34% 2535129/100% 64-bit old cselib cov% samples cumul 0..10 1233211/48% 1233211/48% 11..20 31120/1% 1264331/49% 21..30 39230/1% 1303561/51% 31..40 38887/1% 1342448/52% 41..50 47519/1% 1389967/54% 51..60 45264/1% 1435231/56% 61..70 69431/2% 1504662/59% 71..80 62114/2% 1566776/61% 81..90 104587/4% 1671363/65% 91..100 876085/34% 2547448/100% 64-bit new cselib + var-tracking cov% samples cumul 0..10 1233471/48% 1233471/48% 11..20 31093/1% 1264564/49% 21..30 39217/1% 1303781/51% 31..40 38851/1% 1342632/52% 41..50 47488/1% 1390120/54% 51..60 45224/1% 1435344/56% 61..70 69409/2% 1504753/59% 71..80 62140/2% 1566893/61% 81..90 104616/4% 1671509/65% 91..100 875939/34% 2547448/100% 2020-04-09 Jakub Jelinek <jakub@redhat.com> PR debug/94495 * cselib.h (cselib_record_sp_cfa_base_equiv, cselib_sp_derived_value_p): Declare. * cselib.c (cselib_record_sp_cfa_base_equiv, cselib_sp_derived_value_p): New functions. * var-tracking.c (add_stores): Don't record MO_VAL_SET for cselib_sp_derived_value_p values. (vt_initialize): Call cselib_record_sp_cfa_base_equiv at the start of extended basic blocks other than the first one for !frame_pointer_needed functions.
143 lines
4.5 KiB
C
143 lines
4.5 KiB
C
/* Common subexpression elimination for GNU compiler.
|
|
Copyright (C) 1987-2020 Free Software Foundation, Inc.
|
|
|
|
This file is part of GCC.
|
|
|
|
GCC is free software; you can redistribute it and/or modify it under
|
|
the terms of the GNU General Public License as published by the Free
|
|
Software Foundation; either version 3, or (at your option) any later
|
|
version.
|
|
|
|
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with GCC; see the file COPYING3. If not see
|
|
<http://www.gnu.org/licenses/>. */
|
|
|
|
#ifndef GCC_CSELIB_H
|
|
#define GCC_CSELIB_H
|
|
|
|
/* Describe a value. */
|
|
struct cselib_val
|
|
{
|
|
/* The hash value. */
|
|
unsigned int hash;
|
|
|
|
/* A unique id assigned to values. */
|
|
int uid;
|
|
|
|
/* A VALUE rtx that points back to this structure. */
|
|
rtx val_rtx;
|
|
|
|
/* All rtl expressions that hold this value at the current time during a
|
|
scan. */
|
|
struct elt_loc_list *locs;
|
|
|
|
/* If this value is used as an address, points to a list of values that
|
|
use it as an address in a MEM. */
|
|
struct elt_list *addr_list;
|
|
|
|
struct cselib_val *next_containing_mem;
|
|
};
|
|
|
|
/* A list of rtl expressions that hold the same value. */
|
|
struct elt_loc_list {
|
|
/* Next element in the list. */
|
|
struct elt_loc_list *next;
|
|
/* An rtl expression that holds the value. */
|
|
rtx loc;
|
|
/* The insn that made the equivalence. */
|
|
rtx_insn *setting_insn;
|
|
};
|
|
|
|
/* Describe a single set that is part of an insn. */
|
|
struct cselib_set
|
|
{
|
|
rtx src;
|
|
rtx dest;
|
|
cselib_val *src_elt;
|
|
cselib_val *dest_addr_elt;
|
|
};
|
|
|
|
enum cselib_record_what
|
|
{
|
|
CSELIB_RECORD_MEMORY = 1,
|
|
CSELIB_PRESERVE_CONSTANTS = 2
|
|
};
|
|
|
|
extern void (*cselib_discard_hook) (cselib_val *);
|
|
extern void (*cselib_record_sets_hook) (rtx_insn *insn, struct cselib_set *sets,
|
|
int n_sets);
|
|
|
|
extern cselib_val *cselib_lookup (rtx, machine_mode,
|
|
int, machine_mode);
|
|
extern cselib_val *cselib_lookup_from_insn (rtx, machine_mode,
|
|
int, machine_mode, rtx_insn *);
|
|
extern void cselib_init (int);
|
|
extern void cselib_clear_table (void);
|
|
extern void cselib_finish (void);
|
|
extern void cselib_process_insn (rtx_insn *);
|
|
extern bool fp_setter_insn (rtx_insn *);
|
|
extern machine_mode cselib_reg_set_mode (const_rtx);
|
|
extern int rtx_equal_for_cselib_1 (rtx, rtx, machine_mode, int);
|
|
extern int references_value_p (const_rtx, int);
|
|
extern rtx cselib_expand_value_rtx (rtx, bitmap, int);
|
|
typedef rtx (*cselib_expand_callback)(rtx, bitmap, int, void *);
|
|
extern rtx cselib_expand_value_rtx_cb (rtx, bitmap, int,
|
|
cselib_expand_callback, void *);
|
|
extern bool cselib_dummy_expand_value_rtx_cb (rtx, bitmap, int,
|
|
cselib_expand_callback, void *);
|
|
extern rtx cselib_subst_to_values (rtx, machine_mode);
|
|
extern rtx cselib_subst_to_values_from_insn (rtx, machine_mode, rtx_insn *);
|
|
extern void cselib_invalidate_rtx (rtx);
|
|
|
|
extern void cselib_reset_table (unsigned int);
|
|
extern unsigned int cselib_get_next_uid (void);
|
|
extern void cselib_preserve_value (cselib_val *);
|
|
extern bool cselib_preserved_value_p (cselib_val *);
|
|
extern void cselib_preserve_only_values (void);
|
|
extern void cselib_preserve_cfa_base_value (cselib_val *, unsigned int);
|
|
extern void cselib_add_permanent_equiv (cselib_val *, rtx, rtx_insn *);
|
|
extern bool cselib_have_permanent_equivalences (void);
|
|
extern void cselib_set_value_sp_based (cselib_val *);
|
|
extern bool cselib_sp_based_value_p (cselib_val *);
|
|
extern void cselib_record_sp_cfa_base_equiv (HOST_WIDE_INT, rtx_insn *);
|
|
extern bool cselib_sp_derived_value_p (cselib_val *);
|
|
|
|
extern void dump_cselib_table (FILE *);
|
|
|
|
/* Return the canonical value for VAL, following the equivalence chain
|
|
towards the earliest (== lowest uid) equivalent value. */
|
|
|
|
static inline cselib_val *
|
|
canonical_cselib_val (cselib_val *val)
|
|
{
|
|
cselib_val *canon;
|
|
|
|
if (!val->locs || val->locs->next
|
|
|| !val->locs->loc || GET_CODE (val->locs->loc) != VALUE
|
|
|| val->uid < CSELIB_VAL_PTR (val->locs->loc)->uid)
|
|
return val;
|
|
|
|
canon = CSELIB_VAL_PTR (val->locs->loc);
|
|
gcc_checking_assert (canonical_cselib_val (canon) == canon);
|
|
return canon;
|
|
}
|
|
|
|
/* Return nonzero if we can prove that X and Y contain the same value, taking
|
|
our gathered information into account. */
|
|
|
|
static inline int
|
|
rtx_equal_for_cselib_p (rtx x, rtx y)
|
|
{
|
|
if (x == y)
|
|
return 1;
|
|
|
|
return rtx_equal_for_cselib_1 (x, y, VOIDmode, 0);
|
|
}
|
|
|
|
#endif /* GCC_CSELIB_H */
|