https://gcc.gnu.org/bugzilla/show_bug.cgi?id=116627
Jakub Jelinek <jakub at gcc dot gnu.org> changed: What |Removed |Added ---------------------------------------------------------------------------- CC| |aoliva at gcc dot gnu.org --- Comment #6 from Jakub Jelinek <jakub at gcc dot gnu.org> --- Ah, the thing is that one of the VALUEs is moved from cselib_hash_table to cselib_preserved_hash_table. cselib_find_slot looks for VALUEs first from the latter and only if not found, in the former, which means that the FOR_EACH_MODE_UNTIL (narrow_mode_iter, int_mode) { PUT_MODE_RAW (copy, narrow_mode_iter); cselib_val *v = cselib_lookup (copy, narrow_mode_iter, 0, VOIDmode); if (v) { rtx sub = lowpart_subreg (narrow_mode_iter, e->val_rtx, int_mode); if (sub) new_elt_loc_list (v, sub); } } code finds here a preserved VALUE in cselib_preserved_hash_table table and new_elt_loc_list adds another loc_list to it with a SUBREG of non-preserved VALUE. remove_useless_values then discards locs referencing useless VALUEs from the cselib_hash_table and then actually discards the useless VALUEs, but nothing discards useless locs from cselib_preserved_hash_table table. So, I wonder if we shouldn't do: --- gcc/cselib.cc.jj 2024-04-26 11:46:54.960269768 +0200 +++ gcc/cselib.cc 2024-09-11 10:54:05.018242593 +0200 @@ -751,6 +751,11 @@ remove_useless_values (void) } *p = &dummy_val; + if (cselib_preserve_constants) + cselib_preserved_hash_table->traverse <void *, + discard_useless_locs> (NULL); + gcc_assert (!values_became_useless); + n_useless_values += n_useless_debug_values; n_debug_values -= n_useless_debug_values; n_useless_debug_values = 0; to discard references to useless VALUEs even from the preserved VALUEs. With the above patch the ICE is gone, but completely untested.