https://gcc.gnu.org/g:2fcbe075ec3b32f4a523ebae68a8a32381bb46a9

commit r17-2412-g2fcbe075ec3b32f4a523ebae68a8a32381bb46a9
Author: Richard Biener <[email protected]>
Date:   Wed Jul 15 10:04:18 2026 +0200

    tree-optimization/126171 - SCEV and minus of INT_MIN
    
    The following fixes the existing mitigation against UB for handling
    of subtraction of the most negative value in a type.  We've only
    guarded the negation itself which is effective for avoiding UB in
    that but it does not help in fixing a wrong scev_direction that
    results from flipping the operation from minus to plus.  So the
    patch, instead of only promoting the negation to unsigned, promotes
    the whole operation.
    
            PR tree-optimization/126171
            * tree-scalar-evolution.cc (scev_dfs::add_to_evolution):
            Remove code argument.  Remove MINUS_EXPR handling here.
            (scev_dfs::follow_ssa_edge_binary): Likewise.
            (scev_dfs::follow_ssa_edge_expr): Handle MINUS_EXPR
            separately here, promoting the whole operation to unsigned
            instead of just the addend.
    
            * gcc.dg/pr126171-1.c: New testcase.
            * gcc.dg/torture/pr126171-2.c: Likewise.

Diff:
---
 gcc/testsuite/gcc.dg/pr126171-1.c         | 107 ++++++++++++++++++++++++++++++
 gcc/testsuite/gcc.dg/torture/pr126171-2.c |  52 +++++++++++++++
 gcc/tree-scalar-evolution.cc              |  92 +++++++++++++------------
 3 files changed, 209 insertions(+), 42 deletions(-)

diff --git a/gcc/testsuite/gcc.dg/pr126171-1.c 
b/gcc/testsuite/gcc.dg/pr126171-1.c
new file mode 100644
index 000000000000..4ac67c87c7d5
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr126171-1.c
@@ -0,0 +1,107 @@
+/* { dg-do run } */
+/* { dg-require-effective-target int32plus } */
+/* { dg-options "-O2 -fgimple" } */
+
+static int o;
+
+__attribute__((noipa))
+int
+n ()
+{
+  return 129105662;
+}
+
+
+int __GIMPLE (ssa,startwith("vrp1"),guessed_local(1073741824))
+main ()
+{
+  int am;
+  int ak;
+  int ay;
+  int D_3044;
+  int tem[1];
+  int _10;
+  int _11;
+  int _12;
+  int _21;
+  int _23;
+  int _24;
+  int _25;
+  int _26;
+  int _27;
+  int _29;
+
+  __BB(2,guessed_local(1073741824)):
+  tem[0ul] = _Literal (int) -1;
+  o = 2147483645;
+  goto __BB6(precise(134217728));
+
+  __BB(10,guessed_local(17434151171)):
+  goto __BB3(precise(134217728));
+
+  __BB(3,loop_header(2),guessed_local(19522579055)):
+  ak_20 = __PHI (__BB10: ak_22, __BB6: ak_30);
+  am_7 = __PHI (__BB10: am_9, __BB6: am_31);
+  ay_16 = __PHI (__BB10: ay_17, __BB6: ay_32);
+be:
+  am_9 = am_7 + 1;
+  _10 = n ();
+  _11 = _10 + _Literal (int) -129105632;
+  _12 = am_9 << _11;
+  if (_12 == 0)
+    goto __BB4(guessed(126835753));
+  else
+    goto __BB5(guessed(7381975));
+
+  __BB(4,guessed_local(18448837212)):
+  ay_17 = ay_16 - _Literal (int) -2147483648;
+  _21 = ak_20 + _Literal (int) -1;
+  ak_22 = _21 + 2147483647;
+  if (ak_22 != 0)
+    goto __BB10(guessed(126835753));
+  else
+    goto __BB9(guessed(7381975));
+
+  __BB(5,guessed_local(1073741842)):
+  _23 = o;
+  _24 = _Literal (int) -2 - _23;
+  o = _24;
+  _25 = ak_20 + _Literal (int) -1;
+  __MEM <int> ((int *)&tem) = _25;
+  _26 = ay_16 >> 31;
+  _27 = ak_20 + _26;
+  if (_27 != 2147483645)
+    goto __BB7(guessed(67108864));
+  else
+    goto __BB8(guessed(67108864));
+
+  __BB(9,guessed_local(1014686041)):
+  goto __BB6(precise(134217728));
+
+  __BB(6,loop_header(1),guessed_local(2088427865)):
+  ak_30 = __PHI (__BB2: _Literal (int) -1, __BB9: 0);
+  am_31 = __PHI (__BB2: _Literal (int) -1, __BB9: am_9);
+  ay_32 = __PHI (__BB2: _Literal (int) -1782460880, __BB9: 3);
+az:
+  goto __BB3(precise(134217728));
+
+  __BB(7,guessed_local(536870921)):
+  goto __BB8(precise(134217728));
+
+  __BB(8,guessed_local(1073741842)):
+  _29 = __PHI (__BB5: 0, __BB7: 1);
+  if (_29 != 0)
+    goto __BB11;
+  else
+    goto __BB12;
+
+  __BB(11):
+    __builtin_abort ();
+
+  __BB(12):
+  return _29;
+
+}
+
+
+
diff --git a/gcc/testsuite/gcc.dg/torture/pr126171-2.c 
b/gcc/testsuite/gcc.dg/torture/pr126171-2.c
new file mode 100644
index 000000000000..82df6bfef9b3
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/pr126171-2.c
@@ -0,0 +1,52 @@
+/* { dg-do run } */
+/* { dg-require-effective-target int32plus } */
+
+int ah, o, t, q, aq, as, at;
+
+int __attribute__ ((noipa)) n () {
+  return 129105662;
+}
+
+int a (int ak, int al[1], int am, int bj) {
+  int ay = as = -1782460880;
+  at = -28702851;
+  o = 0 % al[0] + -1 + bj - 1;
+  goto az;
+ba:
+  al[0] = ak - 1;
+  am = -1;
+  goto bb;
+bc:
+  t = -(bj - 2147483646);
+  ay = ay - (-1 % bj - 2147483647);
+  goto bd;
+be:
+  aq = -1704571560;
+  am = am + bj - 2147483646;
+  if (am << (n () - 129105632) == 0)
+    goto bc;
+  goto bf;
+bd:
+  ak = (-1 ^ al[0]) - 1 + ak + 2147483647;
+  if (ak)
+    goto be;
+  goto bg;
+bf:
+  bj = -1 - am - 1 + 2147483647;
+  o = -1 - o - 1;
+  goto ba;
+bg:
+  ay = 3;
+az:
+  goto be;
+bb:
+  q = (ay >> 31) - -ak - 2147483646;
+  if (q != -1) return 1;
+  return 0;
+}
+
+int main () {
+  if (a (-1, (int[]) { -1 }, -1, 2147483647) != 0)
+    __builtin_abort ();
+  return 0;
+}
diff --git a/gcc/tree-scalar-evolution.cc b/gcc/tree-scalar-evolution.cc
index 279ff46474e4..cd99cbe86ce5 100644
--- a/gcc/tree-scalar-evolution.cc
+++ b/gcc/tree-scalar-evolution.cc
@@ -607,8 +607,7 @@ private:
                                           tree *evolution_of_loop, int limit);
   t_bool follow_ssa_edge_inner_loop_phi (gphi *loop_phi_node,
                                         tree *evolution_of_loop, int limit);
