Hi,
this patch solves some problems related to jump function computation and 
maintenance.
In particular:
 1) inliner used to compute jump functions only when indirect inlining is 
enabled.
    We now use them for predicate evaulation and thus we need to compute them 
always
    up-to date (when optimizing).
 2) propagate_info_to_inlined_callees forgot to update indirect call jump 
function.
    This leads to horrible confussion (and wrong code?) when the indirect call 
is
    made direct and later inlined.
 3) update_indirect_edges_after_inlining for some reason kept out of date param
    indexes after inlining.  To avoid wrong code it maintained bitmap of edges 
to
    not look at.  It seems a lot cleaner to maintain the indexes up to date and
    set to -1 when they are no longer known.
    I also made this to happen always so we do not keep out of date info in the
    datastructures
 4) For inlined edges we keep around the jump functions and predicates that are
    no longer updated.  This leads to bugs where one uses them by accident. It 
is
    better to free them when they are no longer useful.
 5) inline-analysis had dirty hack to avoid ICE on indirect edges that should 
not
    longer be needed after the fixes above.

Bootstrapped/regtested x86_64-linux

        * ipa-inline-transform.c (inline_call): Always update jump functions
        after inlining.
        * ipa-inline.c (ipa_inline): Likewise; do not call
        ipa_create_all_structures_for_iinln.
        (ipa_inline): Always free jump functions.
        * ipa-inline-analysis.c (evaluate_conditions_for_edge): Remove
        hack.
        (remap_edge_predicates): Fix pasto.
        (inline_merge_summary): Remove nlined edge predicate; remove hack.
        (inline_analyze_function): Always initialize jump functions.
        (inline_generate_summary): Likewise.
        (inline_write_summary): Always write jump functions when ipa-cp
        is not doing that.
        (inline_read_summary): Always read jump functions when ipa-cp
        is not doing that.
        * ipa-prop.c (iinlining_processed_edges): Remove.
        (update_indirect_edges_after_inlining): Do not use
        iinlining_processed_edges; instead set param_index to -1.
        (propagate_info_to_inlined_callees): Only try to indirect inlining
        when asked to do so; update jump functions of indirect calls, too;
        remove jump functions of the inlined edge.
        (ipa_edge_duplication_hook): Do not copy iinlining_processed_edges.
        (ipa_create_all_structures_for_iinln): Remove.
        (ipa_free_all_structures_after_iinln): Do not free
        iinlining_processed_edges.
        * ipa-prop.h (ipa_create_all_structures_for_iinln): Remove.

Index: ipa-inline-transform.c
===================================================================
*** ipa-inline-transform.c      (revision 179082)
--- ipa-inline-transform.c      (working copy)
*************** inline_call (struct cgraph_edge *e, bool
*** 248,254 ****
      *overall_size += new_size - old_size;
    ncalls_inlined++;
  
!   if (flag_indirect_inlining && optimize)
      return ipa_propagate_indirect_call_infos (curr, new_edges);
    else
      return false;
--- 248,254 ----
      *overall_size += new_size - old_size;
    ncalls_inlined++;
  
!   if (optimize)
      return ipa_propagate_indirect_call_infos (curr, new_edges);
    else
      return false;
Index: ipa-inline.c
===================================================================
*** ipa-inline.c        (revision 179082)
--- ipa-inline.c        (working copy)
*************** ipa_inline (void)
*** 1659,1668 ****
      XCNEWVEC (struct cgraph_node *, cgraph_n_nodes);
    int i;
  
!   if (in_lto_p && flag_indirect_inlining)
      ipa_update_after_lto_read ();
-   if (flag_indirect_inlining)
-     ipa_create_all_structures_for_iinln ();
  
    if (dump_file)
      dump_inline_summaries (dump_file);
--- 1659,1666 ----
      XCNEWVEC (struct cgraph_node *, cgraph_n_nodes);
    int i;
  
!   if (in_lto_p && optimize)
      ipa_update_after_lto_read ();
  
    if (dump_file)
      dump_inline_summaries (dump_file);
*************** ipa_inline (void)
*** 1757,1763 ****
      }
  
    /* Free ipa-prop structures if they are no longer needed.  */
!   if (flag_indirect_inlining)
      ipa_free_all_structures_after_iinln ();
  
    if (dump_file)
--- 1755,1761 ----
      }
  
    /* Free ipa-prop structures if they are no longer needed.  */
!   if (optimize)
      ipa_free_all_structures_after_iinln ();
  
    if (dump_file)
Index: ipa-inline-analysis.c
===================================================================
*** ipa-inline-analysis.c       (revision 179082)
--- ipa-inline-analysis.c       (working copy)
*************** evaluate_conditions_for_edge (struct cgr
*** 619,628 ****
    struct inline_summary *info = inline_summary (callee);
    int i;
  
!   if (ipa_node_params_vector && info->conds
!       /* FIXME: it seems that we forget to get argument count in some cases,
!        probaby for previously indirect edges or so.  */
!       && ipa_get_cs_argument_count (IPA_EDGE_REF (e)))
      {
        struct ipa_node_params *parms_info;
        struct ipa_edge_args *args = IPA_EDGE_REF (e);
--- 619,625 ----
    struct inline_summary *info = inline_summary (callee);
    int i;
  
!   if (ipa_node_params_vector && info->conds)
      {
        struct ipa_node_params *parms_info;
        struct ipa_edge_args *args = IPA_EDGE_REF (e);
*************** evaluate_conditions_for_edge (struct cgr
*** 634,640 ****
        else
          parms_info = IPA_NODE_REF (e->caller);
  
!       VEC_safe_grow_cleared (tree, heap, known_vals, count);
        for (i = 0; i < count; i++)
        {
          tree cst = ipa_cst_from_jfunc (parms_info,
--- 631,638 ----
        else
          parms_info = IPA_NODE_REF (e->caller);
  
!       if (count)
!         VEC_safe_grow_cleared (tree, heap, known_vals, count);
        for (i = 0; i < count; i++)
        {
          tree cst = ipa_cst_from_jfunc (parms_info,
*************** remap_edge_predicates (struct cgraph_nod
*** 2062,2087 ****
      {
        struct inline_edge_summary *es = inline_edge_summary (e);
        struct predicate p;
!       if (es->predicate)
        {
!         p = remap_predicate (info, callee_info,
!                              es->predicate, operand_map, possible_truths,
!                              toplev_predicate);
!         edge_set_predicate (e, &p);
!         /* TODO: We should remove the edge for code that will be optimized 
out,
!            but we need to keep verifiers and tree-inline happy.
!            Make it cold for now.  */
!         if (false_predicate_p (&p))
            {
!             e->count = 0;
!             e->frequency = 0;
            }
        }
!       if (!e->inline_failed)
        remap_edge_predicates (e->callee, info, callee_info, operand_map,
                               possible_truths, toplev_predicate);
-       else
-       edge_set_predicate (e, toplev_predicate);
      }
    for (e = node->indirect_calls; e; e = e->next_callee)
      {
--- 2060,2088 ----
      {
        struct inline_edge_summary *es = inline_edge_summary (e);
        struct predicate p;
!       if (e->inline_failed)
        {
!         if (es->predicate)
            {
!             p = remap_predicate (info, callee_info,
!                                  es->predicate, operand_map, possible_truths,
!                                  toplev_predicate);
!             edge_set_predicate (e, &p);
!             /* TODO: We should remove the edge for code that will be 
optimized out,
!                but we need to keep verifiers and tree-inline happy.
!                Make it cold for now.  */
!             if (false_predicate_p (&p))
!               {
!                 e->count = 0;
!                 e->frequency = 0;
!               }
            }
+         else
+           edge_set_predicate (e, toplev_predicate);
        }
!       else
        remap_edge_predicates (e->callee, info, callee_info, operand_map,
                               possible_truths, toplev_predicate);
      }
    for (e = node->indirect_calls; e; e = e->next_callee)
      {
*************** inline_merge_summary (struct cgraph_edge
*** 2122,2127 ****
--- 2123,2129 ----
    VEC (int, heap) *operand_map = NULL;
    int i;
    struct predicate toplev_predicate;
+   struct predicate true_p = true_predicate ();
    struct inline_edge_summary *es = inline_edge_summary (edge);
  
    if (es->predicate)
*************** inline_merge_summary (struct cgraph_edge
*** 2129,2146 ****
    else
      toplev_predicate = true_predicate ();
  
!   if (ipa_node_params_vector && callee_info->conds
!       /* FIXME: it seems that we forget to get argument count in some cases,
!        probaby for previously indirect edges or so.
!        Removing the test leads to ICE on tramp3d.  */
!       && ipa_get_cs_argument_count (IPA_EDGE_REF (edge)))
      {
        struct ipa_edge_args *args = IPA_EDGE_REF (edge);
        int count = ipa_get_cs_argument_count (args);
        int i;
  
        clause = evaluate_conditions_for_edge (edge, true);
!       VEC_safe_grow_cleared (int, heap, operand_map, count);
        for (i = 0; i < count; i++)
        {
          struct ipa_jump_func *jfunc = ipa_get_ith_jump_func (args, i);
--- 2131,2145 ----
    else
      toplev_predicate = true_predicate ();
  
!   if (ipa_node_params_vector && callee_info->conds)
      {
        struct ipa_edge_args *args = IPA_EDGE_REF (edge);
        int count = ipa_get_cs_argument_count (args);
        int i;
  
        clause = evaluate_conditions_for_edge (edge, true);
!       if (count)
!         VEC_safe_grow_cleared (int, heap, operand_map, count);
        for (i = 0; i < count; i++)
        {
          struct ipa_jump_func *jfunc = ipa_get_ith_jump_func (args, i);
*************** inline_merge_summary (struct cgraph_edge
*** 2176,2181 ****
--- 2175,2183 ----
    inline_update_callee_summaries (edge->callee,
                                  inline_edge_summary (edge)->loop_depth);
  
+   /* We do not maintain predicates of inlined edges, free it.  */
+   edge_set_predicate (edge, &true_p);
+ 
    info->time = (info->time + INLINE_TIME_SCALE / 2) / INLINE_TIME_SCALE;
    info->size = (info->size + INLINE_SIZE_SCALE / 2) / INLINE_SIZE_SCALE;
  }
*************** inline_analyze_function (struct cgraph_n
*** 2389,2397 ****
    if (dump_file)
      fprintf (dump_file, "\nAnalyzing function: %s/%u\n",
             cgraph_node_name (node), node->uid);
!   /* FIXME: We should remove the optimize check after we ensure we never run
!      IPA passes when not optimizing.  */
!   if (flag_indirect_inlining && optimize && !node->thunk.thunk_p)
      inline_indirect_intraprocedural_analysis (node);
    compute_inline_parameters (node, false);
  
--- 2391,2397 ----
    if (dump_file)
      fprintf (dump_file, "\nAnalyzing function: %s/%u\n",
             cgraph_node_name (node), node->uid);
!   if (optimize && !node->thunk.thunk_p)
      inline_indirect_intraprocedural_analysis (node);
    compute_inline_parameters (node, false);
  
*************** inline_generate_summary (void)
*** 2419,2426 ****
    function_insertion_hook_holder =
        cgraph_add_function_insertion_hook (&add_new_function, NULL);
  
!   if (flag_indirect_inlining)
!     ipa_register_cgraph_hooks ();
  
    FOR_EACH_DEFINED_FUNCTION (node)
      if (!node->alias)
--- 2419,2425 ----
    function_insertion_hook_holder =
        cgraph_add_function_insertion_hook (&add_new_function, NULL);
  
!   ipa_register_cgraph_hooks ();
  
    FOR_EACH_DEFINED_FUNCTION (node)
      if (!node->alias)
*************** inline_read_summary (void)
*** 2572,2578 ****
           this should never happen.  */
        fatal_error ("ipa inline summary is missing in input file");
      }
!   if (flag_indirect_inlining)
      {
        ipa_register_cgraph_hooks ();
        if (!flag_ipa_cp)
--- 2571,2577 ----
           this should never happen.  */
        fatal_error ("ipa inline summary is missing in input file");
      }
!   if (optimize)
      {
        ipa_register_cgraph_hooks ();
        if (!flag_ipa_cp)
*************** inline_write_summary (cgraph_node_set se
*** 2676,2682 ****
    produce_asm (ob, NULL);
    destroy_output_block (ob);
  
!   if (flag_indirect_inlining && !flag_ipa_cp)
      ipa_prop_write_jump_functions (set);
  }
  
--- 2675,2681 ----
    produce_asm (ob, NULL);
    destroy_output_block (ob);
  
!   if (optimize && !flag_ipa_cp)
      ipa_prop_write_jump_functions (set);
  }
  
Index: ipa-prop.c
===================================================================
*** ipa-prop.c  (revision 179082)
--- ipa-prop.c  (working copy)
*************** VEC (ipa_node_params_t, heap) *ipa_node_
*** 56,65 ****
  /* Vector where the parameter infos are actually stored. */
  VEC (ipa_edge_args_t, gc) *ipa_edge_args_vector;
  
- /* Bitmap with all UIDs of call graph edges that have been already processed
-    by indirect inlining.  */
- static bitmap iinlining_processed_edges;
- 
  /* Holders of ipa cgraph hooks: */
  static struct cgraph_edge_hook_list *edge_removal_hook_holder;
  static struct cgraph_node_hook_list *node_removal_hook_holder;
--- 56,61 ----
*************** update_indirect_edges_after_inlining (st
*** 1699,1716 ****
        struct ipa_jump_func *jfunc;
  
        next_ie = ie->next_callee;
-       if (bitmap_bit_p (iinlining_processed_edges, ie->uid))
-       continue;
  
-       /* If we ever use indirect edges for anything other than indirect
-        inlining, we will need to skip those with negative param_indices. */
        if (ici->param_index == -1)
        continue;
  
        /* We must check range due to calls with variable number of arguments:  
*/
        if (ici->param_index >= ipa_get_cs_argument_count (top))
        {
!         bitmap_set_bit (iinlining_processed_edges, ie->uid);
          continue;
        }
  
--- 1695,1708 ----
        struct ipa_jump_func *jfunc;
  
        next_ie = ie->next_callee;
  
        if (ici->param_index == -1)
        continue;
  
        /* We must check range due to calls with variable number of arguments:  
*/
        if (ici->param_index >= ipa_get_cs_argument_count (top))
        {
!         ici->param_index = -1;
          continue;
        }
  
*************** update_indirect_edges_after_inlining (st
*** 1725,1731 ****
        }
        else
        /* Either we can find a destination for this edge now or never. */
!       bitmap_set_bit (iinlining_processed_edges, ie->uid);
  
        if (ici->polymorphic)
        new_direct_edge = try_make_edge_direct_virtual_call (ie, jfunc);
--- 1717,1726 ----
        }
        else
        /* Either we can find a destination for this edge now or never. */
!       ici->param_index = -1;
! 
!       if (!flag_indirect_inlining)
!       continue;
  
        if (ici->polymorphic)
        new_direct_edge = try_make_edge_direct_virtual_call (ie, jfunc);
*************** propagate_info_to_inlined_callees (struc
*** 1771,1776 ****
--- 1766,1773 ----
        res |= propagate_info_to_inlined_callees (cs, e->callee, new_edges);
      else
        update_jump_functions_after_inlining (cs, e);
+   for (e = node->indirect_calls; e; e = e->next_callee)
+     update_jump_functions_after_inlining (cs, e);
  
    return res;
  }
*************** bool
*** 1785,1797 ****
  ipa_propagate_indirect_call_infos (struct cgraph_edge *cs,
                                   VEC (cgraph_edge_p, heap) **new_edges)
  {
    /* Do nothing if the preparation phase has not been carried out yet
       (i.e. during early inlining).  */
    if (!ipa_node_params_vector)
      return false;
    gcc_assert (ipa_edge_args_vector);
  
!   return propagate_info_to_inlined_callees (cs, cs->callee, new_edges);
  }
  
  /* Frees all dynamically allocated structures that the argument info points
--- 1782,1800 ----
  ipa_propagate_indirect_call_infos (struct cgraph_edge *cs,
                                   VEC (cgraph_edge_p, heap) **new_edges)
  {
+   bool changed;
    /* Do nothing if the preparation phase has not been carried out yet
       (i.e. during early inlining).  */
    if (!ipa_node_params_vector)
      return false;
    gcc_assert (ipa_edge_args_vector);
  
!   changed = propagate_info_to_inlined_callees (cs, cs->callee, new_edges);
! 
!   /* We do not keep jump functions of inlined edges up to date. Better to free
!      them so we do not access them accidentally.  */
!   ipa_free_edge_args_substructures (IPA_EDGE_REF (cs));
!   return changed;
  }
  
  /* Frees all dynamically allocated structures that the argument info points
*************** ipa_edge_duplication_hook (struct cgraph
*** 1889,1898 ****
  
    new_args->jump_functions = VEC_copy (ipa_jump_func_t, gc,
                                       old_args->jump_functions);
- 
-   if (iinlining_processed_edges
-       && bitmap_bit_p (iinlining_processed_edges, src->uid))
-     bitmap_set_bit (iinlining_processed_edges, dst->uid);
  }
  
  /* Hook that is called by cgraph.c when a node is duplicated.  */
--- 1892,1897 ----
*************** ipa_unregister_cgraph_hooks (void)
*** 1963,1983 ****
    function_insertion_hook_holder = NULL;
  }
  
- /* Allocate all necessary data structures necessary for indirect inlining.  */
- 
- void
- ipa_create_all_structures_for_iinln (void)
- {
-   iinlining_processed_edges = BITMAP_ALLOC (NULL);
- }
- 
  /* Free all ipa_node_params and all ipa_edge_args structures if they are no
     longer needed after ipa-cp.  */
  
  void
  ipa_free_all_structures_after_ipa_cp (void)
  {
!   if (!flag_indirect_inlining)
      {
        ipa_free_all_edge_args ();
        ipa_free_all_node_params ();
--- 1962,1974 ----
    function_insertion_hook_holder = NULL;
  }
  
  /* Free all ipa_node_params and all ipa_edge_args structures if they are no
     longer needed after ipa-cp.  */
  
  void
  ipa_free_all_structures_after_ipa_cp (void)
  {
!   if (!optimize)
      {
        ipa_free_all_edge_args ();
        ipa_free_all_node_params ();
*************** ipa_free_all_structures_after_ipa_cp (vo
*** 1993,2000 ****
  void
  ipa_free_all_structures_after_iinln (void)
  {
-   BITMAP_FREE (iinlining_processed_edges);
- 
    ipa_free_all_edge_args ();
    ipa_free_all_node_params ();
    ipa_unregister_cgraph_hooks ();
--- 1984,1989 ----
Index: ipa-prop.h
===================================================================
*** ipa-prop.h  (revision 179082)
--- ipa-prop.h  (working copy)
*************** void ipa_free_edge_args_substructures (s
*** 282,288 ****
  void ipa_free_node_params_substructures (struct ipa_node_params *);
  void ipa_free_all_node_params (void);
  void ipa_free_all_edge_args (void);
- void ipa_create_all_structures_for_iinln (void);
  void ipa_free_all_structures_after_ipa_cp (void);
  void ipa_free_all_structures_after_iinln (void);
  void ipa_register_cgraph_hooks (void);
--- 282,287 ----

Reply via email to