On Thu, Aug 13, 2026 at 7:20 PM Shreesh Adiga
<[email protected]> wrote:
>
>
>
> On Thu, Aug 13, 2026 at 11:12 PM Andrea Pinski 
> <[email protected]> wrote:
>>
>> On Thu, Aug 13, 2026 at 10:37 AM Shreesh Adiga
>> <[email protected]> wrote:
>> >
>> > This avoids unnecessary moves when either the initial CRC
>> > value or the data operand is a constant zero. For example:
>> > __crc32w(0, x) previously generated "mov w1, 0; crc32w w0, w1, w0"
>> > whereas now it generates "crc32w w0, wzr, w0".
>> >
>> > gcc/ChangeLog:
>> >
>> >         * config/aarch64/aarch64.md: allow usage of zero reg for CRC32
>> >         instructions
>> >
>> > gcc/testsuite/ChangeLog:
>> >
>> >         * gcc.target/aarch64/crc32-zero.c: New test.
>> >
>> > Signed-off-by: Shreesh Adiga <[email protected]>
>> > ---
>> > Changes in v2:
>> >         Added new tests in crc32-zero.c which covers various crc32
>> >         instructions with 0 value for one or both source operands.
>> >
>> >  gcc/config/aarch64/aarch64.md                 |   4 +-
>> >  gcc/testsuite/gcc.target/aarch64/crc32-zero.c | 180 ++++++++++++++++++
>> >  2 files changed, 182 insertions(+), 2 deletions(-)
>> >  create mode 100644 gcc/testsuite/gcc.target/aarch64/crc32-zero.c
>> >
>> > diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md
>> > index 9cb55602c36..9f26e558e48 100644
>> > --- a/gcc/config/aarch64/aarch64.md
>> > +++ b/gcc/config/aarch64/aarch64.md
>> > @@ -4959,8 +4959,8 @@ (define_expand "<neg_not_op><mode>cc"
>> >  ;; CRC32 instructions.
>> >  (define_insn "aarch64_<crc_variant>"
>> >    [(set (match_operand:SI 0 "register_operand" "=r")
>> > -        (unspec:SI [(match_operand:SI 1 "register_operand" "r")
>> > -                    (match_operand:<crc_mode> 2 "register_operand" "r")]
>> > +       (unspec:SI [(match_operand:SI 1 "aarch64_reg_or_zero" "rZ")
>> > +                   (match_operand:<crc_mode> 2 "aarch64_reg_or_zero" 
>> > "rZ")]
>> >           CRC))]
>> >    "TARGET_CRC32"
>> >    {
>> > diff --git a/gcc/testsuite/gcc.target/aarch64/crc32-zero.c 
>> > b/gcc/testsuite/gcc.target/aarch64/crc32-zero.c
>> > new file mode 100644
>> > index 00000000000..b256dd0858a
>> > --- /dev/null
>> > +++ b/gcc/testsuite/gcc.target/aarch64/crc32-zero.c
>> > @@ -0,0 +1,180 @@
>> > +/* { dg-do compile } */
>> > +/* { dg-options "-O2 -march=armv8-a+crc" } */
>> > +
>> > +typedef unsigned int uint32_t;
>> > +typedef unsigned long long uint64_t;
>> > +typedef unsigned short uint16_t;
>> > +typedef unsigned char uint8_t;
>> > +
>> > +uint32_t
>> > +crc32cb_init_zero(uint16_t x)
>> > +{
>> > +  return __builtin_aarch64_crc32cb(0, x);
>> > +}
>> > +
>> > +uint32_t
>> > +crc32cb_data_zero(uint32_t x)
>> > +{
>> > +  return __builtin_aarch64_crc32cb(x, 0);
>> > +}
>> > +
>> > +uint32_t
>> > +crc32cb_both_zero(void)
>> > +{
>> > +  return __builtin_aarch64_crc32cb(0, 0);
>> > +}
>> > +
>> > +uint32_t
>> > +crc32ch_init_zero(uint16_t x)
>> > +{
>> > +  return __builtin_aarch64_crc32ch(0, x);
>> > +}
>> > +
>> > +uint32_t
>> > +crc32ch_data_zero(uint32_t x)
>> > +{
>> > +  return __builtin_aarch64_crc32ch(x, 0);
>> > +}
>> > +
>> > +uint32_t
>> > +crc32ch_both_zero(void)
>> > +{
>> > +  return __builtin_aarch64_crc32ch(0, 0);
>> > +}
>> > +
>> > +uint32_t
>> > +crc32cw_init_zero(uint32_t x)
>> > +{
>> > +  return __builtin_aarch64_crc32cw(0, x);
>> > +}
>> > +
>> > +uint32_t
>> > +crc32cw_data_zero(uint32_t x)
>> > +{
>> > +  return __builtin_aarch64_crc32cw(x, 0);
>> > +}
>> > +
>> > +uint32_t
>> > +crc32cw_both_zero(void)
>> > +{
>> > +  return __builtin_aarch64_crc32cw(0, 0);
>> > +}
>> > +
>> > +uint32_t
>> > +crc32cx_data_zero(uint32_t x)
>> > +{
>> > +  return __builtin_aarch64_crc32cx(x, 0);
>> > +}
>> > +
>> > +uint32_t
>> > +crc32cx_init_zero64(uint64_t x)
>> > +{
>> > +  return __builtin_aarch64_crc32cx(0, x);
>> > +}
>> > +
>> > +uint32_t
>> > +crc32cx_both_zero64(void)
>> > +{
>> > +  return __builtin_aarch64_crc32cx(0, 0);
>> > +}
>> > +
>> > +uint32_t
>> > +crc32b_init_zero(uint16_t x)
>> > +{
>> > +  return __builtin_aarch64_crc32b(0, x);
>> > +}
>> > +
>> > +uint32_t
>> > +crc32b_data_zero(uint32_t x)
>> > +{
>> > +  return __builtin_aarch64_crc32b(x, 0);
>> > +}
>> > +
>> > +uint32_t
>> > +crc32b_both_zero(void)
>> > +{
>> > +  return __builtin_aarch64_crc32b(0, 0);
>> > +}
>> > +
>> > +uint32_t
>> > +crc32h_init_zero(uint16_t x)
>> > +{
>> > +  return __builtin_aarch64_crc32h(0, x);
>> > +}
>> > +
>> > +uint32_t
>> > +crc32h_data_zero(uint32_t x)
>> > +{
>> > +  return __builtin_aarch64_crc32h(x, 0);
>> > +}
>> > +
>> > +uint32_t
>> > +crc32h_both_zero(void)
>> > +{
>> > +  return __builtin_aarch64_crc32h(0, 0);
>> > +}
>> > +
>> > +uint32_t
>> > +crc32w_init_zero(uint32_t x)
>> > +{
>> > +  return __builtin_aarch64_crc32w(0, x);
>> > +}
>> > +
>> > +uint32_t
>> > +crc32w_data_zero(uint32_t x)
>> > +{
>> > +  return __builtin_aarch64_crc32w(x, 0);
>> > +}
>> > +
>> > +uint32_t
>> > +crc32w_both_zero(void)
>> > +{
>> > +  return __builtin_aarch64_crc32w(0, 0);
>> > +}
>> > +
>> > +uint32_t
>> > +crc32x_data_zero(uint32_t x)
>> > +{
>> > +  return __builtin_aarch64_crc32x(x, 0);
>> > +}
>> > +
>> > +uint32_t
>> > +crc32x_init_zero64(uint64_t x)
>> > +{
>> > +  return __builtin_aarch64_crc32x(0, x);
>> > +}
>> > +
>> > +uint32_t
>> > +crc32x_both_zero64(void)
>> > +{
>> > +  return __builtin_aarch64_crc32x(0, 0);
>> > +}
>> > +
>> > +/* { dg-final { scan-assembler-times "crc32b\tw\[0-9\]+, wzr, w\[0-9\]+" 
>> > 1 } } */
>> > +/* { dg-final { scan-assembler-times "crc32h\tw\[0-9\]+, wzr, w\[0-9\]+" 
>> > 1 } } */
>> > +/* { dg-final { scan-assembler-times "crc32w\tw\[0-9\]+, wzr, w\[0-9\]+" 
>> > 1 } } */
>> > +/* { dg-final { scan-assembler-times "crc32x\tw\[0-9\]+, wzr, x\[0-9\]+" 
>> > 1 } } */
>> > +/* { dg-final { scan-assembler-times "crc32b\tw\[0-9\]+, w\[0-9\]+, wzr" 
>> > 1 } } */
>> > +/* { dg-final { scan-assembler-times "crc32h\tw\[0-9\]+, w\[0-9\]+, wzr" 
>> > 1 } } */
>> > +/* { dg-final { scan-assembler-times "crc32w\tw\[0-9\]+, w\[0-9\]+, wzr" 
>> > 1 } } */
>> > +/* { dg-final { scan-assembler-times "crc32x\tw\[0-9\]+, w\[0-9\]+, xzr" 
>> > 1 } } */
>> > +/* { dg-final { scan-assembler-times "crc32b\tw\[0-9\]+, wzr, wzr" 1 } } 
>> > */
>> > +/* { dg-final { scan-assembler-times "crc32h\tw\[0-9\]+, wzr, wzr" 1 } } 
>> > */
>> > +/* { dg-final { scan-assembler-times "crc32w\tw\[0-9\]+, wzr, wzr" 1 } } 
>> > */
>> > +/* { dg-final { scan-assembler-times "crc32x\tw\[0-9\]+, wzr, xzr" 1 } } 
>> > */
>> > +/* { dg-final { scan-assembler-times "crc32cb\tw\[0-9\]+, wzr, w\[0-9\]+" 
>> > 1 } } */
>> > +/* { dg-final { scan-assembler-times "crc32ch\tw\[0-9\]+, wzr, w\[0-9\]+" 
>> > 1 } } */
>> > +/* { dg-final { scan-assembler-times "crc32cw\tw\[0-9\]+, wzr, w\[0-9\]+" 
>> > 1 } } */
>> > +/* { dg-final { scan-assembler-times "crc32cx\tw\[0-9\]+, wzr, x\[0-9\]+" 
>> > 1 } } */
>> > +/* { dg-final { scan-assembler-times "crc32cb\tw\[0-9\]+, w\[0-9\]+, wzr" 
>> > 1 } } */
>> > +/* { dg-final { scan-assembler-times "crc32ch\tw\[0-9\]+, w\[0-9\]+, wzr" 
>> > 1 } } */
>> > +/* { dg-final { scan-assembler-times "crc32cw\tw\[0-9\]+, w\[0-9\]+, wzr" 
>> > 1 } } */
>> > +/* { dg-final { scan-assembler-times "crc32cx\tw\[0-9\]+, w\[0-9\]+, xzr" 
>> > 1 } } */
>> > +/* { dg-final { scan-assembler-times "crc32cb\tw\[0-9\]+, wzr, wzr" 1 } } 
>> > */
>> > +/* { dg-final { scan-assembler-times "crc32ch\tw\[0-9\]+, wzr, wzr" 1 } } 
>> > */
>> > +/* { dg-final { scan-assembler-times "crc32cw\tw\[0-9\]+, wzr, wzr" 1 } } 
>> > */
>> > +/* { dg-final { scan-assembler-times "crc32cx\tw\[0-9\]+, wzr, xzr" 1 } } 
>> > */
>> > +/* { dg-final { scan-assembler-not "mov\tw\[0-9\]+, wzr" } } */
>> > +/* { dg-final { scan-assembler-not "mov\tx\[0-9\]+, xzr" } } */
>> > +/* { dg-final { scan-assembler-not "mov\tw\[0-9\]+, 0" } } */
>> > +/* { dg-final { scan-assembler-not "mov\tx\[0-9\]+, 0" } } */
>>
>> The last 4 scan-assmbler-not could be written as 2 instead:
>> /* { dg-final { scan-assembler-not "mov\t\[xw\]\[0-9\]+, wzr" } } */
>> /* { dg-final { scan-assembler-not "mov\t\[xw\]\[0-9\]+, 0" } } */
>>
>> And a comment right before these last ones would be good.
>> Something like:
>> There should be no moves to a register for zero as it is part of the crc now.
>>
>> > --
>> > 2.54.0
>> >
>
>
> Sure I will update and send a new patch later.
>
> One more thing I was wondering about is to change "__crc32(0, 0)" to "mov 
> <reg>, 0"
> since it is mathematically equivalent to 0 and would be cheaper.
> Currently it is emitted as crc instruction with both zero reg operand after 
> this patch.
> Just wanted some feedback on whether this is a good idea and would like to 
> know
> the high level approach on how to incorporate this change as I am new to GCC
> (and compilers).

Part of that is recorded in
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120720 .
Adding constant folding of __builtin_{rev_,}crc32_data* should be easy.
Changing __builtin_aarch64_crc32x and others to be the other builtins
is not hard. And then those 2 combined together will allow for the
constant folding.

>
> Thanks,
> Shreesh

Reply via email to