https://gcc.gnu.org/bugzilla/show_bug.cgi?id=128212

            Bug ID: 128212
           Summary: __builtin_crc64_data64 loop performs unnecessary moves
                    between XMM/GPR and can be optimized further
           Product: gcc
           Version: 17.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: target
          Assignee: unassigned at gcc dot gnu.org
          Reporter: 16567adigashreesh at gmail dot com
  Target Milestone: ---

For a loop which computes __builtin_rev_crc64_data64 (and similar CRC
builtins), the builtin expansion loads the 64 bit data from memory into GPR and
then performs clmul and moves it back to GPR every iteration.
Godbolt link: https://godbolt.org/z/dx8o798TY

```
#include <stdio.h>
#include <stdint.h>

#define POLY 0x9A6C9329AC4BC9B5
uint64_t crc_loop(uint64_t *arr, size_t len) {
    uint64_t crc = 0;
    for (size_t i = 0; i < len; i++) {
        crc = __builtin_crc64_data64(crc, arr[i], POLY);
    }
    return crc;
}
```
Observed the below assembly:
```
"crc_loop(unsigned long*, unsigned long)":
        test    rsi, rsi
        je      .L4
        movdqa  xmm2, XMMWORD PTR .LC0[rip]
        lea     rdx, [rdi+rsi*8]
        xor     eax, eax
.L3:
        xor     rax, QWORD PTR [rdi]
        add     rdi, 8
        movq    xmm0, rax
        punpcklqdq      xmm0, xmm0
        movdqa  xmm1, xmm0
        pclmulqdq       xmm1, xmm2, 0
        pxor    xmm0, xmm1
        pclmulqdq       xmm0, xmm2, 17
        movq    rax, xmm0
        cmp     rdi, rdx
        jne     .L3
        ret
.L4:
        xor     eax, eax
        ret
.LC0:
        .quad   -2071874871052589118
        .quad   -7319313487190308427
```

It would be more optimal to keep the result in lane 0 instead of lane 1, and
have the data loaded directly into new XMM reg using movq and perform the xor
inside XMM so that we can minimize the GPR<-->XMM transfers and have it done
only at the loop start and end once.

Additionally GCC could implement 128-bit folding algorithm as described in the
Intel whitepaper "Fast CRC Computation for Generic Polynomials Using PCLMULQDQ
Instruction" when the loop is going to include 64 bytes and more. This would
involve computing the constants for 128-bit fold and performing single 128-bit
folds and reducing it at the loop end and processing the tail separately.

Reply via email to