Re: [PATCH v2] aarch64: allow usage of zero reg for CRC32 instructions
Shreesh Adiga <[email protected]>
| Newsgroups | gmane.comp.gcc.patches |
|---|---|
| Message-ID | <CA+-x59agUioBn+OJiUf1ri9VBfM96UHZCuAKdwqym+pH10n_DA@mail.gmail.com> |
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). Thanks, Shreesh