blob: aa6e509855065a119a2034dbfafb8bb1c3caa86c [file]
// Copyright 2026 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build goexperiment.simd && (amd64 || arm64 || wasm)
package simd
import (
"fmt"
"internal/godebug"
"strconv"
)
// The `simd` package provides an architecture and vector-length agnostic API
// for single-instruction-multiple-data "SIMD" vectors and operations. The
// functions and methods in this package are those that can be mostly supported
// in hardware, combined with an emulation for those platforms that are not yet
// supported.
//
// Users can also control emulation and vector length with the 'simd' GODEBUG
// setting. GODEBUG=simd=0 requests emulation, not hardware SIMD, even if
// hardware is available. On platforms that may support multiple vector
// lengths, GODEBUG=simd=N (N=128, 256, or 512) requests a specific vector
// length. If the request cannot be satisfied, the simd package panics
// informatively.
//
// Some platforms may support vectors of a particular length, but not all of the
// expected operations (those appearing in this package) are available at that
// length. In that case, the default is to automatically downgrade to a length
// where the operations are supported, perhaps even to emulated-only
// (size=0). If a size is requested that is not compatible with the available
// features, the simd package will panic (and note the reason). To override
// the feature check, in the case that the user knows that the missing
// operations will not be used, prefix the size request with a '+', for
// example "GODEBUG=simd=+256". A plain '+' will override the feature check at
// whatever the hardware's default vector size happens to be.
var simd = godebug.New("#simd")
var maxVectorSize int
var emulated = false
var hwClmul = true
func init() {
actualMax, allFeatureSize := archMaxVectorSize() // zero == no simd, zero == features unavailable
gosimd := simd.Value()
explicitRequest := false
// No SIMD, must emulate
if actualMax == 0 {
maxVectorSize = 128
emulated = true
hwClmul = false
return
}
maxVectorSize = actualMax
// If gosimd begins with a '+' or is a single '1' then override
// any hardware feature check disabling of hardware SIMD.
// The '+' may be followed by a size, expected to be 0, 128, 256, 512.
// If it is zero (e.g., "0" or +0") then hardware SIMD is still disabled.
if len(gosimd) > 0 && gosimd[0] == '+' {
// override feature reduction
// keep maxVectorSize
// emulated remains false
// note if features missing.
hwClmul = allFeatureSize < actualMax
gosimd = gosimd[1:]
explicitRequest = true
} else if allFeatureSize < actualMax {
if allFeatureSize > 0 {
maxVectorSize = allFeatureSize
hwClmul = true
emulated = false
} else {
maxVectorSize = 128
hwClmul = false
emulated = true
}
}
if gosimd == "" {
return
}
// possible adjustment to chosen size
val, err := strconv.Atoi(gosimd)
if err != nil {
panic(fmt.Errorf("Could not parse GODEBUG=gosimd='%s' as a decimal number, %v", gosimd, err))
}
if val > actualMax {
panic(fmt.Errorf("Requested GODEBUG=gosimd=%d is larger than the simd length (%d) supported on this cpu ", val, actualMax))
}
if !explicitRequest && val > allFeatureSize {
panic(fmt.Errorf("Requested GODEBUG=gosimd=%d is larger than the simd length required for expected features (%d) on this cpu. GODEBUG=gosimd='+%d' will skip this check.", val, allFeatureSize, val))
}
if val < 0 {
panic(fmt.Errorf("Requested GODEBUG=gosimd=%d is negative", val))
}
// user-requested emulation
if val == 0 {
maxVectorSize = 128
hwClmul = false
emulated = true
return
}
hwClmul = allFeatureSize >= val
maxVectorSize = val
emulated = false
return
}
// VectorBitSize returns the bit length of the longest vector available
// on the current hardware. It can be artificially reduced by setting
// GODEBUG=simd=<smaller size> environment variable before running a program.
func VectorBitSize() int {
return maxVectorSize
}
// Emulated returns whether simd operations are emulated or
// running on actual vector hardware.
func Emulated() bool {
return emulated
}
// HasHardwareCarrylessMultiply returns whether this platform
// as a hardware-implemented version of carryless multiply.
// With default GODEBUG=simd settings, if this is false,
// it is emulated and merely slow, but with non-default settings
// this can indicate the possibility of a missing instruction
// that will fail ("SIGILL") if it is executed.
func HasHardwareCarrylessMultiply() bool {
return hwClmul && archHasHwClmul
}