[Bug tree-optimization/124809] [16 Regression] wrong code at -O1 with "-fno-tree-ch -fno-tree-dce" on x86_64-linux-gnu since r16-5322

2026-04-14 Thread amacleod at redhat dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=124809

Andrew Macleod  changed:

   What|Removed |Added

 Resolution|--- |FIXED
 Status|ASSIGNED|RESOLVED

--- Comment #13 from Andrew Macleod  ---
fixed

[Bug tree-optimization/124809] [16 Regression] wrong code at -O1 with "-fno-tree-ch -fno-tree-dce" on x86_64-linux-gnu since r16-5322

2026-04-14 Thread cvs-commit at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=124809

--- Comment #12 from GCC Commits  ---
The master branch has been updated by Andrew Macleod :

https://gcc.gnu.org/g:4b6bbc51a6acfa1692c7143592f01b28eed57da1

commit r16-8612-g4b6bbc51a6acfa1692c7143592f01b28eed57da1
Author: Andrew MacLeod 
Date:   Mon Apr 13 13:37:36 2026 -0400

Register equivalences only once per statement.

When a copy statement is rewritten, do not register a new equivalence
between
the LHS and RHS.

PR tree-optimization/124809
gcc/
* value-relation.cc (equiv_oracle::equiv_oracle): Allocate lhs
equivalence bitmap.
(relation_oracle::record): Check if LHS has already created an
equivalence record.
* value-relation.h (relation_oracle::relation_oracle): New.
(relation_oracle::m_lhs_equiv_set_p): New.

gcc/testsuite/
* gcc.dg/pr124809.c: New.

[Bug tree-optimization/124809] [16 Regression] wrong code at -O1 with "-fno-tree-ch -fno-tree-dce" on x86_64-linux-gnu since r16-5322

2026-04-13 Thread amacleod at redhat dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=124809

Andrew Macleod  changed:

   What|Removed |Added

   Assignee|unassigned at gcc dot gnu.org  |amacleod at redhat dot 
com
 Status|NEW |ASSIGNED

--- Comment #11 from Andrew Macleod  ---
Created attachment 64196
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=64196&action=edit
proopsed patch

DOM rewrites a statement using valid local equivalences, but ranger does not
understans that this is replacing an existing equivalence rather than adding a
new one.

Given:

c = a;
if (a == b)
  d = c;
...
if (c == b)

Ranger infers {a, c, d} as an equivalence class. Since c and b are unrelated,
the final condition is not foldable.

DOM rewrites:
  d = c;
to:
  d = b;

based on a == b and c == a, producing:

c = a;
if (a == b)
  d = b;
...
if (c == b)

This transformation is valid, but DOM then re-runs Ranger on the updated
statement. Ranger sees d = b and adds a new equivalence, expanding the set to
{a, b, c, d}.

This is incorrect. The original equivalence from d = c was not removed, so d
now incorrectly bridges the two sets. As a result, Ranger folds if (c == b) to
true.

The core issue is that equivalences are only added, never removed. After
rewriting, the old equivalence must no longer apply, but there is currently no
mechanism to retract it.

This problem does not exist in VRP or other places because they either 
  a) do no revisit the statement once it is rewritten
  b) save all the rewrites until the end.

I have a Fix which tracks whether an SSA name on the LHS has already had an
equivalence registered *as a LHS*, and only allows this once per stmt. This is
cheap and prevents the second equivalence from being registered.  It does not
affect other equivalences being registered against the SSA_NAME from other
locations.

This is conservative but ensures this situation does not happen.

Currently running through the testsuite.

[Bug tree-optimization/124809] [16 Regression] wrong code at -O1 with "-fno-tree-ch -fno-tree-dce" on x86_64-linux-gnu since r16-5322

2026-04-10 Thread amacleod at redhat dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=124809

--- Comment #10 from Andrew Macleod  ---
(In reply to Richard Biener from comment #9)
> (In reply to Andrew Macleod from comment #8)
> > ick.   We don't remove relations once they are added. Never been a need.
> > 
> > IN this program we have:
> > 
> > 
> >a.0_1 = a;
> >   _2 = (int) a.0_1;
> >   _3 = (int) g_16(D);
> >   _4 = _2 != _3;
> >   _20 = (short unsigned int) _4;
> >   if (a.0_1 != _20)
> > goto ; [5.50%]
> >   else
> > goto ; [94.50%]
> > 
> >[local count: 55807731]:
> >   j_18 = a.0_1 + _20;
> >   k_19 = (int) j_18;
> >   if (a.0_1 == 0)
> > goto ; [50.00%]
> >   else
> > goto ; [50.00%]
> > 
> >[local count: 27903866]:
> >   _21 = k_19 >> _2;
> >   goto ; [100.00%]
> > 
> >[local count: 958878295]:
> >  
> >   <<--- Partial equivalence
> >   if (d.10_9 != 0)
> > goto ; [50.00%]
> >   else
> > goto ; [50.00%]
> > 
> > at some point we register a partial equivalence of 16 bits between a.6_5 and
> > a.0_1
> > (Partial equivalences are also used between values of the same precision but
> > with difference signs as it represents a 16 bit equivalence, not a value.)
> > 
> > DOM continues omn its merry way, and decides at some point that on the else
> > side of 
> >   if (a.0_1 != _20) 
> >  that a.0_1 == _20, and as thats the only way to reach bb6,  it rewrites
> > that statement
> > Optimizing block #6
> > 
> > 1>>> STMT 1 = a.0_1 le_expr _20
> > 1>>> STMT 1 = a.0_1 ge_expr _20
> > 1>>> STMT 1 = a.0_1 eq_expr _20
> > 1>>> STMT 0 = a.0_1 ne_expr _20
> > 0>>> COPY a.0_1 = _20
> > Optimizing statement a.6_5 = (short int) a.0_1;
> >   Replaced 'a.0_1' with variable '_20'
> > 
> > The next time ranger processes that statement, it registers a partial (bit)
> > equivalence between 
> >   a.6_5 and _20
> > but we do NOT delete the previous one... which means we now think that there
> > is an equivalence between a.6_5, _20, and a.0_1
> > Which there is not.
> 
> Not sure if I follow the above correctly, but shouldn't there only
> be a partial equivalence between a.6_5 (signed short) and a.0_1
> (unsinged short) and _20?  And isn't that correct?
> 

These are global equivalences... when we see 
  a.6_5 = (short int) a.0_1;
Its globally true that  a.6_5 and a.0_1 are 16 bit identical.
When it is re-written by DOM into 
  a.6_5 = (short int) _20
And re-processed, the relation oracle now registers a global bit equivalence
between a.6_5 and _20, which then transitively creates a global equivalence
between a.0_1 and  _20...   THAT transitive equivalence is *not* global in
nature.

At the moment, they all share a partial equivalence set.. so there is no direct
way to "disable" this feature.   VRP never encounters this because ranger never
revisits a statement once its is processed fully and rewriiten.  It Looks like
DOM is using it for constant propagation and is revisiting it after it rewrites
the statement.

This may also have something to do with the path ranger which DOM uses.. I'm
not as familiar with how it sets and resets things... 

I'll get back to you in a bit. 


> >  Only one of those  equivalences with a.6_5 can exist. 
> > Either the old one needs to be deleted, or the new one not added.
> > 
> > I'm thinking about it...?

[Bug tree-optimization/124809] [16 Regression] wrong code at -O1 with "-fno-tree-ch -fno-tree-dce" on x86_64-linux-gnu since r16-5322

2026-04-10 Thread rguenth at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=124809

--- Comment #9 from Richard Biener  ---
(In reply to Andrew Macleod from comment #8)
> ick.   We don't remove relations once they are added. Never been a need.
> 
> IN this program we have:
> 
> 
>a.0_1 = a;
>   _2 = (int) a.0_1;
>   _3 = (int) g_16(D);
>   _4 = _2 != _3;
>   _20 = (short unsigned int) _4;
>   if (a.0_1 != _20)
> goto ; [5.50%]
>   else
> goto ; [94.50%]
> 
>[local count: 55807731]:
>   j_18 = a.0_1 + _20;
>   k_19 = (int) j_18;
>   if (a.0_1 == 0)
> goto ; [50.00%]
>   else
> goto ; [50.00%]
> 
>[local count: 27903866]:
>   _21 = k_19 >> _2;
>   goto ; [100.00%]
> 
>[local count: 958878295]:
>  
>   <<--- Partial equivalence
>   if (d.10_9 != 0)
> goto ; [50.00%]
>   else
> goto ; [50.00%]
> 
> at some point we register a partial equivalence of 16 bits between a.6_5 and
> a.0_1
> (Partial equivalences are also used between values of the same precision but
> with difference signs as it represents a 16 bit equivalence, not a value.)
> 
> DOM continues omn its merry way, and decides at some point that on the else
> side of 
>   if (a.0_1 != _20) 
>  that a.0_1 == _20, and as thats the only way to reach bb6,  it rewrites
> that statement
> Optimizing block #6
> 
> 1>>> STMT 1 = a.0_1 le_expr _20
> 1>>> STMT 1 = a.0_1 ge_expr _20
> 1>>> STMT 1 = a.0_1 eq_expr _20
> 1>>> STMT 0 = a.0_1 ne_expr _20
> 0>>> COPY a.0_1 = _20
> Optimizing statement a.6_5 = (short int) a.0_1;
>   Replaced 'a.0_1' with variable '_20'
> 
> The next time ranger processes that statement, it registers a partial (bit)
> equivalence between 
>   a.6_5 and _20
> but we do NOT delete the previous one... which means we now think that there
> is an equivalence between a.6_5, _20, and a.0_1
> Which there is not.

Not sure if I follow the above correctly, but shouldn't there only
be a partial equivalence between a.6_5 (signed short) and a.0_1
(unsinged short) and _20?  And isn't that correct?

>  Only one of those  equivalences with a.6_5 can exist. 
> Either the old one needs to be deleted, or the new one not added.
> 
> I'm thinking about it...?

[Bug tree-optimization/124809] [16 Regression] wrong code at -O1 with "-fno-tree-ch -fno-tree-dce" on x86_64-linux-gnu since r16-5322

2026-04-09 Thread amacleod at redhat dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=124809

--- Comment #8 from Andrew Macleod  ---
ick.   We don't remove relations once they are added. Never been a need.

IN this program we have:


   a.0_1 = a;
  _2 = (int) a.0_1;
  _3 = (int) g_16(D);
  _4 = _2 != _3;
  _20 = (short unsigned int) _4;
  if (a.0_1 != _20)
goto ; [5.50%]
  else
goto ; [94.50%]

   [local count: 55807731]:
  j_18 = a.0_1 + _20;
  k_19 = (int) j_18;
  if (a.0_1 == 0)
goto ; [50.00%]
  else
goto ; [50.00%]

   [local count: 27903866]:
  _21 = k_19 >> _2;
  goto ; [100.00%]

   [local count: 958878295]:

  <<--- Partial equivalence
  if (d.10_9 != 0)
goto ; [50.00%]
  else
goto ; [50.00%]

at some point we register a partial equivalence of 16 bits between a.6_5 and
a.0_1
(Partial equivalences are also used between values of the same precision but
with difference signs as it represents a 16 bit equivalence, not a value.)

DOM continues omn its merry way, and decides at some point that on the else
side of 
  if (a.0_1 != _20) 
 that a.0_1 == _20, and as thats the only way to reach bb6,  it rewrites that
statement
Optimizing block #6

1>>> STMT 1 = a.0_1 le_expr _20
1>>> STMT 1 = a.0_1 ge_expr _20
1>>> STMT 1 = a.0_1 eq_expr _20
1>>> STMT 0 = a.0_1 ne_expr _20
0>>> COPY a.0_1 = _20
Optimizing statement a.6_5 = (short int) a.0_1;
  Replaced 'a.0_1' with variable '_20'

The next time ranger processes that statement, it registers a partial (bit)
equivalence between 
  a.6_5 and _20
but we do NOT delete the previous one... which means we now think that there is
an equivalence between a.6_5, _20, and a.0_1
Which there is not.  Only one of those  equivalences with a.6_5 can exist. 
Either the old one needs to be deleted, or the new one not added.

I'm thinking about it...?

[Bug tree-optimization/124809] [16 Regression] wrong code at -O1 with "-fno-tree-ch -fno-tree-dce" on x86_64-linux-gnu since r16-5322

2026-04-08 Thread amacleod at redhat dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=124809

--- Comment #7 from Andrew Macleod  ---
Yeah, I'm having a look.

[Bug tree-optimization/124809] [16 Regression] wrong code at -O1 with "-fno-tree-ch -fno-tree-dce" on x86_64-linux-gnu since r16-5322

2026-04-08 Thread jakub at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=124809

--- Comment #5 from Jakub Jelinek  ---
Slightly cleaned up:
unsigned short a, c, d;

short
foo (short g, short h)
{
  return h;
}

short
bar (short g, short h)
{
  return g;
}

__attribute__((noipa)) void
baz (...)
{
  __builtin_abort ();
}

__attribute__((noinline)) int
qux (signed char g)
{
  unsigned short j;
  int b = 0, k;
  while (d < 8)
{
  if ((b = a != g) ^ a)
{
  j = b + a;
  k = j;
  return a ? 0 : k >> a;
}
  b = foo (d && c, a);
}
  baz (b);
  return 100;
}

__attribute__((noinline)) int
fred (signed char g)
{
  unsigned short j;
  int b = 0, k;
  while (d < 8)
{
  if ((b = a != g) ^ a)
{
  j = b + a;
  k = j;
  return a ? 0 : k >> a;
}
  b = bar (a, d && c);
}
  baz (b);
  return 100;
}

int
main ()
{
  if (qux (1) != 1 || fred (1) != 1)
__builtin_abort ();
}

[Bug tree-optimization/124809] [16 Regression] wrong code at -O1 with "-fno-tree-ch -fno-tree-dce" on x86_64-linux-gnu since r16-5322

2026-04-08 Thread jakub at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=124809

--- Comment #6 from Jakub Jelinek  ---
And the same with some auto var renames, so that there is no confusion for what
is from which function:
unsigned short a, c, d;

short
foo (short g, short h)
{
  return h;
}

short
bar (short g, short h)
{
  return g;
}

__attribute__((noipa)) void
baz (int b)
{
  __builtin_abort ();
}

__attribute__((noinline)) int
qux (signed char g)
{
  unsigned short j;
  int b = 0, k;
  while (d < 8)
{
  if ((b = a != g) ^ a)
{
  j = b + a;
  k = j;
  return a ? 0 : k >> a;
}
  b = foo (d && c, a);
}
  baz (b);
  return 100;
}

__attribute__((noinline)) int
fred (signed char p)
{
  unsigned short o;
  int m = 0, n;
  while (d < 8)
{
  if ((m = a != p) ^ a)
{
  o = m + a;
  n = o;
  return a ? 0 : n >> a;
}
  m = bar (a, d && c);
}
  baz (m);
  return 100;
}

int
main ()
{
  if (qux (1) != 1 || fred (1) != 1)
__builtin_abort ();
}

At runtime in both cases a is 0 and b/m are 1, so the right shift is 1.
Figuring out that it is >> 0 is correct, and that because it is in ?: last
operand
b + a or m + a is equal to just b or m and that it is [0, 1] is correct, but
somehow it only thinks about [0, 0] and not [0, 1].

[Bug tree-optimization/124809] [16 Regression] wrong code at -O1 with "-fno-tree-ch -fno-tree-dce" on x86_64-linux-gnu since r16-5322

2026-04-08 Thread rguenth at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=124809

--- Comment #4 from Richard Biener  ---
DOM2 comes up with

   e = 0;

from

  # RANGE [irange] int [0, 65535] MASK 0x VALUE 0x0
  k_23 = (int) j_22;
  if (a.0_1 == 0) 
goto ; [50.00%]
  else
goto ; [50.00%]

   [local count: 27903866]:
  iftmp.3_25 = k_23 >> _2;

   [local count: 55807731]:
  # iftmp.3_14 = PHI 
  e = iftmp.3_14;

somehow via

Global Exported: j_22 = [irange] short unsigned int [0, 0][2, 2] MASK 0x3 VALUE
0x0
Global Exported: k_23 = [irange] int [0, 0][2, 2] MASK 0x3 VALUE 0x0

Andrew?

[Bug tree-optimization/124809] [16 Regression] wrong code at -O1 with "-fno-tree-ch -fno-tree-dce" on x86_64-linux-gnu since r16-5322

2026-04-07 Thread pinskia at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=124809

Andrew Pinski  changed:

   What|Removed |Added

 Target||x86_64 aarch64
   Priority|P3  |P1

[Bug tree-optimization/124809] [16 Regression] wrong code at -O1 with "-fno-tree-ch -fno-tree-dce" on x86_64-linux-gnu since r16-5322

2026-04-07 Thread pinskia at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=124809

Andrew Pinski  changed:

   What|Removed |Added

  Attachment #64167|0   |1
is obsolete||

--- Comment #3 from Andrew Pinski  ---
Created attachment 64168
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=64168&action=edit
better testcase

This one is better beca use it does not need defines.

[Bug tree-optimization/124809] [16 Regression] wrong code at -O1 with "-fno-tree-ch -fno-tree-dce" on x86_64-linux-gnu since r16-5322

2026-04-07 Thread jakub at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=124809

Jakub Jelinek  changed:

   What|Removed |Added

   Target Milestone|--- |16.0
 CC||amacleod at redhat dot com,
   ||jakub at gcc dot gnu.org
Summary|wrong code at -O1 with  |[16 Regression] wrong code
   |"-fno-tree-ch   |at -O1 with "-fno-tree-ch
   |-fno-tree-dce" on   |-fno-tree-dce" on
   |x86_64-linux-gnu|x86_64-linux-gnu since
   ||r16-5322
 Ever confirmed|0   |1
   Last reconfirmed||2026-04-07
 Status|UNCONFIRMED |NEW

--- Comment #2 from Jakub Jelinek  ---
Started with r16-5322-g71f41d9b3ac80f428de61486f2cec9604c4d729e