Hi Richard,

On 15 May 2018 at 19:20, Richard Biener <rguent...@suse.de> wrote:
> On Tue, 15 May 2018, Richard Biener wrote:
>
>> On Mon, 14 May 2018, Kugan Vivekanandarajah wrote:
>>
>> > Hi,
>> >
>> > Attached patch handles PR63185 when we reach PHI with temp != NULLL.
>> > We could see the PHI and if there isn't any uses for PHI that is
>> > interesting, we could ignore that ?
>> >
>> > Bootstrapped and regression tested on x86_64-linux-gnu.
>> > Is this OK?
>>
>> No, as Jeff said we can't do it this way.
>>
>> If we end up with multiple VDEFs in the walk of defvar immediate
>> uses we know we are dealing with a CFG fork.  We can't really
>> ignore any of the paths but we have to
>>
>>  a) find the merge point (and the associated VDEF)
>>  b) verify for each each chain of VDEFs with associated VUSEs
>>     up to that merge VDEF that we have no uses of the to classify
>>     store and collect (partial) kills
>>  c) intersect kill info and continue walking from the merge point
>>
>> in b) there's the optional possibility to find sinking opportunities
>> in case we have kills on some paths but uses on others.  This is why
>> DSE should be really merged with (store) sinking.
>>
>> So if we want to enhance DSEs handling of branches then we need
>> to refactor the simple dse_classify_store function.  Let me take
>> an attempt at this today.
>
> First (baby) step is the following - it arranges to collect the
> defs we need to continue walking from and implements trivial
> reduction by stopping at (full) kills.  This allows us to handle
> the new testcase (which was already handled in the very late DSE
> pass with the help of sinking the store).

Thanks for the explanation and thanks for working on this.

>
> I took the opportunity to kill the use_stmt parameter of
> dse_classify_store as the only user is only looking for whether
> the kills were all clobbers which I added a new parameter for.
>
> I didn't adjust the byte-tracking case fully (I'm not fully understanding
> the code in the case of a use and I'm not sure whether it's worth
> doing the def reduction with byte-tracking).

Since byte tracking is tracking the killed subset of bytes in the
original def, in your patch can we calculate the bytes killed by each
defs[i] and then find the intersection for the iteration. If we don't
have complete kill, we can use this to set live bytes and iterate till
all the live_bytes are cleared like it was done earlier.

Thanks,
Kugan

