Source file src/simd/midway_common.go
1 // Copyright 2026 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 //go:build goexperiment.simd && (amd64 || arm64 || wasm) 6 7 package simd 8 9 import ( 10 "fmt" 11 "internal/godebug" 12 "strconv" 13 ) 14 15 // The `simd` package provides an architecture and vector-length agnostic API 16 // for single-instruction-multiple-data "SIMD" vectors and operations. The 17 // functions and methods in this package are those that can be mostly supported 18 // in hardware, combined with an emulation for those platforms that are not yet 19 // supported. 20 // 21 // Users can also control emulation and vector length with the 'simd' GODEBUG 22 // setting. GODEBUG=simd=0 requests emulation, not hardware SIMD, even if 23 // hardware is available. On platforms that may support multiple vector 24 // lengths, GODEBUG=simd=N (N=128, 256, or 512) requests a specific vector 25 // length. If the request cannot be satisfied, the simd package panics 26 // informatively. 27 // 28 // Some platforms may support vectors of a particular length, but not all of the 29 // expected operations (those appearing in this package) are available at that 30 // length. In that case, the default is to automatically downgrade to a length 31 // where the operations are supported, perhaps even to emulated-only 32 // (size=0). If a size is requested that is not compatible with the available 33 // features, the simd package will panic (and note the reason). To override 34 // the feature check, in the case that the user knows that the missing 35 // operations will not be used, prefix the size request with a '+', for 36 // example "GODEBUG=simd=+256". A plain '+' will override the feature check at 37 // whatever the hardware's default vector size happens to be. 38 39 var simd = godebug.New("#simd") 40 41 var maxVectorSize int 42 var emulated = false 43 var hwClmul = true 44 45 func init() { 46 actualMax, allFeatureSize := archMaxVectorSize() // zero == no simd, zero == features unavailable 47 gosimd := simd.Value() 48 explicitRequest := false 49 50 // No SIMD, must emulate 51 if actualMax == 0 { 52 maxVectorSize = 128 53 emulated = true 54 hwClmul = false 55 return 56 } 57 58 maxVectorSize = actualMax 59 60 // If gosimd begins with a '+' or is a single '1' then override 61 // any hardware feature check disabling of hardware SIMD. 62 // The '+' may be followed by a size, expected to be 0, 128, 256, 512. 63 // If it is zero (e.g., "0" or +0") then hardware SIMD is still disabled. 64 if len(gosimd) > 0 && gosimd[0] == '+' { 65 // override feature reduction 66 // keep maxVectorSize 67 // emulated remains false 68 // note if features missing. 69 hwClmul = allFeatureSize < actualMax 70 gosimd = gosimd[1:] 71 explicitRequest = true 72 73 } else if allFeatureSize < actualMax { 74 if allFeatureSize > 0 { 75 maxVectorSize = allFeatureSize 76 hwClmul = true 77 emulated = false 78 } else { 79 maxVectorSize = 128 80 hwClmul = false 81 emulated = true 82 } 83 } 84 85 if gosimd == "" { 86 return 87 } 88 89 // possible adjustment to chosen size 90 val, err := strconv.Atoi(gosimd) 91 if err != nil { 92 panic(fmt.Errorf("Could not parse GODEBUG=gosimd='%s' as a decimal number, %v", gosimd, err)) 93 } 94 if val > actualMax { 95 panic(fmt.Errorf("Requested GODEBUG=gosimd=%d is larger than the simd length (%d) supported on this cpu ", val, actualMax)) 96 } 97 if !explicitRequest && val > allFeatureSize { 98 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)) 99 } 100 if val < 0 { 101 panic(fmt.Errorf("Requested GODEBUG=gosimd=%d is negative", val)) 102 } 103 // user-requested emulation 104 if val == 0 { 105 maxVectorSize = 128 106 hwClmul = false 107 emulated = true 108 return 109 } 110 111 hwClmul = allFeatureSize >= val 112 maxVectorSize = val 113 emulated = false 114 return 115 } 116 117 // VectorBitSize returns the bit length of the longest vector available 118 // on the current hardware. It can be artificially reduced by setting 119 // GODEBUG=simd=<smaller size> environment variable before running a program. 120 func VectorBitSize() int { 121 return maxVectorSize 122 } 123 124 // Emulated returns whether simd operations are emulated or 125 // running on actual vector hardware. 126 func Emulated() bool { 127 return emulated 128 } 129 130 // HasHardwareCarrylessMultiply returns whether this platform 131 // as a hardware-implemented version of carryless multiply. 132 // With default GODEBUG=simd settings, if this is false, 133 // it is emulated and merely slow, but with non-default settings 134 // this can indicate the possibility of a missing instruction 135 // that will fail ("SIGILL") if it is executed. 136 func HasHardwareCarrylessMultiply() bool { 137 return hwClmul && archHasHwClmul 138 } 139