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 v3:
        Modified the test to combine the regex and added comment about
        mov zero to register as per suggestion.
 gcc/config/aarch64/aarch64.md                 |   4 +-
 gcc/testsuite/gcc.target/aarch64/crc32-zero.c | 182 ++++++++++++++++++
 2 files changed, 184 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..4c5bdbef7e1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/crc32-zero.c
@@ -0,0 +1,182 @@
+/* { 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 } } */
+
+/* There should be no moves to a register for zero as it is part of the
+ * crc instruction now.
+ */
+/* { dg-final { scan-assembler-not "mov\t\[wx\]\[0-9\]+, \[wx\]zr" } } */
+/* { dg-final { scan-assembler-not "mov\t\[wx\]\[0-9\]+, 0" } } */
--
2.54.0

Reply via email to