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).

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

Reply via email to