On Mon, 12 Jun 2017, Martin Jambor wrote:

> Hi,
> 
> the patch below fixes PR 80803 (and its newer duplicate 81063), it is
> essentially a semi-rewrite of propagate_subaccesses_across_link.
> 
> When fixing the previous fallout from lazy setting of grp_write flag,
> I failed to see that it does not look on sub-accesses of the LHSs at
> all and thus does not ensure proper transitive propagation if the RHS
> does not have an access that LHS has.  The patch fixes it by
> meticulous checking and invoking subtree_mark_written_and_enqueue to
> handle such cases.
> 
> This might seem like a lot of enqueuing but an access is only enqueued
> if its grp_write bit has been set or if new sub-accesses have been
> created under it, so the number of invocations of
> add_access_to_work_queue is bounded by the number of aggregate
> assignments in the function and twice the number of access
> representatives, so nothing drastic.
> 
> An almost identical patch has passed bootstrap and testing on
> x86_64-linux (all languages including Ada and Go), powerpc64le-linux
> (all languages except Ada but including Go) and Aarch64-linux (the
> same).  I am bootstrapping and testing this very same one on an
> x86_64-linux right now, just to be sure.  OK for trunk?
> 
> Thanks,
> 
> Martin
> 
> 
> 
> 2017-06-12  Martin Jambor  <mjam...@suse.cz>
> 
>       PR tree-optimization/80803
>       PR tree-optimization/81063
>       * tree-sra.c (subtree_mark_written_and_enqueue): Move up in the file.
>       (propagate_subaccesses_across_link): Enqueue subtree whneve necessary

whenever

Ok.

Thanks,
Richard.

