https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63766

--- Comment #3 from Richard Biener <rguenth at gcc dot gnu.org> ---
(In reply to Ilya Enkovich from comment #2)
> Problem caused by the fact that now all function come to local optimizations
> in SSA form.  It affects inline parameters computation and therefore
> inlining order.
> 
> During early SRA we call convert_callers_for_node which recomputes inline
> parameters for functions in SSA form.  Previously it was computed only for
> function already processed by all early local passes.  Now all functions are
> in SSA form and it means we may recompute inline parameters for function not
> yet processed by local optimizations.
> 
> In this test we have function marked as inlinable which is not yet processed
> in do_per_function_toporder called for local_optimization_passes.  It allows
> this function to be inlined and removed before it is actually processed (and
> still sit in order vector).  Another cgraph_node created by SRA is allocated
> at the same slot as removed one and thus the same function is processed
> twice, which causes ICE in profiling pass.
> 
> Solution here would be to either use another condition for inline_parameters
> recomputation or to handle nodes removal in do_per_function_toporder by
> registering proper node removal hook.  Suppose the latter is better because
> allows more early inlining.
> 
> Here is a possible fix (works for reproducer, not fully tested):
> 
> diff --git a/gcc/passes.c b/gcc/passes.c
> index 5e91a79..4799efa 100644
> --- a/gcc/passes.c
> +++ b/gcc/passes.c
> @@ -1609,6 +1609,19 @@ do_per_function (void (*callback) (function *, void
> *data), void *data)
>  static int nnodes;
>  static GTY ((length ("nnodes"))) cgraph_node **order;
> 
> +static void
> +remove_cgraph_node_from_order (cgraph_node *node, void *)
> +{
> +  int i;
> +
> +  for (i = 0; i < nnodes; i++)
> +    if (order[i] == node)
> +      {
> +       order[i] = NULL;
> +       return;
> +      }
> +}

That's quadratic in the number of nodes and thus a no-go.  Why not delay
removing of unreachable nodes instead?  If you go with the above then
you need to change that data-structure used.

>  /* If we are in IPA mode (i.e., current_function_decl is NULL), call
>     function CALLBACK for every function in the call graph.  Otherwise,
>     call CALLBACK on the current function.
> @@ -1622,13 +1635,20 @@ do_per_function_toporder (void (*callback) (function
> *, void *data), void *data)
>      callback (cfun, data);
>    else
>      {
> +      cgraph_node_hook_list *hook;
>        gcc_assert (!order);
>        order = ggc_vec_alloc<cgraph_node *> (symtab->cgraph_count);
>        nnodes = ipa_reverse_postorder (order);
>        for (i = nnodes - 1; i >= 0; i--)
>          order[i]->process = 1;
> +      hook = symtab->add_cgraph_removal_hook (remove_cgraph_node_from_order,
> +                                             NULL);
>        for (i = nnodes - 1; i >= 0; i--)
>         {
> +         /* Function could be inlined and removed as unreachable.  */
> +         if (!order[i])
> +           continue;
> +
>           struct cgraph_node *node = order[i];
> 
>           /* Allow possibly removed nodes to be garbage collected.  */
> @@ -1637,6 +1657,7 @@ do_per_function_toporder (void (*callback) (function
> *, void *data), void *data)
>           if (node->has_gimple_body_p ())
>             callback (DECL_STRUCT_FUNCTION (node->decl), data);
>         }
> +      symtab->remove_cgraph_removal_hook (hook);
>      }
>    ggc_free (order);
>    order = NULL;

Reply via email to