* [PATCH v2 0/3] lib/crypto: x86/chacha: Add a 16-block AVX-512 function
@ 2026-11-02 11:39 Martin Willi
2026-11-02 11:39 ` [PATCH v2 1/3] lib/crypto: x86/chacha: Rename the AVX-512VL assembly file Martin Willi
` (5 more replies)
0 siblings, 6 replies; 7+ messages in thread
From: Martin Willi @ 2026-11-02 11:39 UTC (permalink / raw)
To: Eric Biggers, linux-crypto
Cc: Jason A. Donenfeld, Ard Biesheuvel, Antonio Quartulli
Here is v2 of the 16-block ChaCha function for 512-bit zmm registers.
Patch 1 renames the assembly file, patch 2 wraps the 8-block code in
a macro, and patch 3 adds the 16-block function on top.
I previously mentioned a larger series with more AVX refactorings to
shared macros along with a 4-block zmm variant. That needs some
more work, so here is just the 16-block variant.
v1 used embedded broadcasts for the final ChaCha state add. This comes
with a minor regression on older Intel chips when used in the 8-block
variant. Therefore I kept the state words in registers in the macro
version used by both 8/16-block variants, see patch 3.
I don't have a Zen 4, which splits zmm instructions into two 256-bit
halves, so I can't tell how the 16-block function performs there.
If anybody has access to one, numbers from there would be great.
Changes in v2:
- Rename chacha-avx512vl-x86_64.S to chacha-avx512-x86_64.S
- Generate the 8- and 16-block functions from a shared macro
- Drop the cpu_has_xfeatures() and X86_FEATURE_AVX512F checks
- Keep the state words in registers for the final add
- Benchmark with the ChaCha KUnit suite instead of tcrypt
v1: https://lore.kernel.org/linux-crypto/20260722153247.630519-1-martin@strongswan.org/
Martin Willi (3):
lib/crypto: x86/chacha: Rename the AVX-512VL assembly file
lib/crypto: x86/chacha: Wrap the 8-block AVX-512 code in a macro
lib/crypto: x86/chacha: Add a 16-block AVX-512 function
lib/crypto/Makefile | 2 +-
...x512vl-x86_64.S => chacha-avx512-x86_64.S} | 730 +++++++++++-------
lib/crypto/x86/chacha.h | 28 +-
3 files changed, 477 insertions(+), 283 deletions(-)
rename lib/crypto/x86/{chacha-avx512vl-x86_64.S => chacha-avx512-x86_64.S} (55%)
base-commit: c90bb21618db40f1f30a1c0ed58d4f46b27dba26
--
2.53.0
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v2 1/3] lib/crypto: x86/chacha: Rename the AVX-512VL assembly file
2026-11-02 11:39 [PATCH v2 0/3] lib/crypto: x86/chacha: Add a 16-block AVX-512 function Martin Willi
@ 2026-11-02 11:39 ` Martin Willi
2026-11-02 11:39 ` [PATCH v2 2/3] lib/crypto: x86/chacha: Wrap the 8-block AVX-512 code in a macro Martin Willi
` (4 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Martin Willi @ 2026-11-02 11:39 UTC (permalink / raw)
To: Eric Biggers, linux-crypto
Cc: Jason A. Donenfeld, Ard Biesheuvel, Antonio Quartulli
The file is going to hold a 16-block function on 512-bit zmm registers,
which does not depend on the VL extension. So rename it to
chacha-avx512-x86_64.S and drop VL from its header comment.
Signed-off-by: Martin Willi <martin@strongswan.org>
---
lib/crypto/Makefile | 2 +-
.../x86/{chacha-avx512vl-x86_64.S => chacha-avx512-x86_64.S} | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
rename lib/crypto/x86/{chacha-avx512vl-x86_64.S => chacha-avx512-x86_64.S} (99%)
diff --git a/lib/crypto/Makefile b/lib/crypto/Makefile
index 126e72419ebb..171b926afc39 100644
--- a/lib/crypto/Makefile
+++ b/lib/crypto/Makefile
@@ -129,7 +129,7 @@ libchacha-$(CONFIG_RISCV) += riscv/chacha-riscv64-zvkb.o
libchacha-$(CONFIG_S390) += s390/chacha-s390.o
libchacha-$(CONFIG_X86) += x86/chacha-ssse3-x86_64.o \
x86/chacha-avx2-x86_64.o \
- x86/chacha-avx512vl-x86_64.o
+ x86/chacha-avx512-x86_64.o
endif # CONFIG_CRYPTO_LIB_CHACHA_ARCH
################################################################################
diff --git a/lib/crypto/x86/chacha-avx512vl-x86_64.S b/lib/crypto/x86/chacha-avx512-x86_64.S
similarity index 99%
rename from lib/crypto/x86/chacha-avx512vl-x86_64.S
rename to lib/crypto/x86/chacha-avx512-x86_64.S
index 259383e1ad44..cf784e148bdf 100644
--- a/lib/crypto/x86/chacha-avx512vl-x86_64.S
+++ b/lib/crypto/x86/chacha-avx512-x86_64.S
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
- * ChaCha 256-bit cipher algorithm, x64 AVX-512VL functions
+ * ChaCha 256-bit cipher algorithm, x64 AVX-512 functions
*
* Copyright (C) 2018 Martin Willi
*/
--
2.53.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH v2 2/3] lib/crypto: x86/chacha: Wrap the 8-block AVX-512 code in a macro
2026-11-02 11:39 [PATCH v2 0/3] lib/crypto: x86/chacha: Add a 16-block AVX-512 function Martin Willi
2026-11-02 11:39 ` [PATCH v2 1/3] lib/crypto: x86/chacha: Rename the AVX-512VL assembly file Martin Willi
@ 2026-11-02 11:39 ` Martin Willi
2026-11-02 11:39 ` [PATCH v2 3/3] lib/crypto: x86/chacha: Add a 16-block AVX-512 function Martin Willi
` (3 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Martin Willi @ 2026-11-02 11:39 UTC (permalink / raw)
To: Eric Biggers, linux-crypto
Cc: Jason A. Donenfeld, Ard Biesheuvel, Antonio Quartulli
An upcoming 16-block zmm function shares almost everything with the
existing 8-block ymm function. Prepare for it by wrapping the 8-block
code in a macro parameterized by vector length.
The generated code stays byte-identical.
Signed-off-by: Martin Willi <martin@strongswan.org>
---
lib/crypto/x86/chacha-avx512-x86_64.S | 580 ++++++++++++++------------
1 file changed, 302 insertions(+), 278 deletions(-)
diff --git a/lib/crypto/x86/chacha-avx512-x86_64.S b/lib/crypto/x86/chacha-avx512-x86_64.S
index cf784e148bdf..35e73de1c870 100644
--- a/lib/crypto/x86/chacha-avx512-x86_64.S
+++ b/lib/crypto/x86/chacha-avx512-x86_64.S
@@ -17,13 +17,28 @@ CTR2BL: .octa 0x00000000000000000000000000000000
CTR4BL: .octa 0x00000000000000000000000000000002
.octa 0x00000000000000000000000000000003
-.section .rodata.cst32.CTR8BL, "aM", @progbits, 32
+.section .rodata.cst32.CTRBL, "aM", @progbits, 32
.align 32
-CTR8BL: .octa 0x00000003000000020000000100000000
+CTRBL: .octa 0x00000003000000020000000100000000
.octa 0x00000007000000060000000500000004
.text
+.macro _define_Vi i
+.if VL == 32
+ .set V\i, %ymm\i
+.else
+ .error "Unsupported vector length"
+.endif
+.endm
+
+.macro _define_aliases
+ # alias V0-V31 to the vector registers of the selected width VL
+.irp i, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31
+ _define_Vi \i
+.endr
+.endm
+
SYM_FUNC_START(chacha_2block_xor_avx512vl)
# %rdi: Input state matrix, s
# %rsi: up to 2 data blocks output, o
@@ -455,382 +470,391 @@ SYM_FUNC_START(chacha_4block_xor_avx512vl)
SYM_FUNC_END(chacha_4block_xor_avx512vl)
-SYM_FUNC_START(chacha_8block_xor_avx512vl)
+.macro _chacha_words vl
+ .set VL, \vl
+
+ _define_aliases
+
# %rdi: Input state matrix, s
- # %rsi: up to 8 data blocks output, o
- # %rdx: up to 8 data blocks input, i
+ # %rsi: up to VL/4 data blocks output, o
+ # %rdx: up to VL/4 data blocks input, i
# %rcx: input/output length in bytes
# %r8d: nrounds
- # This function encrypts eight consecutive ChaCha blocks by loading
- # the state matrix in AVX registers eight times. Compared to AVX2, this
- # mostly benefits from the new rotate instructions in VL and the
- # additional registers.
+ # This encrypts VL/4 consecutive ChaCha blocks by loading the state
+ # matrix in as many vector registers. Compared to AVX2, this mostly
+ # benefits from the new rotate instructions and the additional
+ # registers.
+ #
+ # VL=32 encrypts eight blocks in 256-bit ymm registers.
vzeroupper
- # x0..15[0-7] = s[0..15]
- vpbroadcastd 0x00(%rdi),%ymm0
- vpbroadcastd 0x04(%rdi),%ymm1
- vpbroadcastd 0x08(%rdi),%ymm2
- vpbroadcastd 0x0c(%rdi),%ymm3
- vpbroadcastd 0x10(%rdi),%ymm4
- vpbroadcastd 0x14(%rdi),%ymm5
- vpbroadcastd 0x18(%rdi),%ymm6
- vpbroadcastd 0x1c(%rdi),%ymm7
- vpbroadcastd 0x20(%rdi),%ymm8
- vpbroadcastd 0x24(%rdi),%ymm9
- vpbroadcastd 0x28(%rdi),%ymm10
- vpbroadcastd 0x2c(%rdi),%ymm11
- vpbroadcastd 0x30(%rdi),%ymm12
- vpbroadcastd 0x34(%rdi),%ymm13
- vpbroadcastd 0x38(%rdi),%ymm14
- vpbroadcastd 0x3c(%rdi),%ymm15
-
- # x12 += counter values 0-3
- vpaddd CTR8BL(%rip),%ymm12,%ymm12
-
- vmovdqa64 %ymm0,%ymm16
- vmovdqa64 %ymm1,%ymm17
- vmovdqa64 %ymm2,%ymm18
- vmovdqa64 %ymm3,%ymm19
- vmovdqa64 %ymm4,%ymm20
- vmovdqa64 %ymm5,%ymm21
- vmovdqa64 %ymm6,%ymm22
- vmovdqa64 %ymm7,%ymm23
- vmovdqa64 %ymm8,%ymm24
- vmovdqa64 %ymm9,%ymm25
- vmovdqa64 %ymm10,%ymm26
- vmovdqa64 %ymm11,%ymm27
- vmovdqa64 %ymm12,%ymm28
- vmovdqa64 %ymm13,%ymm29
- vmovdqa64 %ymm14,%ymm30
- vmovdqa64 %ymm15,%ymm31
-
-.Ldoubleround8:
+ # x0..15[0-VL/4] = s[0..15]
+ vpbroadcastd 0x00(%rdi),V0
+ vpbroadcastd 0x04(%rdi),V1
+ vpbroadcastd 0x08(%rdi),V2
+ vpbroadcastd 0x0c(%rdi),V3
+ vpbroadcastd 0x10(%rdi),V4
+ vpbroadcastd 0x14(%rdi),V5
+ vpbroadcastd 0x18(%rdi),V6
+ vpbroadcastd 0x1c(%rdi),V7
+ vpbroadcastd 0x20(%rdi),V8
+ vpbroadcastd 0x24(%rdi),V9
+ vpbroadcastd 0x28(%rdi),V10
+ vpbroadcastd 0x2c(%rdi),V11
+ vpbroadcastd 0x30(%rdi),V12
+ vpbroadcastd 0x34(%rdi),V13
+ vpbroadcastd 0x38(%rdi),V14
+ vpbroadcastd 0x3c(%rdi),V15
+
+ # x12 += counter values, one per block
+ vpaddd CTRBL(%rip),V12,V12
+
+ vmovdqa64 V0,V16
+ vmovdqa64 V1,V17
+ vmovdqa64 V2,V18
+ vmovdqa64 V3,V19
+ vmovdqa64 V4,V20
+ vmovdqa64 V5,V21
+ vmovdqa64 V6,V22
+ vmovdqa64 V7,V23
+ vmovdqa64 V8,V24
+ vmovdqa64 V9,V25
+ vmovdqa64 V10,V26
+ vmovdqa64 V11,V27
+ vmovdqa64 V12,V28
+ vmovdqa64 V13,V29
+ vmovdqa64 V14,V30
+ vmovdqa64 V15,V31
+
+.Ldoubleround\@:
# x0 += x4, x12 = rotl32(x12 ^ x0, 16)
- vpaddd %ymm0,%ymm4,%ymm0
- vpxord %ymm0,%ymm12,%ymm12
- vprold $16,%ymm12,%ymm12
+ vpaddd V0,V4,V0
+ vpxord V0,V12,V12
+ vprold $16,V12,V12
# x1 += x5, x13 = rotl32(x13 ^ x1, 16)
- vpaddd %ymm1,%ymm5,%ymm1
- vpxord %ymm1,%ymm13,%ymm13
- vprold $16,%ymm13,%ymm13
+ vpaddd V1,V5,V1
+ vpxord V1,V13,V13
+ vprold $16,V13,V13
# x2 += x6, x14 = rotl32(x14 ^ x2, 16)
- vpaddd %ymm2,%ymm6,%ymm2
- vpxord %ymm2,%ymm14,%ymm14
- vprold $16,%ymm14,%ymm14
+ vpaddd V2,V6,V2
+ vpxord V2,V14,V14
+ vprold $16,V14,V14
# x3 += x7, x15 = rotl32(x15 ^ x3, 16)
- vpaddd %ymm3,%ymm7,%ymm3
- vpxord %ymm3,%ymm15,%ymm15
- vprold $16,%ymm15,%ymm15
+ vpaddd V3,V7,V3
+ vpxord V3,V15,V15
+ vprold $16,V15,V15
# x8 += x12, x4 = rotl32(x4 ^ x8, 12)
- vpaddd %ymm12,%ymm8,%ymm8
- vpxord %ymm8,%ymm4,%ymm4
- vprold $12,%ymm4,%ymm4
+ vpaddd V12,V8,V8
+ vpxord V8,V4,V4
+ vprold $12,V4,V4
# x9 += x13, x5 = rotl32(x5 ^ x9, 12)
- vpaddd %ymm13,%ymm9,%ymm9
- vpxord %ymm9,%ymm5,%ymm5
- vprold $12,%ymm5,%ymm5
+ vpaddd V13,V9,V9
+ vpxord V9,V5,V5
+ vprold $12,V5,V5
# x10 += x14, x6 = rotl32(x6 ^ x10, 12)
- vpaddd %ymm14,%ymm10,%ymm10
- vpxord %ymm10,%ymm6,%ymm6
- vprold $12,%ymm6,%ymm6
+ vpaddd V14,V10,V10
+ vpxord V10,V6,V6
+ vprold $12,V6,V6
# x11 += x15, x7 = rotl32(x7 ^ x11, 12)
- vpaddd %ymm15,%ymm11,%ymm11
- vpxord %ymm11,%ymm7,%ymm7
- vprold $12,%ymm7,%ymm7
+ vpaddd V15,V11,V11
+ vpxord V11,V7,V7
+ vprold $12,V7,V7
# x0 += x4, x12 = rotl32(x12 ^ x0, 8)
- vpaddd %ymm0,%ymm4,%ymm0
- vpxord %ymm0,%ymm12,%ymm12
- vprold $8,%ymm12,%ymm12
+ vpaddd V0,V4,V0
+ vpxord V0,V12,V12
+ vprold $8,V12,V12
# x1 += x5, x13 = rotl32(x13 ^ x1, 8)
- vpaddd %ymm1,%ymm5,%ymm1
- vpxord %ymm1,%ymm13,%ymm13
- vprold $8,%ymm13,%ymm13
+ vpaddd V1,V5,V1
+ vpxord V1,V13,V13
+ vprold $8,V13,V13
# x2 += x6, x14 = rotl32(x14 ^ x2, 8)
- vpaddd %ymm2,%ymm6,%ymm2
- vpxord %ymm2,%ymm14,%ymm14
- vprold $8,%ymm14,%ymm14
+ vpaddd V2,V6,V2
+ vpxord V2,V14,V14
+ vprold $8,V14,V14
# x3 += x7, x15 = rotl32(x15 ^ x3, 8)
- vpaddd %ymm3,%ymm7,%ymm3
- vpxord %ymm3,%ymm15,%ymm15
- vprold $8,%ymm15,%ymm15
+ vpaddd V3,V7,V3
+ vpxord V3,V15,V15
+ vprold $8,V15,V15
# x8 += x12, x4 = rotl32(x4 ^ x8, 7)
- vpaddd %ymm12,%ymm8,%ymm8
- vpxord %ymm8,%ymm4,%ymm4
- vprold $7,%ymm4,%ymm4
+ vpaddd V12,V8,V8
+ vpxord V8,V4,V4
+ vprold $7,V4,V4
# x9 += x13, x5 = rotl32(x5 ^ x9, 7)
- vpaddd %ymm13,%ymm9,%ymm9
- vpxord %ymm9,%ymm5,%ymm5
- vprold $7,%ymm5,%ymm5
+ vpaddd V13,V9,V9
+ vpxord V9,V5,V5
+ vprold $7,V5,V5
# x10 += x14, x6 = rotl32(x6 ^ x10, 7)
- vpaddd %ymm14,%ymm10,%ymm10
- vpxord %ymm10,%ymm6,%ymm6
- vprold $7,%ymm6,%ymm6
+ vpaddd V14,V10,V10
+ vpxord V10,V6,V6
+ vprold $7,V6,V6
# x11 += x15, x7 = rotl32(x7 ^ x11, 7)
- vpaddd %ymm15,%ymm11,%ymm11
- vpxord %ymm11,%ymm7,%ymm7
- vprold $7,%ymm7,%ymm7
+ vpaddd V15,V11,V11
+ vpxord V11,V7,V7
+ vprold $7,V7,V7
# x0 += x5, x15 = rotl32(x15 ^ x0, 16)
- vpaddd %ymm0,%ymm5,%ymm0
- vpxord %ymm0,%ymm15,%ymm15
- vprold $16,%ymm15,%ymm15
+ vpaddd V0,V5,V0
+ vpxord V0,V15,V15
+ vprold $16,V15,V15
# x1 += x6, x12 = rotl32(x12 ^ x1, 16)
- vpaddd %ymm1,%ymm6,%ymm1
- vpxord %ymm1,%ymm12,%ymm12
- vprold $16,%ymm12,%ymm12
+ vpaddd V1,V6,V1
+ vpxord V1,V12,V12
+ vprold $16,V12,V12
# x2 += x7, x13 = rotl32(x13 ^ x2, 16)
- vpaddd %ymm2,%ymm7,%ymm2
- vpxord %ymm2,%ymm13,%ymm13
- vprold $16,%ymm13,%ymm13
+ vpaddd V2,V7,V2
+ vpxord V2,V13,V13
+ vprold $16,V13,V13
# x3 += x4, x14 = rotl32(x14 ^ x3, 16)
- vpaddd %ymm3,%ymm4,%ymm3
- vpxord %ymm3,%ymm14,%ymm14
- vprold $16,%ymm14,%ymm14
+ vpaddd V3,V4,V3
+ vpxord V3,V14,V14
+ vprold $16,V14,V14
# x10 += x15, x5 = rotl32(x5 ^ x10, 12)
- vpaddd %ymm15,%ymm10,%ymm10
- vpxord %ymm10,%ymm5,%ymm5
- vprold $12,%ymm5,%ymm5
+ vpaddd V15,V10,V10
+ vpxord V10,V5,V5
+ vprold $12,V5,V5
# x11 += x12, x6 = rotl32(x6 ^ x11, 12)
- vpaddd %ymm12,%ymm11,%ymm11
- vpxord %ymm11,%ymm6,%ymm6
- vprold $12,%ymm6,%ymm6
+ vpaddd V12,V11,V11
+ vpxord V11,V6,V6
+ vprold $12,V6,V6
# x8 += x13, x7 = rotl32(x7 ^ x8, 12)
- vpaddd %ymm13,%ymm8,%ymm8
- vpxord %ymm8,%ymm7,%ymm7
- vprold $12,%ymm7,%ymm7
+ vpaddd V13,V8,V8
+ vpxord V8,V7,V7
+ vprold $12,V7,V7
# x9 += x14, x4 = rotl32(x4 ^ x9, 12)
- vpaddd %ymm14,%ymm9,%ymm9
- vpxord %ymm9,%ymm4,%ymm4
- vprold $12,%ymm4,%ymm4
+ vpaddd V14,V9,V9
+ vpxord V9,V4,V4
+ vprold $12,V4,V4
# x0 += x5, x15 = rotl32(x15 ^ x0, 8)
- vpaddd %ymm0,%ymm5,%ymm0
- vpxord %ymm0,%ymm15,%ymm15
- vprold $8,%ymm15,%ymm15
+ vpaddd V0,V5,V0
+ vpxord V0,V15,V15
+ vprold $8,V15,V15
# x1 += x6, x12 = rotl32(x12 ^ x1, 8)
- vpaddd %ymm1,%ymm6,%ymm1
- vpxord %ymm1,%ymm12,%ymm12
- vprold $8,%ymm12,%ymm12
+ vpaddd V1,V6,V1
+ vpxord V1,V12,V12
+ vprold $8,V12,V12
# x2 += x7, x13 = rotl32(x13 ^ x2, 8)
- vpaddd %ymm2,%ymm7,%ymm2
- vpxord %ymm2,%ymm13,%ymm13
- vprold $8,%ymm13,%ymm13
+ vpaddd V2,V7,V2
+ vpxord V2,V13,V13
+ vprold $8,V13,V13
# x3 += x4, x14 = rotl32(x14 ^ x3, 8)
- vpaddd %ymm3,%ymm4,%ymm3
- vpxord %ymm3,%ymm14,%ymm14
- vprold $8,%ymm14,%ymm14
+ vpaddd V3,V4,V3
+ vpxord V3,V14,V14
+ vprold $8,V14,V14
# x10 += x15, x5 = rotl32(x5 ^ x10, 7)
- vpaddd %ymm15,%ymm10,%ymm10
- vpxord %ymm10,%ymm5,%ymm5
- vprold $7,%ymm5,%ymm5
+ vpaddd V15,V10,V10
+ vpxord V10,V5,V5
+ vprold $7,V5,V5
# x11 += x12, x6 = rotl32(x6 ^ x11, 7)
- vpaddd %ymm12,%ymm11,%ymm11
- vpxord %ymm11,%ymm6,%ymm6
- vprold $7,%ymm6,%ymm6
+ vpaddd V12,V11,V11
+ vpxord V11,V6,V6
+ vprold $7,V6,V6
# x8 += x13, x7 = rotl32(x7 ^ x8, 7)
- vpaddd %ymm13,%ymm8,%ymm8
- vpxord %ymm8,%ymm7,%ymm7
- vprold $7,%ymm7,%ymm7
+ vpaddd V13,V8,V8
+ vpxord V8,V7,V7
+ vprold $7,V7,V7
# x9 += x14, x4 = rotl32(x4 ^ x9, 7)
- vpaddd %ymm14,%ymm9,%ymm9
- vpxord %ymm9,%ymm4,%ymm4
- vprold $7,%ymm4,%ymm4
+ vpaddd V14,V9,V9
+ vpxord V9,V4,V4
+ vprold $7,V4,V4
sub $2,%r8d
- jnz .Ldoubleround8
-
- # x0..15[0-3] += s[0..15]
- vpaddd %ymm16,%ymm0,%ymm0
- vpaddd %ymm17,%ymm1,%ymm1
- vpaddd %ymm18,%ymm2,%ymm2
- vpaddd %ymm19,%ymm3,%ymm3
- vpaddd %ymm20,%ymm4,%ymm4
- vpaddd %ymm21,%ymm5,%ymm5
- vpaddd %ymm22,%ymm6,%ymm6
- vpaddd %ymm23,%ymm7,%ymm7
- vpaddd %ymm24,%ymm8,%ymm8
- vpaddd %ymm25,%ymm9,%ymm9
- vpaddd %ymm26,%ymm10,%ymm10
- vpaddd %ymm27,%ymm11,%ymm11
- vpaddd %ymm28,%ymm12,%ymm12
- vpaddd %ymm29,%ymm13,%ymm13
- vpaddd %ymm30,%ymm14,%ymm14
- vpaddd %ymm31,%ymm15,%ymm15
+ jnz .Ldoubleround\@
+
+ # x0..15 += s[0..15]
+ vpaddd V16,V0,V0
+ vpaddd V17,V1,V1
+ vpaddd V18,V2,V2
+ vpaddd V19,V3,V3
+ vpaddd V20,V4,V4
+ vpaddd V21,V5,V5
+ vpaddd V22,V6,V6
+ vpaddd V23,V7,V7
+ vpaddd V24,V8,V8
+ vpaddd V25,V9,V9
+ vpaddd V26,V10,V10
+ vpaddd V27,V11,V11
+ vpaddd V28,V12,V12
+ vpaddd V29,V13,V13
+ vpaddd V30,V14,V14
+ vpaddd V31,V15,V15
# interleave 32-bit words in state n, n+1
- vpunpckldq %ymm1,%ymm0,%ymm16
- vpunpckhdq %ymm1,%ymm0,%ymm17
- vpunpckldq %ymm3,%ymm2,%ymm18
- vpunpckhdq %ymm3,%ymm2,%ymm19
- vpunpckldq %ymm5,%ymm4,%ymm20
- vpunpckhdq %ymm5,%ymm4,%ymm21
- vpunpckldq %ymm7,%ymm6,%ymm22
- vpunpckhdq %ymm7,%ymm6,%ymm23
- vpunpckldq %ymm9,%ymm8,%ymm24
- vpunpckhdq %ymm9,%ymm8,%ymm25
- vpunpckldq %ymm11,%ymm10,%ymm26
- vpunpckhdq %ymm11,%ymm10,%ymm27
- vpunpckldq %ymm13,%ymm12,%ymm28
- vpunpckhdq %ymm13,%ymm12,%ymm29
- vpunpckldq %ymm15,%ymm14,%ymm30
- vpunpckhdq %ymm15,%ymm14,%ymm31
+ vpunpckldq V1,V0,V16
+ vpunpckhdq V1,V0,V17
+ vpunpckldq V3,V2,V18
+ vpunpckhdq V3,V2,V19
+ vpunpckldq V5,V4,V20
+ vpunpckhdq V5,V4,V21
+ vpunpckldq V7,V6,V22
+ vpunpckhdq V7,V6,V23
+ vpunpckldq V9,V8,V24
+ vpunpckhdq V9,V8,V25
+ vpunpckldq V11,V10,V26
+ vpunpckhdq V11,V10,V27
+ vpunpckldq V13,V12,V28
+ vpunpckhdq V13,V12,V29
+ vpunpckldq V15,V14,V30
+ vpunpckhdq V15,V14,V31
# interleave 64-bit words in state n, n+2
- vpunpcklqdq %ymm18,%ymm16,%ymm0
- vpunpcklqdq %ymm19,%ymm17,%ymm1
- vpunpckhqdq %ymm18,%ymm16,%ymm2
- vpunpckhqdq %ymm19,%ymm17,%ymm3
- vpunpcklqdq %ymm22,%ymm20,%ymm4
- vpunpcklqdq %ymm23,%ymm21,%ymm5
- vpunpckhqdq %ymm22,%ymm20,%ymm6
- vpunpckhqdq %ymm23,%ymm21,%ymm7
- vpunpcklqdq %ymm26,%ymm24,%ymm8
- vpunpcklqdq %ymm27,%ymm25,%ymm9
- vpunpckhqdq %ymm26,%ymm24,%ymm10
- vpunpckhqdq %ymm27,%ymm25,%ymm11
- vpunpcklqdq %ymm30,%ymm28,%ymm12
- vpunpcklqdq %ymm31,%ymm29,%ymm13
- vpunpckhqdq %ymm30,%ymm28,%ymm14
- vpunpckhqdq %ymm31,%ymm29,%ymm15
+ vpunpcklqdq V18,V16,V0
+ vpunpcklqdq V19,V17,V1
+ vpunpckhqdq V18,V16,V2
+ vpunpckhqdq V19,V17,V3
+ vpunpcklqdq V22,V20,V4
+ vpunpcklqdq V23,V21,V5
+ vpunpckhqdq V22,V20,V6
+ vpunpckhqdq V23,V21,V7
+ vpunpcklqdq V26,V24,V8
+ vpunpcklqdq V27,V25,V9
+ vpunpckhqdq V26,V24,V10
+ vpunpckhqdq V27,V25,V11
+ vpunpcklqdq V30,V28,V12
+ vpunpcklqdq V31,V29,V13
+ vpunpckhqdq V30,V28,V14
+ vpunpckhqdq V31,V29,V15
# interleave 128-bit words in state n, n+4
# xor/write first four blocks
- vmovdqa64 %ymm0,%ymm16
- vperm2i128 $0x20,%ymm4,%ymm0,%ymm0
+ vmovdqa64 V0,V16
+ vperm2i128 $0x20,V4,V0,V0
cmp $0x0020,%rcx
- jl .Lxorpart8
- vpxord 0x0000(%rdx),%ymm0,%ymm0
- vmovdqu64 %ymm0,0x0000(%rsi)
- vmovdqa64 %ymm16,%ymm0
- vperm2i128 $0x31,%ymm4,%ymm0,%ymm4
+ jl .Lxorpart\@
+ vpxord 0x0000(%rdx),V0,V0
+ vmovdqu64 V0,0x0000(%rsi)
+ vmovdqa64 V16,V0
+ vperm2i128 $0x31,V4,V0,V4
- vperm2i128 $0x20,%ymm12,%ymm8,%ymm0
+ vperm2i128 $0x20,V12,V8,V0
cmp $0x0040,%rcx
- jl .Lxorpart8
- vpxord 0x0020(%rdx),%ymm0,%ymm0
- vmovdqu64 %ymm0,0x0020(%rsi)
- vperm2i128 $0x31,%ymm12,%ymm8,%ymm12
+ jl .Lxorpart\@
+ vpxord 0x0020(%rdx),V0,V0
+ vmovdqu64 V0,0x0020(%rsi)
+ vperm2i128 $0x31,V12,V8,V12
- vperm2i128 $0x20,%ymm6,%ymm2,%ymm0
+ vperm2i128 $0x20,V6,V2,V0
cmp $0x0060,%rcx
- jl .Lxorpart8
- vpxord 0x0040(%rdx),%ymm0,%ymm0
- vmovdqu64 %ymm0,0x0040(%rsi)
- vperm2i128 $0x31,%ymm6,%ymm2,%ymm6
+ jl .Lxorpart\@
+ vpxord 0x0040(%rdx),V0,V0
+ vmovdqu64 V0,0x0040(%rsi)
+ vperm2i128 $0x31,V6,V2,V6
- vperm2i128 $0x20,%ymm14,%ymm10,%ymm0
+ vperm2i128 $0x20,V14,V10,V0
cmp $0x0080,%rcx
- jl .Lxorpart8
- vpxord 0x0060(%rdx),%ymm0,%ymm0
- vmovdqu64 %ymm0,0x0060(%rsi)
- vperm2i128 $0x31,%ymm14,%ymm10,%ymm14
+ jl .Lxorpart\@
+ vpxord 0x0060(%rdx),V0,V0
+ vmovdqu64 V0,0x0060(%rsi)
+ vperm2i128 $0x31,V14,V10,V14
- vperm2i128 $0x20,%ymm5,%ymm1,%ymm0
+ vperm2i128 $0x20,V5,V1,V0
cmp $0x00a0,%rcx
- jl .Lxorpart8
- vpxord 0x0080(%rdx),%ymm0,%ymm0
- vmovdqu64 %ymm0,0x0080(%rsi)
- vperm2i128 $0x31,%ymm5,%ymm1,%ymm5
+ jl .Lxorpart\@
+ vpxord 0x0080(%rdx),V0,V0
+ vmovdqu64 V0,0x0080(%rsi)
+ vperm2i128 $0x31,V5,V1,V5
- vperm2i128 $0x20,%ymm13,%ymm9,%ymm0
+ vperm2i128 $0x20,V13,V9,V0
cmp $0x00c0,%rcx
- jl .Lxorpart8
- vpxord 0x00a0(%rdx),%ymm0,%ymm0
- vmovdqu64 %ymm0,0x00a0(%rsi)
- vperm2i128 $0x31,%ymm13,%ymm9,%ymm13
+ jl .Lxorpart\@
+ vpxord 0x00a0(%rdx),V0,V0
+ vmovdqu64 V0,0x00a0(%rsi)
+ vperm2i128 $0x31,V13,V9,V13
- vperm2i128 $0x20,%ymm7,%ymm3,%ymm0
+ vperm2i128 $0x20,V7,V3,V0
cmp $0x00e0,%rcx
- jl .Lxorpart8
- vpxord 0x00c0(%rdx),%ymm0,%ymm0
- vmovdqu64 %ymm0,0x00c0(%rsi)
- vperm2i128 $0x31,%ymm7,%ymm3,%ymm7
+ jl .Lxorpart\@
+ vpxord 0x00c0(%rdx),V0,V0
+ vmovdqu64 V0,0x00c0(%rsi)
+ vperm2i128 $0x31,V7,V3,V7
- vperm2i128 $0x20,%ymm15,%ymm11,%ymm0
+ vperm2i128 $0x20,V15,V11,V0
cmp $0x0100,%rcx
- jl .Lxorpart8
- vpxord 0x00e0(%rdx),%ymm0,%ymm0
- vmovdqu64 %ymm0,0x00e0(%rsi)
- vperm2i128 $0x31,%ymm15,%ymm11,%ymm15
+ jl .Lxorpart\@
+ vpxord 0x00e0(%rdx),V0,V0
+ vmovdqu64 V0,0x00e0(%rsi)
+ vperm2i128 $0x31,V15,V11,V15
# xor remaining blocks, write to output
- vmovdqa64 %ymm4,%ymm0
+ vmovdqa64 V4,V0
cmp $0x0120,%rcx
- jl .Lxorpart8
- vpxord 0x0100(%rdx),%ymm0,%ymm0
- vmovdqu64 %ymm0,0x0100(%rsi)
+ jl .Lxorpart\@
+ vpxord 0x0100(%rdx),V0,V0
+ vmovdqu64 V0,0x0100(%rsi)
- vmovdqa64 %ymm12,%ymm0
+ vmovdqa64 V12,V0
cmp $0x0140,%rcx
- jl .Lxorpart8
- vpxord 0x0120(%rdx),%ymm0,%ymm0
- vmovdqu64 %ymm0,0x0120(%rsi)
+ jl .Lxorpart\@
+ vpxord 0x0120(%rdx),V0,V0
+ vmovdqu64 V0,0x0120(%rsi)
- vmovdqa64 %ymm6,%ymm0
+ vmovdqa64 V6,V0
cmp $0x0160,%rcx
- jl .Lxorpart8
- vpxord 0x0140(%rdx),%ymm0,%ymm0
- vmovdqu64 %ymm0,0x0140(%rsi)
+ jl .Lxorpart\@
+ vpxord 0x0140(%rdx),V0,V0
+ vmovdqu64 V0,0x0140(%rsi)
- vmovdqa64 %ymm14,%ymm0
+ vmovdqa64 V14,V0
cmp $0x0180,%rcx
- jl .Lxorpart8
- vpxord 0x0160(%rdx),%ymm0,%ymm0
- vmovdqu64 %ymm0,0x0160(%rsi)
+ jl .Lxorpart\@
+ vpxord 0x0160(%rdx),V0,V0
+ vmovdqu64 V0,0x0160(%rsi)
- vmovdqa64 %ymm5,%ymm0
+ vmovdqa64 V5,V0
cmp $0x01a0,%rcx
- jl .Lxorpart8
- vpxord 0x0180(%rdx),%ymm0,%ymm0
- vmovdqu64 %ymm0,0x0180(%rsi)
+ jl .Lxorpart\@
+ vpxord 0x0180(%rdx),V0,V0
+ vmovdqu64 V0,0x0180(%rsi)
- vmovdqa64 %ymm13,%ymm0
+ vmovdqa64 V13,V0
cmp $0x01c0,%rcx
- jl .Lxorpart8
- vpxord 0x01a0(%rdx),%ymm0,%ymm0
- vmovdqu64 %ymm0,0x01a0(%rsi)
+ jl .Lxorpart\@
+ vpxord 0x01a0(%rdx),V0,V0
+ vmovdqu64 V0,0x01a0(%rsi)
- vmovdqa64 %ymm7,%ymm0
+ vmovdqa64 V7,V0
cmp $0x01e0,%rcx
- jl .Lxorpart8
- vpxord 0x01c0(%rdx),%ymm0,%ymm0
- vmovdqu64 %ymm0,0x01c0(%rsi)
+ jl .Lxorpart\@
+ vpxord 0x01c0(%rdx),V0,V0
+ vmovdqu64 V0,0x01c0(%rsi)
- vmovdqa64 %ymm15,%ymm0
+ vmovdqa64 V15,V0
cmp $0x0200,%rcx
- jl .Lxorpart8
- vpxord 0x01e0(%rdx),%ymm0,%ymm0
- vmovdqu64 %ymm0,0x01e0(%rsi)
+ jl .Lxorpart\@
+ vpxord 0x01e0(%rdx),V0,V0
+ vmovdqu64 V0,0x01e0(%rsi)
-.Ldone8:
+.Ldone\@:
vzeroupper
RET
-.Lxorpart8:
+.Lxorpart\@:
# xor remaining bytes from partial register into output
mov %rcx,%rax
- and $0x1f,%rcx
- jz .Ldone8
+ and $(VL - 1),%rcx
+ jz .Ldone\@
mov %rax,%r9
- and $~0x1f,%r9
+ and $~(VL - 1),%r9
mov $1,%rax
shld %cl,%rax,%rax
sub $1,%rax
kmovq %rax,%k1
- vmovdqu8 (%rdx,%r9),%ymm1{%k1}{z}
- vpxord %ymm0,%ymm1,%ymm1
- vmovdqu8 %ymm1,(%rsi,%r9){%k1}
+ vmovdqu8 (%rdx,%r9),V1{%k1}{z}
+ vpxord V0,V1,V1
+ vmovdqu8 V1,(%rsi,%r9){%k1}
- jmp .Ldone8
+ jmp .Ldone\@
+.endm
+SYM_FUNC_START(chacha_8block_xor_avx512vl)
+ _chacha_words vl=32
SYM_FUNC_END(chacha_8block_xor_avx512vl)
--
2.53.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH v2 3/3] lib/crypto: x86/chacha: Add a 16-block AVX-512 function
2026-11-02 11:39 [PATCH v2 0/3] lib/crypto: x86/chacha: Add a 16-block AVX-512 function Martin Willi
2026-11-02 11:39 ` [PATCH v2 1/3] lib/crypto: x86/chacha: Rename the AVX-512VL assembly file Martin Willi
2026-11-02 11:39 ` [PATCH v2 2/3] lib/crypto: x86/chacha: Wrap the 8-block AVX-512 code in a macro Martin Willi
@ 2026-11-02 11:39 ` Martin Willi
2026-11-03 13:49 ` [PATCH v2 0/3] " Antonio Quartulli
` (2 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Martin Willi @ 2026-11-02 11:39 UTC (permalink / raw)
To: Eric Biggers, linux-crypto
Cc: Jason A. Donenfeld, Ard Biesheuvel, Antonio Quartulli
The AVX-512VL code processes at most 8 blocks at a time in 256-bit ymm
registers. That width was chosen to avoid the heavy core down-clocking
that 512-bit zmm instructions triggered on Skylake-X.
That penalty is gone on more recent AVX-512 parts, where full 512-bit
registers can encrypt 16 blocks per invocation and roughly double the
data-level parallelism for bulk traffic. So instantiate the shared block
macro a second time at VL=64, where only the final lane-crossing
transpose differs. Enable it on top of the avx512vl path, gated only by
X86_FEATURE_PREFER_YMM, and dispatch to it for inputs larger than
8 blocks.
On a Zen 5 Strix Halo, which has the full 512-bit datapath, the
benchmark_chacha case of the ChaCha KUnit suite reports:
Length Before After Change
====== ========== ========== ======
768 3579 MB/s 7125 MB/s +99.1%
1024 4786 MB/s 9401 MB/s +96.4%
1420 4424 MB/s 6622 MB/s +49.7%
2048 4827 MB/s 9345 MB/s +93.6%
4096 4778 MB/s 9384 MB/s +96.4%
8920 4637 MB/s 9004 MB/s +94.2%
16384 4807 MB/s 9359 MB/s +94.7%
The additional 768 length shows the gain of a single 16-block call
over the 8-block plus 4-block calls. The 1420 length requires a
16-block call followed by an 8-block call, so the gain roughly halves.
Like the 8-block function, the 16-block one keeps the state words in
registers for the final add. Re-adding them straight from the state
matrix via embedded broadcast is about 0.5% faster on that Zen 5. But
in the 8-block function, the same costs a Tiger Lake up to 2%, and that
function carries the bulk traffic there. As a separate code path for
VL=64 isn't worth the small gain, keep the register copy for both
widths.
Signed-off-by: Martin Willi <martin@strongswan.org>
---
lib/crypto/x86/chacha-avx512-x86_64.S | 148 +++++++++++++++++++++++++-
lib/crypto/x86/chacha.h | 28 ++++-
2 files changed, 173 insertions(+), 3 deletions(-)
diff --git a/lib/crypto/x86/chacha-avx512-x86_64.S b/lib/crypto/x86/chacha-avx512-x86_64.S
index 35e73de1c870..92babb1d3844 100644
--- a/lib/crypto/x86/chacha-avx512-x86_64.S
+++ b/lib/crypto/x86/chacha-avx512-x86_64.S
@@ -17,16 +17,20 @@ CTR2BL: .octa 0x00000000000000000000000000000000
CTR4BL: .octa 0x00000000000000000000000000000002
.octa 0x00000000000000000000000000000003
-.section .rodata.cst32.CTRBL, "aM", @progbits, 32
-.align 32
+.section .rodata.cst64.CTRBL, "aM", @progbits, 64
+.align 64
CTRBL: .octa 0x00000003000000020000000100000000
.octa 0x00000007000000060000000500000004
+ .octa 0x0000000b0000000a0000000900000008
+ .octa 0x0000000f0000000e0000000d0000000c
.text
.macro _define_Vi i
.if VL == 32
.set V\i, %ymm\i
+.elseif VL == 64
+ .set V\i, %zmm\i
.else
.error "Unsupported vector length"
.endif
@@ -487,6 +491,7 @@ SYM_FUNC_END(chacha_4block_xor_avx512vl)
# registers.
#
# VL=32 encrypts eight blocks in 256-bit ymm registers.
+ # VL=64 encrypts sixteen blocks in 512-bit zmm registers.
vzeroupper
@@ -704,6 +709,7 @@ SYM_FUNC_END(chacha_4block_xor_avx512vl)
vpunpckldq V15,V14,V30
vpunpckhdq V15,V14,V31
+.if VL == 32
# interleave 64-bit words in state n, n+2
vpunpcklqdq V18,V16,V0
vpunpcklqdq V19,V17,V1
@@ -830,6 +836,140 @@ SYM_FUNC_END(chacha_4block_xor_avx512vl)
jl .Lxorpart\@
vpxord 0x01e0(%rdx),V0,V0
vmovdqu64 V0,0x01e0(%rsi)
+.else
+ # interleave 64-bit words in state n, n+2 -> zmm0..15
+ vpunpcklqdq V18,V16,V0
+ vpunpckhqdq V18,V16,V1
+ vpunpcklqdq V19,V17,V2
+ vpunpckhqdq V19,V17,V3
+ vpunpcklqdq V22,V20,V4
+ vpunpckhqdq V22,V20,V5
+ vpunpcklqdq V23,V21,V6
+ vpunpckhqdq V23,V21,V7
+ vpunpcklqdq V26,V24,V8
+ vpunpckhqdq V26,V24,V9
+ vpunpcklqdq V27,V25,V10
+ vpunpckhqdq V27,V25,V11
+ vpunpcklqdq V30,V28,V12
+ vpunpckhqdq V30,V28,V13
+ vpunpcklqdq V31,V29,V14
+ vpunpckhqdq V31,V29,V15
+
+ # interleave 128-bit lanes in state n, n+4 -> zmm16..31
+ vshufi64x2 $0x88,V4,V0,V16
+ vshufi64x2 $0x88,V12,V8,V20
+ vshufi64x2 $0xdd,V4,V0,V24
+ vshufi64x2 $0xdd,V12,V8,V28
+ vshufi64x2 $0x88,V5,V1,V17
+ vshufi64x2 $0x88,V13,V9,V21
+ vshufi64x2 $0xdd,V5,V1,V25
+ vshufi64x2 $0xdd,V13,V9,V29
+ vshufi64x2 $0x88,V6,V2,V18
+ vshufi64x2 $0x88,V14,V10,V22
+ vshufi64x2 $0xdd,V6,V2,V26
+ vshufi64x2 $0xdd,V14,V10,V30
+ vshufi64x2 $0x88,V7,V3,V19
+ vshufi64x2 $0x88,V15,V11,V23
+ vshufi64x2 $0xdd,V7,V3,V27
+ vshufi64x2 $0xdd,V15,V11,V31
+
+ # fuse the final 256-bit interleave into the xor/store ladder
+ vshufi64x2 $0x88,V20,V16,V0
+ cmp $0x0040,%rcx
+ jl .Lxorpart\@
+ vpxord 0x0000(%rdx),V0,V0
+ vmovdqu64 V0,0x0000(%rsi)
+
+ vshufi64x2 $0x88,V21,V17,V0
+ cmp $0x0080,%rcx
+ jl .Lxorpart\@
+ vpxord 0x0040(%rdx),V0,V0
+ vmovdqu64 V0,0x0040(%rsi)
+
+ vshufi64x2 $0x88,V22,V18,V0
+ cmp $0x00c0,%rcx
+ jl .Lxorpart\@
+ vpxord 0x0080(%rdx),V0,V0
+ vmovdqu64 V0,0x0080(%rsi)
+
+ vshufi64x2 $0x88,V23,V19,V0
+ cmp $0x0100,%rcx
+ jl .Lxorpart\@
+ vpxord 0x00c0(%rdx),V0,V0
+ vmovdqu64 V0,0x00c0(%rsi)
+
+ vshufi64x2 $0x88,V28,V24,V0
+ cmp $0x0140,%rcx
+ jl .Lxorpart\@
+ vpxord 0x0100(%rdx),V0,V0
+ vmovdqu64 V0,0x0100(%rsi)
+
+ vshufi64x2 $0x88,V29,V25,V0
+ cmp $0x0180,%rcx
+ jl .Lxorpart\@
+ vpxord 0x0140(%rdx),V0,V0
+ vmovdqu64 V0,0x0140(%rsi)
+
+ vshufi64x2 $0x88,V30,V26,V0
+ cmp $0x01c0,%rcx
+ jl .Lxorpart\@
+ vpxord 0x0180(%rdx),V0,V0
+ vmovdqu64 V0,0x0180(%rsi)
+
+ vshufi64x2 $0x88,V31,V27,V0
+ cmp $0x0200,%rcx
+ jl .Lxorpart\@
+ vpxord 0x01c0(%rdx),V0,V0
+ vmovdqu64 V0,0x01c0(%rsi)
+
+ vshufi64x2 $0xdd,V20,V16,V0
+ cmp $0x0240,%rcx
+ jl .Lxorpart\@
+ vpxord 0x0200(%rdx),V0,V0
+ vmovdqu64 V0,0x0200(%rsi)
+
+ vshufi64x2 $0xdd,V21,V17,V0
+ cmp $0x0280,%rcx
+ jl .Lxorpart\@
+ vpxord 0x0240(%rdx),V0,V0
+ vmovdqu64 V0,0x0240(%rsi)
+
+ vshufi64x2 $0xdd,V22,V18,V0
+ cmp $0x02c0,%rcx
+ jl .Lxorpart\@
+ vpxord 0x0280(%rdx),V0,V0
+ vmovdqu64 V0,0x0280(%rsi)
+
+ vshufi64x2 $0xdd,V23,V19,V0
+ cmp $0x0300,%rcx
+ jl .Lxorpart\@
+ vpxord 0x02c0(%rdx),V0,V0
+ vmovdqu64 V0,0x02c0(%rsi)
+
+ vshufi64x2 $0xdd,V28,V24,V0
+ cmp $0x0340,%rcx
+ jl .Lxorpart\@
+ vpxord 0x0300(%rdx),V0,V0
+ vmovdqu64 V0,0x0300(%rsi)
+
+ vshufi64x2 $0xdd,V29,V25,V0
+ cmp $0x0380,%rcx
+ jl .Lxorpart\@
+ vpxord 0x0340(%rdx),V0,V0
+ vmovdqu64 V0,0x0340(%rsi)
+
+ vshufi64x2 $0xdd,V30,V26,V0
+ cmp $0x03c0,%rcx
+ jl .Lxorpart\@
+ vpxord 0x0380(%rdx),V0,V0
+ vmovdqu64 V0,0x0380(%rsi)
+
+ vshufi64x2 $0xdd,V31,V27,V0
+ cmp $0x0400,%rcx
+ jl .Lxorpart\@
+ vpxord 0x03c0(%rdx),V0,V0
+ vmovdqu64 V0,0x03c0(%rsi)
+.endif
.Ldone\@:
vzeroupper
@@ -858,3 +998,7 @@ SYM_FUNC_END(chacha_4block_xor_avx512vl)
SYM_FUNC_START(chacha_8block_xor_avx512vl)
_chacha_words vl=32
SYM_FUNC_END(chacha_8block_xor_avx512vl)
+
+SYM_FUNC_START(chacha_16block_xor_avx512)
+ _chacha_words vl=64
+SYM_FUNC_END(chacha_16block_xor_avx512)
diff --git a/lib/crypto/x86/chacha.h b/lib/crypto/x86/chacha.h
index e97f1f252bcc..fdf01b07742e 100644
--- a/lib/crypto/x86/chacha.h
+++ b/lib/crypto/x86/chacha.h
@@ -39,9 +39,14 @@ asmlinkage void chacha_8block_xor_avx512vl(const struct chacha_state *state,
u8 *dst, const u8 *src, size_t len,
int nrounds);
+asmlinkage void chacha_16block_xor_avx512(const struct chacha_state *state,
+ u8 *dst, const u8 *src, size_t len,
+ int nrounds);
+
static __ro_after_init DEFINE_STATIC_KEY_FALSE(chacha_use_simd);
static __ro_after_init DEFINE_STATIC_KEY_FALSE(chacha_use_avx2);
static __ro_after_init DEFINE_STATIC_KEY_FALSE(chacha_use_avx512vl);
+static __ro_after_init DEFINE_STATIC_KEY_FALSE(chacha_use_avx512);
static size_t chacha_advance(size_t len, size_t maxblocks)
{
@@ -52,6 +57,23 @@ static size_t chacha_advance(size_t len, size_t maxblocks)
static void chacha_dosimd(struct chacha_state *state, u8 *dst, const u8 *src,
size_t bytes, int nrounds)
{
+ if (static_branch_likely(&chacha_use_avx512)) {
+ while (bytes >= CHACHA_BLOCK_SIZE * 16) {
+ chacha_16block_xor_avx512(state, dst, src, bytes,
+ nrounds);
+ bytes -= CHACHA_BLOCK_SIZE * 16;
+ src += CHACHA_BLOCK_SIZE * 16;
+ dst += CHACHA_BLOCK_SIZE * 16;
+ state->x[12] += 16;
+ }
+ if (bytes > CHACHA_BLOCK_SIZE * 8) {
+ chacha_16block_xor_avx512(state, dst, src, bytes,
+ nrounds);
+ state->x[12] += chacha_advance(bytes, 16);
+ return;
+ }
+ }
+
if (static_branch_likely(&chacha_use_avx512vl)) {
while (bytes >= CHACHA_BLOCK_SIZE * 8) {
chacha_8block_xor_avx512vl(state, dst, src, bytes,
@@ -169,7 +191,11 @@ static void chacha_mod_init_arch(void)
static_branch_enable(&chacha_use_avx2);
if (boot_cpu_has(X86_FEATURE_AVX512VL) &&
- boot_cpu_has(X86_FEATURE_AVX512BW)) /* kmovq */
+ boot_cpu_has(X86_FEATURE_AVX512BW)) { /* kmovq */
static_branch_enable(&chacha_use_avx512vl);
+
+ if (!boot_cpu_has(X86_FEATURE_PREFER_YMM))
+ static_branch_enable(&chacha_use_avx512);
+ }
}
}
--
2.53.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH v2 0/3] lib/crypto: x86/chacha: Add a 16-block AVX-512 function
2026-11-02 11:39 [PATCH v2 0/3] lib/crypto: x86/chacha: Add a 16-block AVX-512 function Martin Willi
` (2 preceding siblings ...)
2026-11-02 11:39 ` [PATCH v2 3/3] lib/crypto: x86/chacha: Add a 16-block AVX-512 function Martin Willi
@ 2026-11-03 13:49 ` Antonio Quartulli
2026-11-03 23:08 ` Eric Biggers
2026-11-03 23:31 ` Eric Biggers
5 siblings, 0 replies; 7+ messages in thread
From: Antonio Quartulli @ 2026-11-03 13:49 UTC (permalink / raw)
To: Martin Willi, Eric Biggers, linux-crypto
Cc: Jason A. Donenfeld, Ard Biesheuvel
Hi,
On 02/11/2026 12:39, Martin Willi wrote:
> Here is v2 of the 16-block ChaCha function for 512-bit zmm registers.
> Patch 1 renames the assembly file, patch 2 wraps the 8-block code in
> a macro, and patch 3 adds the 16-block function on top.
>
> I previously mentioned a larger series with more AVX refactorings to
> shared macros along with a 4-block zmm variant. That needs some
> more work, so here is just the 16-block variant.
>
> v1 used embedded broadcasts for the final ChaCha state add. This comes
> with a minor regression on older Intel chips when used in the 8-block
> variant. Therefore I kept the state words in registers in the macro
> version used by both 8/16-block variants, see patch 3.
>
> I don't have a Zen 4, which splits zmm instructions into two 256-bit
> halves, so I can't tell how the 16-block function performs there.
> If anybody has access to one, numbers from there would be great.
>
> Changes in v2:
> - Rename chacha-avx512vl-x86_64.S to chacha-avx512-x86_64.S
> - Generate the 8- and 16-block functions from a shared macro
> - Drop the cpu_has_xfeatures() and X86_FEATURE_AVX512F checks
> - Keep the state words in registers for the final add
> - Benchmark with the ChaCha KUnit suite instead of tcrypt
>
> v1: https://lore.kernel.org/linux-crypto/20260722153247.630519-1-martin@strongswan.org/
>
> Martin Willi (3):
> lib/crypto: x86/chacha: Rename the AVX-512VL assembly file
> lib/crypto: x86/chacha: Wrap the 8-block AVX-512 code in a macro
> lib/crypto: x86/chacha: Add a 16-block AVX-512 function
>
> lib/crypto/Makefile | 2 +-
> ...x512vl-x86_64.S => chacha-avx512-x86_64.S} | 730 +++++++++++-------
> lib/crypto/x86/chacha.h | 28 +-
> 3 files changed, 477 insertions(+), 283 deletions(-)
> rename lib/crypto/x86/{chacha-avx512vl-x86_64.S => chacha-avx512-x86_64.S} (55%)
>
>
> base-commit: c90bb21618db40f1f30a1c0ed58d4f46b27dba26
Thanks for this v2!
Unfortunately no Zen 4 here to test with.
This said, I gave the code a go on my Ryzen 9 3950X and I matched the
results without encountering any issue.
For the whole series:
Tested-by: Antonio Quartulli <antonio@mandelbit.com>
Regards,
--
Antonio Quartulli
CEO and Co-Founder
Mandelbit Srl
https://www.mandelbit.com
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v2 0/3] lib/crypto: x86/chacha: Add a 16-block AVX-512 function
2026-11-02 11:39 [PATCH v2 0/3] lib/crypto: x86/chacha: Add a 16-block AVX-512 function Martin Willi
` (3 preceding siblings ...)
2026-11-03 13:49 ` [PATCH v2 0/3] " Antonio Quartulli
@ 2026-11-03 23:08 ` Eric Biggers
2026-11-03 23:31 ` Eric Biggers
5 siblings, 0 replies; 7+ messages in thread
From: Eric Biggers @ 2026-11-03 23:08 UTC (permalink / raw)
To: Martin Willi
Cc: linux-crypto, Jason A. Donenfeld, Ard Biesheuvel,
Antonio Quartulli
On Mon, Nov 02, 2026 at 12:39:23PM +0100, Martin Willi wrote:
> I don't have a Zen 4, which splits zmm instructions into two 256-bit
> halves, so I can't tell how the 16-block function performs there.
> If anybody has access to one, numbers from there would be great.
chacha_kunit benchmark results from AMD Genoa (Zen 4 server processor):
(I added some extra lengths as well:)
| Len | Before | After | Improvement |
+-------+-----------+-----------+-------------+
| 1 | 6 MB/s | 6 MB/s | 0.00% |
| 16 | 106 MB/s | 106 MB/s | 0.00% |
| 64 | 437 MB/s | 437 MB/s | 0.00% |
| 127 | 1078 MB/s | 1072 MB/s | -0.56% |
| 128 | 1106 MB/s | 1101 MB/s | -0.45% |
| 200 | 1361 MB/s | 1316 MB/s | -3.31% |
| 256 | 1674 MB/s | 1612 MB/s | -3.70% |
| 511 | 2950 MB/s | 2970 MB/s | +0.68% |
| 512 | 3052 MB/s | 2976 MB/s | -2.49% |
| 768 | 2674 MB/s | 3417 MB/s | +27.79% |
| 1024 | 3241 MB/s | 4514 MB/s | +39.28% |
| 1420 | 3242 MB/s | 3845 MB/s | +18.60% |
| 2048 | 3587 MB/s | 4829 MB/s | +34.63% |
| 3173 | 3088 MB/s | 4439 MB/s | +43.75% |
| 4096 | 3743 MB/s | 5040 MB/s | +34.65% |
| 8920 | 3606 MB/s | 4846 MB/s | +34.39% |
| 16384 | 3739 MB/s | 5105 MB/s | +36.53% |
Note that mobile Zen 5 processors have only 256-bit ALUs as well. There
the results are similar.
It's still worth enabling AVX-512 code like this on these processors.
It's just not quite as helpful as it is on processors with 512-bit ALUs.
- Eric
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v2 0/3] lib/crypto: x86/chacha: Add a 16-block AVX-512 function
2026-11-02 11:39 [PATCH v2 0/3] lib/crypto: x86/chacha: Add a 16-block AVX-512 function Martin Willi
` (4 preceding siblings ...)
2026-11-03 23:08 ` Eric Biggers
@ 2026-11-03 23:31 ` Eric Biggers
5 siblings, 0 replies; 7+ messages in thread
From: Eric Biggers @ 2026-11-03 23:31 UTC (permalink / raw)
To: Martin Willi
Cc: linux-crypto, Jason A. Donenfeld, Ard Biesheuvel,
Antonio Quartulli
On Mon, Nov 02, 2026 at 12:39:23PM +0100, Martin Willi wrote:
> Here is v2 of the 16-block ChaCha function for 512-bit zmm registers.
> Patch 1 renames the assembly file, patch 2 wraps the 8-block code in
> a macro, and patch 3 adds the 16-block function on top.
>
> I previously mentioned a larger series with more AVX refactorings to
> shared macros along with a 4-block zmm variant. That needs some
> more work, so here is just the 16-block variant.
>
> v1 used embedded broadcasts for the final ChaCha state add. This comes
> with a minor regression on older Intel chips when used in the 8-block
> variant. Therefore I kept the state words in registers in the macro
> version used by both 8/16-block variants, see patch 3.
>
> I don't have a Zen 4, which splits zmm instructions into two 256-bit
> halves, so I can't tell how the 16-block function performs there.
> If anybody has access to one, numbers from there would be great.
>
> Changes in v2:
> - Rename chacha-avx512vl-x86_64.S to chacha-avx512-x86_64.S
> - Generate the 8- and 16-block functions from a shared macro
> - Drop the cpu_has_xfeatures() and X86_FEATURE_AVX512F checks
> - Keep the state words in registers for the final add
> - Benchmark with the ChaCha KUnit suite instead of tcrypt
>
> v1: https://lore.kernel.org/linux-crypto/20260722153247.630519-1-martin@strongswan.org/
>
> Martin Willi (3):
> lib/crypto: x86/chacha: Rename the AVX-512VL assembly file
> lib/crypto: x86/chacha: Wrap the 8-block AVX-512 code in a macro
> lib/crypto: x86/chacha: Add a 16-block AVX-512 function
Applied to https://git.kernel.org/pub/scm/linux/kernel/git/ebiggers/linux.git/log/?h=libcrypto-next
I updated the last commit message to add my results for Zen 4:
Results on Zen 4 (specifically Genoa), which has a 256-bit datapath:
Length Before After Change
====== ========== ========== ======
768 2674 MB/s 3417 MB/s +27.8%
1024 3241 MB/s 4514 MB/s +39.3%
1420 3242 MB/s 3845 MB/s +18.6%
2048 3587 MB/s 4829 MB/s +34.6%
4096 3743 MB/s 5040 MB/s +34.7%
8920 3606 MB/s 4846 MB/s +34.4%
16384 3739 MB/s 5105 MB/s +36.5%
- Eric
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-11-03 23:31 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-02 11:39 [PATCH v2 0/3] lib/crypto: x86/chacha: Add a 16-block AVX-512 function Martin Willi
2026-11-02 11:39 ` [PATCH v2 1/3] lib/crypto: x86/chacha: Rename the AVX-512VL assembly file Martin Willi
2026-11-02 11:39 ` [PATCH v2 2/3] lib/crypto: x86/chacha: Wrap the 8-block AVX-512 code in a macro Martin Willi
2026-11-02 11:39 ` [PATCH v2 3/3] lib/crypto: x86/chacha: Add a 16-block AVX-512 function Martin Willi
2026-11-03 13:49 ` [PATCH v2 0/3] " Antonio Quartulli
2026-11-03 23:08 ` Eric Biggers
2026-11-03 23:31 ` Eric Biggers
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox