diff mbox

Fix visibility handling in ipa-pure-const

Message ID 20151203042417.GB49589@kam.mff.cuni.cz
State New
Headers show

Commit Message

Jan Hubicka Dec. 3, 2015, 4:24 a.m. UTC
Hi,
while analyzing the previous bug I noticed that nothrow propagation handles
visibility wrong wrt aliases.  This patch fixes it and also makes the code a bit
more effective.

Bootstrapped/regtested x86_64-linux, comitted.

Honza

	* ipa-pure-const.c (ignore_edge): Rename to ...
	(ignore_edge_for_nothrow) ... this one; also ignore eges to
	interposable functions or ones that can not throw.
	(propagate_nothrow): Fix handling of availability.
diff mbox

Patch

Index: ipa-pure-const.c
===================================================================
--- ipa-pure-const.c	(revision 231216)
+++ ipa-pure-const.c	(working copy)
@@ -1124,11 +1124,18 @@  pure_const_read_summary (void)
     }
 }
 
+/* We only propagate across edges that can throw externally and their callee
+   is not interposable.  */
 
 static bool
-ignore_edge (struct cgraph_edge *e)
+ignore_edge_for_nothrow (struct cgraph_edge *e)
 {
-  return (!e->can_throw_external);
+  if (!e->can_throw_external || TREE_NOTHROW (e->callee->decl))
+    return true;
+
+  enum availability avail;
+  cgraph_node *n = e->callee->function_or_virtual_thunk_symbol (&avail);
+  return (avail <= AVAIL_INTERPOSABLE || TREE_NOTHROW (n->decl));
 }
 
 /* Return true if NODE is self recursive function.
@@ -1491,7 +1498,8 @@  propagate_nothrow (void)
   int i;
   struct ipa_dfs_info * w_info;
 
-  order_pos = ipa_reduced_postorder (order, true, false, ignore_edge);
+  order_pos = ipa_reduced_postorder (order, true, false,
+				     ignore_edge_for_nothrow);
   if (dump_file)
     {
       cgraph_node::dump_cgraph (dump_file);
@@ -1515,32 +1523,38 @@  propagate_nothrow (void)
       while (w && !can_throw)
 	{
 	  struct cgraph_edge *e, *ie;
-	  funct_state w_l = get_function_state (w);
-
-	  if (w_l->can_throw
-	      || w->get_availability () == AVAIL_INTERPOSABLE)
-	    can_throw = true;
 
-	  for (e = w->callees; e && !can_throw; e = e->next_callee)
+	  if (!TREE_NOTHROW (w->decl))
 	    {
-	      enum availability avail;
-	      struct cgraph_node *y = e->callee->
-				function_or_virtual_thunk_symbol (&avail);
+	      funct_state w_l = get_function_state (w);
 
-	      if (avail > AVAIL_INTERPOSABLE)
+	      if (w_l->can_throw
+		  || w->get_availability () == AVAIL_INTERPOSABLE)
+		can_throw = true;
+
+	      for (e = w->callees; e && !can_throw; e = e->next_callee)
 		{
-		  funct_state y_l = get_function_state (y);
+		  enum availability avail;
+
+		  if (!e->can_throw_external || TREE_NOTHROW (e->callee->decl))
+		    continue;
+
+		  struct cgraph_node *y = e->callee->
+				    function_or_virtual_thunk_symbol (&avail);
 
-		  if (y_l->can_throw && !TREE_NOTHROW (w->decl)
-		      && e->can_throw_external)
+		  /* We can use info about the callee only if we know it can
+		     not be interposed.  */
+		  if (avail <= AVAIL_INTERPOSABLE
+		      || (!TREE_NOTHROW (y->decl)
+			  && get_function_state (y)->can_throw))
 		    can_throw = true;
 		}
-	      else if (e->can_throw_external && !TREE_NOTHROW (y->decl))
-	        can_throw = true;
+	      for (ie = w->indirect_calls; ie && !can_throw;
+		   ie = ie->next_callee)
+		if (ie->can_throw_external
+		    && !(ie->indirect_info->ecf_flags & ECF_NOTHROW))
+		  can_throw = true;
 	    }
-          for (ie = w->indirect_calls; ie && !can_throw; ie = ie->next_callee)
-	    if (ie->can_throw_external)
-	      can_throw = true;
 	  w_info = (struct ipa_dfs_info *) w->aux;
 	  w = w_info->next_cycle;
 	}
@@ -1650,7 +1664,7 @@  skip_function_for_local_pure_const (stru
   if (node->get_availability () <= AVAIL_INTERPOSABLE)
     {
       if (dump_file)
-        fprintf (dump_file, "Function is not available or overwritable; not analyzing.\n");
+        fprintf (dump_file, "Function is not available or interposable; not analyzing.\n");
       return true;
     }
   return false;