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" } } */
