https://gcc.gnu.org/bugzilla/show_bug.cgi?id=127853
--- Comment #6 from Vineet Gupta <vineetg at gcc dot gnu.org> ---
(In reply to Jakub Jelinek from comment #4)
> I think we need
> --- a/gcc/tree-ssa-forwprop.cc 2026-10-02 22:28:59.195109574 +0200
> +++ b/gcc/tree-ssa-forwprop.cc 2026-10-12 14:47:37.704649342 +0200
> @@ -3530,7 +3530,7 @@ simplify_count_zeroes (gimple_stmt_itera
> ctz_val) == 2;
> zero_val = input_bits - 1 - zero_val;
> }
> - int nargs = 2;
> + int nargs = 1 + zero_ok;
My version has slightly different code but equivalent code.
+ int nargs = zero_ok ? 2 : 1;
> @@ -3543,7 +3543,6 @@ simplify_count_zeroes (gimple_stmt_itera
> zero_ok = true;
> zero_val = 0;
> ctz_val = 0;
> - nargs = 1;
> }
I think this needs to stay:
that branch resets ctz_val to 0, so with BMI/LZCNT (zero_ok from the macro) the
call becomes .CTZ (x, 0), claiming ctz (0) == 0 while the insn gives 32.
Consider the test below at -O2 -mbmi:
```
static const unsigned char T[32] = {
0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9
};
__attribute__((noipa)) unsigned h (unsigned v)
{
if (v)
return T[((v & -v) * 0x077CB531U) >> 27];
return 0;
}
```
With the "nargs = 1;" removed, forwprop1 gives
if (v_7(D) != 0) ... _8 = .CTZ (v_7(D), 0);
phiopt2: Applying pattern match.pd:11839, then just .CTZ (v_3(D), 0):
h:
xorl %eax, %eax
tzcntl %edi, %eax
ret
so h (0) returns 32 instead of 0.
Keeping "nargs = 1;" there .CTZ (v_7(D)), the guard survives, h (0) == 0.