On Tue, Jun 3, 2014 at 3:27 PM, Ilya Enkovich <enkovich....@gmail.com> wrote: > 2014-06-03 15:56 GMT+04:00 Richard Biener <richard.guent...@gmail.com>: >> On Tue, Jun 3, 2014 at 1:36 PM, Ilya Enkovich <enkovich....@gmail.com> wrote: >>> 2014-06-03 13:45 GMT+04:00 Richard Biener <richard.guent...@gmail.com>: >>>> On Tue, Jun 3, 2014 at 9:23 AM, Ilya Enkovich <enkovich....@gmail.com> >>>> wrote: >>>>> Hi, >>>>> >>>>> This patch adjusts alloc-free removal algorithm in DCE to take into >>>>> account BUILT_IN_CHKP_BNDRET call returning bounds of allocated memory. >>>>> >>>>> Bootstrapped and tested on linux-x86_64. >>>>> >>>>> Thanks, >>>>> Ilya >>>>> -- >>>>> gcc/ >>>>> >>>>> 2014-06-03 Ilya Enkovich <ilya.enkov...@intel.com> >>>>> >>>>> * tree-ssa-dce.c: Include target.h. >>>>> (propagate_necessity): For free call fed by alloc check >>>>> bounds are also provided by the same alloc. >>>>> (eliminate_unnecessary_stmts): Handle BUILT_IN_CHKP_BNDRET >>>>> used by free calls. >>>>> >>>>> diff --git a/gcc/tree-ssa-dce.c b/gcc/tree-ssa-dce.c >>>>> index 13a71ce..59a0b71 100644 >>>>> --- a/gcc/tree-ssa-dce.c >>>>> +++ b/gcc/tree-ssa-dce.c >>>>> @@ -73,6 +73,7 @@ along with GCC; see the file COPYING3. If not see >>>>> #include "flags.h" >>>>> #include "cfgloop.h" >>>>> #include "tree-scalar-evolution.h" >>>>> +#include "target.h" >>>>> >>>>> static struct stmt_stats >>>>> { >>>>> @@ -778,7 +779,23 @@ propagate_necessity (bool aggressive) >>>>> && DECL_BUILT_IN_CLASS (def_callee) == BUILT_IN_NORMAL >>>>> && (DECL_FUNCTION_CODE (def_callee) == BUILT_IN_MALLOC >>>>> || DECL_FUNCTION_CODE (def_callee) == >>>>> BUILT_IN_CALLOC)) >>>>> - continue; >>>>> + { >>>>> + tree retfndecl >>>>> + = targetm.builtin_chkp_function >>>>> (BUILT_IN_CHKP_BNDRET); >>>>> + gimple bounds_def_stmt; >>>>> + tree bounds; >>>>> + >>>>> + /* For instrumented calls we should also check used >>>>> + bounds are returned by the same allocation call. */ >>>>> + if (!gimple_call_with_bounds_p (stmt) >>>>> + || ((bounds = gimple_call_arg (stmt, 1)) >>>> >>>> Please provide an abstraction for this - I seem to recall seeing multiple >>>> (variants) of this. Esp. repeated calls to the target hook above look >>>> expensive to me (generally it will not be needed). >>>> >>>> I'd like to see gimple_call_bndarg (stmt) to get rid of the "magic" 1 and >>>> I'd >>>> like to see sth similar to gimple_call_builtin_p, for example >>>> gimple_call_chkp_p (stmt, BUILT_IN_CHKP_BNDRET) doing the >>>> target hook invocation and the fndecl check. >>> >>> I do not see how to get rid of constant in gimple_call_arg call here. >>> What semantics does proposed gimple_call_bndarg have? It has to return >>> the first bounds arg but it's not clear from its name and function >>> seems to be very specialized. >> >> Ah, ok. I see now, so the code is ok as-is. >> >>>> >>>>> + && TREE_CODE (bounds) == SSA_NAME >>>> >>>> What about constant bounds? That shouldn't make the call necessary either? >>> >>> Yep, it would be useless. >> >> So please fix. >> >>>> >>>>> + && (bounds_def_stmt = SSA_NAME_DEF_STMT >>>>> (bounds)) >>>>> + && is_gimple_call (bounds_def_stmt) >>>>> + && gimple_call_fndecl (bounds_def_stmt) == >>>>> retfndecl >>>>> + && gimple_call_arg (bounds_def_stmt, 0) == ptr)) >>>>> + continue; >>>> >>>> So this all becomes >>>> >>>> if (!gimple_call_with_bounds_p (stmt) >>>> || ((bounds = gimple_call_bndarg (stmt)) >>>> && TREE_CODE (bounds) == SSA_NAME >>>> && (bounds_def_stmt = SSA_NAME_DEF_STMT >>>> (bounds)) >>>> && is_gimple_call (bounds_def_stmt) >>>> && gimple_call_chkp_p (bounds_def_stmt, >>>> BUILT_IN_CHKP_BNDRET) >>>> ... >>>> >>>> btw, I wonder how BUILT_IN_CHKP_BNDRET is in scope here but you >>>> need a target hook to compare the fndecl? Why isn't it enough to >>>> just check DECL_FUNCTION_CODE and DECL_BUILT_IN? >>> >>> Call is required because builtins for Pointer Bounds Checker are >>> provided by target depending on available features. That is why >>> gimple_call_builtin_p is not used. I may add new interface function >>> into tree-chkp.h as you propose (e.g. chkp_gimple_call_builtin_p). But >>> I do not see how it may speed-up the code. New function would still >>> need to switch by function code and compare with proper decl which is >>> basically what we have with target hook. >> >> I don't understand - does this mean the builtin calls are in the GIMPLE >> IL even though the target doesn't have the feature? Isn't the presence >> of the call enough? > > Call is generated using function decl provided by target. Therefore we > do not know its code and has to compare using fndecl comparison.
So they are target specific builtins after all? IMNSHO it looks wrong that the middle-end has to care about them in that case. Why can't the builtins itself be target independent? >>> It is possible to make faster if use the fact that all chkp builtins >>> codes (normal, not target ones) are consequent. Then we may just check >>> the range and use code as an index in array of chkp fndecls to compare >>> decls. Would it be OK to rely on builtin codes numbering? >> >> Yes, but that's not my point here. In the above code the target hook >> is called all the time, even if !gimple_call_with_bounds_p (). Providing >> a suitable abstraction (or simply relying on DECL_FUNCTION_CODE) >> should fix that. > > Got it. Will fix. > > Thanks, > Ilya > >> >> Richard. >> >>> Ilya >>> >>>> >>>> Richard. >>>> >>>>> + } >>>>> } >>>>> >>>>> FOR_EACH_SSA_TREE_OPERAND (use, stmt, iter, SSA_OP_USE) >>>>> @@ -1204,6 +1221,23 @@ eliminate_unnecessary_stmts (void) >>>>> && !gimple_plf (def_stmt, STMT_NECESSARY)) >>>>> gimple_set_plf (stmt, STMT_NECESSARY, false); >>>>> } >>>>> + /* We did not propagate necessity for free calls fed >>>>> + by allocation function to allow unnecessary >>>>> + alloc-free sequence elimination. For instrumented >>>>> + calls it also means we did not mark bounds producer >>>>> + as necessary and it is time to do it in case free >>>>> + call is not removed. */ >>>>> + if (gimple_call_with_bounds_p (stmt)) >>>>> + { >>>>> + gimple bounds_def_stmt; >>>>> + tree bounds = gimple_call_arg (stmt, 1); >>>>> + gcc_assert (TREE_CODE (bounds) == SSA_NAME); >>>>> + bounds_def_stmt = SSA_NAME_DEF_STMT (bounds); >>>>> + if (bounds_def_stmt >>>>> + && !gimple_plf (bounds_def_stmt, STMT_NECESSARY)) >>>>> + gimple_set_plf (bounds_def_stmt, STMT_NECESSARY, >>>>> + gimple_plf (stmt, STMT_NECESSARY)); >>>>> + } >>>>> } >>>>> >>>>> /* If GSI is not necessary then remove it. */ >>>>> @@ -1216,6 +1250,7 @@ eliminate_unnecessary_stmts (void) >>>>> else if (is_gimple_call (stmt)) >>>>> { >>>>> tree name = gimple_call_lhs (stmt); >>>>> + tree retfn = targetm.builtin_chkp_function >>>>> (BUILT_IN_CHKP_BNDRET); >>>>> >>>>> notice_special_calls (stmt); >>>>> >>>>> @@ -1233,7 +1268,9 @@ eliminate_unnecessary_stmts (void) >>>>> && DECL_FUNCTION_CODE (call) != BUILT_IN_CALLOC >>>>> && DECL_FUNCTION_CODE (call) != BUILT_IN_ALLOCA >>>>> && (DECL_FUNCTION_CODE (call) >>>>> - != BUILT_IN_ALLOCA_WITH_ALIGN)))) >>>>> + != BUILT_IN_ALLOCA_WITH_ALIGN))) >>>>> + /* Avoid doing so for bndret calls for the same reason. >>>>> */ >>>>> + && (!retfn || gimple_call_fndecl (stmt) != retfn)) >>>>> { >>>>> something_changed = true; >>>>> if (dump_file && (dump_flags & TDF_DETAILS))