On Wed, 13 Mar 2019, Jakub Jelinek wrote:

> Hi!
> 
> create_dispatcher_calls iterates over ipa_ref *s referring the current node
> and wants to remove them all and create new ones.  The problem is
> that if there are any ipa_ref objects where two or more of them are from the
> same cgraph node to the current node (in the testcases there are both cases
> where there are two or more foo -> foo self-references, or two or more
> foo.avx -> foo references), when we ref->remove_reference () one of them,
> that method will actually move some other ipa_ref that was last in
> references vector over to that and thus invalidate what some other ipa_ref
> pointers point to (the pointers still point to some elements of some
> references vector, but could either point past the last one, or could point
> to an element that was overwritten with something else).
> 
> The following patch fixes it by remove_reference all references immediately,
> but push into the vector their content first; besides that
> ref->remove_reference we are just accessing a couple of fields from that,
> not calling any other methods.
> 
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

LGTM.

Richard.

> 2019-03-13  Jakub Jelinek  <ja...@redhat.com>
> 
>       PR ipa/89684
>       * multiple_target.c (create_dispatcher_calls): Change
>       references_to_redirect from vector of ipa_ref * to vector of ipa_ref.
>       In the node->iterate_referring loop, push *ref rather than ref, call
>       ref->remove_reference () and always pass 0 to iterate_referring.
> 
> --- gcc/multiple_target.c.jj  2019-03-13 09:23:35.345567298 +0100
> +++ gcc/multiple_target.c     2019-03-13 10:12:49.071371927 +0100
> @@ -103,10 +103,16 @@ create_dispatcher_calls (struct cgraph_n
>      inode->resolve_alias (cgraph_node::get (resolver_decl));
>  
>    auto_vec<cgraph_edge *> edges_to_redirect;
> -  auto_vec<ipa_ref *> references_to_redirect;
> +  /* We need to capture the references by value rather than just pointers to 
> them
> +     and remove them right away, as removing them later would invalidate what
> +     some other reference pointers point to.  */
> +  auto_vec<ipa_ref> references_to_redirect;
>  
> -  for (unsigned i = 0; node->iterate_referring (i, ref); i++)
> -    references_to_redirect.safe_push (ref);
> +  while (node->iterate_referring (0, ref))
> +    {
> +      references_to_redirect.safe_push (*ref);
> +      ref->remove_reference ();
> +    }
>  
>    /* We need to remember NEXT_CALLER as it could be modified in the loop.  */
>    for (cgraph_edge *e = node->callers; e ; e = e->next_caller)
> @@ -146,13 +152,11 @@ create_dispatcher_calls (struct cgraph_n
>               }
>  
>             symtab_node *source = ref->referring;
> -           ref->remove_reference ();
>             source->create_reference (inode, IPA_REF_ADDR);
>           }
>         else if (ref->use == IPA_REF_ALIAS)
>           {
>             symtab_node *source = ref->referring;
> -           ref->remove_reference ();
>             source->create_reference (inode, IPA_REF_ALIAS);
>             source->add_to_same_comdat_group (inode);
>           }
> --- gcc/testsuite/gcc.target/i386/pr89684.c.jj        2019-03-13 
> 10:12:05.677080120 +0100
> +++ gcc/testsuite/gcc.target/i386/pr89684.c   2019-03-13 10:11:56.390231682 
> +0100
> @@ -0,0 +1,23 @@
> +/* PR ipa/89684 */
> +/* { dg-do compile } */
> +/* { dg-require-ifunc "" } */
> +
> +void bar (int, void (*) (void));
> +
> +__attribute__((target_clones ("default", "avx")))
> +void foo (void)
> +{
> +  bar (0, foo);
> +  bar (0, foo);
> +}
> +
> +__attribute__((target_clones ("default", "avx", "avx2")))
> +void baz (void)
> +{
> +  bar (0, foo);
> +  bar (0, foo);
> +  bar (0, foo);
> +  bar (0, foo);
> +  bar (0, foo);
> +  bar (0, foo);
> +}
> 
>       Jakub
> 

-- 
Richard Biener <rguent...@suse.de>
SUSE LINUX GmbH, GF: Felix Imendoerffer, Jane Smithard, Graham Norton, HRB 
21284 (AG Nuernberg)

Reply via email to