[gcc r16-9382] tree-optimization/126171 - SCEV and minus of INT_MIN

Richard Biener via Gcc-cvs <[email protected]>
Newsgroups gmane.comp.gcc.cvs
Message-ID <[email protected]>
https://gcc.gnu.org/g:a32b49435b4e3d6bb2510197f2ee4b3ff887cd62

commit r16-9382-ga32b49435b4e3d6bb2510197f2ee4b3ff887cd62
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.
    
    (cherry picked from commit 2fcbe075ec3b32f4a523ebae68a8a32381bb46a9)

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 5076ce446c13..dcbec9c7a87b 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;
     }
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.