[PATCH, PR 45572] Fix two minor issues with indirect inlining

Richard Guenther richard.guenther@gmail.com
Wed Sep 22 16:46:00 GMT 2010


On Wed, Sep 22, 2010 at 11:51 AM, Martin Jambor <mjambor@suse.cz> wrote:
> Hi,
>
> PR 45572 has three testcases which exhibit two different bugs:
>
> 1) ipa_make_edge_direct_to_target can inadvertently lazily create new
> cgraph nodes when looking up a node for a decl with cgraph_node
> function.  This node then has an uid which is larger than size of
> ipa_node_params_vector, causing index out of bounds assert.  The
> function should not create new nodes and so I replaced the call with a
> call to cgraph_get_node.

That part sounds obvious, you might want to install it separately.

> 2) If recursive indirect edges are discovered during recursive
> inlining, they are added to new_edges but
> cgraph_decide_recursive_inlining then looks them itself and processes
> them immediately.  When edges from new_edges are processed, it
> attempts to inline recursively them again which leads to all sorts of
> weird consequences.  Fixed by teaching the indirect inlining machinery
> not to add recursive edges when doing recursive inlining, which is
> flagged by new parameters of ipa_propagate_indirect_call_infos and
> unfortunately also of cgraph_mark_inline_edge.

Can you expand on the "weird consequences"?  Could we instead
disable indirect inlining during recursive inlining (and would that
make the patch any prettier?).

Thanks,
Richard.

> Bootstrapped and tested on x86_64-linux, OK for trunk?
>
> Thanks,
>
> Martin
>
>
>
> 2010-09-21  Martin Jambor  <mjambor@suse.cz>
>
>        PR tree-optimization/45572
>        * ipa-prop.c (ipa_make_edge_direct_to_target): Use cgraph_get_node
>        instead of cgraph_node.
>        (update_indirect_edges_after_inlining): New parameter ignore.
>        (propagate_info_to_inlined_callees): Likewise.
>        (ipa_propagate_indirect_call_infos): New parameter new_recursive.
>        * ipa-inline.c (cgraph_mark_inline_edge): New parameter new_recursive.
>        Updated all callers.
>
>        * testsuite/g++.dg/torture/pr45572-1.C: New test.
>        * testsuite/g++.dg/torture/pr45572-2.C: Likewise.
>
> Index: icln/gcc/ipa-inline.c
> ===================================================================
> --- icln.orig/gcc/ipa-inline.c
> +++ icln/gcc/ipa-inline.c
> @@ -305,11 +305,13 @@ cgraph_clone_inlined_nodes (struct cgrap
>  /* Mark edge E as inlined and update callgraph accordingly.  UPDATE_ORIGINAL
>    specify whether profile of original function should be updated.  If any new
>    indirect edges are discovered in the process, add them to NEW_EDGES, unless
> -   it is NULL.  Return true iff any new callgraph edges were discovered as a
> -   result of inlining.  */
> +   it is NULL.  NEW_RECURSIVE should be set to false iff new recursive edges
> +   should not be added to NEW_EDGES.  Return true iff any new callgraph edges
> +   were discovered as a result of inlining.  */
>
>  static bool
>  cgraph_mark_inline_edge (struct cgraph_edge *e, bool update_original,
> +                        bool new_recursive,
>                         VEC (cgraph_edge_p, heap) **new_edges)
>  {
>   int old_size = 0, new_size = 0;
> @@ -343,7 +345,7 @@ cgraph_mark_inline_edge (struct cgraph_e
>   /* FIXME: We should remove the optimize check after we ensure we never run
>      IPA passes when not optimizng.  */
>   if (flag_indirect_inlining && optimize)
> -    return ipa_propagate_indirect_call_infos (curr, new_edges);
> +    return ipa_propagate_indirect_call_infos (curr, new_recursive, new_edges);
>   else
>     return false;
>  }
> @@ -365,7 +367,7 @@ cgraph_mark_inline (struct cgraph_edge *
>       next = e->next_caller;
>       if (e->caller == to && e->inline_failed)
>        {
> -          cgraph_mark_inline_edge (e, true, NULL);
> +          cgraph_mark_inline_edge (e, true, false, NULL);
>          if (e == edge)
>            edge = next;
>        }
> @@ -960,7 +962,7 @@ cgraph_decide_recursive_inlining (struct
>          fprintf (dump_file, "\n");
>        }
>       cgraph_redirect_edge_callee (curr, master_clone);
> -      cgraph_mark_inline_edge (curr, false, new_edges);
> +      cgraph_mark_inline_edge (curr, false, false, new_edges);
>       lookup_recursive_calls (node, curr->callee, heap);
>       n++;
>     }
> @@ -1245,7 +1247,7 @@ cgraph_decide_inlining_of_small_function
>            }
>          callee = edge->callee;
>          gcc_checking_assert (!callee->global.inlined_to);
> -         cgraph_mark_inline_edge (edge, true, &new_indirect_edges);
> +         cgraph_mark_inline_edge (edge, true, true, &new_indirect_edges);
>          if (flag_indirect_inlining)
>            add_new_edges_to_heap (heap, new_indirect_edges);
>
> @@ -1409,7 +1411,7 @@ cgraph_flatten (struct cgraph_node *node
>                 cgraph_node_name (e->callee),
>                 cgraph_node_name (e->caller));
>       orig_callee = e->callee;
> -      cgraph_mark_inline_edge (e, true, NULL);
> +      cgraph_mark_inline_edge (e, true, false, NULL);
>       if (e->callee != orig_callee)
>        orig_callee->aux = (void *)(size_t) INLINE_ALL;
>       cgraph_flatten (e->callee);
> Index: icln/gcc/ipa-prop.c
> ===================================================================
> --- icln.orig/gcc/ipa-prop.c
> +++ icln/gcc/ipa-prop.c
> @@ -1444,7 +1444,7 @@ ipa_make_edge_direct_to_target (struct c
>   target = TREE_OPERAND (target, 0);
>   if (TREE_CODE (target) != FUNCTION_DECL)
>     return NULL;
> -  callee = cgraph_node (target);
> +  callee = cgraph_get_node (target);
>   if (!callee)
>     return NULL;
>
> @@ -1543,6 +1543,7 @@ try_make_edge_direct_virtual_call (struc
>  static bool
>  update_indirect_edges_after_inlining (struct cgraph_edge *cs,
>                                      struct cgraph_node *node,
> +                                     struct cgraph_node *ignore,
>                                      VEC (cgraph_edge_p, heap) **new_edges)
>  {
>   struct ipa_edge_args *top;
> @@ -1594,7 +1595,7 @@ update_indirect_edges_after_inlining (st
>       if (new_direct_edge)
>        {
>          new_direct_edge->indirect_inlining_edge = 1;
> -         if (new_edges)
> +         if (new_edges && new_direct_edge->callee != ignore)
>            {
>              VEC_safe_push (cgraph_edge_p, heap, *new_edges,
>                             new_direct_edge);
> @@ -1612,22 +1613,24 @@ update_indirect_edges_after_inlining (st
>    update_indirect_edges_after_inlining on all nodes and
>    update_jump_functions_after_inlining on all non-inlined edges that lead out
>    of this subtree.  Newly discovered indirect edges will be added to
> -   *NEW_EDGES, unless NEW_EDGES is NULL.  Return true iff a new edge(s) were
> -   created.  */
> +   *NEW_EDGES except when NEW_EDGES is NULL or the edge leads to the node
> +   IGNORE.  Return true iff a new edge(s) were added to the vector.  */
>
>  static bool
>  propagate_info_to_inlined_callees (struct cgraph_edge *cs,
>                                   struct cgraph_node *node,
> +                                  struct cgraph_node *ignore,
>                                   VEC (cgraph_edge_p, heap) **new_edges)
>  {
>   struct cgraph_edge *e;
>   bool res;
>
> -  res = update_indirect_edges_after_inlining (cs, node, new_edges);
> +  res = update_indirect_edges_after_inlining (cs, node, ignore, new_edges);
>
>   for (e = node->callees; e; e = e->next_callee)
>     if (!e->inline_failed)
> -      res |= propagate_info_to_inlined_callees (cs, e->callee, new_edges);
> +      res |= propagate_info_to_inlined_callees (cs, e->callee, ignore,
> +                                               new_edges);
>     else
>       update_jump_functions_after_inlining (cs, e);
>
> @@ -1637,13 +1640,16 @@ propagate_info_to_inlined_callees (struc
>  /* Update jump functions and call note functions on inlining the call site CS.
>    CS is expected to lead to a node already cloned by
>    cgraph_clone_inline_nodes.  Newly discovered indirect edges will be added to
> -   *NEW_EDGES, unless NEW_EDGES is NULL.  Return true iff a new edge(s) were +
> -   created.  */
> +   *NEW_EDGES except when NEW_EDGES is NULL or the edge leads to the node
> +   IGNORE.  Return true iff any new edges were added to the vector.  */
>
>  bool
>  ipa_propagate_indirect_call_infos (struct cgraph_edge *cs,
> +                                  bool new_recursive,
>                                   VEC (cgraph_edge_p, heap) **new_edges)
>  {
> +  struct cgraph_node *ignore;
> +
>   /* FIXME lto: We do not stream out indirect call information.  */
>   if (flag_wpa)
>     return false;
> @@ -1654,7 +1660,16 @@ ipa_propagate_indirect_call_infos (struc
>     return false;
>   gcc_assert (ipa_edge_args_vector);
>
> -  return propagate_info_to_inlined_callees (cs, cs->callee, new_edges);
> +  if (new_recursive)
> +    ignore = NULL;
> +  else
> +    {
> +      ignore = cs->caller;
> +      if (ignore->global.inlined_to)
> +       ignore = ignore->global.inlined_to;
> +    }
> +
> +  return propagate_info_to_inlined_callees (cs, cs->callee, ignore, new_edges);
>  }
>
>  /* Frees all dynamically allocated structures that the argument info points
> Index: icln/gcc/ipa-prop.h
> ===================================================================
> --- icln.orig/gcc/ipa-prop.h
> +++ icln/gcc/ipa-prop.h
> @@ -427,6 +427,7 @@ void ipa_analyze_node (struct cgraph_nod
>  /* Function formal parameters related computations.  */
>  void ipa_initialize_node_params (struct cgraph_node *node);
>  bool ipa_propagate_indirect_call_infos (struct cgraph_edge *cs,
> +                                       bool new_recursive,
>                                        VEC (cgraph_edge_p, heap) **new_edges);
>
>  /* Indirect edge and binfo processing.  */
> Index: icln/gcc/testsuite/g++.dg/torture/pr45572-1.C
> ===================================================================
> --- /dev/null
> +++ icln/gcc/testsuite/g++.dg/torture/pr45572-1.C
> @@ -0,0 +1,63 @@
> +// { dg-do compile }
> +
> +extern "C" {
> +typedef long unsigned int size_t;
> +typedef long int __ssize_t;
> +typedef struct _IO_FILE FILE;
> +typedef struct
> +{
> +} __mbstate_t;
> +extern __inline __attribute__ ((__gnu_inline__)) int
> +fgetc_unlocked (FILE *__fp)
> +{
> +}
> +extern __inline __attribute__ ((__gnu_inline__)) int
> +putc_unlocked (int __c, FILE *__stream)
> +{
> +}
> +extern __inline __attribute__ ((__gnu_inline__)) __ssize_t
> +getline (char **__lineptr, size_t *__n, FILE *__stream)
> +{
> +}
> +extern __inline __attribute__ ((__gnu_inline__)) int
> +ferror_unlocked (FILE *__stream) throw ()
> +{
> +}
> +}
> +typedef struct
> +{} __mpf_struct;
> +typedef __mpf_struct mpf_t[1];
> +typedef const __mpf_struct *mpf_srcptr;
> +typedef __mpf_struct *mpf_ptr;
> +extern "C" {
> + void __gmpf_add (mpf_ptr, mpf_srcptr, mpf_srcptr);
> +}
> +class _knumber
> +{
> + public:
> +  enum NumType {SpecialType, IntegerType, FractionType, FloatType};
> +  virtual NumType type(void) const = 0;
> +  virtual _knumber * add(_knumber const & arg2) const = 0;
> +  virtual operator long int(void) const = 0;
> +};
> +class _knumfloat : public _knumber
> +{
> +  _knumfloat(double num = 1.0)
> +  ;
> +  virtual NumType type(void) const ;
> +  virtual _knumber * add(_knumber const & arg2) const;
> +  virtual operator long int (void) const;
> +    mpf_t _mpf;
> +};
> +_knumber *_knumfloat::add(_knumber const & arg2) const
> +{
> +  if (arg2.type() == SpecialType)
> +    return arg2.add(*this);
> +{
> +    _knumfloat tmp_num(arg2);
> +    return tmp_num.add(*this);
> +  }
> +  _knumfloat * tmp_num = new _knumfloat();
> +  __gmpf_add(tmp_num->_mpf, _mpf,
> +   dynamic_cast<_knumfloat const &>(arg2)._mpf);
> +}
> Index: icln/gcc/testsuite/g++.dg/torture/pr45572-2.C
> ===================================================================
> --- /dev/null
> +++ icln/gcc/testsuite/g++.dg/torture/pr45572-2.C
> @@ -0,0 +1,39 @@
> +// { dg-do compile }
> +
> +typedef struct
> +{} __mpf_struct;
> +typedef __mpf_struct mpf_t[1];
> +typedef const __mpf_struct *mpf_srcptr;
> +typedef __mpf_struct *mpf_ptr;
> +extern "C" {
> + void __gmpf_add (mpf_ptr, mpf_srcptr, mpf_srcptr);
> +}
> +class _knumber
> +{
> + public:
> +  enum NumType {SpecialType, IntegerType, FractionType, FloatType};
> +  virtual NumType type(void) const = 0;
> +  virtual _knumber * add(_knumber const & arg2) const = 0;
> +  virtual operator long int(void) const = 0;
> +};
> +class _knumfloat : public _knumber
> +{
> +  _knumfloat(double num = 1.0)
> +  ;
> +  virtual NumType type(void) const ;
> +  virtual _knumber * add(_knumber const & arg2) const;
> +  virtual operator long int (void) const;
> +    mpf_t _mpf;
> +};
> +_knumber *_knumfloat::add(_knumber const & arg2) const
> +{
> +  if (arg2.type() == SpecialType)
> +    return arg2.add(*this);
> +{
> +    _knumfloat tmp_num(arg2);
> +    return tmp_num.add(*this);
> +  }
> +  _knumfloat * tmp_num = new _knumfloat();
> +  __gmpf_add(tmp_num->_mpf, _mpf,
> +   dynamic_cast<_knumfloat const &>(arg2)._mpf);
> +}
>
>



More information about the Gcc-patches mailing list