https://gcc.gnu.org/g:238d2fc116cdef31c3d643e71ade0875b5cba110

commit r16-7183-g238d2fc116cdef31c3d643e71ade0875b5cba110
Author: Jakub Jelinek <[email protected]>
Date:   Fri Jan 30 11:42:41 2026 +0100

    match.pd: Fix up __imag__ .MUL_OVERFLOW simplification [PR123864]
    
    The integer_minus_onep case is really meant for multiplication by
    -1, not by (unsigned char)0xff or (unsigned short)0xffff or 0xffffffffU etc.
    We've already tested that the first operand is signed (otherwise the
    earlier case is used) and also that int_fits_type_p (@1, TREE_TYPE (@0)),
    but if @0 is signed and @1 is unsigned all ones with smaller precision
    than that, it fits into @0's type, integer_minus_onep will be true
    and it still should be handled through the ranges, not as @0 == min.
    
    2026-01-30  Jakub Jelinek  <[email protected]>
    
            PR tree-optimization/123864
            * match.pd (__builtin_mul_overflow_p (x, cst, (stype) 0) ->
            x > stype_max / cst || x < stype_min / cst): Only check
            integer_minus_onep for signed types.
    
            * gcc.c-torture/execute/pr123864.c: New test.
            * gcc.dg/torture/pr123864.c: New test.

Diff:
---
 gcc/match.pd                                   |  2 +-
 gcc/testsuite/gcc.c-torture/execute/pr123864.c | 24 ++++++++++++++++++++++
 gcc/testsuite/gcc.dg/torture/pr123864.c        | 28 ++++++++++++++++++++++++++
 3 files changed, 53 insertions(+), 1 deletion(-)

diff --git a/gcc/match.pd b/gcc/match.pd
index 75511c459fa2..05e8ea7a229d 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -8798,7 +8798,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
    (if (TYPE_UNSIGNED (TREE_TYPE (@0)))
     (convert (gt @0 (trunc_div! { TYPE_MAX_VALUE (TREE_TYPE (@0)); } @1)))
     (if (TYPE_MIN_VALUE (TREE_TYPE (@0)))
-     (if (integer_minus_onep (@1))
+     (if (!TYPE_UNSIGNED (TREE_TYPE (@1)) && integer_minus_onep (@1))
       (convert (eq @0 { TYPE_MIN_VALUE (TREE_TYPE (@0)); }))
       (with
        {
diff --git a/gcc/testsuite/gcc.c-torture/execute/pr123864.c 
b/gcc/testsuite/gcc.c-torture/execute/pr123864.c
new file mode 100644
index 000000000000..c70d1ca823f3
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/execute/pr123864.c
@@ -0,0 +1,24 @@
+/* PR tree-optimization/123864 */
+
+[[gnu::noipa]] static int
+foo (long long x)
+{
+  return __builtin_mul_overflow_p (x, ~0U, x);
+}
+
+int
+main ()
+{
+  if (foo (0))
+    __builtin_abort ();
+#if __SIZEOF_INT__ == 4 && __SIZEOF_LONG_LONG__ == 8 && __CHAR_BIT__ == 8
+  if (foo (__INT_MAX__ + 1LL))
+    __builtin_abort ();
+  if (!foo (__INT_MAX__ + 2LL))
+    __builtin_abort ();
+  if (foo (-__INT_MAX__ - 1LL))
+    __builtin_abort ();
+  if (!foo (-__INT_MAX__ - 2LL))
+    __builtin_abort ();
+#endif
+}
diff --git a/gcc/testsuite/gcc.dg/torture/pr123864.c 
b/gcc/testsuite/gcc.dg/torture/pr123864.c
new file mode 100644
index 000000000000..8f2e375db926
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/pr123864.c
@@ -0,0 +1,28 @@
+/* PR tree-optimization/123864 */
+/* { dg-do run { target int128 } } */
+
+int u, v, x;
+
+[[gnu::noipa]] static void
+foo ()
+{
+  __int128 c = (__int128) 0xa5ee4bc88ULL << 64;
+  long long b = 0x207b8a7f7LL;
+  int a = 4;
+  long long y;
+  __builtin_add_overflow (a, v, &y);
+  c *= y;
+  
+  unsigned z;
+  if (__builtin_add_overflow (b, u, &z))
+    z = 0xffffffffU;
+  x = __builtin_mul_overflow_p (z, c, c);
+}
+
+int
+main ()
+{
+  foo ();
+  if (!x)
+    __builtin_abort ();
+}

Reply via email to