On Wed, Sep 30, 2015 at 7:44 PM, Jeff Law <l...@redhat.com> wrote: > > The SSA_NAME manager currently has a single free list. As names are > released, they're put on the free list and recycled immediately. > > This has led to several problems through the years -- in particular removal > of an edge may result in removal of a PHI when the target of the edge is > unreachable. This can result in released names being left in the IL until > *all* unreachable code is eliminated. Long term we'd like to discover all > the unreachable code exposed by a deleted edge earlier, but that's further > out. > > Richi originally suggested using a two list implementation to avoid this > class of problems. Essentially released names are queued until it's safe to > start recycling them. I agreed, but didn't get around to doing any of the > implementation work. > > Bernd recently took care of the implementation side. This patch is mostly > his. The only change of significance I made is the placement of the call to > flush the pending list. Bernd had it in the ssa updater, I put it after cfg > cleanups. The former does recycle better, but there's nothing that > inherently ensures there aren't unreachables in the CFG during update_ssa > (in practice it's not a problem because we typically update dominators > first, which requires a cleaned cfg). > > I've got a follow-up which exploits this improved safety in DOM to optimize > things better in DOM rather than waiting for jump threading to clean things > up. > > No additional tests in this patch as the only failure seen when I twiddled > things a little was already covered by existing tests. > > Bootstrapped and regression tested on x86-linux-gnu, with and without the > follow-up patch to exploit the capability in DOM. > > Installed on the trunk. > > jeff > > > > > * gimple-ssa.h (gimple_df): Add free_ssanames_queue field. > * passes.c: Include tree-ssanames.h. > (execute_function_todo): Flush the pending free SSA_NAMEs after > eliminating unreachable basic blocks. > * tree-ssanames.c (FREE_SSANAMES_QUEUE): new. > (init_ssanames): Initialize FREE_SSANAMES_QUEUE. > (fini_ssanames): Finalize FREE_SSANAMES_QUEUE. > (flush_ssanames_freelist): New function. > (release_ssaname_fn): Put released names on the queue. > (pass_release_ssa_names::execute): Call flush_ssanames_freelist. > * tree-ssanames.h (flush_ssanames_freelist): Declare. > > > > diff --git a/gcc/gimple-ssa.h b/gcc/gimple-ssa.h > index c89071e..39551da 100644 > --- a/gcc/gimple-ssa.h > +++ b/gcc/gimple-ssa.h > @@ -90,6 +90,9 @@ struct GTY(()) gimple_df { > /* Free list of SSA_NAMEs. */ > vec<tree, va_gc> *free_ssanames; > > + /* Queue of SSA_NAMEs to be freed at the next opportunity. */ > + vec<tree, va_gc> *free_ssanames_queue; > + > /* Hashtable holding definition for symbol. If this field is not NULL, > it > means that the first reference to this variable in the function is a > USE or a VUSE. In those cases, the SSA renamer creates an SSA name > diff --git a/gcc/passes.c b/gcc/passes.c > index d06a293..5b41102 100644 > --- a/gcc/passes.c > +++ b/gcc/passes.c > @@ -84,6 +84,7 @@ along with GCC; see the file COPYING3. If not see > #include "cfgrtl.h" > #include "tree-ssa-live.h" /* For remove_unused_locals. */ > #include "tree-cfgcleanup.h" > +#include "tree-ssanames.h" > > using namespace gcc; > > @@ -1913,6 +1914,14 @@ execute_function_todo (function *fn, void *data) > { > cleanup_tree_cfg (); > > + /* Once unreachable nodes have been removed from the CFG, > + there can't be any lingering references to released > + SSA_NAMES (because there is no more unreachable code). > + > + Thus, now is the time to flush the SSA_NAMEs freelist. */ > + if (fn->gimple_df) > + flush_ssaname_freelist (); > +
Apart from what Jakub said - this keeps the list non-recycled for example after DCE if that doesnt call cleanup_cfg. Likewise after passes that call cleanup_cfg manually. It also doesn't get called after IPA transform passes (which would require calling on each function). To at least catch those passes returning 0 (do nothing) I'd place the call into execute_todo instead, unconditionally on flags. > /* When cleanup_tree_cfg merges consecutive blocks, it may > perform some simplistic propagation when removing single > valued PHI nodes. This propagation may, in turn, cause the > diff --git a/gcc/tree-ssanames.c b/gcc/tree-ssanames.c > index 4199290..e029062 100644 > --- a/gcc/tree-ssanames.c > +++ b/gcc/tree-ssanames.c > @@ -69,6 +69,7 @@ unsigned int ssa_name_nodes_reused; > unsigned int ssa_name_nodes_created; > > #define FREE_SSANAMES(fun) (fun)->gimple_df->free_ssanames > +#define FREE_SSANAMES_QUEUE(fun) (fun)->gimple_df->free_ssanames_queue > > > /* Initialize management of SSA_NAMEs to default SIZE. If SIZE is > @@ -91,6 +92,7 @@ init_ssanames (struct function *fn, int size) > least 50 elements reserved in it. */ > SSANAMES (fn)->quick_push (NULL_TREE); > FREE_SSANAMES (fn) = NULL; > + FREE_SSANAMES_QUEUE (fn) = NULL; > > fn->gimple_df->ssa_renaming_needed = 0; > fn->gimple_df->rename_vops = 0; > @@ -103,6 +105,7 @@ fini_ssanames (void) > { > vec_free (SSANAMES (cfun)); > vec_free (FREE_SSANAMES (cfun)); > + vec_free (FREE_SSANAMES_QUEUE (cfun)); > } > > /* Dump some simple statistics regarding the re-use of SSA_NAME nodes. */ > @@ -114,6 +117,22 @@ ssanames_print_statistics (void) > fprintf (stderr, "SSA_NAME nodes reused: %u\n", ssa_name_nodes_reused); > } > > +/* Move all SSA_NAMEs from FREE_SSA_NAMES_QUEUE to FREE_SSA_NAMES. > + > + We do not, but should have a mode to verify the state of the SSA_NAMEs > + lists. In particular at this point every name must be in the IL, > + on the free list or in the queue. Anything else is an error. */ > + > +void > +flush_ssaname_freelist (void) > +{ > + while (!vec_safe_is_empty (FREE_SSANAMES_QUEUE (cfun))) > + { > + tree t = FREE_SSANAMES_QUEUE (cfun)->pop (); > + vec_safe_push (FREE_SSANAMES (cfun), t); > + } > +} > + > /* Return an SSA_NAME node for variable VAR defined in statement STMT > in function FN. STMT may be an empty statement for artificial > references (e.g., default definitions created when a variable is > @@ -348,8 +367,8 @@ release_ssa_name_fn (struct function *fn, tree var) > /* Note this SSA_NAME is now in the first list. */ > SSA_NAME_IN_FREE_LIST (var) = 1; > > - /* And finally put it on the free list. */ > - vec_safe_push (FREE_SSANAMES (fn), var); > + /* And finally queue it so that it will be put on the free list. */ > + vec_safe_push (FREE_SSANAMES_QUEUE (fn), var); > } > } > > @@ -607,6 +626,7 @@ unsigned int > pass_release_ssa_names::execute (function *fun) > { > unsigned i, j; > + flush_ssaname_freelist (); which would make this redundant as well. I suppose it would be interesting to see some before/after statistics of the release_ssa_names pass. I expect the number of holes removed to increase, hopefully not too much (esp. important for analysis passes using sbitmaps of SSA names). > int n = vec_safe_length (FREE_SSANAMES (fun)); > > /* Now release the freelist. */ > diff --git a/gcc/tree-ssanames.h b/gcc/tree-ssanames.h > index 22ff609..ae9351e 100644 > --- a/gcc/tree-ssanames.h > +++ b/gcc/tree-ssanames.h > @@ -97,6 +97,7 @@ extern void duplicate_ssa_name_range_info (tree, enum > value_range_type, > extern void reset_flow_sensitive_info (tree); > extern void release_defs (gimple *); > extern void replace_ssa_name_symbol (tree, tree); > +extern void flush_ssaname_freelist (void); > > > /* Return an SSA_NAME node for variable VAR defined in statement STMT >