The PR52001 alias.c patch meant to avoid infinite recursion among permanent equivalences within VTA introduced some relatively expensive behavior that showed up as (apparently?)-infinite recursion within dse on AVR for one gcc.c-torture/compile test.
This patch reworks get_addr so that it behaves exactly as before when permanent equivalences are not in use (i.e., any pass other than var tracking) and retains the heuristics that avoids infinite recursion only when permanent equivalences are present, when needed. Regstrapped on x86_64-linux-gnu and i686-pc-linux-gnu, compile-time tested for the given AVR testcase, approved (minus the comment before the newly-added function) by Jakub in bugzilla, checking in.
for gcc/ChangeLog from Alexandre Oliva <aol...@redhat.com> PR debug/52001 PR rtl-optimization/52417 * cselib.c (cselib_any_perm_equivs): New variable. (cselib_reset_table): Check that it's not set when not preserving constants. (cselib_add_permanent_equiv): Set it. (cselib_have_permanent_equivalences): New. (cselib_init, cselib_finish): Reset it. * cselib.h (cselib_have_permanent_equivalences): Declare. * alias.c (get_addr): Restore earlier behavior when there aren't permanent equivalences. Index: gcc/alias.c =================================================================== --- gcc/alias.c.orig 2012-03-01 04:25:47.348625625 -0300 +++ gcc/alias.c 2012-03-01 07:49:11.000000000 -0300 @@ -1811,20 +1811,34 @@ get_addr (rtx x) v = CSELIB_VAL_PTR (x); if (v) { - v = canonical_cselib_val (v); + bool have_equivs = cselib_have_permanent_equivalences (); + if (have_equivs) + v = canonical_cselib_val (v); for (l = v->locs; l; l = l->next) if (CONSTANT_P (l->loc)) return l->loc; for (l = v->locs; l; l = l->next) - if (!REG_P (l->loc) && !MEM_P (l->loc) && GET_CODE (l->loc) != VALUE - && !refs_newer_value_p (l->loc, x)) + if (!REG_P (l->loc) && !MEM_P (l->loc) + /* Avoid infinite recursion when potentially dealing with + var-tracking artificial equivalences, by skipping the + equivalences themselves, and not choosing expressions + that refer to newer VALUEs. */ + && (!have_equivs + || (GET_CODE (l->loc) != VALUE + && !refs_newer_value_p (l->loc, x)))) return l->loc; - for (l = v->locs; l; l = l->next) - if (REG_P (l->loc) || (GET_CODE (l->loc) != VALUE - && !refs_newer_value_p (l->loc, x))) - return l->loc; - /* Return the canonical value. */ - return v->val_rtx; + if (have_equivs) + { + for (l = v->locs; l; l = l->next) + if (REG_P (l->loc) + || (GET_CODE (l->loc) != VALUE + && !refs_newer_value_p (l->loc, x))) + return l->loc; + /* Return the canonical value. */ + return v->val_rtx; + } + if (v->locs) + return v->locs->loc; } return x; } Index: gcc/cselib.c =================================================================== --- gcc/cselib.c.orig 2012-03-01 07:44:32.426668955 -0300 +++ gcc/cselib.c 2012-03-01 13:15:07.000000000 -0300 @@ -52,6 +52,7 @@ struct elt_list { static bool cselib_record_memory; static bool cselib_preserve_constants; +static bool cselib_any_perm_equivs; static int entry_and_rtx_equal_p (const void *, const void *); static hashval_t get_value_hash (const void *); static struct elt_list *new_elt_list (struct elt_list *, cselib_val *); @@ -477,7 +478,10 @@ cselib_reset_table (unsigned int num) if (cselib_preserve_constants) htab_traverse (cselib_hash_table, preserve_constants_and_equivs, NULL); else - htab_empty (cselib_hash_table); + { + htab_empty (cselib_hash_table); + gcc_checking_assert (!cselib_any_perm_equivs); + } n_useless_values = 0; n_useless_debug_values = 0; @@ -2388,6 +2392,8 @@ cselib_add_permanent_equiv (cselib_val * if (nelt != elt) { + cselib_any_perm_equivs = true; + if (!PRESERVED_VALUE_P (nelt->val_rtx)) cselib_preserve_value (nelt); @@ -2397,6 +2403,14 @@ cselib_add_permanent_equiv (cselib_val * cselib_current_insn = save_cselib_current_insn; } +/* Return TRUE if any permanent equivalences have been recorded since + the table was last initialized. */ +bool +cselib_have_permanent_equivalences (void) +{ + return cselib_any_perm_equivs; +} + /* There is no good way to determine how many elements there can be in a PARALLEL. Since it's fairly cheap, use a really large number. */ #define MAX_SETS (FIRST_PSEUDO_REGISTER * 2) @@ -2651,6 +2665,7 @@ cselib_init (int record_what) value_pool = create_alloc_pool ("value", RTX_CODE_SIZE (VALUE), 100); cselib_record_memory = record_what & CSELIB_RECORD_MEMORY; cselib_preserve_constants = record_what & CSELIB_PRESERVE_CONSTANTS; + cselib_any_perm_equivs = false; /* (mem:BLK (scratch)) is a special mechanism to conflict with everything, see canon_true_dependence. This is only created once. */ @@ -2684,6 +2699,7 @@ cselib_finish (void) { cselib_discard_hook = NULL; cselib_preserve_constants = false; + cselib_any_perm_equivs = false; cfa_base_preserved_val = NULL; cfa_base_preserved_regno = INVALID_REGNUM; free_alloc_pool (elt_list_pool); Index: gcc/cselib.h =================================================================== --- gcc/cselib.h.orig 2012-03-01 07:44:32.875663665 -0300 +++ gcc/cselib.h 2012-03-01 07:49:24.608222578 -0300 @@ -98,6 +98,7 @@ extern bool cselib_preserved_value_p (cs 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); +extern bool cselib_have_permanent_equivalences (void); extern void dump_cselib_table (FILE *);
-- Alexandre Oliva, freedom fighter http://FSFLA.org/~lxoliva/ You must be the change you wish to see in the world. -- Gandhi Be Free! -- http://FSFLA.org/ FSF Latin America board member Free Software Evangelist Red Hat Brazil Compiler Engineer