On Tue, Dec 10, 2013 at 11:59:16PM -0700, Jeff Law wrote:
> On 12/10/13 23:35, Bin.Cheng wrote:
> >I know little about GC, so when ggc_collect may be called (between two
> >passes)? If so, I have to call free_affine_expand_cache just after the
> >calling to tree_to_affine_combination_expand in SCEV because it's an
> >analyzer and as you pointed out, the analyzing result is used by
> >different optimizers. The pointer map would be maintained between
> >different passes if it's not instantly freed.
> The garbage collector only runs between passes. If you have roots
> in static storage, then you'll need to decorate them so the garbage
> collector scans them.
>
> There's a fairly extensive discussion of the garbage collector in
> the GCC internals manual.
It isn't that easy, pointer_map isn't a data structure recognized by the
garbage collector at all (plus, as I've said before, the code is inserting
XNEW allocated structures into the pointer_map, which isn't GC friendly
either, but making them GC allocated might increase garbage unnecessarily,
as all the structs are short lived).
I've looked through scev_{initialize,finalize} callers, and almost all
passes initialize it and finalize within the same pass, it is only the loop
optimizations:
NEXT_PASS (pass_tree_loop_init);
NEXT_PASS (pass_lim);
NEXT_PASS (pass_copy_prop);
NEXT_PASS (pass_dce_loop);
NEXT_PASS (pass_tree_unswitch);
NEXT_PASS (pass_scev_cprop);
NEXT_PASS (pass_record_bounds);
NEXT_PASS (pass_check_data_deps);
NEXT_PASS (pass_loop_distribution);
NEXT_PASS (pass_copy_prop);
NEXT_PASS (pass_graphite);
PUSH_INSERT_PASSES_WITHIN (pass_graphite)
NEXT_PASS (pass_graphite_transforms);
NEXT_PASS (pass_lim);
NEXT_PASS (pass_copy_prop);
NEXT_PASS (pass_dce_loop);
POP_INSERT_PASSES ()
NEXT_PASS (pass_iv_canon);
NEXT_PASS (pass_parallelize_loops);
NEXT_PASS (pass_if_conversion);
/* pass_vectorize must immediately follow pass_if_conversion.
Please do not add any other passes in between. */
NEXT_PASS (pass_vectorize);
PUSH_INSERT_PASSES_WITHIN (pass_vectorize)
NEXT_PASS (pass_dce_loop);
POP_INSERT_PASSES ()
NEXT_PASS (pass_predcom);
NEXT_PASS (pass_complete_unroll);
NEXT_PASS (pass_slp_vectorize);
NEXT_PASS (pass_loop_prefetch);
NEXT_PASS (pass_iv_optimize);
NEXT_PASS (pass_lim);
NEXT_PASS (pass_tree_loop_done);
where scev is live in between the passes, and unfortunately there
is no call that each pass calls that you could easily add the free_affine.*
call to (except for execute_function_todo but you'd need to invent another
TODO_* flag for it and the question is how you'd ensure it will be handled
for the non-loop specific passes that are just run in between these
passes (say pass_copy_prop, would we need pass_copy_prop_loop?).
Perhaps you could replace in tree-affine.c and all it's users
{,struct} pointer_map_t * with
struct GTY((user)) affine_expand_cache {
pointer_map_t *cache;
};
and write custom gt_ggc_mx (affine_expand_cache *) function that would
would either pointer_map_traverse the cache and for each cache entry
call gt_ggc_mx on the embedded trees in the structures, or drop the cache
(dunno if the cache is really just a cache and it doesn't matter if it is
dropped any time, or if it can affect code generation). There are also PCH
related functions that need to be defined, though I guess you could just
assert there that the cache is NULL and not walk anything.
Jakub