>       instead of relying on the caller.
> 
> testsuite/
>       gcc.dg/tree-ssa/pr80803.c: New test.
>       gcc.dg/tree-ssa/pr81063.c: Likewise.
> 
> 
> *** /dev/null Mon Jun 12 10:27:38 2017
> --- gcc/testsuite/gcc.dg/tree-ssa/pr80803.c   Mon Jun 12 18:24:30 2017
> ***************
> *** 0 ****
> --- 1,72 ----
> + /* { dg-do run } */
> + /* { dg-options "-O" } */
> + 
> + struct S0
> + {
> +   unsigned a : 15;
> +   int b;
> +   int c;
> + };
> + 
> + struct S1
> + {
> +   struct S0 s0;
> +   int e;
> + };
> + 
> + struct Z
> + {
> +   char c;
> +   int z;
> + } __attribute__((packed));
> + 
> + union U
> + {
> +   struct S1 s1;
> +   struct Z z;
> + };
> + 
> + 
> + int __attribute__((noinline, noclone))
> + return_zero (void)
> + {
> +   return 0;
> + }
> + 
> + volatile union U gu;
> + struct S0 gs;
> + 
> + int __attribute__((noinline, noclone))
> + check_outcome ()
> + {
> +   if (gs.a != 6
> +       || gs.b != 80000)
> +     __builtin_abort ();
> + }
> + 
> + int
> + main (int argc, char *argv[])
> + {
> +   union U u;
> +   struct S1 m,n;
> +   struct S0 l;
> + 
> +   if (return_zero ())
> +     u.z.z = 20000;
> +   else
> +     {
> +       u.s1.s0.a = 6;
> +       u.s1.s0.b = 80000;
> +       u.s1.e = 2;
> + 
> +       n = u.s1;
> +       m = n;
> +       m.s0.c = 0;
> +       l = m.s0;
> +       gs = l;
> +     }
> + 
> +   gu = u;
> +   check_outcome ();
> +   return 0;
> + }
> *** /dev/null Mon Jun 12 10:27:38 2017
> --- gcc/testsuite/gcc.dg/tree-ssa/pr81063.c   Mon Jun 12 18:24:30 2017
> ***************
> *** 0 ****
> --- 1,28 ----
> + /* { dg-do run } */
> + /* { dg-options "-O" } */
> + 
> + struct A
> + {
> +   int b;
> +   int c:2;
> + };
> + 
> + struct B
> + {
> +   int e;
> +   struct A f;
> + } g = {0, {0, 1}}, j;
> + 
> + struct A *h = &g.f;
> + 
> + int main ()
> + {
> +   struct A k;
> +   struct B l = j, i = l;
> +   if (!i.f.b)
> +     k = i.f;
> +   *h = k;
> +   if (g.f.c != 0)
> +     __builtin_abort ();
> +   return 0;
> + }
> *** /tmp/Xkl4Ch_tree-sra.c    Mon Jun 12 18:33:42 2017
> --- gcc/tree-sra.c    Mon Jun 12 18:24:30 2017
> *************** create_artificial_child_access (struct a
> *** 2558,2566 ****
>   }
>   
>   
> ! /* Propagate all subaccesses of RACC across an assignment link to LACC. 
> Return
> !    true if any new subaccess was created.  Additionally, if RACC is a scalar
> !    access but LACC is not, change the type of the latter, if possible.  */
>   
>   static bool
>   propagate_subaccesses_across_link (struct access *lacc, struct access *racc)
> --- 2558,2585 ----
>   }
>   
>   
> ! /* Beginning with ACCESS, traverse its whole access subtree and mark all
> !    sub-trees as written to.  If any of them has not been marked so 
> previously
> !    and has assignment links leading from it, re-enqueue it.  */
> ! 
> ! static void
> ! subtree_mark_written_and_enqueue (struct access *access)
> ! {
> !   if (access->grp_write)
> !     return;
> !   access->grp_write = true;
> !   add_access_to_work_queue (access);
> ! 
> !   struct access *child;
> !   for (child = access->first_child; child; child = child->next_sibling)
> !     subtree_mark_written_and_enqueue (child);
> ! }
> ! 
> ! /* Propagate subaccesses and grp_write flags of RACC across an assignment 
> link
> !    to LACC.  Enqueue sub-accesses as necessary so that the write flag is
> !    propagated transitively.  Return true if anything changed.  
> Additionally, if
> !    RACC is a scalar access but LACC is not, change the type of the latter, 
> if
> !    possible.  */
>   
>   static bool
>   propagate_subaccesses_across_link (struct access *lacc, struct access *racc)
> *************** propagate_subaccesses_across_link (struc
> *** 2576,2582 ****
>         gcc_checking_assert (!comes_initialized_p (racc->base));
>         if (racc->grp_write)
>       {
> !       lacc->grp_write = true;
>         ret = true;
>       }
>       }
> --- 2595,2601 ----
>         gcc_checking_assert (!comes_initialized_p (racc->base));
>         if (racc->grp_write)
>       {
> !       subtree_mark_written_and_enqueue (lacc);
>         ret = true;
>       }
>       }
> *************** propagate_subaccesses_across_link (struc
> *** 2585,2597 ****
>         || lacc->grp_unscalarizable_region
>         || racc->grp_unscalarizable_region)
>       {
> !       ret |= !lacc->grp_write;
> !       lacc->grp_write = true;
>         return ret;
>       }
>   
>     if (is_gimple_reg_type (racc->type))
>       {
>         if (!lacc->first_child && !racc->first_child)
>       {
>         tree t = lacc->base;
> --- 2604,2624 ----
>         || lacc->grp_unscalarizable_region
>         || racc->grp_unscalarizable_region)
>       {
> !       if (!lacc->grp_write)
> !     {
> !       ret = true;
> !       subtree_mark_written_and_enqueue (lacc);
> !     }
>         return ret;
>       }
>   
>     if (is_gimple_reg_type (racc->type))
>       {
> +       if (!lacc->grp_write)
> +     {
> +       ret = true;
> +       subtree_mark_written_and_enqueue (lacc);
> +     }
>         if (!lacc->first_child && !racc->first_child)
>       {
>         tree t = lacc->base;
> *************** propagate_subaccesses_across_link (struc
> *** 2616,2636 ****
>         struct access *new_acc = NULL;
>         HOST_WIDE_INT norm_offset = rchild->offset + norm_delta;
>   
> -       if (rchild->grp_unscalarizable_region)
> -     {
> -       lacc->grp_write = true;
> -       continue;
> -     }
> - 
>         if (child_would_conflict_in_lacc (lacc, norm_offset, rchild->size,
>                                       &new_acc))
>       {
>         if (new_acc)
>           {
> !           if (!new_acc->grp_write
> !               && (lacc->grp_write || rchild->grp_write))
>               {
> !               new_acc ->grp_write = true;
>                 ret = true;
>               }
>   
> --- 2643,2657 ----
>         struct access *new_acc = NULL;
>         HOST_WIDE_INT norm_offset = rchild->offset + norm_delta;
>   
>         if (child_would_conflict_in_lacc (lacc, norm_offset, rchild->size,
>                                       &new_acc))
>       {
>         if (new_acc)
>           {
> !           if (!new_acc->grp_write && rchild->grp_write)
>               {
> !               gcc_assert (!lacc->grp_write);
> !               subtree_mark_written_and_enqueue (new_acc);
>                 ret = true;
>               }
>   
> *************** propagate_subaccesses_across_link (struc
> *** 2640,2646 ****
>               ret |= propagate_subaccesses_across_link (new_acc, rchild);
>           }
>         else
> !         lacc->grp_write = true;
>         continue;
>       }
>   
> --- 2661,2683 ----
>               ret |= propagate_subaccesses_across_link (new_acc, rchild);
>           }
>         else
> !         {
> !           if (rchild->grp_write && !lacc->grp_write)
> !             {
> !               ret = true;
> !               subtree_mark_written_and_enqueue (lacc);
> !             }
> !         }
> !       continue;
> !     }
> ! 
> !       if (rchild->grp_unscalarizable_region)
> !     {
> !       if (rchild->grp_write && !lacc->grp_write)
> !         {
> !           ret = true;
> !           subtree_mark_written_and_enqueue (lacc);
> !         }
>         continue;
>       }
>   
> *************** propagate_subaccesses_across_link (struc
> *** 2648,2683 ****
>         new_acc = create_artificial_child_access (lacc, rchild, norm_offset,
>                                               lacc->grp_write
>                                               || rchild->grp_write);
> !       if (new_acc)
> !     {
> !       ret = true;
> !       if (racc->first_child)
> !         propagate_subaccesses_across_link (new_acc, rchild);
> !     }
>       }
>   
>     return ret;
>   }
>   
> - /* Beginning with ACCESS, traverse its whole access subtree and mark all
> -    sub-trees as written to.  If any of them has not been marked so 
> previously
> -    and has assignment links leading from it, re-enqueue it.  */
> - 
> - static void
> - subtree_mark_written_and_enqueue (struct access *access)
> - {
> -   if (access->grp_write)
> -     return;
> -   access->grp_write = true;
> -   add_access_to_work_queue (access);
> - 
> -   struct access *child;
> -   for (child = access->first_child; child; child = child->next_sibling)
> -     subtree_mark_written_and_enqueue (child);
> - }
> - 
> - 
> - 
>   /* Propagate all subaccesses across assignment links.  */
>   
>   static void
> --- 2685,2701 ----
>         new_acc = create_artificial_child_access (lacc, rchild, norm_offset,
>                                               lacc->grp_write
>                                               || rchild->grp_write);
> !       gcc_checking_assert (new_acc);
> !       if (racc->first_child)
> !     propagate_subaccesses_across_link (new_acc, rchild);
> ! 
> !       add_access_to_work_queue (lacc);
> !       ret = true;
>       }
>   
>     return ret;
>   }
>   
>   /* Propagate all subaccesses across assignment links.  */
>   
>   static void
> 
> 

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

Reply via email to