https://gcc.gnu.org/g:fea8a2b9bf26f654ec0b97d43259dad5b0275c00

commit r17-4401-gfea8a2b9bf26f654ec0b97d43259dad5b0275c00
Author: Andrew MacLeod <[email protected]>
Date:   Wed Sep 16 07:15:42 2026 -0400

    Keep partial equivalences out of ordering relations.
    
    If a partial equivalence and a normal relation both exist, prefer the
    normal relation.  Also, partial equivalences should not be entered
    into the path oracle, nor should they be combined with normal relations
    when recording a relation.
    
    Assisted-By: Claude Opus 5
    
            gcc/
            * value-relation.cc (dom_oracle::query): Prefer a normal
            relation over a partial equivalency.
            (path_oracle::record): Do not record partial equivalences, nor
            intersect one with the relation being recorded.
    
            gcc/testsuite/
            * gcc.dg/tree-ssa/vrp-rel3.c: New.

Diff:
---
 gcc/testsuite/gcc.dg/tree-ssa/vrp-rel3.c | 42 ++++++++++++++++++++++++++++++++
 gcc/value-relation.cc                    | 28 +++++++++++++--------
 2 files changed, 60 insertions(+), 10 deletions(-)

diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp-rel3.c 
b/gcc/testsuite/gcc.dg/tree-ssa/vrp-rel3.c
new file mode 100644
index 000000000000..6a0a32fee01c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp-rel3.c
@@ -0,0 +1,42 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-evrp" } */
+
+/* Masking with 0xff makes C a partial equivalence of A, and unlike the cast
+   case both names have the same type, so an ordinary comparison can relate
+   the pair as well.  A partial equivalence and an ordering relation do not
+   combine, but the partial equivalence must not hide the ordering either.  */
+
+void keep (void);
+void kill (void);
+
+void
+f1 (int a, int b)
+{
+  int c = a & 0xff;
+  if (c > b)
+    if (b > a)
+      {
+       if (c > a)
+         keep ();
+       else
+         kill ();
+      }
+}
+
+/* Same shape with a mask which is not a partial equivalence, as a control.  */
+void
+f2 (int a, int b)
+{
+  int c = a & 0xfe;
+  if (c > b)
+    if (b > a)
+      {
+       if (c > a)
+         keep ();
+       else
+         kill ();
+      }
+}
+
+/* { dg-final { scan-tree-dump-not "kill" "evrp" } } */
+/* { dg-final { scan-tree-dump-times "keep" 2 "evrp" } } */
diff --git a/gcc/value-relation.cc b/gcc/value-relation.cc
index 0eb6bdec75fa..f5b286128353 100644
--- a/gcc/value-relation.cc
+++ b/gcc/value-relation.cc
@@ -1880,17 +1880,17 @@ dom_oracle::query (basic_block bb, tree ssa1, tree ssa2)
   if (bitmap_bit_p (equiv1, v2) && bitmap_bit_p (equiv2, v1))
     return VREL_EQ;
 
-  kind = partial_equiv (ssa1, ssa2);
-  if (kind != VREL_VARYING)
-    return kind;
-
-  // Initially look for a direct relationship and just return that.
+  // A statement such as c = a & 0xff makes a partial equivalence between
+  // c and a, and an ordinary comparison can then relate the same pair.
+  // If both exist, prefer the relation, so look for that first.
   kind = find_relation_dom (bb, ssa1, ssa2);
-  if (kind != VREL_VARYING)
-    return kind;
+  // If no direct relation exists, try the query using the equivalence sets.
+  if (kind == VREL_VARYING)
+    kind = query (bb, equiv1, equiv2);
 
-  // Query using the equivalence sets.
-  kind = query (bb, equiv1, equiv2);
+  // Finally look for partial equivalences.
+  if (kind == VREL_VARYING)
+    kind = partial_equiv (ssa1, ssa2);
   return kind;
 }
 
@@ -2078,8 +2078,16 @@ path_oracle::record (basic_block bb, relation_kind k, 
tree ssa1, tree ssa2)
   if (ssa1 == ssa2)
     return false;
 
+  // Partial equivalences are tracked in the root equivalence oracle rather
+  // than on the path.  Registering a partial equivalence in the path would
+  // cause normal relations to collapse to VARYING.
+  if (relation_partial_equiv_p (k))
+    return false;
+
   relation_kind curr = query (bb, ssa1, ssa2);
-  if (curr != VREL_VARYING)
+  // Likewise, a partial equivalency result should not be combined with K
+  // or the result drops to VARYING.
+  if (curr != VREL_VARYING && !relation_partial_equiv_p (curr))
     k = relation_intersect (curr, k);
 
   // Do not register an impossible relation.

Reply via email to