Skip to contentSkip to conversation

lib/crc: x86: rewrite crc32c_x86_3way() in C with inline asm

PATCH In review Qu Wenruo 4 participants 8 messages Nov 9 – Nov 10

Subsystems (3)
lore
Share & tools
lore

Qu Wenruo

author
#0 lore raw

PATCH 1/1 lib/crc: x86: rewrite crc32c_x86_3way() in C with inline asm

Unlike user space, we can not use intrinsics, so some instructions must still use inlined ASM, but that is only limited to crc32_u*() helpers and the PCLMULQDQ based lanes combination.

Those wrappers are in the new crc32c-inst.h header, and are also utilized by crc32c_arch() and the new C based crc32c_x86_3way().

The hot loop is the same sequence of crc32 instructions as in the asm version, with the same lane addressing.
The differences in the generated code (x86_64, clang, function tracing enabled) are as follows.

The old 4x unrolled loop is 12 memory-operand crc32q plus 3 bookkeeping instructions per iteration:

    crc32q  (bufp), crc0_q
    crc32q  (bufp,chunk_bytes_q), crc1
    crc32q  (bufp,chunk_bytes_q,2), crc2

... same for offsets 8, 16 and 24 ...
add $32, bufp
sub $4, %eax
jge .Lcrc_3lanes_4x_loop

The new one has the same 12 crc32 and the same addressing, but clang can't fold the load into the instruction because ASM_INPUT_RM is "r" for clang, so every crc32 has a preceding mov:

    mov     (%rsi),%r14
    crc32   %r14,%r9
    mov     (%rsi,%rdx,8),%r14
    crc32   %r14,%r11
    mov     (%rsi,%r10,1),%r14
    crc32   %r14,%rax
    ... same for offsets 8, 16 and 24 ...
    add     $-4,%rbx
    add     $0x20,%rsi
    cmp     $3,%rbx
    ja      <loop>

Thus 12 extra loads per iteration. They don't matter in practice, as the loop is bound by the latency of the three crc32 dependency chains, not by uop throughput.
Forcing the memory form with "m" made no difference either in a userspace benchmark. gcc accepts "rm" and folds the loads into crc32q (checked on a userspace build of the same code).

The combination step is the same instructions, with the old code being

pmovzxdq (K_table-8)(%rax,chunk_bytes_q), %xmm0
movq crc0_q, %xmm1
pclmulqdq $0x00, %xmm0, %xmm1
movq crc1, %xmm2
pclmulqdq $0x10, %xmm0, %xmm2
pxor %xmm2, %xmm1
movq %xmm1, %rax
xor (bufp,chunk_bytes_q,2), %rax
mov crc2, crc0_q
crc32 %rax, crc0_q

and the new one

    mov     %r9d,%r9d
    mov     %r11d,%r11d
    pmovzxdq 0x0(%rdi,%rdx,8),%xmm0
    movq    %r9,%xmm1
    pclmulqdq $0x00,%xmm0,%xmm1
    movq    %r11,%xmm2
    pclmulqdq $0x10,%xmm0,%xmm2
    pxor    %xmm2,%xmm1
    movq    %xmm1,%rdx
    xor     (%rsi,%r10,1),%rdx
    crc32   %rdx,%rax

The two movs at the top are the (u64) zero extensions of the lane CRCs, which are redundant as crc32q already zeroes the upper half. The register copy of crc2 disappears as crc2 is just the accumulator for the final crc32.

The rest (prologue/epilogue, alignment head and sub-qword tail) is not performance critical. The only visible difference is the usual kernel function prologue with a few callee-saved register pushes.

Measured throughput matches the old implementation within noise, both in a userspace comparison (gcc and clang, 200 bytes to 1 MiB) and in the in-kernel CRC32C KUnit benchmark, using a Zen5 (HX 370) based system.

Assisted-by LLM (coding and testing)

---
Reason for RFC:

The idea is inspired when I was cleaning up btrfs-progs, to prepare for new arm64 CRC32C implementation, as a preparation I want to remove all ASM file and inline ASM usages in userspace btrfs-progs. That works pretty well, so here I'm trying to cross-port this change to the kernel 3way acceleration path.

Although I would prefer a code base with less minimal ASM files, I'm not sure if everyone prefers this solution other than hand-written ASM code.

Furthermore all my tests are on a Zen5 based system (HX 370), with cpuid masking to test the 3way optimization code.

So no test on older platforms.

If this one is fine, I can continue converting the AVX512 version too. And hopefully can cross-port the C version of AVX512 back to btrfs-progs.

---
 lib/crc/x86/crc32.h       |  18 +-
 lib/crc/x86/crc32c-3way.S | 360 --------------------------------------
 lib/crc/x86/crc32c-3way.c | 309 ++++++++++++++++++++++++++++++++
 lib/crc/x86/crc32c-3way.h |   9 +
 lib/crc/x86/crc32c-inst.h |  42 +++++
 5 files changed, 366 insertions(+), 372 deletions(-)
 delete mode 100644 lib/crc/x86/crc32c-3way.S
 create mode 100644 lib/crc/x86/crc32c-3way.c
 create mode 100644 lib/crc/x86/crc32c-3way.h
 create mode 100644 lib/crc/x86/crc32c-inst.h
lib/crc/x86/crc32.h +6 -12
index 19a5e3c6c73b..b0763cc82696 100644
@@ -8,6 +8,8 @@
  */
 
 #include "crc-pclmul-template.h"
+#include "crc32c-3way.h"
+#include "crc32c-inst.h"
 
 static __ro_after_init DEFINE_STATIC_KEY_FALSE(have_crc32);
 static __ro_after_init DEFINE_STATIC_KEY_FALSE(have_pclmulqdq);
@@ -22,20 +24,12 @@ static inline u32 crc32_le_arch(u32 crc, const u8 *p, size_t len)
 	return crc32_le_base(crc, p, len);
 }
 
-#ifdef CONFIG_X86_64
-#define CRC32_INST "crc32q %1, %q0"
-#else
-#define CRC32_INST "crc32l %1, %0"
-#endif
-
 /*
  * Use carryless multiply version of crc32c when buffer size is >= 512 to
  * account for FPU state save/restore overhead.
  */
 #define CRC32C_PCLMUL_BREAKEVEN	512
 
-asmlinkage u32 crc32c_x86_3way(u32 crc, const u8 *buffer, size_t len);
-
 static inline u32 crc32c_arch(u32 crc, const u8 *p, size_t len)
 {
 	size_t num_longs;
@@ -87,18 +81,18 @@ static inline u32 crc32c_arch(u32 crc, const u8 *p, size_t len)
 
 	for (num_longs = len / sizeof(unsigned long);
 	     num_longs != 0; num_longs--, p += sizeof(unsigned long))
-		asm(CRC32_INST : "+r" (crc) : ASM_INPUT_RM (*(unsigned long *)p));
+		crc = crc32c_ulong(crc, *(unsigned long *)p);
 
 	if (sizeof(unsigned long) > 4 && (len & 4)) {
-		asm("crc32l %1, %0" : "+r" (crc) : ASM_INPUT_RM (*(u32 *)p));
+		crc = crc32c_u32(crc, *(u32 *)p);
 		p += 4;
 	}
 	if (len & 2) {
-		asm("crc32w %1, %0" : "+r" (crc) : ASM_INPUT_RM (*(u16 *)p));
+		crc = crc32c_u16(crc, *(u16 *)p);
 		p += 2;
 	}
 	if (len & 1)
-		asm("crc32b %1, %0" : "+r" (crc) : ASM_INPUT_RM (*p));
+		crc = crc32c_u8(crc, *p);
 
 	return crc;
 }
lib/crc/x86/crc32c-3way.S deleted +0 -360

360 lines not on this page · raw message

