From: Loeka Rogge <[email protected]>
The clmul-based reversed crc expansion multiplies by the reflected
polynomial shifted left by one. For a 32-bit crc on rv32 that operand
is 33 bits wide and does not fit in a register, so rv32 fell back to the
table based expansion.
clmulr produces bits 2*xlen-2:xlen-1 of the carry-less product, which is
what clmulh produces from an operand that is already shifted left by one:
clmulh (a, ref_poly << 1) = (a * ref_poly)[62:31] = clmulr (a, ref_poly)
so the shift can be dropped and the unshifted 32-bit reflected polynomial
handed to clmulr instead.
The Linux kernel uses the same identity in crc32_le_zbc(),
arch/riscv/lib/crc32.c (since moved to lib/crc/riscv/):
/* We don't have a "clmulrh" insn, so use clmul + slli instead. */
asm volatile (".option push\n"
".option arch,+zbc\n"
"clmul %0, %1, %2\n"
"slli %0, %0, 1\n"
"xor %0, %0, %1\n"
"clmulr %0, %0, %3\n"
".option pop\n"
: "=&r" (crc)
: "r" (s), "r" (poly_qt), "r" (poly) :);
__builtin_rev_crc32_data32 (crc, data, 0x04C11DB7) on rv32_zbc now
generates:
li a5,305479680
addi t0,a5,1791
li a4,-150925312
xor t1,a0,t0
addi t2,a4,1601
clmul a1,t1,t2
li a0,-306675712
addi a2,a0,800
clmulr a0,a1,a2
Regtested for rv32gc and rv64gc.
gcc/ChangeLog:
* config/riscv/bitmanip.md (crc_rev<ANYI1:mode><ANYI:mode>4):
Use the clmul expansion for a word-sized crc on rv32 with Zbc.
* config/riscv/riscv.cc (expand_reversed_crc_using_clmul): Use
clmulr with the unshifted reflected polynomial when the crc is
word-sized.
(riscv_optab_supported_p): Allow crc_rev for a word-sized result
on rv32 with Zbc when optimizing for size.
gcc/testsuite/ChangeLog:
* gcc.target/riscv/crc-builtin-zbc32.c: Add reversed crc32 tests.
Signed-off-by: Michiel Derhaeg <[email protected]>
Signed-off-by: Loeka Rogge <[email protected]>
---
gcc/config/riscv/bitmanip.md | 9 +++--
gcc/config/riscv/riscv.cc | 38 ++++++++++++++-----
.../gcc.target/riscv/crc-builtin-zbc32.c | 18 ++++++++-
3 files changed, 52 insertions(+), 13 deletions(-)
diff --git a/gcc/config/riscv/bitmanip.md b/gcc/config/riscv/bitmanip.md
index a9fc5af5a0e..55bbf304bff 100644
--- a/gcc/config/riscv/bitmanip.md
+++ b/gcc/config/riscv/bitmanip.md
@@ -1385,7 +1385,7 @@
"clmulr\t%0,%1,%2"
[(set_attr "type" "clmul")])
-;; Reversed CRC 8, 16, 32 for TARGET_64
+;; Reversed CRC 8, 16, 32
(define_expand "crc_rev<ANYI1:mode><ANYI:mode>4"
;; return value (calculated CRC)
[(set (match_operand:ANYI 0 "register_operand")
@@ -1403,8 +1403,11 @@
it is possible to store the quotient within a single variable
(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. */
- if ((TARGET_ZBKC || TARGET_ZBC || TARGET_ZVBC) && <ANYI:MODE>mode <
word_mode)
+ then use clmul instruction to implement the CRC.
+ We can also use clmulr for CRC-32 on RV32, requiring ZBC. */
+ if (((TARGET_ZBKC || TARGET_ZBC || TARGET_ZVBC)
+ && <ANYI:MODE>mode < word_mode)
+ || (!TARGET_64BIT && 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 0b73f03e169..61444a81224 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -13422,8 +13422,9 @@ riscv_optab_supported_p (int op, machine_mode,
machine_mode result_mode,
/* The second CRC optab mode is the result mode. The CLMUL expansion
requires room for a quotient wider than the CRC value itself. */
if (op == crc_rev_optab && opt_type != OPTIMIZE_FOR_SPEED)
- return ((TARGET_ZBKC || TARGET_ZBC || TARGET_ZVBC)
- && result_mode < word_mode);
+ return (((TARGET_ZBKC || TARGET_ZBC || TARGET_ZVBC)
+ && result_mode < word_mode)
+ || (!TARGET_64BIT && TARGET_ZBC && result_mode == word_mode));
return true;
}
@@ -15858,11 +15859,22 @@ expand_reversed_crc_using_clmul (scalar_mode
crc_mode, scalar_mode data_mode,
unsigned HOST_WIDE_INT
ref_polynomial = reflect_hwi (UINTVAL (polynomial),
crc_size);
- rtx t1 = gen_reg_rtx (word_mode);
- riscv_emit_move (t1, gen_int_mode (ref_polynomial << 1, word_mode));
- rtx crc = gen_rtx_ZERO_EXTEND (word_mode, operands[1]);
- rtx data = gen_rtx_ZERO_EXTEND (word_mode, operands[2]);
+ bool use_clmulr = crc_size == BITS_PER_WORD;
+ gcc_assert (TARGET_ZBC || !use_clmulr);
+
+ rtx t1 = gen_reg_rtx (word_mode);
+ if (use_clmulr)
+ riscv_emit_move (t1, gen_int_mode (ref_polynomial, word_mode));
+ else
+ riscv_emit_move (t1, gen_int_mode (ref_polynomial << 1, word_mode));
+
+ rtx crc = operands[1];
+ if (crc_size != BITS_PER_WORD)
+ crc = gen_rtx_ZERO_EXTEND (word_mode, crc);
+ rtx data = operands[2];
+ if (data_size != BITS_PER_WORD)
+ data = gen_rtx_ZERO_EXTEND (word_mode, data);
rtx a0 = gen_reg_rtx (word_mode);
riscv_expand_op (XOR, word_mode, a0, crc, data);
@@ -15876,10 +15888,18 @@ expand_reversed_crc_using_clmul (scalar_mode
crc_mode, scalar_mode data_mode,
rtx num_shift = gen_int_mode (BITS_PER_WORD - data_size, word_mode);
riscv_expand_op (ASHIFT, word_mode, a0, a0, num_shift);
- if (TARGET_64BIT)
- emit_insn (gen_riscv_clmulh_di (a0, a0, t1));
+ if (use_clmulr)
+ {
+ gcc_assert (!TARGET_64BIT);
+ emit_insn (gen_riscv_clmulr_si (a0, a0, t1));
+ }
else
- emit_insn (gen_riscv_clmulh_si (a0, a0, t1));
+ {
+ if (TARGET_64BIT)
+ emit_insn (gen_riscv_clmulh_di (a0, a0, t1));
+ else
+ emit_insn (gen_riscv_clmulh_si (a0, a0, t1));
+ }
}
else
{
diff --git a/gcc/testsuite/gcc.target/riscv/crc-builtin-zbc32.c
b/gcc/testsuite/gcc.target/riscv/crc-builtin-zbc32.c
index 8496555b93d..ba0b855ee55 100644
--- a/gcc/testsuite/gcc.target/riscv/crc-builtin-zbc32.c
+++ b/gcc/testsuite/gcc.target/riscv/crc-builtin-zbc32.c
@@ -19,4 +19,20 @@ int16_t crc16_data16 (int16_t x)
return __builtin_crc16_data16 (x, 0x3214, 0x1021);
}
-/* { dg-final { scan-assembler-times "clmul\t" 6 } } */
+int32_t rev_crc32_data8 (int32_t x)
+{
+ return __builtin_rev_crc32_data8 (x, 'a', 0x04C11DB7);
+}
+
+int32_t rev_crc32_data16 (int32_t x)
+{
+ return __builtin_rev_crc32_data16 (x, 0x3214, 0x04C11DB7);
+}
+
+int32_t rev_crc32_data32 (int32_t x)
+{
+ return __builtin_rev_crc32_data32 (x, 0x123546ff, 0x04C11DB7);
+}
+
+/* { dg-final { scan-assembler-times "clmul\t" 9 } } */
+/* { dg-final { scan-assembler-times "clmulr\t" 3 } } */
--
2.54.0