https://gcc.gnu.org/g:392fd9cd9db00d174bf3e2bcf62ef2df47bd1e5a

commit r17-5340-g392fd9cd9db00d174bf3e2bcf62ef2df47bd1e5a
Author: Kyrylo Tkachov <[email protected]>
Date:   Fri Oct 9 08:41:00 2026 -0700

    match.pd: Fix the CTZ compare fold for a value at zero below the constant
    
    For 0 < C < prec the fold
    
      .CTZ (x, V) >= C -> (x & ((1 << C) - 1)) == 0
      .CTZ (x, V) < C -> (x & ((1 << C) - 1)) != 0
    
    applies when V < 0 or V >= prec.  For x = 0 the bit test is true, so the
    fold is correct only if V >= C.  For
    
      _1 = .CTZ (x_4(D), -1);
      _2 = _1 >= 3;
    
    and x = 0, _2 is 0, but the fold gives
    
      _5 = x_4(D) & 7;
      _2 = _5 == 0;
    
    which is 1.  gcn, and rs6000 without TARGET_CTZ and TARGET_POPCNTD,
    define -1 as the value at zero, so __builtin_ctzg (x, -1) >= 3 is
    miscompiled there.  The condition comes from r12-151 (PR95527).
    
    Fold only if V >= C.
    
    Bootstrapped and tested on aarch64-none-linux-gnu and x86_64-linux.
    
    gcc/ChangeLog:
    
            * match.pd (.CTZ (x, V) >= C -> (x & ((1 << C) - 1)) == 0):
            Require that the value at zero is at least C.
    
    gcc/testsuite/ChangeLog:
    
            * gcc.dg/tree-ssa/ctz-cmp-value-at-zero-1.c: New test.
    
    Signed-off-by: Kyrylo Tkachov <[email protected]>

Diff:
---
 gcc/match.pd                                       |  2 +-
 .../gcc.dg/tree-ssa/ctz-cmp-value-at-zero-1.c      | 69 ++++++++++++++++++++++
 2 files changed, 70 insertions(+), 1 deletion(-)

diff --git a/gcc/match.pd b/gcc/match.pd
index a341669bf69a..2adb45c50dea 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -11444,7 +11444,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
       (if (val >= prec)
        (if (ok && zero_val < val)
        { constant_boolean_node (cmp != EQ_EXPR, type); })
-       (if (ok && (zero_val < 0 || zero_val >= prec))
+       (if (ok && zero_val >= val)
        (cmp (bit_and @0 { wide_int_to_tree (type0,
                                             wi::mask (val, false, prec)); })
             { build_zero_cst (type0); })))))))
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ctz-cmp-value-at-zero-1.c 
b/gcc/testsuite/gcc.dg/tree-ssa/ctz-cmp-value-at-zero-1.c
new file mode 100644
index 000000000000..777885063926
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ctz-cmp-value-at-zero-1.c
@@ -0,0 +1,69 @@
+/* .CTZ (X, V) >= C becomes (X & ((1 << C) - 1)) == 0 only if V >= C,
+   because the bit test is true for X = 0.  */
+/* { dg-do compile } */
+/* { dg-require-effective-target int32 } */
+/* { dg-require-effective-target ctzsi } */
+/* { dg-options "-O2 -fgimple -fdump-tree-optimized" } */
+
+/* .CTZ (0, -1) is -1, which is smaller than 3.  */
+
+int __GIMPLE (ssa)
+gem1 (unsigned int x)
+{
+  int _1;
+  _Bool _2;
+  int _3;
+
+  __BB(2):
+  _1 = .CTZ (x_4(D), -1);
+  _2 = _1 >= 3;
+  _3 = (int) _2;
+  return _3;
+}
+
+int __GIMPLE (ssa)
+ltm1 (unsigned int x)
+{
+  int _1;
+  _Bool _2;
+  int _3;
+
+  __BB(2):
+  _1 = .CTZ (x_4(D), -1);
+  _2 = _1 < 3;
+  _3 = (int) _2;
+  return _3;
+}
+
+/* .CTZ (0, 32) is 32, which is not smaller than 3.  */
+
+int __GIMPLE (ssa)
+ge32 (unsigned int x)
+{
+  int _1;
+  _Bool _2;
+  int _3;
+
+  __BB(2):
+  _1 = .CTZ (x_4(D), 32);
+  _2 = _1 >= 3;
+  _3 = (int) _2;
+  return _3;
+}
+
+int __GIMPLE (ssa)
+lt32 (unsigned int x)
+{
+  int _1;
+  _Bool _2;
+  int _3;
+
+  __BB(2):
+  _1 = .CTZ (x_4(D), 32);
+  _2 = _1 < 3;
+  _3 = (int) _2;
+  return _3;
+}
+
+/* { dg-final { scan-tree-dump-times "\\.CTZ" 2 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " & 7;" 2 "optimized" } } */

Reply via email to