https://gcc.gnu.org/g:84fddf4484bb948049a2f39280da2d107b068e9f

commit r17-5508-g84fddf4484bb948049a2f39280da2d107b068e9f
Author: Loeka Rogge <[email protected]>
Date:   Fri Oct 23 07:27:32 2026 -0600

    RISC-V: Use clmulr for reversed crc64 on rv64
    
    This removes the guards that disables the clmulr pattern added by
    patch r17-4206-ge91f79891fc657: Use clmulr for reversed crc32 on rv32
    from being used on rv64.
    
    This changes the calculation of the reflected quotient (on the host) to
    fit inside 64 bits. gf2n_poly_long_div_quotient calculates
    x^128 / (x^64 + lower order terms) = x^64 + lower order terms.
    Meaning the result is missing an implicit 1 in front of the msb.
    
    After reversing, this missing 1 should be after the lsb. This is
    re-added with a shift and an or. This causes the msb to fall outside
    the result stored in t0.
    
    The value in t0 is only used by the emitted clmul or vclmul
    instructions. Clmul only emits the bottom 64 bits, representing x^63 and
    lower order terms. This is unaffected by the missing bit that
    represents x^64, because it would always fall outside the result.
    
    Regtested on rv32gc, rv32gc_zbc, rv64gc, and rv64gc_zbc.
    
    gcc/ChangeLog:
    
            * config/riscv/bitmanip.md (crc_rev<ANYI1:mode><ANYI:mode>4):
            Remove 64 bit guard.
            * config/riscv/riscv.cc (riscv_optab_supported_p): Likewise.
            64 bit guard.
            (expand_reversed_crc_using_clmul): Adapt quotient calculation
            for 65 bits.
    
    gcc/testsuite/ChangeLog:
    
            * gcc.target/riscv/crc-builtin-zbc64.c: test whether clmulr is
            applied for crc64
            * gcc.target/riscv/crc-rev-crc64-rv64-zbc.c: New test.
    
    Signed-off-by: Loeka Rogge <[email protected]>

Diff:
---
 gcc/config/riscv/bitmanip.md                       |  5 ++-
 gcc/config/riscv/riscv.cc                          | 36 +++++++++++----
 gcc/testsuite/gcc.target/riscv/crc-builtin-zbc64.c | 23 +++++++++-
 .../gcc.target/riscv/crc-rev-crc64-rv64-zbc.c      | 51 ++++++++++++++++++++++
 4 files changed, 103 insertions(+), 12 deletions(-)

diff --git a/gcc/config/riscv/bitmanip.md b/gcc/config/riscv/bitmanip.md
index 52cf0fccd8a1..b18d4c8e5c6f 100644
--- a/gcc/config/riscv/bitmanip.md
+++ b/gcc/config/riscv/bitmanip.md
@@ -1375,10 +1375,11 @@
      (E.g.  CRC64's quotient may need 65 bits,
      we can't keep it in 64 bit variable.)
      then use clmul instruction to implement the CRC.
-     We can also use clmulr for CRC-32 on RV32, requiring ZBC.  */
+     If we have the ZBC extension (ie, clmulr) 1 bit can be left
+     implicit, allowing CRC64 using a 64 bit variable.  */
   if (((TARGET_ZBKC || TARGET_ZBC || TARGET_ZVBC)
        && <ANYI:MODE>mode < word_mode)
-      || (!TARGET_64BIT && TARGET_ZBC && <ANYI:MODE>mode == word_mode))
+      || (TARGET_ZBC && <ANYI:MODE>mode == word_mode))
     expand_reversed_crc_using_clmul (<ANYI:MODE>mode, <ANYI1:MODE>mode,
                                     operands);
   else
diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index 47b20b8cdb4a..ec3a03421962 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -13534,7 +13534,7 @@ riscv_optab_supported_p (int op, machine_mode, 
machine_mode result_mode,
   if (op == crc_rev_optab && opt_type != OPTIMIZE_FOR_SPEED)
     return (((TARGET_ZBKC || TARGET_ZBC || TARGET_ZVBC)
             && result_mode < word_mode)
-           || (!TARGET_64BIT && TARGET_ZBC && result_mode == word_mode));
+           || (TARGET_ZBC && result_mode == word_mode));
 
   return true;
 }
@@ -15978,15 +15978,31 @@ expand_reversed_crc_using_clmul (scalar_mode 
crc_mode, scalar_mode data_mode,
   gcc_assert (!CONST_INT_P (operands[0]));
   gcc_assert (CONST_INT_P (operands[3]));
   unsigned short crc_size = GET_MODE_BITSIZE (crc_mode);
-  gcc_assert (crc_size <= 32);
+  gcc_assert (crc_size <= BITS_PER_WORD);
   unsigned short data_size = GET_MODE_BITSIZE (data_mode);
   rtx polynomial = operands[3];
 
-  /* Calculate the quotient.  */
-  unsigned HOST_WIDE_INT
-  q = gf2n_poly_long_div_quotient (UINTVAL (polynomial), crc_size);
-  /* Reflect the calculated quotient.  */
-  q = reflect_hwi (q, crc_size + 1);
+  unsigned HOST_WIDE_INT q;
+  if (crc_size == 64)
+    {
+      /* Calculate the quotient.
+       x^64 is left implicit at the msb to fit in 64 bits.  */
+      q = gf2n_poly_long_div_quotient (UINTVAL (polynomial), crc_size);
+      /* Reflect the calculated quotient.
+       Implicit bit is now missing at the lsb.  */
+      q = reflect_hwi (q, crc_size);
+      /* Add the implicit bit back at the lsb.
+       This is okay because the extra bit falls outside the 64 lsbs output
+       by clmul.  */
+      q = (q << 1) | 1;
+    }
+  else
+    {
+      /* Calculate the quotient.  */
+      q = gf2n_poly_long_div_quotient (UINTVAL (polynomial), crc_size);
+      /* Reflect the calculated quotient.  */
+      q = reflect_hwi (q, crc_size + 1);
+    }
   rtx t0 = gen_reg_rtx (word_mode);
   riscv_emit_move (t0, gen_int_mode (q, word_mode));
 
@@ -16025,8 +16041,10 @@ expand_reversed_crc_using_clmul (scalar_mode crc_mode, 
scalar_mode data_mode,
 
       if (use_clmulr)
        {
-         gcc_assert (!TARGET_64BIT);
-         emit_insn (gen_riscv_clmulr_si (a0, a0, t1));
+         if (TARGET_64BIT)
+           emit_insn (gen_riscv_clmulr_di (a0, a0, t1));
+         else
+           emit_insn (gen_riscv_clmulr_si (a0, a0, t1));
        }
       else
        {
diff --git a/gcc/testsuite/gcc.target/riscv/crc-builtin-zbc64.c 
b/gcc/testsuite/gcc.target/riscv/crc-builtin-zbc64.c
index 1f46300b140e..927405889416 100644
--- a/gcc/testsuite/gcc.target/riscv/crc-builtin-zbc64.c
+++ b/gcc/testsuite/gcc.target/riscv/crc-builtin-zbc64.c
@@ -63,5 +63,26 @@ int32_t rev_crc32_data32 (int32_t x)
 {
   return __builtin_rev_crc32_data32 (x, 0x123546ff, 0x4002123);
 }
-/* { dg-final { scan-assembler-times "clmul\t" 18 } } */
+
+int64_t rev_crc64_data8 (int64_t x)
+{
+  return __builtin_rev_crc64_data8 (x, 0x32, 0x4002123);
+}
+
+int64_t rev_crc64_data16 (int64_t x)
+{
+  return __builtin_rev_crc64_data16 (x, 0x3232, 0x4002123);
+}
+
+int64_t rev_crc64_data32 (int64_t x)
+{
+  return __builtin_rev_crc64_data32 (x, 0x123546ff, 0x4002123);
+}
+
+int64_t rev_crc64_data64 (int64_t x)
+{
+  return __builtin_rev_crc64_data64 (x, 0x123546ff123546ff, 0x4002123);
+}
+/* { dg-final { scan-assembler-times "clmul\t" 22 } } */
 /* { dg-final { scan-assembler-times "clmulh" 6 } } */
+/* { dg-final { scan-assembler-times "clmulr" 4 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/crc-rev-crc64-rv64-zbc.c 
b/gcc/testsuite/gcc.target/riscv/crc-rev-crc64-rv64-zbc.c
new file mode 100644
index 000000000000..0643ef3ac1c0
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/crc-rev-crc64-rv64-zbc.c
@@ -0,0 +1,51 @@
+/* { dg-do run { target { rv64 && riscv_zbc_ok } } } */
+/* { dg-options "-march=rv64gc_zbc -O2 -save-temps" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-Og" "-Os" "-Oz" } } */
+
+#include <stdint-gcc.h>
+
+#define CRC64_POLY 0x42f0e1eba9ea3693ull
+
+__attribute__ ((target ("arch=rv64gc"), noinline))
+int64_t
+rev_crc64_ref (int64_t crc, int64_t data)
+{
+  return __builtin_rev_crc64_data64 (crc, data, CRC64_POLY);
+}
+
+__attribute__ ((noinline))
+int64_t
+rev_crc64_fast (int64_t crc, int64_t data)
+{
+  return __builtin_rev_crc64_data64 (crc, data, CRC64_POLY);
+}
+
+int
+main (void)
+{
+  int64_t crc = 0x0D800D800D800D80LL;
+
+  for (int64_t i = 0; i < 0xff; i++)
+    {
+      int64_t ref = rev_crc64_ref (crc, i);
+      int64_t fast = rev_crc64_fast (crc, i);
+      if (ref != fast)
+       __builtin_abort ();
+      crc = ref;
+    }
+
+  for (int64_t i = 0; i < 0xff; i++)
+    {
+      int64_t j = (i << 40) | i;
+      int64_t ref = rev_crc64_ref (crc, j);
+      int64_t fast = rev_crc64_fast (crc, j);
+      if (ref != fast)
+       __builtin_abort ();
+      crc = ref;
+    }
+
+  return 0;
+}
+
+/* rev_crc64_fast only: Zbc clmulr (rev_crc64_ref is rv64gc / table).  */
+/* { dg-final { scan-assembler-times "clmulr" 1 } } */

Reply via email to