Skip to content

highway

highway (maintained fork)

Repository → · upstream: ajroetker/go-highway · Apache-2.0

go-simd/highway is a fork, not one of the go-asmgen packages. It is not generated by go-asmgen, it does not carry the suite’s 100 % coverage gate, and its numbers are upstream’s. It exists for one reason: consumers could not build against upstream’s published releases.

import "github.com/go-simd/highway/hwy"
go get github.com/go-simd/highway@latest

Why a fork

go-highway v0.0.12 requires its own hwy/goat tool module at v0.0.0, a version that was never published, and points it at a local directory with replace. A replace applies only to the module that declares it, never to the modules that depend on it. So every consumer that ran go mod tidy or go list -m all failed. On 2026-10-18, 48 fleet modules required go-highway, all of them indirectly through go-images/jpeg2000. The fix was proposed upstream (issue #73, PR #74) and is not released there yet.

What differs from upstream

changewhy
module path github.com/ajroetker/go-highway → github.com/go-simd/highwaya fork usable by consumers needs its own path; a replace in our go.mod would reach nobody either
hwy/goat published as hwy/goat/v0.0.2 and required at that versionthe defect itself
retract [v0.0.1, v0.0.12]GitHub forks inherit tags, so the proxy had cached upstream’s broken releases under the new path
golang.org/x/text v0.39.0 (v0.0.14)GO-2026-5970, reachable from cmd/hwygen

NOTICE in the repository records the origin and these changes. Generated assembly keeps upstream’s file-system paths in its comments, because those record where the files were generated and are not module paths.

Releases

versioncontent
v0.0.13upstream main under the new path, goat published, old tags retracted
v0.0.14x/text security update

Read before you measure: GOEXPERIMENT=simd

On arm64 highway calls hand-written NEON assembly, which needs no experiment. On amd64 the AVX2 and AVX-512 kernels are built only with GOEXPERIMENT=simd. Without it, as on every other architecture, highway dispatches to its generic Vec[T], which emulates a vector with a heap-allocated slice and allocates in every Load, Add, Mul, Sub and ShiftRight. The float kernels’ fallback does not allocate; the integer ones do.

Measured on GitHub ubuntu-latest (Go 1.27.2, n=10), the JPEG 2000 integer RCT on one 4K frame took 402.8 ms through highway against 61.3 ms as a plain loop, with 12.45 million allocations.

arm64 is not automatically better off. The NEON kernel itself took 6.3 ms on that frame. But the caller first copied its planes into highway Images and then copied them back, and the whole path took 29.9 ms against 14.1 ms for the loop. go-images/jpeg2000 therefore uses the plain loop for the RCT on every architecture (#32).

Before attributing a timing to SIMD, check which *_amd64.gen.go or *_other.gen.go file your build compiles, and time the path the caller actually runs, conversions included.

Retirement

When upstream releases the goat fix, consumers move back to github.com/ajroetker/go-highway and this fork is archived.