Skip to content

perf: float32 pairwise sum blocks on s390x (VFASB, z14+) - #58

Merged
tannevaled merged 1 commit into
mainfrom
float32-blocks-vx
Oct 18, 2026
Merged

tannevaled merged 1 commit into
mainfrom
float32-blocks-vx

Conversation

@tannevaled

Copy link
Copy Markdown
Contributor

blocks8VXE, the float32 pairwise-sum block kernel for s390x. Every 64-bit target now has a SIMD float32 block (SSE2 #54, NEON #54, RVV/LSX #55, VSX #56).

  • Kernel. The eight accumulators sit in two vector registers, so there are two dependency chains. Each block is added with vfasb, one IEEE float32 addition per lane, so the result is the scalar loop's bit for bit. VL/VST keep memory order. The kernel runs behind useVXE (vector-enhancements facility 1, z14+), the same gate as max/min; older CPUs take the scalar loop.
  • Encoding. Go's assembler has no vfasb. go-asmgen v0.19.0 (gap/s390x: vector float32 family (VFASB ... WFSQSB) as 6-byte entries go-asmgen/asmgen#29) emits it as WORD+BYTE+BYTE, pinned against GNU as 2.42 and llvm-mc, and executed bit-exact on the same z machine. The cmd/asm spelling is CL 846286. Regenerating the other targets with v0.19.0 changes no byte.
  • Measured on IBM Z (LinuxONE, vxe/vxe2). Base and head runs alternated, GOMAXPROCS=1, pinned core, benchstat n=10:
2¹⁴ 2²⁰
float32 Sum −72.7% −77.6%
int32 Sum (control) ~ ~
float64 Sum (control) ~ +2.0%

The float64 kernel is byte-identical; the change moved sumVX by 32 bytes (0x18f920 → 0x18f940). The +2.0% is attributed to layout, not proven.

  • Tests on the z machine. The kernel tests, the PROT_NONE fence and the whole root suite pass. A sabotaged kernel (one vfssb) fails TestAddBlocks8F32MatchesScalar.
  • Docs. docs/perf.md gets an s390x section, and SECURITY.md gets an audit entry.

🤖 Generated with Claude Code

blocks8VXE keeps the eight accumulators in two vector registers (two
dependency chains) and adds each block with vfasb, one IEEE float32
addition per lane, bit-identical to the scalar loop. It runs behind
useVXE (vector-enhancements facility 1), the gate max/min already use.

Go's assembler has no vfasb; go-asmgen v0.19.0 emits it as WORD+BYTE+BYTE
pinned against GNU as and llvm-mc (go-asmgen/asmgen#29; the cmd/asm side
is CL 846286). Regenerating the other targets with v0.19.0 changes no byte.

IBM Z (LinuxONE), alternating base/head, GOMAXPROCS=1, pinned core,
benchstat n=10: float32 Sum -73% (2^14) / -78% (2^20); int32 unchanged;
float64 unchanged at 2^14 and +2.0% at 2^20 with a byte-identical kernel
that moved 32 bytes (layout, not proven). Kernel tests, the PROT_NONE fence
and the whole suite pass there; a sabotaged kernel (vfssb) fails.

Every 64-bit target now has a SIMD float32 block.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@tannevaled
tannevaled merged commit 0906fd8 into main Oct 18, 2026
12 checks passed
@tannevaled
tannevaled deleted the float32-blocks-vx branch October 18, 2026 20:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant