https://gcc.gnu.org/bugzilla/show_bug.cgi?id=116899
--- Comment #8 from Jakub Jelinek <jakub at gcc dot gnu.org> --- I've gathered some statistics using: --- gcc/gimple-range-cache.h.jj 2024-07-02 15:07:55.231913151 +0200 +++ gcc/gimple-range-cache.h 2024-09-30 19:03:35.848466925 +0200 @@ -141,6 +141,7 @@ private: bool edge_range (vrange &r, edge e, tree name, enum rfd_mode); vec<basic_block> m_workback; + unsigned m_workback_init, m_workback_max; class update_list *m_update; }; --- gcc/gimple-range-cache.cc.jj 2024-08-10 10:47:48.154848100 +0200 +++ gcc/gimple-range-cache.cc 2024-09-30 19:07:03.103591896 +0200 @@ -1000,6 +1000,8 @@ ranger_cache::ranger_cache (int not_exec m_workback.create (0); m_workback.safe_grow_cleared (last_basic_block_for_fn (cfun)); m_workback.truncate (0); + m_workback_init = last_basic_block_for_fn (cfun); + m_workback_max = 0; m_temporal = new temporal_cache; // If DOM info is available, spawn an oracle as well. @@ -1027,6 +1029,9 @@ ranger_cache::~ranger_cache () destroy_relation_oracle (); delete m_temporal; m_workback.release (); +FILE *f = fopen ("/tmp/rangercache", "a"); +fprintf (f, "%d %s %s %d/%d\n", (int) BITS_PER_WORD, main_input_filename ? main_input_filename : "-", current_function_name (), m_workback_max, m_workback_init); +fclose (f); } // Dump the global caches to file F. if GORI_DUMP is true, dump the @@ -1558,6 +1563,7 @@ ranger_cache::fill_block_cache (tree nam // m_visited at the end will contain all the blocks that we needed to set // the range_on_entry cache for. m_workback.quick_push (bb); + m_workback_max = MAX (m_workback_max, m_workback.length ()); undefined.set_undefined (); m_on_entry.set_bb_range (name, bb, undefined); gcc_checking_assert (m_update->empty_p ()); @@ -1632,6 +1638,7 @@ ranger_cache::fill_block_cache (tree nam gcc_checking_assert (!m_on_entry.bb_range_p (name, pred)); m_on_entry.set_bb_range (name, pred, undefined); m_workback.quick_push (pred); + m_workback_max = MAX (m_workback_max, m_workback.length ()); } } @@ -1726,7 +1733,10 @@ ranger_cache::range_from_dom (vrange &r, // This block has an outgoing range. if (gori ().has_edge_range_p (name, bb)) - m_workback.quick_push (prev_bb); + { + m_workback.quick_push (prev_bb); + m_workback_max = MAX (m_workback_max, m_workback.length ()); + } else { // Normally join blocks don't carry any new range information on @@ -1750,7 +1760,10 @@ ranger_cache::range_from_dom (vrange &r, break; } if (all_dom) - m_workback.quick_push (prev_bb); + { + m_workback.quick_push (prev_bb); + m_workback_max = MAX (m_workback_max, m_workback.length ()); + } } } >From the 305386 entries in /tmp/rangercache (not everything small, 64 entries even have more than 10000 basic blocks, 535 entries have 1000-9999 basic blocks, 11670 have 100-999 basic blocks) there was just one case where m_workback had 11 entries as maximum, 3 with 10 entries as maximum, 56863 with 1-9 entries as maximum and 248519 with 0 entries maximum. So, even the create (last_basic_block_for_fn (cfun)); seems to be very wasteful to me, I'd think much better would be m_workback = vNULL; and using safe_push instead of quick_push. Yes, we'll quickly compare the m_alloc with m_num + 1 in 4 spots and have some usually non-executed allocation code around, but we'll allocate only what is really needed (and with the exponential growth won't be reallocating that much, on the gathered samples in 81.3% won't allocate anything, in 18.4% allocate once (4 elements), in 0.21% cases allocate and reallocate once and in 0.0085% (26 cases in the samples) allocate and reallocate twice.