// 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= 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 }