[apologies if this is a dupe; I accidentally hit the send keystroke before adding the last paragraph, and I'm not sure I was quick enough to cancel it]
The first patch for PR debug/59992 cut down vt_initialize time in insn-recog to less than 1/3, by avoiding quadratic behavior in remove_useless_values, but the affected calls were always followed by cselib_reset_table, which would also iterate over the entire table looking for non-constant non-permanent values to remove. That was not just redundant, but quadratic as well. What's worse is that, unlike remove_useless_values, this is a cleanup that we really have to do at the end of extended basic blocks, but for large functions, most of the entries in the table are going to be preserved values that we're going to visit over and over, but never remove. Instead of creating a list of recently-created values to revisit, I figured it would be smarter to move the preserved values to a separate table, that won't have to be cleaned up till we're through with the function. Lookups first search the permanent table (if it's enabled, i.e., only in var-tracking), always without insertion (we only insert in the original table), and that's all it took to make it work, again without any change to the asm output for i686 insn-recog. The patch turned out to be quite easy and safe, and it cut down vt_initialize time in i686 insn-recog from 500 seconds to only 5 seconds. Regstrapped on x86_64-linux-gnu and i686-linux-gnu, along with the other patch for PR debug/59992. Ok to install? for gcc/ChangeLog PR debug/59992 * cselib.c (cselib_hasher::equal): Special-case VALUE lookup. (cselib_preserved_hash_table): New. (preserve_constants_and_equivs): Move preserved vals to it. (cselib_find_slot): Look it up first. (cselib_init): Initialize it. (cselib_finish): Release it. (dump_cselib_table): Dump it. --- gcc/cselib.c | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/gcc/cselib.c b/gcc/cselib.c index dabd2d3..0fcfe28 100644 --- a/gcc/cselib.c +++ b/gcc/cselib.c @@ -132,6 +132,9 @@ cselib_hasher::equal (const value_type *v, const compare_type *x_arg) || GET_CODE (XEXP (x, 0)) == CONST_FIXED)) x = XEXP (x, 0); + if (GET_CODE (x) == VALUE) + return x == v->val_rtx; + /* We don't guarantee that distinct rtx's have different hash values, so we need to do a comparison. */ for (l = v->locs; l; l = l->next) @@ -147,6 +150,9 @@ cselib_hasher::equal (const value_type *v, const compare_type *x_arg) /* A table that enables us to look up elts by their value. */ static hash_table <cselib_hasher> cselib_hash_table; +/* A table to hold preserved values. */ +static hash_table <cselib_hasher> cselib_preserved_hash_table; + /* This is a global so we don't have to pass this through every function. It is used in new_elt_loc_list to set SETTING_INSN. */ static rtx cselib_current_insn; @@ -490,8 +496,17 @@ preserve_constants_and_equivs (cselib_val **x, void *info ATTRIBUTE_UNUSED) { cselib_val *v = *x; - if (!invariant_or_equiv_p (v)) - cselib_hash_table.clear_slot (x); + if (invariant_or_equiv_p (v)) + { + cselib_val **slot + = cselib_preserved_hash_table.find_slot_with_hash (v->val_rtx, + v->hash, INSERT); + gcc_assert (!*slot); + *slot = v; + } + + cselib_hash_table.clear_slot (x); + return 1; } @@ -565,9 +580,13 @@ static cselib_val ** cselib_find_slot (rtx x, hashval_t hash, enum insert_option insert, enum machine_mode memmode) { - cselib_val **slot; + cselib_val **slot = NULL; find_slot_memmode = memmode; - slot = cselib_hash_table.find_slot_with_hash (x, hash, insert); + if (cselib_preserve_constants) + slot = cselib_preserved_hash_table.find_slot_with_hash (x, hash, + NO_INSERT); + if (!slot) + slot = cselib_hash_table.find_slot_with_hash (x, hash, insert); find_slot_memmode = VOIDmode; return slot; } @@ -2742,6 +2761,8 @@ cselib_init (int record_what) used_regs = XNEWVEC (unsigned int, cselib_nregs); n_used_regs = 0; cselib_hash_table.create (31); + if (cselib_preserve_constants) + cselib_preserved_hash_table.create (31); next_uid = 1; } @@ -2750,6 +2771,7 @@ cselib_init (int record_what) void cselib_finish (void) { + bool preserved = cselib_preserve_constants; cselib_discard_hook = NULL; cselib_preserve_constants = false; cselib_any_perm_equivs = false; @@ -2761,6 +2783,8 @@ cselib_finish (void) free_alloc_pool (value_pool); cselib_clear_table (); cselib_hash_table.dispose (); + if (preserved) + cselib_preserved_hash_table.dispose (); free (used_regs); used_regs = 0; n_useless_values = 0; @@ -2850,6 +2874,8 @@ dump_cselib_table (FILE *out) { fprintf (out, "cselib hash table:\n"); cselib_hash_table.traverse <FILE *, dump_cselib_val> (out); + fprintf (out, "cselib preserved hash table:\n"); + cselib_preserved_hash_table.traverse <FILE *, dump_cselib_val> (out); if (first_containing_mem != &dummy_val) { fputs ("first mem ", out); -- 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 Toolchain Engineer