lib/crc/x86/crc32c-3way.c new file +309 -0

309 lines not on this page · raw message

lib/crc/x86/crc32c-3way.h new file +9 -0
new file mode 100644
index 000000000000..717729cd28a9
@@ -0,0 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef _CRC32C_3WAY_H
+#define _CRC32C_3WAY_H
+
+#include <linux/types.h>
+
+u32 crc32c_x86_3way(u32 crc, const u8 *p, size_t len);
+
+#endif /* _CRC32C_3WAY_H */
lib/crc/x86/crc32c-inst.h new file +42 -0

42 lines not on this page · raw message

Signature · 1 line
2.56.0
maintainer
#1 lore raw
Quoted 100 lines · Qu Wenruo

Unlike user space, we can not use intrinsics, so some instructions must still use inlined ASM, but that is only limited to crc32_u*() helpers and the PCLMULQDQ based lanes combination.

Those wrappers are in the new crc32c-inst.h header, and are also utilized by crc32c_arch() and the new C based crc32c_x86_3way().

The hot loop is the same sequence of crc32 instructions as in the asm version, with the same lane addressing.
The differences in the generated code (x86_64, clang, function tracing enabled) are as follows.

The old 4x unrolled loop is 12 memory-operand crc32q plus 3 bookkeeping instructions per iteration:

    crc32q  (bufp), crc0_q
    crc32q  (bufp,chunk_bytes_q), crc1
    crc32q  (bufp,chunk_bytes_q,2), crc2

... same for offsets 8, 16 and 24 ...
add $32, bufp
sub $4, %eax
jge .Lcrc_3lanes_4x_loop

The new one has the same 12 crc32 and the same addressing, but clang can't fold the load into the instruction because ASM_INPUT_RM is "r" for clang, so every crc32 has a preceding mov:

    mov     (%rsi),%r14
    crc32   %r14,%r9
    mov     (%rsi,%rdx,8),%r14
    crc32   %r14,%r11
    mov     (%rsi,%r10,1),%r14
    crc32   %r14,%rax
    ... same for offsets 8, 16 and 24 ...
    add     $-4,%rbx
    add     $0x20,%rsi
    cmp     $3,%rbx
    ja      <loop>

Thus 12 extra loads per iteration. They don't matter in practice, as the loop is bound by the latency of the three crc32 dependency chains, not by uop throughput.
Forcing the memory form with "m" made no difference either in a userspace benchmark. gcc accepts "rm" and folds the loads into crc32q (checked on a userspace build of the same code).

The combination step is the same instructions, with the old code being

pmovzxdq (K_table-8)(%rax,chunk_bytes_q), %xmm0
movq crc0_q, %xmm1
pclmulqdq $0x00, %xmm0, %xmm1
movq crc1, %xmm2
pclmulqdq $0x10, %xmm0, %xmm2
pxor %xmm2, %xmm1
movq %xmm1, %rax
xor (bufp,chunk_bytes_q,2), %rax
mov crc2, crc0_q
crc32 %rax, crc0_q

and the new one

    mov     %r9d,%r9d
    mov     %r11d,%r11d
    pmovzxdq 0x0(%rdi,%rdx,8),%xmm0
    movq    %r9,%xmm1
    pclmulqdq $0x00,%xmm0,%xmm1
    movq    %r11,%xmm2
    pclmulqdq $0x10,%xmm0,%xmm2
    pxor    %xmm2,%xmm1
    movq    %xmm1,%rdx
    xor     (%rsi,%r10,1),%rdx
    crc32   %rdx,%rax

The two movs at the top are the (u64) zero extensions of the lane CRCs, which are redundant as crc32q already zeroes the upper half. The register copy of crc2 disappears as crc2 is just the accumulator for the final crc32.

The rest (prologue/epilogue, alignment head and sub-qword tail) is not performance critical. The only visible difference is the usual kernel function prologue with a few callee-saved register pushes.

Measured throughput matches the old implementation within noise, both in a userspace comparison (gcc and clang, 200 bytes to 1 MiB) and in the in-kernel CRC32C KUnit benchmark, using a Zen5 (HX 370) based system.

Assisted-by LLM (coding and testing)

---
Reason for RFC:

The idea is inspired when I was cleaning up btrfs-progs, to prepare for new arm64 CRC32C implementation, as a preparation I want to remove all ASM file and inline ASM usages in userspace btrfs-progs. That works pretty well, so here I'm trying to cross-port this change to the kernel 3way acceleration path.

Although I would prefer a code base with less minimal ASM files, I'm not sure if everyone prefers this solution other than hand-written ASM code.

Quoted 8 lines

Furthermore all my tests are on a Zen5 based system (HX 370), with cpuid masking to test the 3way optimization code.

So no test on older platforms.

If this one is fine, I can continue converting the AVX512 version too. And hopefully can cross-port the C version of AVX512 back to btrfs-progs.

As much as I'd like to reduce the use of asm, I'm not sure this is super convincing. We get worse code generation and have to fall back to inline asm anyway, as the x86 intrinsics are still unusable in the kernel (which is different from userspace).

This patch also introduces a compiler error with gcc. It seems only clang was tested. (Showing again that this kind of code often has compiler-specific issues, and we have to be extra careful to test it with every supported compiler version.)

There's also a subtle bug where the inline asm blocks are missing the volatile qualifier, so technically they could be reordered after the kernel_fpu_end() and corrupt a userspace process's XMM registers. Without inline asm, this issue would not have been possible.

I'd be interested in seeing what you can come up with for crc-pclmul-template.S, though I think that one is going to be harder to replace.

- Eric

maintainer
#2 lore raw
Quoted 10 lines · Eric Biggers

As much as I'd like to reduce the use of asm, I'm not sure this is super convincing. We get worse code generation and have to fall back to inline asm anyway, as the x86 intrinsics are still unusable in the kernel (which is different from userspace).

This patch also introduces a compiler error with gcc. It seems only clang was tested. (Showing again that this kind of code often has compiler-specific issues, and we have to be extra careful to test it with every supported compiler version.)

Quoted 8 lines

There's also a subtle bug where the inline asm blocks are missing the volatile qualifier, so technically they could be reordered after the kernel_fpu_end() and corrupt a userspace process's XMM registers. Without inline asm, this issue would not have been possible.

I'd be interested in seeing what you can come up with for crc-pclmul-template.S, though I think that one is going to be harder to replace.

Also, just to emphasize: most "C" code using this strategy will be mostly inline asm blocks, since that's what is needed to access the vector registers in kernel code. See lib/raid/*/x86/ for some examples.

crc32c_x86_3way() is an exception because it mostly use scalar instructions, with only a few vector instructions. So it makes this strategy seem a bit more workable. But actually, as soon as this same strategy is adopted for crc-pclmul-template.S or any of the many crypto assembly files (AES, GHASH, ChaCha, Poly1305, BLAKE2, etc.) that use far more vector instructions, it will become mostly inline asm blocks, just like the RAID code.

So I feel it's kind of an odd path to go down. Perhaps as a prerequisite for reimplementing some of this code in C (or will it soon be Rust?), we should get the x86 intrinsics working in the kernel first?

- Eric

author
#3 lore raw
Quoted 32 lines · Eric Biggers
Quoted 10 lines · Eric Biggers

As much as I'd like to reduce the use of asm, I'm not sure this is super convincing. We get worse code generation and have to fall back to inline asm anyway, as the x86 intrinsics are still unusable in the kernel (which is different from userspace).

This patch also introduces a compiler error with gcc. It seems only clang was tested. (Showing again that this kind of code often has compiler-specific issues, and we have to be extra careful to test it with every supported compiler version.)

Quoted 8 lines

There's also a subtle bug where the inline asm blocks are missing the volatile qualifier, so technically they could be reordered after the kernel_fpu_end() and corrupt a userspace process's XMM registers. Without inline asm, this issue would not have been possible.

I'd be interested in seeing what you can come up with for crc-pclmul-template.S, though I think that one is going to be harder to replace.

Also, just to emphasize: most "C" code using this strategy will be mostly inline asm blocks, since that's what is needed to access the vector registers in kernel code. See lib/raid/*/x86/ for some examples.

crc32c_x86_3way() is an exception because it mostly use scalar instructions, with only a few vector instructions. So it makes this strategy seem a bit more workable. But actually, as soon as this same strategy is adopted for crc-pclmul-template.S or any of the many crypto assembly files (AES, GHASH, ChaCha, Poly1305, BLAKE2, etc.) that use far more vector instructions, it will become mostly inline asm blocks, just like the RAID code.

Quoted 3 lines

So I feel it's kind of an odd path to go down. Perhaps as a prerequisite for reimplementing some of this code in C (or will it soon be Rust?), we should get the x86 intrinsics working in the kernel first?

Indeed, it works almost flawlessly in user space just because there are already intrinsics available, and most of the code is just regular control flow, with mostly scalar code.

Thanks for the feedback, I'll just give up the idea in kernel, and enjoy the complete intrinsics in user space for now.

Thanks,
Qu

Quoted 2 lines

- Eric

maintainer
#4 lore raw
Quoted 41 lines · Qu Wenruo
Quoted 32 lines · Eric Biggers
Quoted 10 lines · Eric Biggers

As much as I'd like to reduce the use of asm, I'm not sure this is super convincing. We get worse code generation and have to fall back to inline asm anyway, as the x86 intrinsics are still unusable in the kernel (which is different from userspace).

This patch also introduces a compiler error with gcc. It seems only clang was tested. (Showing again that this kind of code often has compiler-specific issues, and we have to be extra careful to test it with every supported compiler version.)

Quoted 8 lines

There's also a subtle bug where the inline asm blocks are missing the volatile qualifier, so technically they could be reordered after the kernel_fpu_end() and corrupt a userspace process's XMM registers. Without inline asm, this issue would not have been possible.

I'd be interested in seeing what you can come up with for crc-pclmul-template.S, though I think that one is going to be harder to replace.

Also, just to emphasize: most "C" code using this strategy will be mostly inline asm blocks, since that's what is needed to access the vector registers in kernel code. See lib/raid/*/x86/ for some examples.

crc32c_x86_3way() is an exception because it mostly use scalar instructions, with only a few vector instructions. So it makes this strategy seem a bit more workable. But actually, as soon as this same strategy is adopted for crc-pclmul-template.S or any of the many crypto assembly files (AES, GHASH, ChaCha, Poly1305, BLAKE2, etc.) that use far more vector instructions, it will become mostly inline asm blocks, just like the RAID code.

Quoted 3 lines

So I feel it's kind of an odd path to go down. Perhaps as a prerequisite for reimplementing some of this code in C (or will it soon be Rust?), we should get the x86 intrinsics working in the kernel first?

Indeed, it works almost flawlessly in user space just because there are already intrinsics available, and most of the code is just regular control flow, with mostly scalar code.

Quoted 5 lines

Thanks for the feedback, I'll just give up the idea in kernel, and enjoy the complete intrinsics in user space for now.

Thanks,
Qu

Okay. I'd be interested in someone trying to get the x86 intrinsics working in the kernel, though. Just when I last tried it, it still wasn't possible to include <immintrin.h> without errors.

- Eric

#5 lore raw
Quoted 45 lines · Eric Biggers
Quoted 44 lines · Qu Wenruo
Quoted 32 lines · Eric Biggers
Quoted 10 lines · Eric Biggers

As much as I'd like to reduce the use of asm, I'm not sure this is super convincing. We get worse code generation and have to fall back to inline asm anyway, as the x86 intrinsics are still unusable in the kernel (which is different from userspace).