-  tree add_to_evolution (tree chrec_before, enum tree_code code,
-                        tree to_add, gimple *at_stmt);
+  tree add_to_evolution (tree chrec_before, tree to_add, gimple *at_stmt);
   tree add_to_evolution_1 (tree chrec_before, tree to_add, gimple *at_stmt);
 
   class loop *loop;
@@ -853,10 +852,8 @@ scev_dfs::add_to_evolution_1 (tree chrec_before, tree 
to_add, gimple *at_stmt)
 */
 
 tree
-scev_dfs::add_to_evolution (tree chrec_before, enum tree_code code,
-                           tree to_add, gimple *at_stmt)
+scev_dfs::add_to_evolution (tree chrec_before, tree to_add, gimple *at_stmt)
 {
-  tree type = chrec_type (to_add);
   tree res = NULL_TREE;
 
   if (to_add == NULL_TREE)
@@ -879,25 +876,6 @@ scev_dfs::add_to_evolution (tree chrec_before, enum 
tree_code code,
       fprintf (dump_file, ")\n");
     }
 
-  if (code == MINUS_EXPR)
-    {
-      if (INTEGRAL_TYPE_P (type)
-         && TYPE_OVERFLOW_UNDEFINED (type)
-         && !expr_not_equal_to (to_add,
-                                wi::to_wide (TYPE_MIN_VALUE (type))))
-       {
-         tree utype = unsigned_type_for (type);
-         to_add = chrec_convert_rhs (utype, to_add);
-         to_add = chrec_fold_multiply (utype, to_add,
-                                       build_int_cst_type (utype, -1));
-         to_add = chrec_convert_rhs (type, to_add);
-       }
-      else
-       to_add = chrec_fold_multiply (type, to_add, SCALAR_FLOAT_TYPE_P (type)
-                                     ? build_real (type, dconstm1)
-                                     : build_int_cst_type (type, -1));
-    }
-
   res = add_to_evolution_1 (chrec_before, to_add, at_stmt);
 
   if (dump_file && (dump_flags & TDF_SCEV))
@@ -942,7 +920,7 @@ scev_dfs::follow_ssa_edge_binary (gimple *at_stmt, tree 
type, tree rhs0,
              res = follow_ssa_edge_expr (at_stmt, rhs0, &evol, limit);
              if (res == t_true)
                *evolution_of_loop = add_to_evolution
-                   (chrec_convert (type, evol, at_stmt), code, rhs1, at_stmt);
+                   (chrec_convert (type, evol, at_stmt), rhs1, at_stmt);
              else if (res == t_false)
                {
                  res = follow_ssa_edge_expr
@@ -950,7 +928,7 @@ scev_dfs::follow_ssa_edge_binary (gimple *at_stmt, tree 
type, tree rhs0,
                  if (res == t_true)
                    *evolution_of_loop = add_to_evolution
                        (chrec_convert (type, *evolution_of_loop, at_stmt),
-                        code, rhs0, at_stmt);
+                        rhs0, at_stmt);
                }
            }
 
@@ -966,7 +944,7 @@ scev_dfs::follow_ssa_edge_binary (gimple *at_stmt, tree 
type, tree rhs0,
          if (res == t_true)
            *evolution_of_loop = add_to_evolution
                (chrec_convert (type, *evolution_of_loop, at_stmt),
-                code, rhs0, at_stmt);
+                rhs0, at_stmt);
        }
 
       else
