diff mbox

[1/2,PR,63814] Strengthen cgraph_edge_brings_value_p

Message ID 20141121185911.GB7784@virgil.suse
State New
Headers show

Commit Message

Martin Jambor Nov. 21, 2014, 6:59 p.m. UTC
Hi,

PR 63814 is caused by cgraph_edge_brings_value_p misidentifying an
edge to an expanded artificial thunk as an edge to the original node,
which then leads to crazy double-cloning and doubling the thunks along
the call.

This patch fixes the bug by strengthening the predicate so that it
knows where the value is supposed to go and can check that it goes
there and not anywhere else.  It also adds an extra availability check
that was probably missing in it.

Bootstrapped and tested on x86_64-linux, and i686-linux.  OK for
trunk?

Thanks,

Martin


2014-11-20  Martin Jambor  <mjambor@suse.cz>

	PR ipa/63814
	* ipa-cp.c (same_node_or_its_all_contexts_clone_p): New function.
	(cgraph_edge_brings_value_p): New parameter dest, use
	same_node_or_its_all_contexts_clone_p and check availability.
	(cgraph_edge_brings_value_p): Likewise.
	(get_info_about_necessary_edges): New parameter dest, pass it to
	cgraph_edge_brings_value_p.  Update caller.
	(gather_edges_for_value): Likewise.
	(perhaps_add_new_callers): Use cgraph_edge_brings_value_p to check
	both the destination and availability.

Comments

Martin Jambor Dec. 1, 2014, 5:26 p.m. UTC | #1
Ping.

Thx,

Martin

