On Wed, 13 Jan 2016, Tom de Vries wrote:

> On 13/01/16 09:40, Richard Biener wrote:
> > On Wed, 13 Jan 2016, Tom de Vries wrote:
> > 
> > > Hi,
> > > 
> > > Consider testcase test.c:
> > > ...
> > > struct pgm_slist_t
> > > {
> > >    struct pgm_slist_t *__restrict next;
> > > };
> > > 
> > > void
> > > fn1 (struct pgm_slist_t p1)
> > > {
> > > 
> > > }
> > > ...
> > > 
> > > The compilation of the testcase enters into infinite recursion, due to the
> > > more aggressive restrict support added recently.
> > > 
> > > The patch fixes this by:-
> > > - tracking which structs are being traversed when following restrict
> > >    pointers in create_variable_info_for_1, and
> > > - not following restrict pointers that point to already tracked structs.
> > > 
> > > Bootstrapped and reg-tested on x86_64.
> > > 
> > > OK for trunk?
> > 
> > > Fix infinite recursion in create_variable_info_for_1
> > > 
> > >   PR tree-optimization/69169
> > >   * tree-ssa-structalias.c (handled_struct_type): New hash set.
> > >   (create_variable_info_for_1): Use handled_struct_type to keep track
> > >   of structs recursed by following restrict pointers.
> > >   (intra_create_variable_infos): Allocate and cleanup
> > >   handled_struct_type.
> > > 
> > >   * gcc.dg/pr69169.c: New test.
> > > 
> > > ---
> > >   gcc/testsuite/gcc.dg/pr69169.c | 13 +++++++++++++
> > >   gcc/tree-ssa-structalias.c     | 19 ++++++++++++++++---
> > >   2 files changed, 29 insertions(+), 3 deletions(-)
> > > 
> > > diff --git a/gcc/testsuite/gcc.dg/pr69169.c
> > > b/gcc/testsuite/gcc.dg/pr69169.c
> > > new file mode 100644
> > > index 0000000..ecf847c
> > > --- /dev/null
> > > +++ b/gcc/testsuite/gcc.dg/pr69169.c
> > > @@ -0,0 +1,13 @@
> > > +/* { dg-do compile } */
> > > +/* { dg-options "-O2" } */
> > > +
> > > +struct pgm_slist_t
> > > +{
> > > +  struct pgm_slist_t *__restrict next;
> > > +};
> > > +
> > > +void
> > > +fn1 (struct pgm_slist_t p1)
> > > +{
> > > +
> > > +}
> > > diff --git a/gcc/tree-ssa-structalias.c b/gcc/tree-ssa-structalias.c
> > > index fd98352..72bef07 100644
> > > --- a/gcc/tree-ssa-structalias.c
> > > +++ b/gcc/tree-ssa-structalias.c
> > > @@ -5767,6 +5767,12 @@ check_for_overlaps (vec<fieldoff_s> fieldstack)
> > >     return false;
> > >   }
> > > 
> > > +/* Hash set used to register structs traversed in
> > > create_variable_info_for_1
> > > +   by following restrict pointers.  This is needed to prevent infinite
> > > +   recursion.  */
> > > +
> > > +hash_set<tree> *handled_struct_type = NULL;
> > > +
> > 
> > A bitmap indexed by TYPE_UID would be cheaper I guess?
> 
> Done.
> 
> > Maybe not.
> > At least a hash_set<unsigned> would be ;)
> > 
> 
> A hash_set<unsigned> doesn't seem to work. So I use a bitmap now.
> 
> > Plase make the above static and GTY((skip)), no need to put it in
> > GC memory.
> 
> I've made a param out of handled_struct_type, so there's no global decl
> anymore.
> 
> > >   /* Create a varinfo structure for NAME and DECL, and add it to VARMAP.
> > >      This will also create any varinfo structures necessary for fields
> > >      of DECL.  DECL is a function parameter if HANDLE_PARAM is set.  */
> > > @@ -5851,7 +5857,8 @@ create_variable_info_for_1 (tree decl, const char
> > > *name, bool add_id,
> > >           vi->only_restrict_pointers = 1;
> > >         if (vi->only_restrict_pointers
> > >             && !type_contains_placeholder_p (TREE_TYPE (decl_type))
> > > -   && handle_param)
> > > +   && handle_param
> > > +   && !handled_struct_type->contains (TREE_TYPE (decl_type)))
> > >           {
> > >             varinfo_t rvi;
> > >             tree heapvar = build_fake_var_decl (TREE_TYPE (decl_type));
> > 
> > This path misses to add/remove decl_type to the set.  Thus
> > struct X { struct X * restrict p; } *; would still recurse infinitely?
> 
> I tried that out, but no.
> 
> > > 
> > > @@ -5871,6 +5878,8 @@ create_variable_info_for_1 (tree decl, const char
> > > *name, bool add_id,
> > >     vi->fullsize = tree_to_uhwi (declsize);
> > >     if (fieldstack.length () == 1)
> > >       vi->is_full_var = true;
> > > +  if (handle_param)
> > > +    handled_struct_type->add (decl_type);
> > 
> > while here we add it to the set even if in the end we won't create
> > a fake var decl (and recurse).  I think we should add to the set only
> > if we actually recurse.
> 
> Done.
> 
> > >     for (i = 0, newvi = vi;
> > >          fieldstack.iterate (i, &fo);
> > >          ++i, newvi = vi_next (newvi))
> > > @@ -5902,7 +5911,8 @@ create_variable_info_for_1 (tree decl, const char
> > > *name, bool add_id,
> > >         newvi->only_restrict_pointers = fo->only_restrict_pointers;
> > >         if (handle_param
> > >             && newvi->only_restrict_pointers
> > > -   && !type_contains_placeholder_p (fo->restrict_pointed_type))
> > > +   && !type_contains_placeholder_p (fo->restrict_pointed_type)
> > > +   && !handled_struct_type->contains (fo->restrict_pointed_type))
> > >           {
> > >             varinfo_t rvi;
> > >             tree heapvar = build_fake_var_decl 
> > > (fo->restrict_pointed_type);
> > > @@ -5921,6 +5931,8 @@ create_variable_info_for_1 (tree decl, const char
> > > *name, bool add_id,
> > >             tem->head = vi->id;
> > >           }
> > >       }
> > > +  if (handle_param)
> > > +    handled_struct_type->remove (decl_type);
> > > 
> > >     return vi;
> > >   }
> > > @@ -6065,10 +6077,11 @@ intra_create_variable_infos (struct function *fn)
> > >        passed-by-reference argument.  */
> > >     for (t = DECL_ARGUMENTS (fn->decl); t; t = DECL_CHAIN (t))
> > >       {
> > > +      handled_struct_type = hash_set<tree>::create_ggc (4);
> > > 
> > As said, please put it in heap memory and eventually just pass it down
> > as argument to create_variable_info_for_1 avoiding the global variable
> > (it's just three callers as far as I can see).
> 
> Done.
> 
> Retesting patch below (copy-pasted as plain text).

Ok if successful.

Thanks,
Richard.

> Thanks,
> - Tom
> 
> --
> 
> Fix infinite recursion in create_variable_info_for_1
> 
>       PR tree-optimization/69169
>       * tree-ssa-structalias.c (create_variable_info_for_1): Add and handle
>       handled_struct_type param.
>       (create_variable_info_for, intra_create_variable_infos): Call
>       create_variable_info_for_1 with extra arg.
> 
>       * gcc.dg/pr69169.c: New test.
> 
> ---
>  gcc/testsuite/gcc.dg/pr69169.c | 13 +++++++++++++
>  gcc/tree-ssa-structalias.c     | 42
> ++++++++++++++++++++++++++++++++++--------
>  2 files changed, 47 insertions(+), 8 deletions(-)
> 
> diff --git a/gcc/testsuite/gcc.dg/pr69169.c b/gcc/testsuite/gcc.dg/pr69169.c
> new file mode 100644
> index 0000000..ecf847c
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/pr69169.c
> @@ -0,0 +1,13 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O2" } */
> +
> +struct pgm_slist_t
> +{
> +  struct pgm_slist_t *__restrict next;
> +};
> +
> +void
> +fn1 (struct pgm_slist_t p1)
> +{
> +
> +}
> diff --git a/gcc/tree-ssa-structalias.c b/gcc/tree-ssa-structalias.c
> index fd98352..e7d0797 100644
> --- a/gcc/tree-ssa-structalias.c
> +++ b/gcc/tree-ssa-structalias.c
> @@ -5769,11 +5769,13 @@ check_for_overlaps (vec<fieldoff_s> fieldstack)
> 
>  /* Create a varinfo structure for NAME and DECL, and add it to VARMAP.
>     This will also create any varinfo structures necessary for fields
> -   of DECL.  DECL is a function parameter if HANDLE_PARAM is set.  */
> +   of DECL.  DECL is a function parameter if HANDLE_PARAM is set.
> +   HANDLED_STRUCT_TYPE is used to register struct types reached by following
> +   restrict pointers.  This is needed to prevent infinite recursion.  */
> 
>  static varinfo_t
>  create_variable_info_for_1 (tree decl, const char *name, bool add_id,
> -                         bool handle_param)
> +                         bool handle_param, bitmap handled_struct_type)
>  {
>    varinfo_t vi, newvi;
>    tree decl_type = TREE_TYPE (decl);
> @@ -5851,13 +5853,21 @@ create_variable_info_for_1 (tree decl, const char
> *name, bool add_id,
>       vi->only_restrict_pointers = 1;
>        if (vi->only_restrict_pointers
>         && !type_contains_placeholder_p (TREE_TYPE (decl_type))
> -       && handle_param)
> +       && handle_param
> +       && !bitmap_bit_p (handled_struct_type,
> +                         TYPE_UID (TREE_TYPE (decl_type))))
>       {
>         varinfo_t rvi;
>         tree heapvar = build_fake_var_decl (TREE_TYPE (decl_type));
>         DECL_EXTERNAL (heapvar) = 1;
> +       if (var_can_have_subvars (heapvar))
> +         bitmap_set_bit (handled_struct_type,
> +                         TYPE_UID (TREE_TYPE (decl_type)));
>         rvi = create_variable_info_for_1 (heapvar, "PARM_NOALIAS", true,
> -                                         true);
> +                                         true, handled_struct_type);
> +       if (var_can_have_subvars (heapvar))
> +         bitmap_clear_bit (handled_struct_type,
> +                           TYPE_UID (TREE_TYPE (decl_type)));
>         rvi->is_restrict_var = 1;
>         insert_vi_for_tree (heapvar, rvi);
>         make_constraint_from (vi, rvi->id);
> @@ -5902,13 +5912,21 @@ create_variable_info_for_1 (tree decl, const char
> *name, bool add_id,
>        newvi->only_restrict_pointers = fo->only_restrict_pointers;
>        if (handle_param
>         && newvi->only_restrict_pointers
> -       && !type_contains_placeholder_p (fo->restrict_pointed_type))
> +       && !type_contains_placeholder_p (fo->restrict_pointed_type)
> +       && !bitmap_bit_p (handled_struct_type,
> +                         TYPE_UID (fo->restrict_pointed_type)))
>       {
>         varinfo_t rvi;
>         tree heapvar = build_fake_var_decl (fo->restrict_pointed_type);
>         DECL_EXTERNAL (heapvar) = 1;
> +       if (var_can_have_subvars (heapvar))
> +         bitmap_set_bit (handled_struct_type,
> +                         TYPE_UID (fo->restrict_pointed_type));
>         rvi = create_variable_info_for_1 (heapvar, "PARM_NOALIAS", true,
> -                                         true);
> +                                         true, handled_struct_type);
> +       if (var_can_have_subvars (heapvar))
> +         bitmap_clear_bit (handled_struct_type,
> +                           TYPE_UID (fo->restrict_pointed_type));
>         rvi->is_restrict_var = 1;
>         insert_vi_for_tree (heapvar, rvi);
>         make_constraint_from (newvi, rvi->id);
> @@ -5928,7 +5946,7 @@ create_variable_info_for_1 (tree decl, const char *name,
> bool add_id,
>  static unsigned int
>  create_variable_info_for (tree decl, const char *name, bool add_id)
>  {
> -  varinfo_t vi = create_variable_info_for_1 (decl, name, add_id, false);
> +  varinfo_t vi = create_variable_info_for_1 (decl, name, add_id, false,
> NULL);
>    unsigned int id = vi->id;
> 
>    insert_vi_for_tree (decl, vi);
> @@ -6059,19 +6077,27 @@ static void
>  intra_create_variable_infos (struct function *fn)
>  {
>    tree t;
> +  bitmap handled_struct_type = NULL;
> 
>    /* For each incoming pointer argument arg, create the constraint ARG
>       = NONLOCAL or a dummy variable if it is a restrict qualified
>       passed-by-reference argument.  */
>    for (t = DECL_ARGUMENTS (fn->decl); t; t = DECL_CHAIN (t))
>      {
> +      if (handled_struct_type == NULL)
> +     handled_struct_type = BITMAP_ALLOC (NULL);
> +
>        varinfo_t p
> -     = create_variable_info_for_1 (t, alias_get_name (t), false, true);
> +     = create_variable_info_for_1 (t, alias_get_name (t), false, true,
> +                                   handled_struct_type);
>        insert_vi_for_tree (t, p);
> 
>        make_param_constraints (p);
>      }
> 
> +  if (handled_struct_type != NULL)
> +    BITMAP_FREE (handled_struct_type);
> +
>    /* Add a constraint for a result decl that is passed by reference.  */
>    if (DECL_RESULT (fn->decl)
>        && DECL_BY_REFERENCE (DECL_RESULT (fn->decl)))
> 
> 

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

Reply via email to