On Sun, Aug 23, 2026 at 8:36 PM Jeffrey Law
<[email protected]> wrote:
>
>
>
> On 8/13/2026 4:03 AM, Milan Tripkovic wrote:
> > This patch fixes PR123905, where the compiler generates redundant sign
> > Extensions and bit masks on RISC-V when using __builtin_clz, __builtin_ctz
> > and __builtin_popcount.
> >
> > To solve this, the patch introduces the following changes based on
> > Jeff's suggestions:
> >
> > ext-dce.cc: Extracted the redundant sign extension check into a new helper
> > function is_trivially_redundant_extension. This uses num_sign_bit_copies
> > evaluated in the outer mode to check if the extension is already
> > redundant,
> > which allows combine to eliminate it instead of ext-dce leaving SUBREGs
> > that are harder to optimize.
> >
> > rtlanal.cc: Improve nonzero_bits1 and num_sign_bit_copies1 so that
> > they recognize that the results of CLZ, CTZ, and POPCOUNT are
> > bounded by floor_log2 (bitwidth) + 1 bits, meaning that all higher
> > bits are known to be zero.
> >
> > ASM Before:
> > clzw a0,a0
> > andn t0,a0,a1
> > sext.w a0,t0
> > ret
> >
> > ASM After:
> > clzw  a0,a0
> > andn  a0,a0,a1
> > ret
> >
> > Additionally, this patch includes a new test case
> > gcc.target/riscv/pr123905.c
> > which covers several scenarios: AND, ANDN, and combinations like clz & ctz
> > and clz & ctz & popcount.
> >
> > 2026-08-13  Milan Tripkovic  <[email protected]>
> >
> > gcc/ChangeLog:
> >
> > * ext-dce.cc (is_trivially_redundant_extension): New helper
> > function.
> > (ext_dce_try_optimize_extension): Keep trivially redundant
> > SIGN_EXTENDs.
> > * rtlanal.cc (nonzero_bits1): Handle POPCOUNT/CLZ/CTZ.
> > (num_sign_bit_copies1): Add CLZ/CTZ/POPCOUNT handling.
> >
> > gcc/testsuite/ChangeLog:
> >
> > * gcc.target/riscv/pr123905.c: New test case.
> Conceptually it looks good.  Since this is a generic change, it needs to
> be bootstrapped and regression tested on at least one major platform.
> Most folks use x86_64 or aarch64.
>
> I threw it into my tester to do some broader testing and it failed to
> build on x86_64:
>
> > x86_64-linux-gnu-g++ -std=c++14  -fno-PIE -c    -DIN_GCC
> > -fno-exceptions -fno-rtti -fasynchronous-unwind-tables -W -Wall
> > -Wno-error=narrowing -Wwrite-strings -Wcast-qual -Wno-format
> > -Wmissing-format-attribute -Wconditionally-supported
> > -Woverloaded-virtual -pedantic -Wno-long-long -Wno-variadic-macros
> > -Wno-overlength-strings -DHAVE_CONFIG_H -fno-PIE -I. -I.
> > -I../../../gcc/gcc -I../../../gcc/gcc/. -I../../../gcc/gcc/../include
> > -I../../../gcc/gcc/../libcpp/include -I../../../gcc/gcc/../libcody
> > -I../../../gcc/gcc/../libdecnumber
> > -I../../../gcc/gcc/../libdecnumber/bid -I../libdecnumber
> > -I../../../gcc/gcc/../libbacktrace   -o rtlanal.o -MT rtlanal.o -MMD
> > -MP -MF ./.deps/rtlanal.TPo ../../../gcc/gcc/rtlanal.cc
> > In file included from ./tm.h:29,
> >                  from ../../../gcc/gcc/backend.h:28,
> >                  from ../../../gcc/gcc/rtlanal.cc:24:
> > ../../../gcc/gcc/rtlanal.cc: In function 'long unsigned int
> > nonzero_bits1(const_rtx, scalar_int_mode, const_rtx, machine_mode,
> > long unsigned int)':
> > ../../../gcc/gcc/config/i386/i386.h:3059:37: error: cannot convert
> > 'poly_uint16' {aka 'poly_int<1, short unsigned int>'} to 'long int' in
> > assignment
> >  3059 |         ((VALUE) = GET_MODE_BITSIZE (MODE), TARGET_LZCNT ? 2 : 0)
> >       |                    ~~~~~~~~~~~~~~~~~^~~~~~
> >       |                                     |
> >       |                                     poly_uint16 {aka
> > poly_int<1, short unsigned int>}
> > ../../../gcc/gcc/rtlanal.cc:5238:32: note: in expansion of macro
> > 'CLZ_DEFINED_VALUE_AT_ZERO'
> >  5238 |             if (code == CLZ && CLZ_DEFINED_VALUE_AT_ZERO
> > (op_mode, val_at_zero))
> >       |                                ^~~~~~~~~~~~~~~~~~~~~~~~~
> > ../../../gcc/gcc/config/i386/i386.h:3057:37: error: cannot convert
> > 'poly_uint16' {aka 'poly_int<1, short unsigned int>'} to 'long int' in
> > assignment
> >  3057 |         ((VALUE) = GET_MODE_BITSIZE (MODE), TARGET_BMI ? 2 : 0)
> >       |                    ~~~~~~~~~~~~~~~~~^~~~~~
> >       |                                     |
> >       |                                     poly_uint16 {aka
> > poly_int<1, short unsigned int>}
> > ../../../gcc/gcc/rtlanal.cc:5241:20: note: in expansion of macro
> > 'CTZ_DEFINED_VALUE_AT_ZERO'
> >  5241 |                 && CTZ_DEFINED_VALUE_AT_ZERO (op_mode,
> > val_at_zero))
> >       |                    ^~~~~~~~~~~~~~~~~~~~~~~~~
> > make: *** [Makefile:1218: rtlanal.o] Error 1
>
> So there's still a bit of work to do, but it looks to be on the right
> track to me.


What most other places that use CLZ_DEFINED_VALUE_AT_ZERO is just int
type for the val argument rather of CLZ_DEFINED_VALUE_AT_ZERO than
HOST_WIDE_INT.
Why using HWI here does not work is a good question though.  Because
poly_int<1, short unsigned int> should be able to convert to long just
fine, for `NUM_POLY_INT_COEFFS == 1` targets (x86_64 should be that),
there should be an `operator short unsigned` as part of poly_int<1,
short unsigned int>.

Maybe there is something I am missing now.

>
> jeff

Reply via email to