Hi,

when I tested aggregate IPA-CP on SCCs, I did not notice that IPA-CP
confused itself on the testcase and did not work as intended.  That
will be fixed by the next patch, this one fixes function
cgraph_edge_brings_all_agg_vals_for_node which did not work on edges
IPA-CP clones and ICEd when it saw them, which is a bit of a problem
given that it is there primarily for such edges.

The patch below re-uses a big part of function
find_aggregate_values_for_callers_subset rather than re-implementing
the propagation once more.  It means that aggregate replacement values
are traversed a few times in the process but the list should be
usually tiny and even in pathologic cases their size is limited by
PARAM_IPA_MAX_AGG_ITEMS * number of parameters, so I do not think it's
worth a bitmap.

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

Thanks,

Martin


2012-11-19  Martin Jambor  <mjam...@suse.cz>

        PR tree-optimization/55260
        * ipa-cp.c (intersect_aggregates_with_edge): New function.
        (find_aggregate_values_for_callers_subset): Part moved to the function
        above.  Call it.
        (cgraph_edge_brings_all_agg_vals_for_node): Reimplemented using
        intersect_aggregates_with_edge.

        * testsuite/g++.dg/torture/pr55260-2.C: New test.

Index: src/gcc/testsuite/g++.dg/torture/pr55260-2.C
===================================================================
*** /dev/null
--- src/gcc/testsuite/g++.dg/torture/pr55260-2.C
***************
*** 0 ****
--- 1,16 ----
+ /* { dg-do compile } */
+ /* { dg-add-options bind_pic_locally } */
+ 
+ struct B
+ {
+     virtual void test_suite_finish ();
+ };
+ void
+ fn1 (B & p2)
+ {
+     fn1 (p2);
+     B & a = p2;
+     a.test_suite_finish ();
+     B b;
+     fn1 (b);
+ }
Index: src/gcc/ipa-cp.c
===================================================================
*** src.orig/gcc/ipa-cp.c
--- src/gcc/ipa-cp.c
*************** intersect_with_agg_replacements (struct
*** 2852,2857 ****
--- 2852,2978 ----
      }
  }
  
+ /* Intersect values in INTER with aggregate values that come along edge CS to
+    parameter number INDEX and return it.  If INTER does not actually exist 
yet,
+    copy all incoming values to it.  If we determine we ended up with no values
+    whatsoever, return a released vector.  */
+ 
+ static vec<ipa_agg_jf_item_t>
+ intersect_aggregates_with_edge (struct cgraph_edge *cs, int index,
+                               vec<ipa_agg_jf_item_t> inter)
+ {
+   struct ipa_jump_func *jfunc;
+   jfunc = ipa_get_ith_jump_func (IPA_EDGE_REF (cs), index);
+   if (jfunc->type == IPA_JF_PASS_THROUGH
+       && ipa_get_jf_pass_through_operation (jfunc) == NOP_EXPR)
+     {
+       struct ipa_node_params *caller_info = IPA_NODE_REF (cs->caller);
+       int src_idx = ipa_get_jf_pass_through_formal_id (jfunc);
+ 
+       if (caller_info->ipcp_orig_node)
+       {
+         struct cgraph_node *orig_node = caller_info->ipcp_orig_node;
+         struct ipcp_param_lattices *orig_plats;
+         orig_plats = ipa_get_parm_lattices (IPA_NODE_REF (orig_node),
+                                             src_idx);
+         if (agg_pass_through_permissible_p (orig_plats, jfunc))
+           {
+             if (!inter.exists ())
+               inter = agg_replacements_to_vector (cs->caller, 0);
+             else
+               intersect_with_agg_replacements (cs->caller, src_idx,
+                                                &inter, 0);
+           }
+       }
+       else
+       {
+         struct ipcp_param_lattices *src_plats;
+         src_plats = ipa_get_parm_lattices (caller_info, src_idx);
+         if (agg_pass_through_permissible_p (src_plats, jfunc))
+           {
+             /* Currently we do not produce clobber aggregate jump
+                functions, adjust when we do.  */
+             gcc_checking_assert (!jfunc->agg.items);
+             if (!inter.exists ())
+               inter = copy_plats_to_inter (src_plats, 0);
+             else
+               intersect_with_plats (src_plats, &inter, 0);
+           }
+       }
+     }
+   else if (jfunc->type == IPA_JF_ANCESTOR
+          && ipa_get_jf_ancestor_agg_preserved (jfunc))
+     {
+       struct ipa_node_params *caller_info = IPA_NODE_REF (cs->caller);
+       int src_idx = ipa_get_jf_ancestor_formal_id (jfunc);
+       struct ipcp_param_lattices *src_plats;
+       HOST_WIDE_INT delta = ipa_get_jf_ancestor_offset (jfunc);
+ 
+       if (caller_info->ipcp_orig_node)
+       {
+         if (!inter.exists ())
+           inter = agg_replacements_to_vector (cs->caller, delta);
+         else
+           intersect_with_agg_replacements (cs->caller, index, &inter,
+                                            delta);
+       }
+       else
+       {
+         src_plats = ipa_get_parm_lattices (caller_info, src_idx);;
+         /* Currently we do not produce clobber aggregate jump
+            functions, adjust when we do.  */
+         gcc_checking_assert (!src_plats->aggs || !jfunc->agg.items);
+         if (!inter.exists ())
+           inter = copy_plats_to_inter (src_plats, delta);
+         else
+           intersect_with_plats (src_plats, &inter, delta);
+       }
+     }
+   else if (jfunc->agg.items)
+     {
+       struct ipa_agg_jf_item *item;
+       int k;
+ 
+       if (!inter.exists ())
+       for (unsigned i = 0; i < jfunc->agg.items->length (); i++)
+         inter.safe_push ((*jfunc->agg.items)[i]);
+       else
+       FOR_EACH_VEC_ELT (inter, k, item)
+         {
+           int l = 0;
+           bool found = false;;
+ 
+           if (!item->value)
+             continue;
+ 
+           while ((unsigned) l < jfunc->agg.items->length ())
+             {
+               struct ipa_agg_jf_item *ti;
+               ti = &(*jfunc->agg.items)[l];
+               if (ti->offset > item->offset)
+                 break;
+               if (ti->offset == item->offset)
+                 {
+                   gcc_checking_assert (ti->value);
+                   if (values_equal_for_ipcp_p (item->value,
+                                                ti->value))
+                     found = true;
+                   break;
+                 }
+               l++;
+             }
+           if (!found)
+             item->value = NULL;
+         }
+     }
+   else
+     {
+       inter.release();
+       return vec<ipa_agg_jf_item_t>();
+     }
+   return inter;
+ }
+ 
  /* Look at edges in CALLERS and collect all known aggregate values that arrive
     from all of them.  */
  
*************** find_aggregate_values_for_callers_subset
*** 2885,2995 ****
  
        FOR_EACH_VEC_ELT (callers, j, cs)
        {
!         struct ipa_jump_func *jfunc;
!         jfunc = ipa_get_ith_jump_func (IPA_EDGE_REF (cs), i);
!         if (jfunc->type == IPA_JF_PASS_THROUGH
!             && ipa_get_jf_pass_through_operation (jfunc) == NOP_EXPR)
!           {
!             struct ipa_node_params *caller_info = IPA_NODE_REF (cs->caller);
!             int src_idx = ipa_get_jf_pass_through_formal_id (jfunc);
! 
!             if (caller_info->ipcp_orig_node)
!               {
!                 struct cgraph_node *orig_node = caller_info->ipcp_orig_node;
!                 struct ipcp_param_lattices *orig_plats;
!                 orig_plats = ipa_get_parm_lattices (IPA_NODE_REF (orig_node),
!                                                     src_idx);
!                 if (agg_pass_through_permissible_p (orig_plats, jfunc))
!                   {
!                     if (!inter.exists ())
!                       inter = agg_replacements_to_vector (cs->caller, 0);
!                     else
!                       intersect_with_agg_replacements (cs->caller, src_idx,
!                                                        &inter, 0);
!                   }
!               }
!             else
!               {
!                 struct ipcp_param_lattices *src_plats;
!                 src_plats = ipa_get_parm_lattices (caller_info, src_idx);
!                 if (agg_pass_through_permissible_p (src_plats, jfunc))
!                   {
!                     /* Currently we do not produce clobber aggregate jump
!                        functions, adjust when we do.  */
!                     gcc_checking_assert (!jfunc->agg.items);
!                     if (!inter.exists ())
!                       inter = copy_plats_to_inter (src_plats, 0);
!                     else
!                       intersect_with_plats (src_plats, &inter, 0);
!                   }
!               }
!           }
!         else if (jfunc->type == IPA_JF_ANCESTOR
!                  && ipa_get_jf_ancestor_agg_preserved (jfunc))
!           {
!             struct ipa_node_params *caller_info = IPA_NODE_REF (cs->caller);
!             int src_idx = ipa_get_jf_ancestor_formal_id (jfunc);
!             struct ipcp_param_lattices *src_plats;
!             HOST_WIDE_INT delta = ipa_get_jf_ancestor_offset (jfunc);
! 
!             if (caller_info->ipcp_orig_node)
!               {
!                 if (!inter.exists ())
!                   inter = agg_replacements_to_vector (cs->caller, delta);
!                 else
!                   intersect_with_agg_replacements (cs->caller, i, &inter,
!                                                    delta);
!               }
!             else
!               {
!                 src_plats = ipa_get_parm_lattices (caller_info, src_idx);;
!                 /* Currently we do not produce clobber aggregate jump
!                    functions, adjust when we do.  */
!                 gcc_checking_assert (!src_plats->aggs || !jfunc->agg.items);
!                 if (!inter.exists ())
!                   inter = copy_plats_to_inter (src_plats, delta);
!                 else
!                   intersect_with_plats (src_plats, &inter, delta);
!               }
!           }
!         else if (jfunc->agg.items)
!           {
!             int k;
! 
!             if (!inter.exists ())
!               for (unsigned i = 0; i < jfunc->agg.items->length (); i++)
!                 inter.safe_push ((*jfunc->agg.items)[i]);
!             else
!               FOR_EACH_VEC_ELT (inter, k, item)
!                 {
!                   int l = 0;
!                   bool found = false;;
! 
!                   if (!item->value)
!                     continue;
! 
!                   while ((unsigned) l < jfunc->agg.items->length ())
!                     {
!                       struct ipa_agg_jf_item *ti;
!                       ti = &(*jfunc->agg.items)[l];
!                       if (ti->offset > item->offset)
!                         break;
!                       if (ti->offset == item->offset)
!                         {
!                           gcc_checking_assert (ti->value);
!                           if (values_equal_for_ipcp_p (item->value,
!                                                         ti->value))
!                             found = true;
!                           break;
!                         }
!                       l++;
!                     }
!                   if (!found)
!                     item->value = NULL;
!                 }
!           }
!         else
!           goto next_param;
  
          if (!inter.exists ())
            goto next_param;
--- 3006,3012 ----
  
        FOR_EACH_VEC_ELT (callers, j, cs)
        {
!         inter = intersect_aggregates_with_edge (cs, i, inter);
  
          if (!inter.exists ())
            goto next_param;
*************** static bool
*** 3081,3117 ****
  cgraph_edge_brings_all_agg_vals_for_node (struct cgraph_edge *cs,
                                          struct cgraph_node *node)
  {
!   struct ipa_node_params *caller_info = IPA_NODE_REF (cs->caller);
    struct ipa_agg_replacement_value *aggval;
  
    aggval = ipa_get_agg_replacements_for_node (node);
!   while (aggval)
      {
!       bool found = false;
        struct ipcp_param_lattices *plats;
!       plats = ipa_get_parm_lattices (caller_info, aggval->index);
!       if (plats->aggs_bottom || plats->aggs_contain_variable)
        return false;
-       for (struct ipcp_agg_lattice *aglat = plats->aggs;
-          aglat;
-          aglat = aglat->next)
-         if (aglat->offset == aggval->offset)
-           {
-             if (ipa_lat_is_single_const (aglat)
-                 && values_equal_for_ipcp_p (aggval->value,
-                                             aglat->values->value))
-               {
-                 found = true;
-                 break;
-               }
-             else
-               return false;
-           }
  
!       if (!found)
        return false;
  
!       aggval = aggval->next;
      }
    return true;
  }
--- 3098,3160 ----
  cgraph_edge_brings_all_agg_vals_for_node (struct cgraph_edge *cs,
                                          struct cgraph_node *node)
  {
!   struct ipa_node_params *orig_caller_info = IPA_NODE_REF (cs->caller);
    struct ipa_agg_replacement_value *aggval;
+   int i, ec, count;
  
    aggval = ipa_get_agg_replacements_for_node (node);
!   if (!aggval)
!     return true;
! 
!   count = ipa_get_param_count (IPA_NODE_REF (node));
!   ec = ipa_get_cs_argument_count (IPA_EDGE_REF (cs));
!   if (ec < count)
!     for (struct ipa_agg_replacement_value *av = aggval; av; av = av->next)
!       if (aggval->index >= ec)
!       return false;
! 
!   if (orig_caller_info->ipcp_orig_node)
!     orig_caller_info = IPA_NODE_REF (orig_caller_info->ipcp_orig_node);
! 
!   for (i = 0; i < count; i++)
      {
!       static vec<ipa_agg_jf_item_t> values = vec<ipa_agg_jf_item_t>();
        struct ipcp_param_lattices *plats;
!       bool interesting = false;
!       for (struct ipa_agg_replacement_value *av = aggval; av; av = av->next)
!       if (aggval->index == i)
!         {
!           interesting = true;
!           break;
!         }
!       if (!interesting)
!       continue;
! 
!       plats = ipa_get_parm_lattices (orig_caller_info, aggval->index);
!       if (plats->aggs_bottom)
        return false;
  
!       values = intersect_aggregates_with_edge (cs, i, values);
!       if (!values.exists())
        return false;
  
!       for (struct ipa_agg_replacement_value *av = aggval; av; av = av->next)
!       if (aggval->index == i)
!         {
!           struct ipa_agg_jf_item *item;
!           int j;
!           bool found = false;
!           FOR_EACH_VEC_ELT (values, j, item)
!             if (item->value
!                 && item->offset == av->offset
!                 && values_equal_for_ipcp_p (item->value, av->value))
!               found = true;
!           if (!found)
!             {
!               values.release();
!               return false;
!             }
!         }
      }
    return true;
  }

Reply via email to