On 9/13/26 2:47 AM, Michiel Derhaeg wrote:
Jeff Law <[email protected]> writes:

On 9/11/26 4:19 PM, Michiel Derhaeg wrote:
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.
This looks good, but it seems like it ought to also work for
TARGET_64BIT.  So I'm puzzled why things are conditional on !TARGET_64BIT?

jeff
Ah.. now that you mention it, so am I.  I think we were too focussed on
making sure it was correct for rv32.  We'll look into rv64.

Up to you if it can be pushed as is.  Either way, we'll post a patch
with rv64 support soon.
I'm always torn on this kind of thing.  Your patch clearly makes things better and the ask is an extension to that which we think, but do not know with certainty, will improve things further.  I have a suspicion the additional work would result in this patch being simpler.

I went ahead and pushed to the trunk, but I'm very interested to see if this can work for cases on rv64.  My recollection was there were some real world CRCs we failed to optimize because of this issue.

Thanks, both for this patch and agreeing to look at it in the rv64 context.

Jeff

Reply via email to