@@ -976,17 +954,6 @@ scev_dfs::follow_ssa_edge_binary (gimple *at_stmt, tree 
type, tree rhs0,
        res = t_false;
       break;
 
-    case MINUS_EXPR:
-      /* This case is under the form "opnd0 = rhs0 - rhs1".  */
-      if (TREE_CODE (rhs0) == SSA_NAME)
-       gcc_unreachable (); /* Handled in caller.  */
-      else
-       /* Otherwise, match an assignment under the form:
-          "a = ... - ...".  */
-       /* And there is nothing to do.  */
-       res = t_false;
-      break;
-
     default:
       res = t_false;
     }
@@ -1283,10 +1250,8 @@ scev_dfs::follow_ssa_edge_expr (gimple *at_stmt, tree 
expr,
       /* Fallthru.  */
     case POINTER_PLUS_EXPR:
     case PLUS_EXPR:
-    case MINUS_EXPR:
       /* This case is under the form "rhs0 +- rhs1".  */
-      if (TREE_CODE (rhs0) == SSA_NAME
-         && (TREE_CODE (rhs1) != SSA_NAME || code == MINUS_EXPR))
+      if (TREE_CODE (rhs0) == SSA_NAME && TREE_CODE (rhs1) != SSA_NAME)
        {
          /* Match an assignment under the form:
             "a = b +- ...".  */
@@ -1295,13 +1260,56 @@ scev_dfs::follow_ssa_edge_expr (gimple *at_stmt, tree 
expr,
          if (res == t_true)
            *evolution_of_loop = add_to_evolution
                (chrec_convert (type, *evolution_of_loop, at_stmt),
-                code, rhs1, at_stmt);
+                rhs1, at_stmt);
          return res;
        }
       /* Else search for the SCC in both rhs0 and rhs1.  */
       return follow_ssa_edge_binary (at_stmt, type, rhs0, code, rhs1,
                                     evolution_of_loop, limit);
 
+
+    case MINUS_EXPR:
+      /* This case is under the form "rhs0 - rhs1".  */
+      if (TREE_CODE (rhs0) == SSA_NAME)
+       {
+         /* Match an assignment under the form:
+            "a = b +- ...".  */
+         t_bool res = follow_ssa_edge_expr (at_stmt, rhs0,
+                                            evolution_of_loop, limit);
+         if (res != t_true)
+           return res;
+         /* We have to avoid negating INT_MIN given that a) invokes UB,
+            b) results in a wrong scev_direction.  See PR126171.  */
+         if (INTEGRAL_TYPE_P (type)
+             && TYPE_OVERFLOW_UNDEFINED (type)
+             && !expr_not_equal_to (rhs1,
+                                    wi::to_wide (TYPE_MIN_VALUE (type))))
+           {
+             tree utype = unsigned_type_for (type);
+             tree to_add = chrec_convert_rhs (utype, rhs1);
+             to_add = chrec_fold_multiply (utype, to_add,
+                                           build_int_cst_type (utype, -1));
+             *evolution_of_loop
+               = chrec_convert (utype, *evolution_of_loop, at_stmt);
+             *evolution_of_loop = add_to_evolution (*evolution_of_loop,
+                                                    to_add, at_stmt);
+             *evolution_of_loop
+               = chrec_convert (type, *evolution_of_loop, at_stmt);
+           }
+         else
+           {
+             tree to_add = chrec_fold_multiply (type, rhs1,
+                                                build_minus_one_cst (type));
+             *evolution_of_loop
+               = add_to_evolution (chrec_convert (type, *evolution_of_loop,
+                                                  at_stmt),
+                                   to_add, at_stmt);
+           }
+         return res;
+       }
+      /* There is nothing to do.  */
+      return t_false;
+
     default:
       return t_false;
     }

Reply via email to