Repository navigation
cmd/compile: break false dependency on Zen 4 and 5 (compress/expand) #81609
Description
The simd/archsimd packages added in Go 1.26 and Go 1.27 work great for me, see also https://michael.stapelberg.ch/posts/2026-09-06-dcs-fast-turbopfor-go-simd/
I did run into one issue, though, which is that AMD Zen 4 and Zen 5 CPUs have a false dependency in their compress and expand implementation.
The effect of this is that certain workloads, like the TurboPFor decoder I’m using in Debian Code Search, slow down significantly: consecutive expands need 4 cycles instead of 1 cycle.
LLVM has a fix for this: LLVM emits a SIMD Zeroing Idiom before compress/expand to break the false dependency. See AMD’s “Software Optimization Guide for the AMD Zen5 Microarchitecture”, section 2.9.2 for more details on zeroing idioms. See llvm/llvm-project#206849 for the LLVM issue with more details.
I can send a CL to make Go break the false dependency, too.
Steps to reproduce:
- Clone https://github.com/Debian/dcs
- Run
make bench-baselineininternal/turbopfor/pfordec - Undo the workaround I added:
diff --git i/internal/turbopfor/pfordec/bitunpack256vex_amd64.go w/internal/turbopfor/pfordec/bitunpack256vex_amd64.go
index 7bf24c8b..48534fda 100644
--- i/internal/turbopfor/pfordec/bitunpack256vex_amd64.go
+++ w/internal/turbopfor/pfordec/bitunpack256vex_amd64.go
@@ -130,10 +130,7 @@ func bitunpack256v32Ex(input []byte, fulloutput []uint32, nbits int, exmap *[32]
// gatherExceptions loads 8 exceptions at offset j, per bitmask m.
func gatherExceptions(exceptions *[256]uint32, j int, m byte) archsimd.Uint32x8 {
- // VPEXPANDD has a false dependency on Zen 4 and Zen 5 (at least).
- // Xor(zero) is a workaround; the Go compiler should do this.
- var zero archsimd.Uint32x8
- return archsimd.LoadUint32x8Array((*[8]uint32)(exceptions[j : j+8])).Xor(zero).Expand(archsimd.Mask32x8FromBits(m))
+ return archsimd.LoadUint32x8Array((*[8]uint32)(exceptions[j : j+8])).Expand(archsimd.Mask32x8FromBits(m))
}
func bitunpack256v32ExSIMDUnrolled[T bitWidthT](input []byte, output *[256]uint32, exmap *[32]byte, exceptions *[256]uint32) {- Run
make bench-relativeand observe how performance drops to half:
make -k -C \~/dcs/internal/turbopfor/pfordec/ bench-relative
make: Entering directory '/home/michael/dcs/internal/turbopfor/pfordec'
go test -pgo=decode.cpuprof
PASS
ok github.com/Debian/dcs/internal/turbopfor/pfordec 0.020s
taskset -c 1 go test -pgo=decode.cpuprof -run=^$ -bench=. -benchtime=200000x -count=6 | tee bench.txt
[…]
benchstat -filter '/impl:go .unit:(Mval/s)' baseline.txt bench.txt
goos: linux
goarch: amd64
pkg: github.com/Debian/dcs/internal/turbopfor/pfordec
cpu: AMD Ryzen 9 9950X3D 16-Core Processor
│ baseline.txt │ bench.txt │
│ Mval/s │ Mval/s vs base │
[…]
Decode/n=2048/vals=debian-mix/impl=go 12.121k ± 1% 6.641k ± 0% -45.21% (p=0.002 n=6)
[…]
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsIn Progress
Activity
stapelberg commentedon Sep 19, 2026
Sent http://go.dev/cl/835405 to break the false dependency.
gabyhelp commentedon Sep 19, 2026
Related Issues
Related Code Changes
(Emoji vote if this was helpful or unhelpful; more detailed feedback welcome in this discussion.)
gopherbot commentedon Sep 19, 2026
Change https://go.dev/cl/835405 mentions this issue:
cmd/compile: break false dependency on Zen 4 and 5prattmic commentedon Sep 29, 2026
cc @golang/compiler