This patch also introduces a compiler error with gcc. It seems only clang was tested. (Showing again that this kind of code often has compiler-specific issues, and we have to be extra careful to test it with every supported compiler version.)

Quoted 8 lines

There's also a subtle bug where the inline asm blocks are missing the volatile qualifier, so technically they could be reordered after the kernel_fpu_end() and corrupt a userspace process's XMM registers. Without inline asm, this issue would not have been possible.

I'd be interested in seeing what you can come up with for crc-pclmul-template.S, though I think that one is going to be harder to replace.

Also, just to emphasize: most "C" code using this strategy will be mostly inline asm blocks, since that's what is needed to access the vector registers in kernel code. See lib/raid/*/x86/ for some examples.

crc32c_x86_3way() is an exception because it mostly use scalar instructions, with only a few vector instructions. So it makes this strategy seem a bit more workable. But actually, as soon as this same strategy is adopted for crc-pclmul-template.S or any of the many crypto assembly files (AES, GHASH, ChaCha, Poly1305, BLAKE2, etc.) that use far more vector instructions, it will become mostly inline asm blocks, just like the RAID code.

Quoted 3 lines

So I feel it's kind of an odd path to go down. Perhaps as a prerequisite for reimplementing some of this code in C (or will it soon be Rust?), we should get the x86 intrinsics working in the kernel first?

Indeed, it works almost flawlessly in user space just because there are already intrinsics available, and most of the code is just regular control flow, with mostly scalar code.

Thanks for the feedback, I'll just give up the idea in kernel, and enjoy the complete intrinsics in user space for now.

Quoted 6 lines
Quoted 2 lines

Thanks,
Qu

Okay. I'd be interested in someone trying to get the x86 intrinsics working in the kernel, though. Just when I last tried it, it still wasn't possible to include <immintrin.h> without errors.

I don't think we can use the compiler's wrappers directly, there are quite a lot of conflicts with kernel's library.

So a different, independent copy may be needed.

If we can get that part done, it will be much easier to do the conversion. Although introducing the intrinsics itself may be a much larger project.

Thanks,
Qu

Quoted 2 lines

- Eric

author
#6 lore raw
Quoted 55 lines · Qu Wenruo
Quoted 45 lines · Eric Biggers
Quoted 44 lines · Qu Wenruo
Quoted 32 lines · Eric Biggers
Quoted 10 lines · Eric Biggers

As much as I'd like to reduce the use of asm, I'm not sure this is super convincing.  We get worse code generation and have to fall back to inline asm anyway, as the x86 intrinsics are still unusable in the kernel (which is different from userspace).

This patch also introduces a compiler error with gcc. It seems only clang was tested.  (Showing again that this kind of code often has compiler-specific issues, and we have to be extra careful to test it with every supported compiler version.)

Quoted 8 lines

There's also a subtle bug where the inline asm blocks are missing the volatile qualifier, so technically they could be reordered after the kernel_fpu_end() and corrupt a userspace process's XMM registers. Without inline asm, this issue would not have been possible.

I'd be interested in seeing what you can come up with for crc-pclmul-template.S, though I think that one is going to be harder to replace.

Also, just to emphasize: most "C" code using this strategy will be mostly inline asm blocks, since that's what is needed to access the vector registers in kernel code.  See lib/raid/*/x86/ for some examples.

crc32c_x86_3way() is an exception because it mostly use scalar instructions, with only a few vector instructions.  So it makes this strategy seem a bit more workable.  But actually, as soon as this same strategy is adopted for crc-pclmul-template.S or any of the many crypto assembly files (AES, GHASH, ChaCha, Poly1305, BLAKE2, etc.) that use far more vector instructions, it will become mostly inline asm blocks, just like the RAID code.

Quoted 3 lines

So I feel it's kind of an odd path to go down.  Perhaps as a prerequisite for reimplementing some of this code in C (or will it soon be Rust?), we should get the x86 intrinsics working in the kernel first?

Indeed, it works almost flawlessly in user space just because there are already intrinsics available, and most of the code is just regular control flow, with mostly scalar code.

Thanks for the feedback, I'll just give up the idea in kernel, and enjoy the complete intrinsics in user space for now.

Quoted 6 lines
Quoted 2 lines

Thanks,
Qu

Okay.  I'd be interested in someone trying to get the x86 intrinsics working in the kernel, though.  Just when I last tried it, it still wasn't possible to include <immintrin.h> without errors.

Quoted 6 lines

I don't think we can use the compiler's wrappers directly, there are quite a lot of conflicts with kernel's library.

So a different, independent copy may be needed.

If we can get that part done, it will be much easier to do the conversion. Although introducing the intrinsics itself may be a much larger project.

It looks like there is already arch/arm64/include/asm/neon-intrinsics.h including the intrinsics from the compiler and solves the conflicts manually.

So that looks like a solution to pull in the needed intrinsics to make things a little simpler.

Quoted 7 lines

Thanks,
Qu

Quoted 2 lines

- Eric

#7 lore raw
In reply to Qu Wenruo
kernel test robot noticed the following build errors:

Hi Qu,

kernel test robot noticed the following build errors:

[auto build test ERROR on ebiggers/crc-next]
[also build test ERROR on linus/master v7.4-rc2 next-20261109] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Qu-Wenruo/lib-crc-x86-rewrite-crc32c_x86_3way-in-C-with-inline-asm/20261110-102248
base:   https://git.kernel.org/pub/scm/linux/kernel/git/ebiggers/linux.git crc-next
patch link:    https://lore.kernel.org/r/090c5f6603b1102c877c8649f7a6569f362bfe61.1794268279.git.wqu%40suse.com
patch subject: [PATCH] lib/crc: x86: rewrite crc32c_x86_3way() in C with inline asm
config: x86_64-rhel-9.4 (https://download.01.org/0day-ci/archive/20261110/[email protected]/config)
compiler: gcc-14 (Debian 14.2.0-19) 14.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20261110/[email protected]/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <[email protected]>
| Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/

All errors (new ones prefixed by >>):

In function 'crc32c_fold_lanes',

       inlined from 'crc32c_x86_3way' at lib/crc/x86/crc32c-3way.c:285:12:
>> lib/crc/x86/crc32c-3way.c:217:9: error: the register 'xmm2' cannot be clobbered in 'asm' for the current target
     217 |         asm("pmovzxdq   %[k], %%xmm0\n\t"       /* 2 consts: K2:K1 */
         |         ^~~

vim +217 lib/crc/x86/crc32c-3way.c

208
209 /*
210 * Fold the CRCs of lane 0 and lane 1 into a single 64-bit value, which is to be
211 * XOR'ed into the last qword of lane 2 before being CRC'ed.
212 */
213 static __always_inline u64 crc32c_fold_lanes(u32 crc0, u32 crc1, const u32 *k)
214 {
215 u64 res;
216

 > 217		asm("pmovzxdq	%[k], %%xmm0\n\t"	/* 2 consts: K2:K1 */
   218		    "movq	%[crc0], %%xmm1\n\t"	/* CRC for lane 0 */
   219		    "pclmulqdq	$0x00, %%xmm0, %%xmm1\n\t" /* Multiply by K2 */
   220		    "movq	%[crc1], %%xmm2\n\t"	/* CRC for lane 1 */
   221		    "pclmulqdq	$0x10, %%xmm0, %%xmm2\n\t" /* Multiply by K1 */
   222		    "pxor	%%xmm2, %%xmm1\n\t"
   223		    "movq	%%xmm1, %[res]"
   224		    : [res] "=r" (res)
   225		    : [crc0] "r" ((u64)crc0), [crc1] "r" ((u64)crc1),

226 [k] "m" (*(const u64 *)k)
227 : "xmm0", "xmm1", "xmm2");
228 return res;
229 }
230

--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki