A small experiment inspired by ISPC for ordinary Go code.
The current prototype is a source generator. You write a scalar per-index kernel as normal Go, annotate it, and ispc-go generates a wrapper that runs the kernel across 0..n using Go 1.27's standard simd package.
//ispcgo:kernel Saxpy
func saxpy(i int, x, y, out []float32, a float32) {
out[i] = a*x[i] + y[i]
}Generated API:
func Saxpy(n int, x []float32, y []float32, out []float32, a float32)Run it:
go run ./cmd/ispc-go -input examples/saxpy/saxpy.go -output examples/saxpy/saxpy_ispcgo.go
GOEXPERIMENT=simd go test ./...The local Go 1.27 toolchain still places simd behind the goexperiment.simd build constraint, so generated SIMD code currently needs GOEXPERIMENT=simd when building or testing.
Backends:
go run ./cmd/ispc-go -backend simd -input kernels.go
go run ./cmd/ispc-go -backend scalar -input kernels.goThe SIMD backend currently recognizes simple []float32 elementwise assignments, for example out[i] = a*x[i] + y[i]. The scalar backend remains useful as a correctness fallback and for kernels the SIMD recognizer does not support yet.
It also supports a first ISPC-like control-flow subset: if and if/else over float32 comparisons. Divergent branches are lowered to masks and Float32s.IfElse.
The examples/power package shows a more ISPC-like per-lane loop:
//ispcgo:kernel PowInt
func powInt(i int, numbers []float32, exponents []int32, out []float32) {
result := float32(1)
for j := int32(0); j < exponents[i]; j++ {
result *= numbers[i]
}
out[i] = result
}