From ebd5148f3e7768ee4663356f73b75be53e28f266 Mon Sep 17 00:00:00 2001 From: masih Date: Mon, 14 Sep 2026 17:10:39 +0000 Subject: [PATCH 1/2] Clear upper vector registers after the LtHash AVX-512 kernels --- .../state_db/sc/flatkv/lthash/backend_simd_amd64.go | 11 +++++++++++ sei-db/state_db/sc/flatkv/lthash/zeroupper_amd64.s | 8 ++++++++ 2 files changed, 19 insertions(+) create mode 100644 sei-db/state_db/sc/flatkv/lthash/zeroupper_amd64.s diff --git a/sei-db/state_db/sc/flatkv/lthash/backend_simd_amd64.go b/sei-db/state_db/sc/flatkv/lthash/backend_simd_amd64.go index 8c689b5caf..22a356d3d1 100644 --- a/sei-db/state_db/sc/flatkv/lthash/backend_simd_amd64.go +++ b/sei-db/state_db/sc/flatkv/lthash/backend_simd_amd64.go @@ -12,6 +12,11 @@ import ( //go:generate go run gen_blake3_xof16.go +// vzeroupper clears the upper halves of the vector registers. +// +//go:noescape +func vzeroupper() + // simdBackendName is the name reported by ActiveBackend for the AVX-512 path. const simdBackendName = "simd" @@ -60,6 +65,10 @@ func expandSIMD(data []byte, dst *LtHash) { in[12][lane] = 16 } xof16(&in, &out[1]) + // The compiler emits no VZEROUPPER after AVX-512 code, and legacy-SSE + // code in the caller (memmove, encoding) runs several times slower while + // the upper halves are dirty. + vzeroupper() } // singleChunkRoot compresses all but the last block of a one-chunk message @@ -154,6 +163,7 @@ func addSIMD(dst, src *LtHash) { for i := range a { archsimd.LoadUint16x32Array(&a[i]).Add(archsimd.LoadUint16x32Array(&b[i])).StoreArray(&a[i]) } + vzeroupper() } func subSIMD(dst, src *LtHash) { @@ -161,4 +171,5 @@ func subSIMD(dst, src *LtHash) { for i := range a { archsimd.LoadUint16x32Array(&a[i]).Sub(archsimd.LoadUint16x32Array(&b[i])).StoreArray(&a[i]) } + vzeroupper() } diff --git a/sei-db/state_db/sc/flatkv/lthash/zeroupper_amd64.s b/sei-db/state_db/sc/flatkv/lthash/zeroupper_amd64.s new file mode 100644 index 0000000000..6c4dd6d709 --- /dev/null +++ b/sei-db/state_db/sc/flatkv/lthash/zeroupper_amd64.s @@ -0,0 +1,8 @@ +//go:build goexperiment.simd && amd64 + +#include "textflag.h" + +// func vzeroupper() +TEXT ·vzeroupper(SB), NOSPLIT, $0-0 + VZEROUPPER + RET From 52b46512c316625368d552106e79ce9fb79a8bd7 Mon Sep 17 00:00:00 2001 From: masih Date: Mon, 14 Sep 2026 17:17:34 +0000 Subject: [PATCH 2/2] Clear upper registers in simdBackend wrappers instead of each kernel --- .../sc/flatkv/lthash/backend_simd_amd64.go | 27 ++++++++++++------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/sei-db/state_db/sc/flatkv/lthash/backend_simd_amd64.go b/sei-db/state_db/sc/flatkv/lthash/backend_simd_amd64.go index 22a356d3d1..4d78f56295 100644 --- a/sei-db/state_db/sc/flatkv/lthash/backend_simd_amd64.go +++ b/sei-db/state_db/sc/flatkv/lthash/backend_simd_amd64.go @@ -27,11 +27,24 @@ func simdBackend() (backend, bool) { if !archsimd.X86.AVX512() || !archsimd.X86.AVX512VBMI2() { return backend{}, false } + // The compiler emits no VZEROUPPER after AVX-512 code, and legacy-SSE code + // in the caller (memmove, SHA-NI) runs several times slower while the upper + // halves are dirty, so every kernel is wrapped here rather than trusting + // each one to clear them. return backend{ - name: simdBackendName, - expand: expandSIMD, - add: addSIMD, - sub: subSIMD, + name: simdBackendName, + expand: func(data []byte, dst *LtHash) { + expandSIMD(data, dst) + vzeroupper() + }, + add: func(dst, src *LtHash) { + addSIMD(dst, src) + vzeroupper() + }, + sub: func(dst, src *LtHash) { + subSIMD(dst, src) + vzeroupper() + }, }, true } @@ -65,10 +78,6 @@ func expandSIMD(data []byte, dst *LtHash) { in[12][lane] = 16 } xof16(&in, &out[1]) - // The compiler emits no VZEROUPPER after AVX-512 code, and legacy-SSE - // code in the caller (memmove, encoding) runs several times slower while - // the upper halves are dirty. - vzeroupper() } // singleChunkRoot compresses all but the last block of a one-chunk message @@ -163,7 +172,6 @@ func addSIMD(dst, src *LtHash) { for i := range a { archsimd.LoadUint16x32Array(&a[i]).Add(archsimd.LoadUint16x32Array(&b[i])).StoreArray(&a[i]) } - vzeroupper() } func subSIMD(dst, src *LtHash) { @@ -171,5 +179,4 @@ func subSIMD(dst, src *LtHash) { for i := range a { archsimd.LoadUint16x32Array(&a[i]).Sub(archsimd.LoadUint16x32Array(&b[i])).StoreArray(&a[i]) } - vzeroupper() }