>
> Your testcase can be handled by reducing the PHI and the call def
> by seeing that the only use of a candidate def is another def
> we have already processed.  Not sure if worth special-casing though,
> I'd rather have a go at "recursing".  That will be the next
> patch.
>
> Bootstrap & regtest running on x86_64-unknown-linux-gnu.
>
> Richard.
>
> 2018-05-15  Richard Biener  <rguent...@suse.de>
>
>         * tree-ssa-dse.c (dse_classify_store): Remove use_stmt parameter,
>         add by_clobber_p one.  Change algorithm to collect all defs
>         representing uses we need to walk and try reducing them to
>         a single one before failing.
>         (dse_dom_walker::dse_optimize_stmt): Adjust.
>
>         * gcc.dg/tree-ssa/ssa-dse-31.c: New testcase.
>
> diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-dse-31.c 
> b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dse-31.c
> new file mode 100644
> index 00000000000..9ea9268fe1d
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dse-31.c
> @@ -0,0 +1,16 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O -fdump-tree-dse1-details" } */
> +
> +void g();
> +void f(int n, char *p)
> +{
> +  *p = 0;
> +  if (n)
> +    {
> +      *p = 1;
> +      g();
> +    }
> +  *p = 2;
> +}
> +
> +/* { dg-final { scan-tree-dump-times "Deleted dead store" 1 "dse1" } } */
> diff --git a/gcc/tree-ssa-dse.c b/gcc/tree-ssa-dse.c
> index 9220fea7f2e..126592a1d13 100644
> --- a/gcc/tree-ssa-dse.c
> +++ b/gcc/tree-ssa-dse.c
> @@ -516,18 +516,21 @@ live_bytes_read (ao_ref use_ref, ao_ref *ref, sbitmap 
> live)
>  }
>
>  /* A helper of dse_optimize_stmt.
> -   Given a GIMPLE_ASSIGN in STMT that writes to REF, find a candidate
> -   statement *USE_STMT that may prove STMT to be dead.
> -   Return TRUE if the above conditions are met, otherwise FALSE.  */
> +   Given a GIMPLE_ASSIGN in STMT that writes to REF, classify it
> +   according to downstream uses and defs.  Sets *BY_CLOBBER_P to true
> +   if only clobber statements influenced the classification result.
> +   Returns the classification.  */
>
>  static dse_store_status
> -dse_classify_store (ao_ref *ref, gimple *stmt, gimple **use_stmt,
> -                   bool byte_tracking_enabled, sbitmap live_bytes)
> +dse_classify_store (ao_ref *ref, gimple *stmt,
> +                   bool byte_tracking_enabled, sbitmap live_bytes,
> +                   bool *by_clobber_p = NULL)
>  {
>    gimple *temp;
>    unsigned cnt = 0;
>
> -  *use_stmt = NULL;
> +  if (by_clobber_p)
> +    *by_clobber_p = true;
>
>    /* Find the first dominated statement that clobbers (part of) the
>       memory stmt stores to with no intermediate statement that may use
> @@ -551,7 +554,7 @@ dse_classify_store (ao_ref *ref, gimple *stmt, gimple 
> **use_stmt,
>        else
>         defvar = gimple_vdef (temp);
>        defvar_def = temp;
> -      temp = NULL;
> +      auto_vec<gimple *, 10> defs;
>        FOR_EACH_IMM_USE_STMT (use_stmt, ui, defvar)
>         {
>           cnt++;
> @@ -569,9 +572,8 @@ dse_classify_store (ao_ref *ref, gimple *stmt, gimple 
> **use_stmt,
>              See gcc.c-torture/execute/20051110-*.c.  */
>           else if (gimple_code (use_stmt) == GIMPLE_PHI)
>             {
> -             if (temp
> -                 /* Make sure we are not in a loop latch block.  */
> -                 || gimple_bb (stmt) == gimple_bb (use_stmt)
> +             /* Make sure we are not in a loop latch block.  */
> +             if (gimple_bb (stmt) == gimple_bb (use_stmt)
>                   || dominated_by_p (CDI_DOMINATORS,
>                                      gimple_bb (stmt), gimple_bb (use_stmt))
>                   /* We can look through PHIs to regions post-dominating
> @@ -589,7 +591,7 @@ dse_classify_store (ao_ref *ref, gimple *stmt, gimple 
> **use_stmt,
>                   && !dominated_by_p (CDI_DOMINATORS,
>                                       gimple_bb (defvar_def),
>                                       gimple_bb (use_stmt)))
> -               temp = use_stmt;
> +               defs.safe_push (use_stmt);
>             }
>           /* If the statement is a use the store is not dead.  */
>           else if (ref_maybe_used_by_stmt_p (use_stmt, ref))
> @@ -597,7 +599,8 @@ dse_classify_store (ao_ref *ref, gimple *stmt, gimple 
> **use_stmt,
>               /* Handle common cases where we can easily build an ao_ref
>                  structure for USE_STMT and in doing so we find that the
>                  references hit non-live bytes and thus can be ignored.  */
> -             if (byte_tracking_enabled && (!gimple_vdef (use_stmt) || !temp))
> +             if (byte_tracking_enabled
> +                 && (!gimple_vdef (use_stmt) || defs.is_empty ()))
>                 {
>                   if (is_gimple_assign (use_stmt))
>                     {
> @@ -613,7 +616,7 @@ dse_classify_store (ao_ref *ref, gimple *stmt, gimple 
> **use_stmt,
>                           /* If this statement has a VDEF, then it is the
>                              first store we have seen, so walk through it.  */
>                           if (gimple_vdef (use_stmt))
> -                           temp = use_stmt;
> +                           defs.safe_push (use_stmt);
>                           continue;
>                         }
>                     }
> @@ -622,17 +625,10 @@ dse_classify_store (ao_ref *ref, gimple *stmt, gimple 
> **use_stmt,
>               fail = true;
>               BREAK_FROM_IMM_USE_STMT (ui);
>             }
> -         /* If this is a store, remember it or bail out if we have
> -            multiple ones (the will be in different CFG parts then).  */
> +         /* If this is a store, remember it as we possibly need to walk the
> +            defs uses.  */
>           else if (gimple_vdef (use_stmt))
> -           {
> -             if (temp)
> -               {
> -                 fail = true;
> -                 BREAK_FROM_IMM_USE_STMT (ui);
> -               }
> -             temp = use_stmt;
> -           }
> +           defs.safe_push (use_stmt);
>         }
>
>        if (fail)
> @@ -647,25 +643,54 @@ dse_classify_store (ao_ref *ref, gimple *stmt, gimple 
> **use_stmt,
>        /* If we didn't find any definition this means the store is dead
>           if it isn't a store to global reachable memory.  In this case
>          just pretend the stmt makes itself dead.  Otherwise fail.  */
> -      if (!temp)
> +      if (defs.is_empty ())
>         {
>           if (ref_may_alias_global_p (ref))
>             return DSE_STORE_LIVE;
>
> -         temp = stmt;
> -         break;
> +         if (by_clobber_p)
> +           *by_clobber_p = false;
> +         return DSE_STORE_DEAD;
>         }
>
> -      if (byte_tracking_enabled && temp)
> -       clear_bytes_written_by (live_bytes, temp, ref);
> -    }
> -  /* Continue walking until we reach a full kill as a single statement
> -     or there are no more live bytes.  */
> -  while (!stmt_kills_ref_p (temp, ref)
> -        && !(byte_tracking_enabled && bitmap_empty_p (live_bytes)));
> +      /* Process defs and remove paths starting with a kill from further
> +         processing.  */
> +      for (unsigned i = 0; i < defs.length (); ++i)
> +       if (stmt_kills_ref_p (defs[i], ref))
> +         {
> +           if (by_clobber_p && !gimple_clobber_p (defs[i]))
> +             *by_clobber_p = false;
> +           defs.unordered_remove (i);
> +         }
> +
> +      /* If all defs kill the ref we are done.  */
> +      if (defs.is_empty ())
> +       return DSE_STORE_DEAD;
> +      /* If more than one def survives fail.  */
> +      if (defs.length () > 1)
> +       {
> +         /* STMT might be partially dead and we may be able to reduce
> +            how many memory locations it stores into.  */
> +         if (byte_tracking_enabled && !gimple_clobber_p (stmt))
> +           return DSE_STORE_MAYBE_PARTIAL_DEAD;
> +         return DSE_STORE_LIVE;
> +       }
> +      temp = defs[0];
>
> -  *use_stmt = temp;
> -  return DSE_STORE_DEAD;
> +      /* Track partial kills.  */
> +      if (byte_tracking_enabled)
> +       {
> +         clear_bytes_written_by (live_bytes, temp, ref);
> +         if (bitmap_empty_p (live_bytes))
> +           {
> +             if (by_clobber_p && !gimple_clobber_p (temp))
> +               *by_clobber_p = false;
> +             return DSE_STORE_DEAD;
> +           }
> +       }
> +    }
> +  /* Continue walking until there are no more live bytes.  */
> +  while (1);
>  }
>
>
> @@ -795,11 +820,10 @@ dse_dom_walker::dse_optimize_stmt (gimple_stmt_iterator 
> *gsi)
>                   return;
>                 }
>
> -             gimple *use_stmt;
>               enum dse_store_status store_status;
>               m_byte_tracking_enabled
>                 = setup_live_bytes_from_ref (&ref, m_live_bytes);
> -             store_status = dse_classify_store (&ref, stmt, &use_stmt,
> +             store_status = dse_classify_store (&ref, stmt,
>                                                  m_byte_tracking_enabled,
>                                                  m_live_bytes);
>               if (store_status == DSE_STORE_LIVE)
> @@ -823,20 +847,20 @@ dse_dom_walker::dse_optimize_stmt (gimple_stmt_iterator 
> *gsi)
>
>    if (is_gimple_assign (stmt))
>      {
> -      gimple *use_stmt;
> +      bool by_clobber_p = false;
>
>        /* Self-assignments are zombies.  */
>        if (operand_equal_p (gimple_assign_rhs1 (stmt),
>                            gimple_assign_lhs (stmt), 0))
> -       use_stmt = stmt;
> +       ;
>        else
>         {
>           m_byte_tracking_enabled
>             = setup_live_bytes_from_ref (&ref, m_live_bytes);
>           enum dse_store_status store_status;
> -         store_status = dse_classify_store (&ref, stmt, &use_stmt,
> +         store_status = dse_classify_store (&ref, stmt,
>                                              m_byte_tracking_enabled,
> -                                            m_live_bytes);
> +                                            m_live_bytes, &by_clobber_p);
>           if (store_status == DSE_STORE_LIVE)
>             return;
>
> @@ -852,7 +876,7 @@ dse_dom_walker::dse_optimize_stmt (gimple_stmt_iterator 
> *gsi)
>        /* But only remove *this_2(D) ={v} {CLOBBER} if killed by
>          another clobber stmt.  */
>        if (gimple_clobber_p (stmt)
> -         && !gimple_clobber_p (use_stmt))
> +         && !by_clobber_p)
>         return;
>
>        delete_dead_assignment (gsi);

Reply via email to