gnu/gcc/e91f79891fc657d48310f82da0da61eb4a0587ed [PATCH] RISC-V: Use clmulr for reversed crc32 on rv32
From: Loeka Rogge <loeka.rogge@globalfoundries.com>
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 <michiel.derhaeg@globalfoundries.com>
Signed-off-by: Loeka Rogge <loeka.rogge@globalfoundries.com>
3 files changed