On Fri, Nov 21, 2014 at 07:59:11PM +0100, Martin Jambor wrote:
> Hi,
> 
> PR 63814 is caused by cgraph_edge_brings_value_p misidentifying an
> edge to an expanded artificial thunk as an edge to the original node,
> which then leads to crazy double-cloning and doubling the thunks along
> the call.
> 
> This patch fixes the bug by strengthening the predicate so that it
> knows where the value is supposed to go and can check that it goes
> there and not anywhere else.  It also adds an extra availability check
> that was probably missing in it.
> 
> Bootstrapped and tested on x86_64-linux, and i686-linux.  OK for
> trunk?
> 
> Thanks,
> 
> Martin
> 
> 
> 2014-11-20  Martin Jambor  <mjambor@suse.cz>
> 
> 	PR ipa/63814
> 	* ipa-cp.c (same_node_or_its_all_contexts_clone_p): New function.
> 	(cgraph_edge_brings_value_p): New parameter dest, use
> 	same_node_or_its_all_contexts_clone_p and check availability.
> 	(cgraph_edge_brings_value_p): Likewise.
> 	(get_info_about_necessary_edges): New parameter dest, pass it to
> 	cgraph_edge_brings_value_p.  Update caller.
> 	(gather_edges_for_value): Likewise.
> 	(perhaps_add_new_callers): Use cgraph_edge_brings_value_p to check
> 	both the destination and availability.
> 
> 
> Index: src/gcc/ipa-cp.c
> ===================================================================
> --- src.orig/gcc/ipa-cp.c
> +++ src/gcc/ipa-cp.c
> @@ -2785,17 +2785,31 @@ get_clone_agg_value (struct cgraph_node
>    return NULL_TREE;
>  }
>  
> -/* Return true if edge CS does bring about the value described by SRC.  */
> +/* Return true is NODE is DEST or its clone for all contexts.  */
>  
>  static bool
> -cgraph_edge_brings_value_p (struct cgraph_edge *cs,
> -			    ipcp_value_source<tree> *src)
> +same_node_or_its_all_contexts_clone_p (cgraph_node *node, cgraph_node *dest)
> +{
> +  if (node == dest)
> +    return true;
> +
> +  struct ipa_node_params *info = IPA_NODE_REF (node);
> +  return info->is_all_contexts_clone && info->ipcp_orig_node == dest;
> +}
> +
> +/* Return true if edge CS does bring about the value described by SRC to node
> +   DEST or its clone for all contexts.  */
> +
> +static bool
> +cgraph_edge_brings_value_p (cgraph_edge *cs, ipcp_value_source<tree> *src,
> +			    cgraph_node *dest)
>  {
>    struct ipa_node_params *caller_info = IPA_NODE_REF (cs->caller);
> -  cgraph_node *real_dest = cs->callee->function_symbol ();
> -  struct ipa_node_params *dst_info = IPA_NODE_REF (real_dest);
> +  enum availability availability;
> +  cgraph_node *real_dest = cs->callee->function_symbol (&availability);
>  
> -  if ((dst_info->ipcp_orig_node && !dst_info->is_all_contexts_clone)
> +  if (!same_node_or_its_all_contexts_clone_p (real_dest, dest)
> +      || availability <= AVAIL_INTERPOSABLE
>        || caller_info->node_dead)
>      return false;
>    if (!src->val)
> @@ -2834,18 +2848,18 @@ cgraph_edge_brings_value_p (struct cgrap
>      }
>  }
>  
> -/* Return true if edge CS does bring about the value described by SRC.  */
> +/* Return true if edge CS does bring about the value described by SRC to node
> +   DEST or its clone for all contexts.  */
>  
>  static bool
> -cgraph_edge_brings_value_p (struct cgraph_edge *cs,
> -			    ipcp_value_source<ipa_polymorphic_call_context>
> -			    *src)
> +cgraph_edge_brings_value_p (cgraph_edge *cs,
> +			    ipcp_value_source<ipa_polymorphic_call_context> *src,
> +			    cgraph_node *dest)
>  {
>    struct ipa_node_params *caller_info = IPA_NODE_REF (cs->caller);
>    cgraph_node *real_dest = cs->callee->function_symbol ();
> -  struct ipa_node_params *dst_info = IPA_NODE_REF (real_dest);
>  
> -  if ((dst_info->ipcp_orig_node && !dst_info->is_all_contexts_clone)
> +  if (!same_node_or_its_all_contexts_clone_p (real_dest, dest)
>        || caller_info->node_dead)
>      return false;
>    if (!src->val)
> @@ -2871,13 +2885,14 @@ get_next_cgraph_edge_clone (struct cgrap
>    return next_edge_clone[cs->uid];
>  }
>  
> -/* Given VAL, iterate over all its sources and if they still hold, add their
> -   edge frequency and their number into *FREQUENCY and *CALLER_COUNT
> -   respectively.  */
> +/* Given VAL that is intended for DEST, iterate over all its sources and if
> +   they still hold, add their edge frequency and their number into *FREQUENCY
> +   and *CALLER_COUNT respectively.  */
>  
>  template <typename valtype>
>  static bool
> -get_info_about_necessary_edges (ipcp_value<valtype> *val, int *freq_sum,
> +get_info_about_necessary_edges (ipcp_value<valtype> *val, cgraph_node *dest,
> +				int *freq_sum,
>  				gcov_type *count_sum, int *caller_count)
>  {
>    ipcp_value_source<valtype> *src;
> @@ -2890,7 +2905,7 @@ get_info_about_necessary_edges (ipcp_val
>        struct cgraph_edge *cs = src->cs;
>        while (cs)
>  	{
> -	  if (cgraph_edge_brings_value_p (cs, src))
> +	  if (cgraph_edge_brings_value_p (cs, src, dest))
>  	    {
>  	      count++;
>  	      freq += cs->frequency;
> @@ -2907,12 +2922,13 @@ get_info_about_necessary_edges (ipcp_val
>    return hot;
>  }
>  
> -/* Return a vector of incoming edges that do bring value VAL.  It is assumed
> -   their number is known and equal to CALLER_COUNT.  */
> +/* Return a vector of incoming edges that do bring value VAL to node DEST.  It
> +   is assumed their number is known and equal to CALLER_COUNT.  */
>  
>  template <typename valtype>
>  static vec<cgraph_edge *>
> -gather_edges_for_value (ipcp_value<valtype> *val, int caller_count)
> +gather_edges_for_value (ipcp_value<valtype> *val, cgraph_node *dest,
> +			int caller_count)
>  {
>    ipcp_value_source<valtype> *src;
>    vec<cgraph_edge *> ret;
> @@ -2923,7 +2939,7 @@ gather_edges_for_value (ipcp_value<valty
>        struct cgraph_edge *cs = src->cs;
>        while (cs)
>  	{
> -	  if (cgraph_edge_brings_value_p (cs, src))
> +	  if (cgraph_edge_brings_value_p (cs, src, dest))
>  	    ret.quick_push (cs);
>  	  cs = get_next_cgraph_edge_clone (cs);
>  	}
> @@ -3784,27 +3800,20 @@ perhaps_add_new_callers (cgraph_node *no
>        struct cgraph_edge *cs = src->cs;
>        while (cs)
>  	{
> -	  enum availability availability;
> -	  struct cgraph_node *dst = cs->callee->function_symbol (&availability);
> -	  if ((dst == node || IPA_NODE_REF (dst)->is_all_contexts_clone)
> -	      && availability > AVAIL_INTERPOSABLE
> -	      && cgraph_edge_brings_value_p (cs, src))
> +	  if (cgraph_edge_brings_value_p (cs, src, node)
> +	      && cgraph_edge_brings_all_scalars_for_node (cs, val->spec_node)
> +	      && cgraph_edge_brings_all_agg_vals_for_node (cs, val->spec_node))
>  	    {
> -	      if (cgraph_edge_brings_all_scalars_for_node (cs, val->spec_node)
> -		  && cgraph_edge_brings_all_agg_vals_for_node (cs,
> -							       val->spec_node))
> -		{
> -		  if (dump_file)
> -		    fprintf (dump_file, " - adding an extra caller %s/%i"
> -			     " of %s/%i\n",
> -			     xstrdup (cs->caller->name ()),
> -			     cs->caller->order,
> -			     xstrdup (val->spec_node->name ()),
> -			     val->spec_node->order);
> +	      if (dump_file)
> +		fprintf (dump_file, " - adding an extra caller %s/%i"
> +			 " of %s/%i\n",
> +			 xstrdup (cs->caller->name ()),
> +			 cs->caller->order,
> +			 xstrdup (val->spec_node->name ()),
> +			 val->spec_node->order);
>  
> -		  cs->redirect_callee (val->spec_node);
> -		  redirected_sum += cs->count;
> -		}
> +	      cs->redirect_callee (val->spec_node);
> +	      redirected_sum += cs->count;
>  	    }
>  	  cs = get_next_cgraph_edge_clone (cs);
>  	}
> @@ -3929,7 +3938,7 @@ decide_about_value (struct cgraph_node *
>  		 val->local_size_cost + overall_size);
>        return false;
>      }
> -  else if (!get_info_about_necessary_edges (val, &freq_sum, &count_sum,
> +  else if (!get_info_about_necessary_edges (val, node, &freq_sum, &count_sum,
>  					    &caller_count))
>      return false;
>  
> @@ -3959,7 +3968,7 @@ decide_about_value (struct cgraph_node *
>      fprintf (dump_file, "  Creating a specialized node of %s/%i.\n",
>  	     node->name (), node->order);
>  
> -  callers = gather_edges_for_value (val, caller_count);
> +  callers = gather_edges_for_value (val, node, caller_count);
>    if (offset == -1)
>      modify_known_vectors_with_val (&known_csts, &known_contexts, val, index);
>    else
Jan Hubicka Dec. 1, 2014, 9:40 p.m. UTC | #2
> > Hi,
> > 
> > PR 63814 is caused by cgraph_edge_brings_value_p misidentifying an
> > edge to an expanded artificial thunk as an edge to the original node,
> > which then leads to crazy double-cloning and doubling the thunks along
> > the call.
> > 
> > This patch fixes the bug by strengthening the predicate so that it
> > knows where the value is supposed to go and can check that it goes
> > there and not anywhere else.  It also adds an extra availability check
> > that was probably missing in it.
> > 
> > Bootstrapped and tested on x86_64-linux, and i686-linux.  OK for
> > trunk?
> > 
> > Thanks,
> > 
> > Martin
> > 
> > 
> > 2014-11-20  Martin Jambor  <mjambor@suse.cz>
> > 
> > 	PR ipa/63814
> > 	* ipa-cp.c (same_node_or_its_all_contexts_clone_p): New function.
> > 	(cgraph_edge_brings_value_p): New parameter dest, use
> > 	same_node_or_its_all_contexts_clone_p and check availability.
> > 	(cgraph_edge_brings_value_p): Likewise.
> > 	(get_info_about_necessary_edges): New parameter dest, pass it to
> > 	cgraph_edge_brings_value_p.  Update caller.
> > 	(gather_edges_for_value): Likewise.
> > 	(perhaps_add_new_callers): Use cgraph_edge_brings_value_p to check
> > 	both the destination and availability.

OK
diff mbox

Patch

Index: src/gcc/ipa-cp.c
===================================================================
--- src.orig/gcc/ipa-cp.c
+++ src/gcc/ipa-cp.c
@@ -2785,17 +2785,31 @@  get_clone_agg_value (struct cgraph_node
   return NULL_TREE;
 }
 
-/* Return true if edge CS does bring about the value described by SRC.  */
+/* Return true is NODE is DEST or its clone for all contexts.  */
 
 static bool
-cgraph_edge_brings_value_p (struct cgraph_edge *cs,
-			    ipcp_value_source<tree> *src)
+same_node_or_its_all_contexts_clone_p (cgraph_node *node, cgraph_node *dest)
+{
+  if (node == dest)
+    return true;
+
+  struct ipa_node_params *info = IPA_NODE_REF (node);
+  return info->is_all_contexts_clone && info->ipcp_orig_node == dest;
+}
+
+/* Return true if edge CS does bring about the value described by SRC to node
+   DEST or its clone for all contexts.  */
+
+static bool
+cgraph_edge_brings_value_p (cgraph_edge *cs, ipcp_value_source<tree> *src,
+			    cgraph_node *dest)
 {
   struct ipa_node_params *caller_info = IPA_NODE_REF (cs->caller);
-  cgraph_node *real_dest = cs->callee->function_symbol ();
-  struct ipa_node_params *dst_info = IPA_NODE_REF (real_dest);
+  enum availability availability;
+  cgraph_node *real_dest = cs->callee->function_symbol (&availability);
 
-  if ((dst_info->ipcp_orig_node && !dst_info->is_all_contexts_clone)
+  if (!same_node_or_its_all_contexts_clone_p (real_dest, dest)
+      || availability <= AVAIL_INTERPOSABLE
       || caller_info->node_dead)
     return false;
   if (!src->val)
@@ -2834,18 +2848,18 @@  cgraph_edge_brings_value_p (struct cgrap
     }
 }
 
-/* Return true if edge CS does bring about the value described by SRC.  */
+/* Return true if edge CS does bring about the value described by SRC to node
+   DEST or its clone for all contexts.  */
 
 static bool
-cgraph_edge_brings_value_p (struct cgraph_edge *cs,
-			    ipcp_value_source<ipa_polymorphic_call_context>
-			    *src)
+cgraph_edge_brings_value_p (cgraph_edge *cs,
+			    ipcp_value_source<ipa_polymorphic_call_context> *src,
+			    cgraph_node *dest)
 {
   struct ipa_node_params *caller_info = IPA_NODE_REF (cs->caller);
   cgraph_node *real_dest = cs->callee->function_symbol ();
-  struct ipa_node_params *dst_info = IPA_NODE_REF (real_dest);
 
-  if ((dst_info->ipcp_orig_node && !dst_info->is_all_contexts_clone)
+  if (!same_node_or_its_all_contexts_clone_p (real_dest, dest)
       || caller_info->node_dead)
     return false;
   if (!src->val)
@@ -2871,13 +2885,14 @@  get_next_cgraph_edge_clone (struct cgrap
   return next_edge_clone[cs->uid];
 }
 
-/* Given VAL, iterate over all its sources and if they still hold, add their
-   edge frequency and their number into *FREQUENCY and *CALLER_COUNT
-   respectively.  */
+/* Given VAL that is intended for DEST, iterate over all its sources and if
+   they still hold, add their edge frequency and their number into *FREQUENCY
+   and *CALLER_COUNT respectively.  */
 
 template <typename valtype>
 static bool
-get_info_about_necessary_edges (ipcp_value<valtype> *val, int *freq_sum,
+get_info_about_necessary_edges (ipcp_value<valtype> *val, cgraph_node *dest,
+				int *freq_sum,
 				gcov_type *count_sum, int *caller_count)
 {
   ipcp_value_source<valtype> *src;
@@ -2890,7 +2905,7 @@  get_info_about_necessary_edges (ipcp_val
       struct cgraph_edge *cs = src->cs;
       while (cs)
 	{
-	  if (cgraph_edge_brings_value_p (cs, src))
+	  if (cgraph_edge_brings_value_p (cs, src, dest))
 	    {
 	      count++;
 	      freq += cs->frequency;
@@ -2907,12 +2922,13 @@  get_info_about_necessary_edges (ipcp_val
   return hot;
 }
 
-/* Return a vector of incoming edges that do bring value VAL.  It is assumed
-   their number is known and equal to CALLER_COUNT.  */
+/* Return a vector of incoming edges that do bring value VAL to node DEST.  It
+   is assumed their number is known and equal to CALLER_COUNT.  */
 
 template <typename valtype>
 static vec<cgraph_edge *>
-gather_edges_for_value (ipcp_value<valtype> *val, int caller_count)
+gather_edges_for_value (ipcp_value<valtype> *val, cgraph_node *dest,
+			int caller_count)
 {
   ipcp_value_source<valtype> *src;
   vec<cgraph_edge *> ret;
@@ -2923,7 +2939,7 @@  gather_edges_for_value (ipcp_value<valty
       struct cgraph_edge *cs = src->cs;
       while (cs)
 	{
-	  if (cgraph_edge_brings_value_p (cs, src))
+	  if (cgraph_edge_brings_value_p (cs, src, dest))
 	    ret.quick_push (cs);
 	  cs = get_next_cgraph_edge_clone (cs);
 	}
@@ -3784,27 +3800,20 @@  perhaps_add_new_callers (cgraph_node *no
       struct cgraph_edge *cs = src->cs;
       while (cs)
 	{
-	  enum availability availability;
-	  struct cgraph_node *dst = cs->callee->function_symbol (&availability);
-	  if ((dst == node || IPA_NODE_REF (dst)->is_all_contexts_clone)
-	      && availability > AVAIL_INTERPOSABLE
-	      && cgraph_edge_brings_value_p (cs, src))
+	  if (cgraph_edge_brings_value_p (cs, src, node)
+	      && cgraph_edge_brings_all_scalars_for_node (cs, val->spec_node)
+	      && cgraph_edge_brings_all_agg_vals_for_node (cs, val->spec_node))
 	    {
-	      if (cgraph_edge_brings_all_scalars_for_node (cs, val->spec_node)
-		  && cgraph_edge_brings_all_agg_vals_for_node (cs,
-							       val->spec_node))
-		{
-		  if (dump_file)
-		    fprintf (dump_file, " - adding an extra caller %s/%i"
-			     " of %s/%i\n",
-			     xstrdup (cs->caller->name ()),
-			     cs->caller->order,
-			     xstrdup (val->spec_node->name ()),
-			     val->spec_node->order);
+	      if (dump_file)
+		fprintf (dump_file, " - adding an extra caller %s/%i"
+			 " of %s/%i\n",
+			 xstrdup (cs->caller->name ()),
+			 cs->caller->order,
+			 xstrdup (val->spec_node->name ()),
+			 val->spec_node->order);
 
-		  cs->redirect_callee (val->spec_node);
-		  redirected_sum += cs->count;
-		}
+	      cs->redirect_callee (val->spec_node);
+	      redirected_sum += cs->count;
 	    }
 	  cs = get_next_cgraph_edge_clone (cs);
 	}
@@ -3929,7 +3938,7 @@  decide_about_value (struct cgraph_node *
 		 val->local_size_cost + overall_size);
       return false;
     }
-  else if (!get_info_about_necessary_edges (val, &freq_sum, &count_sum,
+  else if (!get_info_about_necessary_edges (val, node, &freq_sum, &count_sum,
 					    &caller_count))
     return false;
 
@@ -3959,7 +3968,7 @@  decide_about_value (struct cgraph_node *
     fprintf (dump_file, "  Creating a specialized node of %s/%i.\n",
 	     node->name (), node->order);
 
-  callers = gather_edges_for_value (val, caller_count);
+  callers = gather_edges_for_value (val, node, caller_count);
   if (offset == -1)
     modify_known_vectors_with_val (&known_csts, &known_contexts, val, index);
   else