diff mbox

Improve pure/const propagation across interposable function with non-interposable aliases

Message ID 20160504152207.GE24787@kam.mff.cuni.cz
State New
Headers show

Commit Message

Jan Hubicka May 4, 2016, 3:22 p.m. UTC
Hi,
the API dealing with aliases is somewhow flawed by fact it makes difference between
the main symbol (defining function) and its aliases. There is nothing special about
the main symbol. This is fixed by this patch.

Bootstrapped/regtested x86_64-linux, will commit it shortly.

Honza

	* cgraph.c (cgraph_node::call_for_symbol_thunks_and_aliases):
	Check availability on NODE, too.
	* cgraph.h (symtab_node::call_for_symbol_and_aliases): Likewise.
	(cgraph_node::call_for_symbol_and_aliases): Likewise.
	(varpool_node::call_for_symbol_and_aliase): Likewise.
	* ipa-pure-const.c (add_new_function): Analyze all bodies.
	(propagate_pure_const): Propagate across interposable functions, too.
	(skip_function_for_local_pure_const): Do not skip interposable bodies
	with aliases.
	(pass_local_pure_const::execute): Update.

	* gcc.dg/ipa/pure-const-3.c: New testcase.
diff mbox

Patch

Index: cgraph.c
===================================================================
--- cgraph.c	(revision 235839)
+++ cgraph.c	(working copy)
@@ -2289,7 +2289,7 @@  cgraph_node::can_be_local_p (void)
 }
 
 /* Call callback on cgraph_node, thunks and aliases associated to cgraph_node.
-   When INCLUDE_OVERWRITABLE is false, overwritable aliases and thunks are
+   When INCLUDE_OVERWRITABLE is false, overwritable symbols are
    skipped.  When EXCLUDE_VIRTUAL_THUNKS is true, virtual thunks are
    skipped.  */
 bool
@@ -2301,9 +2301,14 @@  cgraph_node::call_for_symbol_thunks_and_
 {
   cgraph_edge *e;
   ipa_ref *ref;
+  enum availability avail = AVAIL_AVAILABLE;
 
-  if (callback (this, data))
-    return true;
+  if (include_overwritable
+      || (avail = get_availability ()) > AVAIL_INTERPOSABLE)
+    {
+      if (callback (this, data))
+        return true;
+    }
   FOR_EACH_ALIAS (this, ref)
     {
       cgraph_node *alias = dyn_cast <cgraph_node *> (ref->referring);
@@ -2314,7 +2319,7 @@  cgraph_node::call_for_symbol_thunks_and_
 						     exclude_virtual_thunks))
 	  return true;
     }
