diff mbox series

PR tree-optimization/109417 - Check if dependency is valid before using in may_recompute_p.

Message ID a1a81da3-99ab-482e-14aa-59a8f1025ffe@redhat.com
State New
Headers show
Series PR tree-optimization/109417 - Check if dependency is valid before using in may_recompute_p. | expand

Commit Message

Andrew MacLeod April 5, 2023, 8:10 p.m. UTC
When a statement is first processed, any SSA_NAMEs that are dependencies 
are cached for quick future access.

if we ;later rewrite the statement (say propagate a constant into it), 
its possible the ssa-name in this cache is no longer active.   Normally 
this is not a problem, but the changed to may_recompute_p forgot to take 
that into account, and was checking a dependency from the cache that was 
in the SSA_NAME_FREE_LIST. It thus had no SSA_NAME_DEF_STMT when we were 
expecting one.

This patch simply rejects dependencies from consideration if they are in 
the free list.

Bootstrapping on x86_64-pc-linux-gnu  and presuming no regressio0ns, OK 
for trunk?

Andrew

Comments

Jeff Law April 5, 2023, 9:52 p.m. UTC | #1
On 4/5/23 14:10, Andrew MacLeod via Gcc-patches wrote:
> When a statement is first processed, any SSA_NAMEs that are dependencies 
> are cached for quick future access.
> 
> if we ;later rewrite the statement (say propagate a constant into it), 
> its possible the ssa-name in this cache is no longer active.   Normally 
> this is not a problem, but the changed to may_recompute_p forgot to take 
> that into account, and was checking a dependency from the cache that was 
> in the SSA_NAME_FREE_LIST. It thus had no SSA_NAME_DEF_STMT when we were 
> expecting one.
> 
> This patch simply rejects dependencies from consideration if they are in 
> the free list.
> 
> Bootstrapping on x86_64-pc-linux-gnu  and presuming no regressio0ns, OK 
> for trunk?
eek.  So you've got a released name in the cache?  What happens if the 
name gets released, then re-used?  Aren't you going to get bogus results 
in that case?

jeff
Jakub Jelinek April 6, 2023, 10:38 a.m. UTC | #2
On Wed, Apr 05, 2023 at 04:10:25PM -0400, Andrew MacLeod via Gcc-patches wrote:
> When a statement is first processed, any SSA_NAMEs that are dependencies are
> cached for quick future access.
> 
> if we ;later rewrite the statement (say propagate a constant into it), its
> possible the ssa-name in this cache is no longer active.   Normally this is
> not a problem, but the changed to may_recompute_p forgot to take that into
> account, and was checking a dependency from the cache that was in the
> SSA_NAME_FREE_LIST. It thus had no SSA_NAME_DEF_STMT when we were expecting
> one.
> 
> This patch simply rejects dependencies from consideration if they are in the
> free list.
> 
> Bootstrapping on x86_64-pc-linux-gnu  and presuming no regressio0ns, OK for
> trunk?
> 
> Andrew

> commit ecd86e159e8499feb387bc4d99bd37a5fd6a0d68
> Author: Andrew MacLeod <amacleod@redhat.com>
> Date:   Wed Apr 5 15:59:38 2023 -0400
> 
>     Check if dependency is valid before using in may_recompute_p.
>     
>     When the IL is rewritten after a statement has been processed and
>     dependencies cached, its possible that an ssa-name in the dependency
>     cache is no longer in the IL.  Check this before trying to recompute.
>     
>             PR tree-optimization/109417
>             gcc/
>             * gimple-range-gori.cc (gori_compute::may_recompute_p): Check if
>             dependency is in SSA_NAME_FREE_LIST.
>     
>             gcc/testsuite/
>             * gcc.dg/pr109417.c: New.

Ok for trunk (mainly to unbreak the recent regression).
But please be ready to adjust if Richi disagrees next week.

> --- a/gcc/gimple-range-gori.cc
> +++ b/gcc/gimple-range-gori.cc
> @@ -1314,7 +1314,9 @@ gori_compute::may_recompute_p (tree name, basic_block bb, int depth)
>    tree dep2 = depend2 (name);
>  
>    // If the first dependency is not set, there is no recomputation.
> -  if (!dep1)
> +  // Dependencies reflect original IL, not current state.   Check if the
> +  // SSA_NAME is still valid as well.
> +  if (!dep1 || SSA_NAME_IN_FREE_LIST (dep1))
>      return false;
>  
>    // Don't recalculate PHIs or statements with side_effects.

	Jakub
Richard Biener April 11, 2023, 9:21 a.m. UTC | #3
On Wed, Apr 5, 2023 at 11:53 PM Jeff Law via Gcc-patches
<gcc-patches@gcc.gnu.org> wrote:
>
>
>
> On 4/5/23 14:10, Andrew MacLeod via Gcc-patches wrote:
> > When a statement is first processed, any SSA_NAMEs that are dependencies
> > are cached for quick future access.
> >
> > if we ;later rewrite the statement (say propagate a constant into it),
> > its possible the ssa-name in this cache is no longer active.   Normally
> > this is not a problem, but the changed to may_recompute_p forgot to take
> > that into account, and was checking a dependency from the cache that was
> > in the SSA_NAME_FREE_LIST. It thus had no SSA_NAME_DEF_STMT when we were
> > expecting one.
> >
> > This patch simply rejects dependencies from consideration if they are in
> > the free list.
> >
> > Bootstrapping on x86_64-pc-linux-gnu  and presuming no regressio0ns, OK
> > for trunk?
> eek.  So you've got a released name in the cache?  What happens if the
> name gets released, then re-used?  Aren't you going to get bogus results
> in that case?

We never re-use SSA names from within the pass releasing it.  But if
the ranger cache
persists across passes this could be a problem.  See
flush_ssaname_freelist which
for example resets the SCEV hash table which otherwise would have the
same issue.

IIRC ranger never outlives a pass so the patch should be OK.

_But_ I wonder how ranger gets at the tree SSA name in the first place - usually
caches are indexed by SSA_NAME_VERSION (because that's cheaper and
better than a pointer to the tree) and ssa_name (ver) will return NULL
for released
SSA names.  So range_def_chain::rdc could be just

  struct rdc {
   int ssa1;           // First direct dependency
   int ssa2;           // Second direct dependency
   bitmap bm;           // All dependencies
   bitmap m_import;
  };

and ::depend1 return ssa_name (m_def_chain[v].ssa1) and everything would
work automatically (and save 8 bytes of storage).

Richard.

> jeff
Andrew MacLeod April 24, 2023, 1:51 p.m. UTC | #4
On 4/11/23 05:21, Richard Biener via Gcc-patches wrote:
> On Wed, Apr 5, 2023 at 11:53 PM Jeff Law via Gcc-patches
> <gcc-patches@gcc.gnu.org> wrote:
>>
>>
>> On 4/5/23 14:10, Andrew MacLeod via Gcc-patches wrote:
>>> When a statement is first processed, any SSA_NAMEs that are dependencies
>>> are cached for quick future access.
>>>
>>> if we ;later rewrite the statement (say propagate a constant into it),
>>> its possible the ssa-name in this cache is no longer active.   Normally
>>> this is not a problem, but the changed to may_recompute_p forgot to take
>>> that into account, and was checking a dependency from the cache that was
>>> in the SSA_NAME_FREE_LIST. It thus had no SSA_NAME_DEF_STMT when we were
>>> expecting one.
>>>
>>> This patch simply rejects dependencies from consideration if they are in
>>> the free list.
>>>
>>> Bootstrapping on x86_64-pc-linux-gnu  and presuming no regressio0ns, OK
>>> for trunk?
>> eek.  So you've got a released name in the cache?  What happens if the
>> name gets released, then re-used?  Aren't you going to get bogus results
>> in that case?

Its not a real cache..  its merely a statement shortcut in dependency 
analysis to avoid re-parsing statements every time we look at them for 
dependency analysis

It is not suppose to be used for anything other than dependency 
checking.   ie, if an SSA_NAME changes, we can check if it matches 
either of the 2 "cached" names on this DEF, and if so, we know this name 
is stale.  we are never actually suppose to use the dependency cached 
values to drive anything, merely respond to the question if either 
matches a given name.   So it doesnt matter if the name here has been freed


> We never re-use SSA names from within the pass releasing it.  But if
> the ranger cache
> persists across passes this could be a problem.  See


This particular valueswould never persist beyond a current pass.. its 
just the dependency chains and they would get rebuilt every time because 
the IL has changed.


> flush_ssaname_freelist which
> for example resets the SCEV hash table which otherwise would have the
> same issue.
>
> IIRC ranger never outlives a pass so the patch should be OK.
>
> _But_ I wonder how ranger gets at the tree SSA name in the first place - usually
> caches are indexed by SSA_NAME_VERSION (because that's cheaper and


Its stored when we process a statement the first time when building 
dependency chains.  All comparisons down the road for 
staleness/dependency chain existence are against a pointer.. but we 
could simple change it to be an "unsigned int",  we'd then just have to 
compare again SSA_NAME_VERSION(name) instead..


> better than a pointer to the tree) and ssa_name (ver) will return NULL
> for released
> SSA names.  So range_def_chain::rdc could be just
>
>    struct rdc {
>     int ssa1;           // First direct dependency
>     int ssa2;           // Second direct dependency
>     bitmap bm;           // All dependencies
>     bitmap m_import;
>    };
>
> and ::depend1 return ssa_name (m_def_chain[v].ssa1) and everything woul
if the ssa-name is no longer in existence, does ssa_name (x) it return 
NULL?
> work automatically (and save 8 bytes of storage).
>
> Richard.

>> jeff
Richard Biener April 25, 2023, 7:17 a.m. UTC | #5
On Mon, Apr 24, 2023 at 3:51 PM Andrew MacLeod <amacleod@redhat.com> wrote:
>
>
> On 4/11/23 05:21, Richard Biener via Gcc-patches wrote:
> > On Wed, Apr 5, 2023 at 11:53 PM Jeff Law via Gcc-patches
> > <gcc-patches@gcc.gnu.org> wrote:
> >>
> >>
> >> On 4/5/23 14:10, Andrew MacLeod via Gcc-patches wrote:
> >>> When a statement is first processed, any SSA_NAMEs that are dependencies
> >>> are cached for quick future access.
> >>>
> >>> if we ;later rewrite the statement (say propagate a constant into it),
> >>> its possible the ssa-name in this cache is no longer active.   Normally
> >>> this is not a problem, but the changed to may_recompute_p forgot to take
> >>> that into account, and was checking a dependency from the cache that was
> >>> in the SSA_NAME_FREE_LIST. It thus had no SSA_NAME_DEF_STMT when we were
> >>> expecting one.
> >>>
> >>> This patch simply rejects dependencies from consideration if they are in
> >>> the free list.
> >>>
> >>> Bootstrapping on x86_64-pc-linux-gnu  and presuming no regressio0ns, OK
> >>> for trunk?
> >> eek.  So you've got a released name in the cache?  What happens if the
> >> name gets released, then re-used?  Aren't you going to get bogus results
> >> in that case?
>
> Its not a real cache..  its merely a statement shortcut in dependency
> analysis to avoid re-parsing statements every time we look at them for
> dependency analysis
>
> It is not suppose to be used for anything other than dependency
> checking.   ie, if an SSA_NAME changes, we can check if it matches
> either of the 2 "cached" names on this DEF, and if so, we know this name
> is stale.  we are never actually suppose to use the dependency cached
> values to drive anything, merely respond to the question if either
> matches a given name.   So it doesnt matter if the name here has been freed
>
>
> > We never re-use SSA names from within the pass releasing it.  But if
> > the ranger cache
> > persists across passes this could be a problem.  See
>
>
> This particular valueswould never persist beyond a current pass.. its
> just the dependency chains and they would get rebuilt every time because
> the IL has changed.
>
>
> > flush_ssaname_freelist which
> > for example resets the SCEV hash table which otherwise would have the
> > same issue.
> >
> > IIRC ranger never outlives a pass so the patch should be OK.
> >
> > _But_ I wonder how ranger gets at the tree SSA name in the first place - usually
> > caches are indexed by SSA_NAME_VERSION (because that's cheaper and
>
>
> Its stored when we process a statement the first time when building
> dependency chains.  All comparisons down the road for
> staleness/dependency chain existence are against a pointer.. but we
> could simple change it to be an "unsigned int",  we'd then just have to
> compare again SSA_NAME_VERSION(name) instead..
>
>
> > better than a pointer to the tree) and ssa_name (ver) will return NULL
> > for released
> > SSA names.  So range_def_chain::rdc could be just
> >
> >    struct rdc {
> >     int ssa1;           // First direct dependency
> >     int ssa2;           // Second direct dependency
> >     bitmap bm;           // All dependencies
> >     bitmap m_import;
> >    };
> >
> > and ::depend1 return ssa_name (m_def_chain[v].ssa1) and everything woul
> if the ssa-name is no longer in existence, does ssa_name (x) it return
> NULL?

