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