-  if (get_availability () <= AVAIL_INTERPOSABLE)
+  if (avail <= AVAIL_INTERPOSABLE)
     return false;
   for (e = callers; e; e = e->next_caller)
     if (e->caller->thunk.thunk_p
Index: cgraph.h
===================================================================
--- cgraph.h	(revision 235837)
+++ cgraph.h	(working copy)
@@ -3096,8 +3096,7 @@  symtab_node::get_availability (symtab_no
 }
 
 /* Call calback on symtab node and aliases associated to this node.
-   When INCLUDE_OVERWRITABLE is false, overwritable aliases and thunks are
-   skipped. */
+   When INCLUDE_OVERWRITABLE is false, overwritable symbols are skipped. */
 
 inline bool
 symtab_node::call_for_symbol_and_aliases (bool (*callback) (symtab_node *,
@@ -3105,15 +3104,19 @@  symtab_node::call_for_symbol_and_aliases
 					  void *data,
 					  bool include_overwritable)
 {
-  if (callback (this, data))
-    return true;
+  if (include_overwritable
+      || get_availability () > AVAIL_INTERPOSABLE)
+    {
+      if (callback (this, data))
+        return true;
+    }
   if (has_aliases_p ())
     return call_for_symbol_and_aliases_1 (callback, data, include_overwritable);
   return false;
 }
 
 /* Call callback on function and aliases associated to the function.
-   When INCLUDE_OVERWRITABLE is false, overwritable aliases and thunks are
+   When INCLUDE_OVERWRITABLE is false, overwritable symbols are
    skipped.  */
 
 inline bool
@@ -3122,15 +3125,19 @@  cgraph_node::call_for_symbol_and_aliases
 					  void *data,
 					  bool include_overwritable)
 {
-  if (callback (this, data))
-    return true;
+  if (include_overwritable
+      || get_availability () > AVAIL_INTERPOSABLE)
+    {
+      if (callback (this, data))
+        return true;
+    }
   if (has_aliases_p ())
     return call_for_symbol_and_aliases_1 (callback, data, include_overwritable);
   return false;
 }
 
 /* Call calback on varpool symbol and aliases associated to varpool symbol.
-   When INCLUDE_OVERWRITABLE is false, overwritable aliases and thunks are
+   When INCLUDE_OVERWRITABLE is false, overwritable symbols are
    skipped. */
 
 inline bool
@@ -3139,8 +3146,12 @@  varpool_node::call_for_symbol_and_aliase
 					   void *data,
 					   bool include_overwritable)
 {
-  if (callback (this, data))
-    return true;
+  if (include_overwritable
+      || get_availability () > AVAIL_INTERPOSABLE)
+    {
+      if (callback (this, data))
+        return true;
+    }
   if (has_aliases_p ())
     return call_for_symbol_and_aliases_1 (callback, data, include_overwritable);
   return false;
Index: ipa-pure-const.c
===================================================================
--- ipa-pure-const.c	(revision 235837)
+++ ipa-pure-const.c	(working copy)
@@ -927,8 +927,6 @@  end:
 static void
 add_new_function (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED)
 {
- if (node->get_availability () < AVAIL_INTERPOSABLE)
-   return;
   /* There are some shared nodes, in particular the initializers on
      static declarations.  We do not need to scan them more than once
      since all we would be interested in are the addressof
@@ -1222,6 +1220,7 @@  propagate_pure_const (void)
   int i;
   struct ipa_dfs_info * w_info;
   bool remove_p = false;
+  bool has_cdtor;
 
   order_pos = ipa_reduced_postorder (order, true, false,
 				     ignore_edge_for_pure_const);
@@ -1274,26 +1273,6 @@  propagate_pure_const (void)
 	  if (pure_const_state == IPA_NEITHER)
 	    break;
 
-	  /* For interposable nodes we can not assume anything.
-	     FIXME: It should be safe to remove this conditional and allow
-	     interposable functions with non-interposable aliases next
-	     stage 1.  */
-	  if (w->get_availability () == AVAIL_INTERPOSABLE)
-	    {
-	      worse_state (&pure_const_state, &looping,
-			   w_l->state_previously_known,
-			   w_l->looping_previously_known,
-			   NULL, NULL);
-	      if (dump_file && (dump_flags & TDF_DETAILS))
-		{
-		  fprintf (dump_file,
-			   "    Interposable. state %s looping %i\n",
-			   pure_const_names[w_l->state_previously_known],
-			   w_l->looping_previously_known);
-		}
-	      break;
-	    }
-
 	  count++;
 
 	  /* We consider recursive cycles as possibly infinite.
@@ -1506,9 +1485,22 @@  propagate_pure_const (void)
 			       this_looping ? "looping " : "",
 			       w->name ());
 		  }
-		remove_p |= w->call_for_symbol_and_aliases (cdtor_p,
-							    NULL, true);
-		w->set_const_flag (true, this_looping);
+		/* Turning constructor or destructor to non-looping const/pure
+		   enables us to possibly remove the function completely.  */
+		if (this_looping)
+		  has_cdtor = false;
+		else
+		  has_cdtor = w->call_for_symbol_and_aliases (cdtor_p,
+							      NULL, true);
+		if (w->set_const_flag (true, this_looping))
+		  {
+		    if (dump_file)
+		      fprintf (dump_file,
+			       "Declaration updated to be %sconst: %s\n",
+			       this_looping ? "looping " : "",
+			       w->name ());
+		    remove_p |= has_cdtor;
+		  }
 		break;
 
 	      case IPA_PURE:
@@ -1520,9 +1512,20 @@  propagate_pure_const (void)
 			       this_looping ? "looping " : "",
 			       w->name ());
 		  }
-		remove_p |= w->call_for_symbol_and_aliases (cdtor_p,
-							    NULL, true);
-		w->set_pure_flag (true, this_looping);
+		if (this_looping)
+		  has_cdtor = false;
+		else
+		  has_cdtor = w->call_for_symbol_and_aliases (cdtor_p,
+							      NULL, true);
+		if (w->set_pure_flag (true, this_looping))
+		  {
+		    if (dump_file)
+		      fprintf (dump_file,
+			       "Declaration updated to be %spure: %s\n",
+			       this_looping ? "looping " : "",
+			       w->name ());
+		    remove_p |= has_cdtor;
+		  }
 		break;
 
 	      default:
@@ -1723,11 +1726,14 @@  skip_function_for_local_pure_const (stru
         fprintf (dump_file, "Function called in recursive cycle; ignoring\n");
       return true;
     }
-  if (node->get_availability () <= AVAIL_INTERPOSABLE)
+  /* Save some work and do not analyze functions which are interposable and
+     do not have any non-interposable aliases.  */
+  if (node->get_availability () <= AVAIL_INTERPOSABLE
+      && !node->has_aliases_p ())
     {
       if (dump_file)
         fprintf (dump_file,
-		 "Function is not available or interposable; not analyzing.\n");
+		 "Function is interposable; not analyzing.\n");
       return true;
     }
   return false;
@@ -1806,11 +1812,6 @@  pass_local_pure_const::execute (function
       if (!TREE_READONLY (current_function_decl))
 	{
 	  warn_function_const (current_function_decl, !l->looping);
-	  if (!skip)
-	    {
-	      node->set_const_flag (true, l->looping);
-	      changed = true;
-	    }
 	  if (dump_file)
 	    fprintf (dump_file, "Function found to be %sconst: %s\n",
 		     l->looping ? "looping " : "",
@@ -1819,25 +1820,23 @@  pass_local_pure_const::execute (function
       else if (DECL_LOOPING_CONST_OR_PURE_P (current_function_decl)
 	       && !l->looping)
 	{
-	  if (!skip)
-	    {
-	      node->set_const_flag (true, false);
-	      changed = true;
-	    }
 	  if (dump_file)
 	    fprintf (dump_file, "Function found to be non-looping: %s\n",
 		     current_function_name ());
 	}
+      if (!skip && node->set_const_flag (true, l->looping))
+	{
+	  if (dump_file)
+	    fprintf (dump_file, "Declaration updated to be %sconst: %s\n",
+		     l->looping ? "looping " : "",
+		     current_function_name ());
+	  changed = true;
+	}
       break;
 
     case IPA_PURE:
       if (!DECL_PURE_P (current_function_decl))
 	{
-	  if (!skip)
-	    {
-	      node->set_pure_flag (true, l->looping);
-	      changed = true;
-	    }
 	  warn_function_pure (current_function_decl, !l->looping);
 	  if (dump_file)
 	    fprintf (dump_file, "Function found to be %spure: %s\n",
@@ -1847,15 +1846,18 @@  pass_local_pure_const::execute (function
       else if (DECL_LOOPING_CONST_OR_PURE_P (current_function_decl)
 	       && !l->looping)
 	{
-	  if (!skip)
-	    {
-	      node->set_pure_flag (true, false);
-	      changed = true;
-	    }
 	  if (dump_file)
 	    fprintf (dump_file, "Function found to be non-looping: %s\n",
 		     current_function_name ());
 	}
+      if (!skip && node->set_pure_flag (true, l->looping))
+	{
+	  if (dump_file)
+	    fprintf (dump_file, "Declaration updated to be %spure: %s\n",
+		     l->looping ? "looping " : "",
+		     current_function_name ());
+	  changed = true;
+	}
       break;
 
     default:
Index: testsuite/gcc.dg/ipa/pure-const-3.c
===================================================================
--- testsuite/gcc.dg/ipa/pure-const-3.c	(revision 0)
+++ testsuite/gcc.dg/ipa/pure-const-3.c	(working copy)
@@ -0,0 +1,24 @@ 
+/* { dg-do run } */
+/* { dg-require-alias "" }  */
+/* { dg-options "-O2 -fdump-tree-local-pure-const1" } */
+
+__attribute__ ((weak))
+__attribute__ ((noinline))
+int a(int v)
+{
+  return v;
+}
+__attribute__ ((noinline))
+static int b(int v) __attribute__ ((alias("a")));
+int
+main()
+{
+  int c = a(1)==a(1);
+  int d = b(1)==b(1);
+  if (__builtin_constant_p (c))
+    __builtin_abort ();
+  if (!__builtin_constant_p (d))
+    __builtin_abort ();
+  return 0;
+}
+/* { dg-final { scan-ipa-dump "found to be const" "pure-const"} } */