]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
match: Handle X != INT_MIN ? -X : INT_MIN [PR125050]
authorAvinal Kumar <avinal.xlvii@gmail.com>
Thu, 21 May 2026 10:24:12 +0000 (15:54 +0530)
committerAndrew Pinski <andrew.pinski@oss.qualcomm.com>
Fri, 22 May 2026 04:48:00 +0000 (21:48 -0700)
The pattern X != C1 ? -X : C2 currently bails out when C1 is
INT_MIN and the type doesn't wrap, because a signed negation
of INT_MIN is undefined behavior.  But the whole expression is
well-defined: it is equivalent to (signed)(-(unsigned)X).

Handle the wi::only_sign_bit_p case by emitting an unsigned
negate instead of giving up, mirroring what the abs pattern
already does for the same edge case.

PR tree-optimization/125050

gcc/ChangeLog:

* match.pd: (X != C1 ? -X : C2): Handle C1 being INT_MIN
by emitting (signed)(-(unsigned)X) instead of bailing out.

gcc/testsuite/ChangeLog:

* gcc.dg/fold-condneg-2.c: Update expected optimization.
* gcc.dg/pr125050.c: New test.
* gcc.dg/tree-ssa/phi-opt-50.c: New test.
* gcc.dg/tree-ssa/phi-opt-51.c: New test.

Signed-off-by: Avinal Kumar <avinal.xlvii@gmail.com>
gcc/match.pd
gcc/testsuite/gcc.dg/fold-condneg-2.c
gcc/testsuite/gcc.dg/pr125050.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/phi-opt-50.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/phi-opt-51.c [new file with mode: 0644]

index 195d10c80c73fbfa4bf03f9415038c5962d13d84..c6272c1e24ea152f3870fadfc11f8a706696b43c 100644 (file)
@@ -6755,14 +6755,18 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
 )
 #endif
 
-/* X != C1 ? -X : C2 simplifies to -X when -C1 == C2.  */
+/* X != C1 ? -X : C2 simplifies to -X when -C1 == C2.  Additionally,
+   when C1 is the minimum signed value (e.g.  INT_MIN), -X would be
+   undefined for signed types, so emit (signed)(-(unsigned)X) instead.  */
 (simplify
  (cond (ne @0 INTEGER_CST@1) (negate@3 @0) INTEGER_CST@2)
  (if (!TYPE_SATURATING (type)
-      && (TYPE_OVERFLOW_WRAPS (type)
-         || !wi::only_sign_bit_p (wi::to_wide (@1)))
       && wi::eq_p (wi::neg (wi::to_wide (@1)), wi::to_wide (@2)))
-  @3))
+  (if (TYPE_OVERFLOW_WRAPS (type)
+       || !wi::only_sign_bit_p (wi::to_wide (@1)))
+   @3
+   (with { tree utype = unsigned_type_for (TREE_TYPE (@0)); }
+    (convert (negate (convert:utype @0)))))))
 
 /* X != C1 ? ~X : C2 simplifies to ~X when ~C1 == C2.  */
 (simplify
index 1af24636ec764eedde843e4274e9bbb439aa3197..932f883a6e278165869c36c0830da499ddf4d20d 100644 (file)
@@ -8,4 +8,6 @@ int test(int x)
   return x != INT_MIN ? -x : INT_MIN;
 }
 
-/* { dg-final { scan-tree-dump "goto" "optimized" } } */
+/* The branch should now be eliminated since we emit
+   (signed)(-(unsigned)x) which is well-defined.  */
+/* { dg-final { scan-tree-dump-not "goto" "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/pr125050.c b/gcc/testsuite/gcc.dg/pr125050.c
new file mode 100644 (file)
index 0000000..5f2009a
--- /dev/null
@@ -0,0 +1,13 @@
+/* PR tree-optimization/125050 */
+/* { dg-do compile } */
+/* { dg-options "-O1 -fdump-tree-phiopt2" } */
+
+int f(int a)
+{
+  if (a == -__INT_MAX__ - 1)
+    return -__INT_MAX__ - 1;
+  return -a;
+}
+
+/* This should be converted to (int)(-(unsigned)a).  */
+/* { dg-final { scan-tree-dump-not "if " "phiopt2" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-50.c b/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-50.c
new file mode 100644 (file)
index 0000000..3cfb768
--- /dev/null
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-options "-O1 -fdump-tree-phiopt2-raw" } */
+
+/* a == INT_MIN ? INT_MIN : -a  ->  (int)(-(unsigned)a) */
+int f1(int a)
+{
+  if (a == -__INT_MAX__ - 1)
+    return -__INT_MAX__ - 1;
+  return -a;
+}
+
+/* a != INT_MIN ? -a : INT_MIN  ->  (int)(-(unsigned)a) */
+int f2(int a)
+{
+  if (a != -__INT_MAX__ - 1)
+    return -a;
+  return -__INT_MAX__ - 1;
+}
+
+/* { dg-final { scan-tree-dump-times "negate_expr" 2 "phiopt2" } } */
+/* { dg-final { scan-tree-dump-not "gimple_cond <" "phiopt2" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-51.c b/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-51.c
new file mode 100644 (file)
index 0000000..6c5809f
--- /dev/null
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-options "-O1 -fdump-tree-phiopt2-raw" } */
+
+/* Try the same pattern with different integer types.  */
+
+long f_long(long a)
+{
+  if (a == -__LONG_MAX__ - 1)
+    return -__LONG_MAX__ - 1;
+  return -a;
+}
+
+long long f_ll(long long a)
+{
+  if (a == -__LONG_LONG_MAX__ - 1)
+    return -__LONG_LONG_MAX__ - 1;
+  return -a;
+}
+
+/* { dg-final { scan-tree-dump-times "negate_expr" 2 "phiopt2" } } */
+/* { dg-final { scan-tree-dump-not "gimple_cond <" "phiopt2" } } */