diff mbox series

Add handling of bulitins to ipa-modref

Message ID 20200927223150.GE52458@kam.mff.cuni.cz
State New
Headers show
Series Add handling of bulitins to ipa-modref | expand

Commit Message

Jan Hubicka Sept. 27, 2020, 10:31 p.m. UTC
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  <hubicka@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 mbox series

Patch

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