Yes.

> > work automatically (and save 8 bytes of storage).
> >
> > Richard.
>
> >> jeff
>
Jeff Law April 26, 2023, 2:34 a.m. UTC | #6
On 4/24/23 07:51, Andrew MacLeod wrote:

> 
> Its not a real cache..  its merely a statement shortcut in dependency 
> analysis to avoid re-parsing statements every time we look at them for 
> dependency analysis
> 
> It is not suppose to be used for anything other than dependency 
> checking.   ie, if an SSA_NAME changes, we can check if it matches 
> either of the 2 "cached" names on this DEF, and if so, we know this name 
> is stale.  we are never actually suppose to use the dependency cached 
> values to drive anything, merely respond to the question if either 
> matches a given name.   So it doesnt matter if the name here has been freed
OK.  I'll take your word for it.  Note that a free'd SSA_NAME may have 
an empty TREE_TYPE or an unexpected TREE_CHAIN field IIRC.  So you have 
to be a bit careful if you're going to allow them.

> 
> 
>> We never re-use SSA names from within the pass releasing it.  But if
>> the ranger cache
>> persists across passes this could be a problem.  See
> 
> 
> This particular valueswould never persist beyond a current pass.. its 
> just the dependency chains and they would get rebuilt every time because 
> the IL has changed.
Good.  THat would limit the concerns significantly.  I don't think we 
recycle names within a pass anymore (we used to within DOM due to the 
way threading worked eons ago, but we no longer take things out of SSA 
form to handle the CFG/SSA graph updates.  One could even argue we don't 
need to maintain the freelist and recycle names anymore.

Jeff
diff mbox series

Patch

commit ecd86e159e8499feb387bc4d99bd37a5fd6a0d68
Author: Andrew MacLeod <amacleod@redhat.com>
Date:   Wed Apr 5 15:59:38 2023 -0400

    Check if dependency is valid before using in may_recompute_p.
    
    When the IL is rewritten after a statement has been processed and
    dependencies cached, its possible that an ssa-name in the dependency
    cache is no longer in the IL.  Check this before trying to recompute.
    
            PR tree-optimization/109417
            gcc/
            * gimple-range-gori.cc (gori_compute::may_recompute_p): Check if
            dependency is in SSA_NAME_FREE_LIST.
    
            gcc/testsuite/
            * gcc.dg/pr109417.c: New.

diff --git a/gcc/gimple-range-gori.cc b/gcc/gimple-range-gori.cc
index 5f4313b27dd..6e2f9533038 100644
--- a/gcc/gimple-range-gori.cc
+++ b/gcc/gimple-range-gori.cc
@@ -1314,7 +1314,9 @@  gori_compute::may_recompute_p (tree name, basic_block bb, int depth)
   tree dep2 = depend2 (name);
 
   // If the first dependency is not set, there is no recomputation.
-  if (!dep1)
+  // Dependencies reflect original IL, not current state.   Check if the
+  // SSA_NAME is still valid as well.
+  if (!dep1 || SSA_NAME_IN_FREE_LIST (dep1))
     return false;
 
   // Don't recalculate PHIs or statements with side_effects.
diff --git a/gcc/testsuite/gcc.dg/pr109417.c b/gcc/testsuite/gcc.dg/pr109417.c
new file mode 100644
index 00000000000..15711dbbafe
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr109417.c
@@ -0,0 +1,24 @@ 
+/* { dg-do compile } */
+/* { dg-options "-O3" } */
+
+int printf(const char *, ...);
+int c, d, *e, f[1][2], g;
+int main() {
+  int h = 0, *a = &h, **b[1] = {&a};
+  while (e)
+    while (g) {
+    L:
+      for (h = 0; h < 2; h++) {
+        while (d)
+          for (*e = 0; *e < 1;)
+            printf("0");
+        while (c)
+          ;
+        f[g][h] = 0;
+      }
+    }
+  if (h)
+    goto L;
+  return 0;
+}
+