Re: [PATCH v2] aarch64: allow usage of zero reg for CRC32 instructions

Andrea Pinski <[email protected]>
Newsgroups gmane.comp.gcc.patches
Message-ID <CALvbMcBquREdtpT2vTEPvV5GLbvvD11bBQHsWABUDi65GkKceQ@mail.gmail.com>
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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.