* [PATCH] lib/crypto: x86/nh: Optimize nh_avx2()
@ 2026-11-05 4:24 Eric Biggers
0 siblings, 0 replies; only message in thread
From: Eric Biggers @ 2026-11-05 4:24 UTC (permalink / raw)
To: linux-crypto
Cc: Ard Biesheuvel, Jason A . Donenfeld, Herbert Xu, Eric Biggers
Various microoptimizations for nh_avx2(). Nothing too exciting:
- Instead of adding the message words to the key words and then
permuting both, do the following: permute both when loading, add the
permuted words, and multiply together adjacent pairs. This saves one
vpshufd instruction per 32 bytes processed, and the ones that remain
are now better separated in the flow.
- Reassign register aliases to put the most frequently used variables in
%ymm0-%ymm7, which take fewer bytes to encode in many instructions.
- Update the registers used in _nh_2xstride() to match nh_sse2() and
eliminate the need for T7.
- Replace the initial 'add $0x20, KEY' with base+displacement
addressing, which was already being used anyway in most cases.
- Update the horizontal sum algorithm at the end of the function to save
a couple instructions.
nh_avx2() shrinks from 664 bytes to 518 bytes, and a quick benchmark
shows 1% faster Adiantum encryption on x86_64.
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
lib/crypto/x86/nh-avx2.S | 116 +++++++++++++++++++--------------------
1 file changed, 57 insertions(+), 59 deletions(-)
diff --git a/lib/crypto/x86/nh-avx2.S b/lib/crypto/x86/nh-avx2.S
index 9c085a31b137..a2e9ed68dcd4 100644
--- a/lib/crypto/x86/nh-avx2.S
+++ b/lib/crypto/x86/nh-avx2.S
@@ -9,55 +9,55 @@
#include <linux/linkage.h>
-#define PASS0_SUMS %ymm0
-#define PASS1_SUMS %ymm1
-#define PASS2_SUMS %ymm2
-#define PASS3_SUMS %ymm3
-#define K0 %ymm4
-#define K0_XMM %xmm4
-#define K1 %ymm5
-#define K1_XMM %xmm5
-#define K2 %ymm6
-#define K2_XMM %xmm6
-#define K3 %ymm7
-#define K3_XMM %xmm7
-#define T0 %ymm8
-#define T1 %ymm9
-#define T2 %ymm10
-#define T2_XMM %xmm10
-#define T3 %ymm11
-#define T3_XMM %xmm11
-#define T4 %ymm12
-#define T5 %ymm13
-#define T6 %ymm14
-#define T7 %ymm15
+#define K0 %ymm0
+#define K0_XMM %xmm0
+#define K1 %ymm1
+#define K1_XMM %xmm1
+#define K2 %ymm2
+#define K2_XMM %xmm2
+#define K3 %ymm3
+#define K3_XMM %xmm3
+#define T0 %ymm4
+#define T1 %ymm5
+#define T2 %ymm6
+#define T2_XMM %xmm6
+#define T3 %ymm7
+#define T3_XMM %xmm7
+#define T4 %ymm8
+#define T5 %ymm9
+#define T6 %ymm10
+#define PASS0_SUMS %ymm11
+#define PASS1_SUMS %ymm12
+#define PASS2_SUMS %ymm13
+#define PASS3_SUMS %ymm14
#define KEY %rdi
#define MESSAGE %rsi
#define MESSAGE_LEN %rdx
#define HASH %rcx
+// Process 32 message bytes and accumulate the NH sums in PASS[0-3]_SUMS. The
+// message words are expected in T3 and the key words in \k0-\k3. Each group of
+// four message and key words must be in the order (0, 2, 1, 3), so that the
+// words multiplied by NH are next to each other. This clobbers \k0 and T0-T6.
+// It leaves \k1-\k3 alone, since they're needed for the next 32 bytes.
.macro _nh_2xstride k0, k1, k2, k3
- // Add message words to key words
- vpaddd \k0, T3, T0
+ // Add permuted message words to permuted key words
+ vpaddd \k0, T3, \k0
vpaddd \k1, T3, T1
vpaddd \k2, T3, T2
vpaddd \k3, T3, T3
- // Multiply 32x32 => 64 and accumulate
- vpshufd $0x10, T0, T4
- vpshufd $0x32, T0, T0
- vpshufd $0x10, T1, T5
- vpshufd $0x32, T1, T1
- vpshufd $0x10, T2, T6
- vpshufd $0x32, T2, T2
- vpshufd $0x10, T3, T7
- vpshufd $0x32, T3, T3
- vpmuludq T4, T0, T0
- vpmuludq T5, T1, T1
- vpmuludq T6, T2, T2
- vpmuludq T7, T3, T3
- vpaddq T0, PASS0_SUMS, PASS0_SUMS
+ // Multiply 32x32 (adjacent pairs) => 64 and accumulate
+ vpshufd $0x31, \k0, T4
+ vpshufd $0x31, T1, T5
+ vpshufd $0x31, T2, T6
+ vpshufd $0x31, T3, T0
+ vpmuludq \k0, T4, \k0
+ vpmuludq T1, T5, T1
+ vpmuludq T2, T6, T2
+ vpmuludq T3, T0, T3
+ vpaddq \k0, PASS0_SUMS, PASS0_SUMS
vpaddq T1, PASS1_SUMS, PASS1_SUMS
vpaddq T2, PASS2_SUMS, PASS2_SUMS
vpaddq T3, PASS3_SUMS, PASS3_SUMS
@@ -71,9 +71,8 @@
*/
SYM_FUNC_START(nh_avx2)
- vmovdqu 0x00(KEY), K0
- vmovdqu 0x10(KEY), K1
- add $0x20, KEY
+ vpshufd $0xd8, 0x00(KEY), K0
+ vpshufd $0xd8, 0x10(KEY), K1
vpxor PASS0_SUMS, PASS0_SUMS, PASS0_SUMS
vpxor PASS1_SUMS, PASS1_SUMS, PASS1_SUMS
vpxor PASS2_SUMS, PASS2_SUMS, PASS2_SUMS
@@ -82,14 +81,14 @@ SYM_FUNC_START(nh_avx2)
sub $0x40, MESSAGE_LEN
jl .Lloop4_done
.Lloop4:
- vmovdqu (MESSAGE), T3
- vmovdqu 0x00(KEY), K2
- vmovdqu 0x10(KEY), K3
+ vpshufd $0xd8, (MESSAGE), T3
+ vpshufd $0xd8, 0x20(KEY), K2
+ vpshufd $0xd8, 0x30(KEY), K3
_nh_2xstride K0, K1, K2, K3
- vmovdqu 0x20(MESSAGE), T3
- vmovdqu 0x20(KEY), K0
- vmovdqu 0x30(KEY), K1
+ vpshufd $0xd8, 0x20(MESSAGE), T3
+ vpshufd $0xd8, 0x40(KEY), K0
+ vpshufd $0xd8, 0x50(KEY), K1
_nh_2xstride K2, K3, K0, K1
add $0x40, MESSAGE
@@ -105,9 +104,9 @@ SYM_FUNC_START(nh_avx2)
jl .Llast
// 2 or 3 strides remain; do 2 more.
- vmovdqu (MESSAGE), T3
- vmovdqu 0x00(KEY), K2
- vmovdqu 0x10(KEY), K3
+ vpshufd $0xd8, (MESSAGE), T3
+ vpshufd $0xd8, 0x20(KEY), K2
+ vpshufd $0xd8, 0x30(KEY), K3
_nh_2xstride K0, K1, K2, K3
add $0x20, MESSAGE
add $0x20, KEY
@@ -118,11 +117,11 @@ SYM_FUNC_START(nh_avx2)
.Llast:
// Last stride. Zero the high 128 bits of the message and keys so they
// don't affect the result when processing them like 2 strides.
- vmovdqu (MESSAGE), T3_XMM
+ vpshufd $0xd8, (MESSAGE), T3_XMM
vmovdqa K0_XMM, K0_XMM
vmovdqa K1_XMM, K1_XMM
- vmovdqu 0x00(KEY), K2_XMM
- vmovdqu 0x10(KEY), K3_XMM
+ vpshufd $0xd8, 0x20(KEY), K2_XMM
+ vpshufd $0xd8, 0x30(KEY), K3_XMM
_nh_2xstride K0, K1, K2, K3
.Ldone:
@@ -144,14 +143,13 @@ SYM_FUNC_START(nh_avx2)
vpunpcklqdq PASS3_SUMS, PASS2_SUMS, T2 // T2 = (2A 3A 2C 3C)
vpunpckhqdq PASS3_SUMS, PASS2_SUMS, T3 // T3 = (2B 3B 2D 3D)
- vinserti128 $0x1, T2_XMM, T0, T4 // T4 = (0A 1A 2A 3A)
- vinserti128 $0x1, T3_XMM, T1, T5 // T5 = (0B 1B 2B 3B)
- vperm2i128 $0x31, T2, T0, T0 // T0 = (0C 1C 2C 3C)
- vperm2i128 $0x31, T3, T1, T1 // T1 = (0D 1D 2D 3D)
+ vpaddq T1, T0, T0 // T0 = (0A+0B 1A+1B 0C+0D 1C+1D)
+ vpaddq T3, T2, T2 // T2 = (2A+2B 3A+3B 2C+2D 3C+3D)
+
+ vinserti128 $0x1, T2_XMM, T0, T1 // T1 = (0A+0B 1A+1B 2A+2B 3A+3B)
+ vperm2i128 $0x31, T2, T0, T0 // T0 = (0C+0D 1C+1D 2C+2D 3C+3D)
- vpaddq T5, T4, T4
vpaddq T1, T0, T0
- vpaddq T4, T0, T0
vmovdqu T0, (HASH)
vzeroupper
RET
base-commit: 9fbbbaefd5f95551da18426c200cf41e1b4255a1
--
2.56.0
^ permalink raw reply related [flat|nested] only message in thread
only message in thread, other threads:[~2026-11-05 4:24 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-05 4:24 [PATCH] lib/crypto: x86/nh: Optimize nh_avx2() Eric Biggers
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox