Hi,
this patch implements basic builtins handling to ipa-modref.
It breaks three additional Fortran testcases due to Fortran frontend
TBAA bugs as discussed in
https://gcc.gnu.org/pipermail/gcc-patches/2020-September/554936.html

Otherwise it bootstraps and regtests x86_64-linux.  With cc1plus I now
get:


Alias oracle query stats:
  refs_may_alias_p: 63538841 disambiguations, 73864959 queries
  ref_maybe_used_by_call_p: 142582 disambiguations, 64434151 queries
  call_may_clobber_ref_p: 23601 disambiguations, 30140 queries
  nonoverlapping_component_refs_p: 0 disambiguations, 38132 queries
  nonoverlapping_refs_since_match_p: 19438 disambiguations, 55708 must 
overlaps, 75971 queries
  aliasing_component_refs_p: 55152 disambiguations, 755956 queries
  TBAA oracle: 25191597 disambiguations 58468366 queries
               16860532 are in alias set 0
               10457818 queries asked about the same object
               125 queries asked about the same alias set
               0 access volatile
               4033743 are dependent in the DAG
               1924551 are aritificially in conflict with void *

Modref stats:
  modref use: 12085 disambiguations, 56415 queries
  modref clobber: 1613560 disambiguations, 2391667 queries
  6026445 tbaa queries (2.519768 per modref query)
  433921 base compares (0.181430 per modref query)

PTA query stats:
  pt_solution_includes: 982378 disambiguations, 13627506 queries
  pt_solutions_intersect: 1029380 disambiguations, 13198579 queries


This is 15% more use disambiguations and 38% clobber disambiguations
compared to previous build in
https://gcc.gnu.org/pipermail/gcc-patches/2020-September/554930.html

Good part of clobber disambiguation is probalby due to the bugfix
https://gcc.gnu.org/pipermail/gcc-patches/2020-September/554937.html
but that should not affect uses and thus there is certainly noticeable
improvement for builtin handling.

I get no noticeable difference for tramp3d presumably because most
alocations are on-stack or via C++ new.

gcc/ChangeLog:

2020-09-28  Jan Hubicka  <hubi...@ucw.cz>

        * ipa-modref.c: Include tree-ssa-alias.h.
        (modref_summary::dump): Dump writes_errno.
        (parm_map_for): Break out from...
        (merge_call_side_effects): ... here.
        (analyze_call): Handle builtins.
        (analyze_function): Initialize writes_errno.
        (modref_summaries::duplicate): Copy writes_errno.
        (modref_write): Stream writes_errno.
        (read_section): Stream writes_errno.
        (compute_parm_map): Be ready for missing callee info.
        (ipa_merge_modref_summary_after_inlining): Skip stores for pure
        functions.
        (collapse_stores): New function.
        (modref_propagate_in_scc): Handle bultins.
        * ipa-modref.h (modref_summary): Add writes_errno.
        * tree-ssa-alias.c (call_may_clobber_ref_p_1): Check for errno.

diff --git a/gcc/ipa-modref.c b/gcc/ipa-modref.c
index 6225552e41a..bba9f0db71d 100644
--- a/gcc/ipa-modref.c
+++ b/gcc/ipa-modref.c
@@ -59,6 +59,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "value-range.h"
 #include "ipa-prop.h"
 #include "ipa-fnsummary.h"
+#include "tree-ssa-alias.h"
 
 /* Class (from which there is one global instance) that holds modref summaries
    for all analyzed functions.  */
@@ -257,6 +258,8 @@ modref_summary::dump (FILE *out)
       fprintf (out, "  LTO stores:\n");
       dump_lto_records (stores_lto, out);
     }
+  if (writes_errno)
+    fprintf (out, "  Writes errno\n");
 }
 
 
@@ -437,6 +440,35 @@ ignore_stores_p (tree caller, int flags)
   return false;
 }
 
+/* Return parm map value for OP.
+   This means returning nonnegative value if OP is function parameter,
+   -2 is OP points to local or readonly memory and -1 otherwise.  */
+static int
+parm_map_for (tree op)
+{
+  if (TREE_CODE (op) == SSA_NAME
+      && SSA_NAME_IS_DEFAULT_DEF (op)
+      && TREE_CODE (SSA_NAME_VAR (op)) == PARM_DECL)
+    {
+      int index = 0;
+      for (tree t = DECL_ARGUMENTS (current_function_decl);
+          t != SSA_NAME_VAR (op); t = DECL_CHAIN (t))
+       {
+         if (!t)
+           {
+             index = -1;
+             break;
+           }
+         index++;
+       }
+      return index;
+    }
+  else if (points_to_local_or_readonly_memory_p (op))
+    return -2;
+  else
+    return -1;
+}
+
 /* Merge side effects of call STMT to function with CALLEE_SUMMARY
    int CUR_SUMMARY.  Return true if something changed.
    If IGNORE_STORES is true, do not merge stores.  */
@@ -451,31 +483,7 @@ merge_call_side_effects (modref_summary *cur_summary,
 
   parm_map.safe_grow (gimple_call_num_args (stmt));
   for (unsigned i = 0; i < gimple_call_num_args (stmt); i++)
-    {
-      tree op = gimple_call_arg (stmt, i);
-      STRIP_NOPS (op);
-      if (TREE_CODE (op) == SSA_NAME
-         && SSA_NAME_IS_DEFAULT_DEF (op)
-         && TREE_CODE (SSA_NAME_VAR (op)) == PARM_DECL)
-       {
-         int index = 0;
-         for (tree t = DECL_ARGUMENTS (current_function_decl);
-              t != SSA_NAME_VAR (op); t = DECL_CHAIN (t))
-           {
-             if (!t)
-               {
-                 index = -1;
-                 break;
-               }
-             index++;
-           }
-         parm_map[i] = index;
-       }
-      else if (points_to_local_or_readonly_memory_p (op))
-       parm_map[i] = -2;
-      else
-       parm_map[i] = -1;
-    }
+    parm_map[i] = parm_map_for (gimple_call_arg (stmt, i));
 
   /* Merge with callee's summary.  */
   if (cur_summary->loads)
@@ -491,6 +499,7 @@ merge_call_side_effects (modref_summary *cur_summary,
       if (cur_summary->stores_lto)
        changed |= cur_summary->stores_lto->merge (callee_summary->stores_lto,
                                                   &parm_map);
+      cur_summary->writes_errno |= callee_summary->writes_errno;
     }
   return changed;
 }
@@ -544,6 +553,85 @@ analyze_call (modref_summary *cur_summary,
       return false;
     }
 
+  struct ao_function_info info;
+  if (callee
+      && gimple_call_builtin_p (stmt, BUILT_IN_NORMAL)
+      && ao_classify_builtin (callee, &info)
+      && !(info.flags & AO_FUNCTION_BARRIER))
+    {
+      bool collapse_loads = false, collapse_stores = false;
+      if (info.num_param_reads >= 0)
+       {
+         for (int i = 0; i < info.num_param_reads && !collapse_loads; i++)
+           {
+             int map = parm_map_for
+                         (gimple_call_arg (stmt,
+                                           info.reads[i].param));
+             if (map == -2)
+               continue;
+             else if (map == -1)
+               collapse_loads = true;
+             else
+               {
+                 modref_access_node a = {map};
+                 if (cur_summary->loads)
+                   cur_summary->loads->insert (0, 0, a);
+                 if (cur_summary->loads_lto)
+                   cur_summary->loads_lto->insert (NULL, NULL, a);
+               }
+           }
+       }
+      else
+       collapse_loads = true;
+      if (collapse_loads)
+       {
+         if (cur_summary->loads)
+           cur_summary->loads->collapse ();
+         if (cur_summary->loads_lto)
+           cur_summary->loads_lto->collapse ();
+       }
+      if (ignore_stores)
+       ;
+      else if (info.num_param_writes >= 0)
+       {
+         if ((info.flags & AO_FUNCTION_ERRNO) && flag_errno_math)
+           cur_summary->writes_errno = true;
+         for (int i = 0; i < info.num_param_writes && !collapse_stores;
+              i++)
+           {
+             int map = parm_map_for
+                         (gimple_call_arg (stmt,
+                                           info.writes[i].param));
+             if (map == -2)
+               continue;
+             else if (map == -1)
+               collapse_stores = true;
+             else
+               {
+                 modref_access_node a = {map};
+                 if (cur_summary->stores)
+                   cur_summary->stores->insert (0, 0, a);
+                 if (cur_summary->stores_lto)
+                   cur_summary->stores_lto->insert (NULL, NULL, a);
+               }
+           }
+       }
+      else
+       collapse_stores = true;
+
+      if (collapse_stores)
+       {
+         if (cur_summary->stores)
+           cur_summary->stores->collapse ();
+         if (cur_summary->stores_lto)
+           cur_summary->stores_lto->collapse ();
+       }
+      return true;
+    }
+  else if (dump_file && gimple_call_builtin_p (stmt, BUILT_IN_NORMAL))
+    fprintf (dump_file, "      Unclassified builtin %s\n",
+            IDENTIFIER_POINTER (DECL_NAME (callee)));
+
   struct cgraph_node *callee_node = cgraph_node::get_create (callee);
 
   /* We can not safely optimize based on summary of callee if it does
@@ -772,6 +860,7 @@ analyze_function (function *f, bool ipa)
                                  param_modref_max_accesses);
     }
   summary->finished = false;
+  summary->writes_errno = false;
   int ecf_flags = flags_from_decl_or_type (current_function_decl);
   auto_vec <gimple *, 32> recursive_calls;
 
@@ -872,6 +961,7 @@ modref_summaries::duplicate (cgraph_node *, cgraph_node *,
There are many missing cases that could be added incrementally: I tried to
keep only the logic that was there before.
                             modref_summary *dst_data)
 {
   dst_data->finished = src_data->finished;
+  dst_data->writes_errno = src_data->writes_errno;
   if (src_data->stores)
     {
       dst_data->stores = modref_records::create_ggc
@@ -1151,6 +1241,7 @@ modref_write ()
            write_modref_records (r->loads_lto, ob);
          if (r->stores_lto)
            write_modref_records (r->stores_lto, ob);
+         streamer_write_uhwi (ob, r->writes_errno);
        }
     }
   streamer_write_char_stream (ob->main_stream, 0);
@@ -1204,6 +1295,7 @@ read_section (struct lto_file_decl_data *file_data, const 
char *data,
         read_modref_records (&ib, data_in,
                              &modref_sum->stores,
                              &modref_sum->stores_lto);
+      modref_sum->writes_errno = streamer_read_uhwi (&ib);
       if (dump_file)
        {
          fprintf (dump_file, "Read modref for %s\n",
@@ -1365,10 +1457,10 @@ compute_parm_map (cgraph_edge *callee_edge, vec<int> 
*parm_map)
             = ipa_get_ith_jump_func (args, i);
          if (jf)
            {
-             tree cst = ipa_value_from_jfunc (caller_parms_info,
-                                              jf,
-                                              ipa_get_type
-                                                (callee_pi, i));
+             tree cst = NULL;
+             if (callee_pi)
+               cst = ipa_value_from_jfunc (caller_parms_info, jf,
+                                            ipa_get_type (callee_pi, i));
              if (cst && points_to_local_or_readonly_memory_p (cst))
                {
                  (*parm_map)[i] = -2;
@@ -1438,12 +1530,16 @@ ipa_merge_modref_summary_after_inlining (cgraph_edge 
*edge)
 
       if (to_info->loads)
        to_info->loads->merge (callee_info->loads, &parm_map);
-      if (to_info->stores)
-       to_info->stores->merge (callee_info->stores, &parm_map);
       if (to_info->loads_lto)
        to_info->loads_lto->merge (callee_info->loads_lto, &parm_map);
-      if (to_info->stores_lto)
-       to_info->stores_lto->merge (callee_info->stores_lto, &parm_map);
+      if (!ignore_stores_p (edge->callee->decl, flags))
+       {
+         if (to_info->stores)
+           to_info->stores->merge (callee_info->stores, &parm_map);
+         if (to_info->stores_lto)
+           to_info->stores_lto->merge (callee_info->stores_lto, &parm_map);
+         to_info->writes_errno |= callee_info->writes_errno;
+       }
     }
   if (!to_info->useful_p (flags))
     summaries->remove (to);
@@ -1472,6 +1568,27 @@ collapse_loads (modref_summary *cur_summary)
   return changed;
 }
 
+/* Collapse stores and return true if something changed.  */
+
+bool
+collapse_stores (modref_summary *cur_summary)
+{
+  bool changed = false;
+
+  if (cur_summary->stores && !cur_summary->stores->every_base)
+    {
+      cur_summary->stores->collapse ();
+      changed = true;
+    }
+  if (cur_summary->stores_lto
+      && !cur_summary->stores_lto->every_base)
+    {
+      cur_summary->stores_lto->collapse ();
+      changed = true;
+    }
+  return changed;
+}
+
 /* Perform iterative dataflow on SCC component starting in COMPONENT_NODE.  */
 
 static void
@@ -1553,6 +1670,94 @@ modref_propagate_in_scc (cgraph_node *component_node)
 
              bool ignore_stores = ignore_stores_p (cur->decl, flags);
 
+             struct ao_function_info info;
+             if (callee
+                 && fndecl_built_in_p (callee->decl, BUILT_IN_NORMAL)
+                 && ao_classify_builtin (callee->decl, &info)
+                 && !(info.flags & AO_FUNCTION_BARRIER))
+               {
+                 bool collapse_loads_p = false, collapse_stores_p = false;
+                 auto_vec <int, 32> parm_map;
+
+                 compute_parm_map (callee_edge, &parm_map);
+
+                 if (info.num_param_reads >= 0)
+                   {
+                     for (int i = 0; i < info.num_param_reads
+                          && !collapse_loads_p; i++)
+                       {
+                         int map = i < (int) parm_map.length ()
+                                   ? parm_map[i] : -1;
+
+                         if (dump_file && i >= (int) parm_map.length ())
+                           fprintf (dump_file, "      Untracked param %i\n",
+                                    i);
+
+                         if (map == -2)
+                           continue;
+                         else if (map == -1)
+                           collapse_loads_p = true;
+                         else
+                           {
+                             modref_access_node a = {map};
+                             if (cur_summary->loads)
+                               changed |= cur_summary->loads->insert (0, 0, a);
+                             if (cur_summary->loads_lto)
+                               changed |= cur_summary->loads_lto->insert
+                                                (NULL, NULL, a);
+                           }
+                       }
+                   }
+                 else
+                   collapse_loads_p = true;
+                 if (collapse_loads_p)
+                   changed |= collapse_loads (cur_summary);
+                 if (ignore_stores)
+                   ;
+                 else if (info.num_param_writes >= 0)
+                   {
+                     if ((info.flags & AO_FUNCTION_ERRNO) && flag_errno_math)
+                       cur_summary->writes_errno = true;
+                     for (int i = 0;
+                          i < info.num_param_writes && !collapse_stores_p;
+                          i++)
+                       {
+                         int map = i < (int) parm_map.length ()
+                                   ? parm_map[i] : -1;
+
+                         if (dump_file && i >= (int) parm_map.length ())
+                           fprintf (dump_file, "      Untracked param %i\n",
+                                    i);
+
+                         if (map == -2)
+                           continue;
+                         else if (map == -1)
+                           collapse_stores_p = true;
+                         else
+                           {
+                             modref_access_node a = {map};
+                             if (cur_summary->stores)
+                               changed |= cur_summary->stores->insert
+                                              (0, 0, a);
+                             if (cur_summary->stores_lto)
+                               changed |= cur_summary->stores_lto->insert
+                                               (NULL, NULL, a);
+                           }
+                       }
+                   }
+                 else
+                   collapse_stores_p = true;
+
+                 if (collapse_stores_p)
+                   changed |= collapse_stores (cur_summary);
+
+                 continue;
+               }
+             else if (dump_file && callee
+                      && fndecl_built_in_p (callee->decl, BUILT_IN_NORMAL))
+               fprintf (dump_file, "      Unclassified builtin %s\n",
+                        IDENTIFIER_POINTER (DECL_NAME (callee->decl)));
+
              /* We don't know anything about CALLEE, hence we cannot tell
                 anything about the entire component.  */
 
diff --git a/gcc/ipa-modref.h b/gcc/ipa-modref.h
index b6621b498f0..a9c71800750 100644
--- a/gcc/ipa-modref.h
+++ b/gcc/ipa-modref.h
@@ -37,6 +37,7 @@ struct GTY(()) modref_summary
   modref_records_lto *loads_lto;
   modref_records_lto *stores_lto;
   bool finished;
+  bool writes_errno;
 
   modref_summary ();
   ~modref_summary ();
diff --git a/gcc/ipa-modref.h b/gcc/ipa-modref.h
index b6621b498f0..a9c71800750 100644
--- a/gcc/ipa-modref.h
+++ b/gcc/ipa-modref.h
@@ -37,6 +37,7 @@ struct GTY(()) modref_summary
   modref_records_lto *loads_lto;
   modref_records_lto *stores_lto;
   bool finished;
+  bool writes_errno;
 
   modref_summary ();
   ~modref_summary ();
diff --git a/gcc/tree-ssa-alias.c b/gcc/tree-ssa-alias.c
index fe390d4ffbe..c182e7bb39c 100644
--- a/gcc/tree-ssa-alias.c
+++ b/gcc/tree-ssa-alias.c
@@ -2961,7 +3280,9 @@ call_may_clobber_ref_p_1 (gcall *call, ao_ref *ref, bool 
tbaa_p)
          modref_summary *summary = get_modref_function_summary (node);
          if (summary)
            {
-             if (!modref_may_conflict (call, summary->stores, ref, tbaa_p))
+             if (!modref_may_conflict (call, summary->stores, ref, tbaa_p)
+                 && (!summary->writes_errno
+                     || !targetm.ref_may_alias_errno (ref)))
                {
                  alias_stats.modref_clobber_no_alias++;
                  if (dump_file && (dump_flags & TDF_DETAILS))

Reply via email to