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  <mjam...@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

Reply via email to