On 10/27/2015 03:49 PM, Richard Biener wrote: > On Tue, Oct 27, 2015 at 1:36 PM, Martin Liška <mli...@suse.cz> wrote: >> On 10/26/2015 02:48 PM, Richard Biener wrote: >>> On Thu, Oct 22, 2015 at 1:02 PM, Martin Liška <mli...@suse.cz> wrote: >>>> On 10/21/2015 04:06 PM, Richard Biener wrote: >>>>> On Wed, Oct 21, 2015 at 1:24 PM, Martin Liška <mli...@suse.cz> wrote: >>>>>> On 10/21/2015 11:59 AM, Richard Biener wrote: >>>>>>> On Wed, Oct 21, 2015 at 11:19 AM, Martin Liška <mli...@suse.cz> wrote: >>>>>>>> On 10/20/2015 03:39 PM, Richard Biener wrote: >>>>>>>>> On Tue, Oct 20, 2015 at 3:00 PM, Martin Liška <mli...@suse.cz> wrote: >>>>>>>>>> Hello. >>>>>>>>>> >>>>>>>>>> As part of upcoming merge of HSA branch, we would like to have >>>>>>>>>> possibility to terminate >>>>>>>>>> pass manager after execution of the HSA generation pass. The HSA >>>>>>>>>> back-end is implemented >>>>>>>>>> as a tree pass that directly emits HSAIL from gimple tree >>>>>>>>>> representation. The pass operates >>>>>>>>>> on clones created by HSA IPA pass and the pass manager should stop >>>>>>>>>> execution of further >>>>>>>>>> RTL passes. >>>>>>>>>> >>>>>>>>>> Suggested patch survives bootstrap and regression tests on >>>>>>>>>> x86_64-linux-pc. >>>>>>>>>> >>>>>>>>>> What do you think about it? >>>>>>>>> >>>>>>>>> Are you sure it works this way? >>>>>>>>> >>>>>>>>> Btw, you will miss executing of all the cleanup passes that will >>>>>>>>> eventually free memory >>>>>>>>> associated with the function. So I'd rather support a >>>>>>>>> TODO_discard_function which >>>>>>>>> should basically release the body from the cgraph. >>>>>>>> >>>>>>>> Hi. >>>>>>>> >>>>>>>> Agree with you that I should execute all TODOs, which can be easily >>>>>>>> done. >>>>>>>> However, if I just try to introduce the suggested TODO and handle it >>>>>>>> properly >>>>>>>> by calling cgraph_node::release_body, then for instance fn->gimple_df, >>>>>>>> fn->cfg are >>>>>>>> released and I hit ICEs on many places. >>>>>>>> >>>>>>>> Stopping the pass manager looks necessary, or do I miss something? >>>>>>> >>>>>>> "Stopping the pass manager" is necessary after TODO_discard_function, >>>>>>> yes. >>>>>>> But that may be simply done via a has_body () check then? >>>>>> >>>>>> Thanks, there's second version of the patch. I'm going to start >>>>>> regression tests. >>>>> >>>>> As release_body () will free cfun you should pop_cfun () before >>>>> calling it (and thus >>>> >>>> Well, release_function_body calls both push & pop, so I think calling pop >>>> before cgraph_node::release_body is not necessary. >>> >>> (ugh). >>> >>>> If tried to call pop_cfun before cgraph_node::release_body, I have cfun >>>> still >>>> pointing to the same (function *) (which is gcc_freed, but cfun != NULL). >>> >>> Hmm, I meant to call pop_cfun then after it (unless you want to fix the >>> above, >>> none of the freeing functions should techincally need 'cfun', just add >>> 'fn' parameters ...). >>> >>> I expected pop_cfun to eventually set cfun to NULL if it popped the >>> "last" cfun. Why >>> doesn't it do that? >>> >>>>> drop its modification). Also TODO_discard_functiuon should be only set >>>>> for >>>>> local passes thus you should probably add a gcc_assert (cfun). >>>>> I'd move its handling earlier, definitely before the ggc_collect, >>>>> eventually >>>>> before the pass_fini_dump_file () (do we want a last dump of the >>>>> function or not?). >>>> >>>> Fully agree, moved here. >>>> >>>>> >>>>> @@ -2397,6 +2410,10 @@ execute_pass_list_1 (opt_pass *pass) >>>>> { >>>>> gcc_assert (pass->type == GIMPLE_PASS >>>>> || pass->type == RTL_PASS); >>>>> + >>>>> + >>>>> + if (!gimple_has_body_p (current_function_decl)) >>>>> + return; >>>>> >>>>> too much vertical space. With popping cfun before releasing the body the >>>>> check >>>>> might just become if (!cfun) and >>>> >>>> As mentioned above, as release body is symmetric (calling push & pop), the >>>> suggested >>>> guard will not work. >>> >>> I suggest to fix it. If it calls push/pop it should leave with the >>> original cfun, popping again >>> should make it NULL? >>> >>>>> >>>>> @@ -2409,7 +2426,7 @@ execute_pass_list (function *fn, opt_pass *pass) >>>>> { >>>>> push_cfun (fn); >>>>> execute_pass_list_1 (pass); >>>>> - if (fn->cfg) >>>>> + if (gimple_has_body_p (current_function_decl) && fn->cfg) >>>>> { >>>>> free_dominance_info (CDI_DOMINATORS); >>>>> free_dominance_info (CDI_POST_DOMINATORS); >>>>> >>>>> here you'd need to guard the pop_cfun call on cfun != NULL. IMHO it's >>>>> better >>>>> to not let cfun point to deallocated data. >>>> >>>> As I've read the code, since we gcc_free 'struct function', one can just >>>> rely on >>>> gimple_has_body_p (current_function_decl) as it correctly realizes that >>>> DECL_STRUCT_FUNCTION (current_function_decl) == NULL. >>> >>> I'm sure that with some GC checking ggc_free makes them #deadbeef or so: >>> >>> void >>> ggc_free (void *p) >>> { >>> ... >>> #ifdef ENABLE_GC_CHECKING >>> /* Poison the data, to indicate the data is garbage. */ >>> VALGRIND_DISCARD (VALGRIND_MAKE_MEM_UNDEFINED (p, size)); >>> memset (p, 0xa5, size); >>> #endif >>> >>> so I don't think that's a good thing to rely on ;) >>> >>> Richard. >> >> Hi Richi, fully agree that relying of 0xdeadbeaf is not good. >> I'm sending quite simple patch v4 where I enable popping up >> the stack to eventually set cfun = current_function_decl = NULL. >> >> Question of using push & pop in cgraph_node::release_body should >> be orthogonal as there are other places where the function is used. >> >> What do you think about the patch? > > @@ -4763,6 +4763,13 @@ push_cfun (struct function *new_cfun) > void > pop_cfun (void) > { > + if (cfun_stack.is_empty ()) > + { > + set_cfun (NULL); > + current_function_decl = NULL_TREE; > + return; > + } > + > > I'd like to avoid this by... > > @@ -2405,11 +2428,12 @@ execute_pass_list (function *fn, opt_pass *pass) > { > push_cfun (fn); > execute_pass_list_1 (pass); > - if (fn->cfg) > + if (current_function_decl && fn->cfg) > { > free_dominance_info (CDI_DOMINATORS); > free_dominance_info (CDI_POST_DOMINATORS); > } > + > pop_cfun (); > > making this conditional on if (cfun). Btw, please check cfun against NULL, > not current_function_decl.
Done. > > + if (dom_info_available_p (CDI_POST_DOMINATORS)) > + free_dominance_info (CDI_POST_DOMINATORS); > + > + /* Pop function inserted in execute_pass_list. */ > + pop_cfun (); > + > + cgraph_node::get (cfun->decl)->release_body (); > + > + /* Set cfun and current_function_decl to be NULL. */ > + pop_cfun (); > + } > > this also looks weird. Because you pop_cfun and then access cfun and > then you pop cfun again? I'd say most clean would be > > + if (dom_info_available_p (CDI_POST_DOMINATORS)) > + free_dominance_info (CDI_POST_DOMINATORS); > + tree fn = cfun->decl; > pop_cfun (); > cgraph_node::get (fn)->release_body (); > } > > or does the comment say that the current function is on the stack > twice somehow? How can that happen? You are right, your change applied. Sending V5. If OK, I'll create corresponding changelog entry and run regression tests. Thanks, Martin > > Richard. > > >> Thanks, >> Martin >> >>> >>>> I'm attaching v3. >>>> >>>> Thanks, >>>> Martin >>>> >>>>> >>>>> Otherwise looks good to me. >>>>> >>>>> Richard. >>>>> >>>>> >>>>>> Martin >>>>>> >>>>>>> >>>>>>>> Thanks, >>>>>>>> Martin >>>>>>>> >>>>>>>>> >>>>>>>>> Richard. >>>>>>>>> >>>>>>>>>> Thanks, >>>>>>>>>> Martin >>>>>>>> >>>>>> >>>> >>
>From 9cefde12a9f52e402a0ab9a4b3b3077a34e7a38e Mon Sep 17 00:00:00 2001 From: marxin <mli...@suse.cz> Date: Thu, 22 Oct 2015 12:46:16 +0200 Subject: [PATCH] Version 5. --- gcc/function.c | 7 +++++++ gcc/hsa-gen.c | 3 +-- gcc/passes.c | 28 +++++++++++++++++++++++++++- gcc/tree-pass.h | 3 +++ 4 files changed, 38 insertions(+), 3 deletions(-) diff --git a/gcc/function.c b/gcc/function.c index db5bc1c..6878e9d 100644 --- a/gcc/function.c +++ b/gcc/function.c @@ -4763,6 +4763,13 @@ push_cfun (struct function *new_cfun) void pop_cfun (void) { + if (cfun_stack.is_empty ()) + { + set_cfun (NULL); + current_function_decl = NULL_TREE; + return; + } + struct function *new_cfun = cfun_stack.pop (); /* When in_dummy_function, we do have a cfun but current_function_decl is NULL. We also allow pushing NULL cfun and subsequently changing diff --git a/gcc/passes.c b/gcc/passes.c index 8b3fb2f..7b84d17 100644 --- a/gcc/passes.c +++ b/gcc/passes.c @@ -2378,6 +2378,28 @@ execute_one_pass (opt_pass *pass) current_pass = NULL; + if (todo_after & TODO_discard_function) + { + gcc_assert (cfun); + /* As cgraph_node::release_body expects release dominators info, + we have to release it. */ + if (dom_info_available_p (CDI_DOMINATORS)) + free_dominance_info (CDI_DOMINATORS); + + if (dom_info_available_p (CDI_POST_DOMINATORS)) + free_dominance_info (CDI_POST_DOMINATORS); + + tree fn = cfun->decl; + + /* Pop function inserted in execute_pass_list. */ + pop_cfun (); + + cgraph_node::get (fn)->release_body (); + + /* Set cfun and current_function_decl to be NULL. */ + pop_cfun (); + } + /* Signal this is a suitable GC collection point. */ if (!((todo_after | pass->todo_flags_finish) & TODO_do_not_ggc_collect)) ggc_collect (); @@ -2392,6 +2414,9 @@ execute_pass_list_1 (opt_pass *pass) { gcc_assert (pass->type == GIMPLE_PASS || pass->type == RTL_PASS); + + if (cfun == NULL) + return; if (execute_one_pass (pass) && pass->sub) execute_pass_list_1 (pass->sub); @@ -2405,11 +2430,12 @@ execute_pass_list (function *fn, opt_pass *pass) { push_cfun (fn); execute_pass_list_1 (pass); - if (fn->cfg) + if (cfun && fn->cfg) { free_dominance_info (CDI_DOMINATORS); free_dominance_info (CDI_POST_DOMINATORS); } + pop_cfun (); } diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h index 7a5f476..2627df3 100644 --- a/gcc/tree-pass.h +++ b/gcc/tree-pass.h @@ -296,6 +296,9 @@ protected: /* Rebuild the callgraph edges. */ #define TODO_rebuild_cgraph_edges (1 << 22) +/* Release function body and stop pass manager. */ +#define TODO_discard_function (1 << 23) + /* Internally used in execute_function_todo(). */ #define TODO_update_ssa_any \ (TODO_update_ssa \ -- 2.6.2