On Sun, Dec 5, 2021 at 10:59 PM Richard Sandiford via Gcc-patches <gcc-patches@gcc.gnu.org> wrote: > > When compiling an optabs.ii at -O2 with a release-checking build, > we spent a lot of time in call_may_clobber_ref_p. One of the > first things the function tries is the get_modref_function_summary > approach, but that also seems to be the most expensive check. > At least for the optabs.ii test, most of the things g_m_f_s could > handle could also be handled by points-to analysis, which is much > cheaper. > > This patch therefore rearranges the tests in approximate order > of cheapness. One wart is that points-to analysis can't be > used on its own for this purpose; it has to be used in > conjunction with check_fnspec. This is because the argument > information in the fnspec is not reflected in the points-to > information, which instead contains overly optimistic (rather > than conservatively pessimistic) information. > > Specifically, find_func_aliases_for_builtin_call short-circuits > the handle_rhs_call/handle_call_arg logic and doesn't itself add > any compensating information about the arguments. This means that: > > free (foo) > > does not have an points-to information for foo (it has an empty > set instead).
Huh? The gimple_call_use/clobber_sets should be conservative and stand on their own. Can you share a testcase that breaks when returning early if independent_pt? Does this problem also exist on the branch? I wonder if, at this point, we should split the patch up to do the trivial move of the ao_ref_base dependent and volatile checks and leave this more complicated detail for a second patch? The first part is pre-approved, I'd like to understand the second part before considering it. Thanks, Richard. > > It would be good to fix that for compile-time reasons if nothing else. > Doing points-to analysis without check_fnspec gave a measureable > speed-up, since PTA resolved the vast majority of queries, and > (as expected) the vast majority of calls had no fnspec. > > This gave about a ~2% compile-time improvement for the test above. > > Tested on aarch64-linux-gnu and x86_64-linux-gnu. OK to install? > > Richard > > > gcc/ > * tree-ssa-alias.c (call_may_clobber_ref_p_1): Reorder checks > to the cheaper ones come first. > --- > gcc/tree-ssa-alias.c | 145 +++++++++++++++++++++---------------------- > 1 file changed, 70 insertions(+), 75 deletions(-) > > diff --git a/gcc/tree-ssa-alias.c b/gcc/tree-ssa-alias.c > index 88fd7821c5e..573766278bc 100644 > --- a/gcc/tree-ssa-alias.c > +++ b/gcc/tree-ssa-alias.c > @@ -2952,9 +2952,6 @@ ref_maybe_used_by_stmt_p (gimple *stmt, tree ref, bool > tbaa_p) > bool > call_may_clobber_ref_p_1 (gcall *call, ao_ref *ref, bool tbaa_p) > { > - tree base; > - tree callee; > - > /* If the call is pure or const it cannot clobber anything. */ > if (gimple_call_flags (call) > & (ECF_PURE|ECF_CONST|ECF_LOOPING_CONST_OR_PURE|ECF_NOVOPS)) > @@ -2977,9 +2974,64 @@ call_may_clobber_ref_p_1 (gcall *call, ao_ref *ref, > bool tbaa_p) > break; > } > > - callee = gimple_call_fndecl (call); > + tree base = ao_ref_base (ref); > + if (base > + && (TREE_CODE (base) == SSA_NAME > + || CONSTANT_CLASS_P (base))) > + return false; > + > + /* A call that is not without side-effects might involve volatile > + accesses and thus conflicts with all other volatile accesses. */ > + if (ref->volatile_p) > + return true; > + > + bool independent_pt = false; > + if (base && DECL_P (base)) > + { > + /* If the reference is based on a decl that is not aliased the call > + cannot possibly clobber it. */ > + if (!may_be_aliased (base) > + /* But local non-readonly statics can be modified through > + recursion or the call may implement a threading barrier which > + we must treat as may-def. */ > + && (TREE_READONLY (base) > + || !is_global_var (base))) > + return false; > > - if (callee != NULL_TREE && !ref->volatile_p) > + auto clobbers = gimple_call_clobber_set (call); > + independent_pt = !pt_solution_includes (clobbers, base); > + } > + else if (base > + && (TREE_CODE (base) == MEM_REF > + || TREE_CODE (base) == TARGET_MEM_REF) > + && TREE_CODE (TREE_OPERAND (base, 0)) == SSA_NAME) > + { > + tree addr = TREE_OPERAND (base, 0); > + > + /* If the reference is based on a pointer that points to memory that > + may not be written to then the call cannot possibly clobber it. */ > + if (SSA_NAME_POINTS_TO_READONLY_MEMORY (addr)) > + return false; > + > + /* Check if the base variable is call-clobbered. */ > + if (auto *pi = SSA_NAME_PTR_INFO (addr)) > + { > + auto clobbers = gimple_call_clobber_set (call); > + independent_pt = !pt_solutions_intersect (clobbers, &pi->pt); > + } > + } > + > + /* Points-to information needs to be tested in conjunction with > + check_fnspec. The fnspec argument information for built-in > + functions is excluded from the PT sets. */ > + int res = check_fnspec (call, ref, true); > + if (res >= 0) > + return res; > + > + if (independent_pt) > + return false; > + > + if (tree callee = gimple_call_fndecl (call)) > { > struct cgraph_node *node = cgraph_node::get (callee); > if (node) > @@ -3017,77 +3069,20 @@ call_may_clobber_ref_p_1 (gcall *call, ao_ref *ref, > bool tbaa_p) > return false; > } > alias_stats.modref_clobber_may_alias++; > - } > - } > - } > - > - base = ao_ref_base (ref); > - if (!base) > - return true; > - > - if (TREE_CODE (base) == SSA_NAME > - || CONSTANT_CLASS_P (base)) > - return false; > - > - /* A call that is not without side-effects might involve volatile > - accesses and thus conflicts with all other volatile accesses. */ > - if (ref->volatile_p) > - return true; > - > - /* If the reference is based on a decl that is not aliased the call > - cannot possibly clobber it. */ > - if (DECL_P (base) > - && !may_be_aliased (base) > - /* But local non-readonly statics can be modified through recursion > - or the call may implement a threading barrier which we must > - treat as may-def. */ > - && (TREE_READONLY (base) > - || !is_global_var (base))) > - return false; > - > - /* If the reference is based on a pointer that points to memory > - that may not be written to then the call cannot possibly clobber it. */ > - if ((TREE_CODE (base) == MEM_REF > - || TREE_CODE (base) == TARGET_MEM_REF) > - && TREE_CODE (TREE_OPERAND (base, 0)) == SSA_NAME > - && SSA_NAME_POINTS_TO_READONLY_MEMORY (TREE_OPERAND (base, 0))) > - return false; > - > - if (int res = check_fnspec (call, ref, true)) > - { > - if (res == 1) > - return true; > - } > - else > - return false; > - > - /* Check if base is a global static variable that is not written > - by the function. */ > - if (callee != NULL_TREE && VAR_P (base) && TREE_STATIC (base)) > - { > - struct cgraph_node *node = cgraph_node::get (callee); > - bitmap written; > - int id; > - > - if (node > - && (id = ipa_reference_var_uid (base)) != -1 > - && (written = ipa_reference_get_written_global (node)) > - && !bitmap_bit_p (written, id)) > - return false; > - } > - > - /* Check if the base variable is call-clobbered. */ > - if (DECL_P (base)) > - return pt_solution_includes (gimple_call_clobber_set (call), base); > - else if ((TREE_CODE (base) == MEM_REF > - || TREE_CODE (base) == TARGET_MEM_REF) > - && TREE_CODE (TREE_OPERAND (base, 0)) == SSA_NAME) > - { > - struct ptr_info_def *pi = SSA_NAME_PTR_INFO (TREE_OPERAND (base, 0)); > - if (!pi) > - return true; > + } > > - return pt_solutions_intersect (gimple_call_clobber_set (call), > &pi->pt); > + /* Check if base is a global static variable that is not written > + by the function. */ > + bitmap written; > + int id; > + if (base > + && VAR_P (base) > + && TREE_STATIC (base) > + && (id = ipa_reference_var_uid (base)) != -1 > + && (written = ipa_reference_get_written_global (node)) > + && !bitmap_bit_p (written, id)) > + return false; > + } > } > > return true; > -- > 2.31.1 >