Source file src/internal/cpu/cpu.go
1 // Copyright 2017 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 // Package cpu implements processor feature detection 6 // used by the Go standard library. 7 package cpu 8 9 import _ "unsafe" // for linkname 10 11 // CacheLinePad is used to pad structs to avoid false sharing. 12 type CacheLinePad struct{ _ [CacheLinePadSize]byte } 13 14 // CacheLineSize is the CPU's assumed cache line size. 15 // There is currently no runtime detection of the real cache line size 16 // so we use the constant per GOARCH CacheLinePadSize as an approximation. 17 var CacheLineSize uintptr = CacheLinePadSize 18 19 // The booleans in X86 contain the correspondingly named cpuid feature bit. 20 // HasAVX and HasAVX2 are only set if the OS does support XMM and YMM registers 21 // in addition to the cpuid feature bit being set. 22 // The struct is padded to avoid false sharing. 23 var X86 struct { 24 _ CacheLinePad 25 HasAES bool 26 HasADX bool 27 HasAVX bool 28 HasAVXVNNI bool 29 HasAVX2 bool 30 HasAVX512 bool // Virtual feature: F+CD+BW+DQ+VL 31 HasAVX512F bool 32 HasAVX512CD bool 33 HasAVX512BW bool 34 HasAVX512DQ bool 35 HasAVX512VL bool 36 HasAVX512GFNI bool 37 HasAVX512VAES bool 38 HasAVX512VNNI bool 39 HasAVX512VBMI bool 40 HasAVX512VBMI2 bool 41 HasAVX512BITALG bool 42 HasAVX512VPOPCNTDQ bool 43 HasAVX512VPCLMULQDQ bool 44 HasBMI1 bool 45 HasBMI2 bool 46 HasERMS bool 47 HasFSRM bool 48 HasFMA bool 49 HasGFNI bool 50 HasOSXSAVE bool 51 HasPCLMULQDQ bool 52 HasPOPCNT bool 53 HasRDTSCP bool 54 HasSHA bool 55 HasSSE3 bool 56 HasSSSE3 bool 57 HasSSE41 bool 58 HasSSE42 bool 59 HasVAES bool 60 _ CacheLinePad 61 } 62 63 // The booleans in ARM contain the correspondingly named cpu feature bit. 64 // The struct is padded to avoid false sharing. 65 var ARM struct { 66 _ CacheLinePad 67 HasVFPv4 bool 68 HasIDIVA bool 69 HasV7Atomics bool 70 _ CacheLinePad 71 } 72 73 // The booleans in ARM64 contain the correspondingly named cpu feature bit. 74 // The struct is padded to avoid false sharing. 75 var ARM64 struct { 76 _ CacheLinePad 77 HasAES bool 78 HasPMULL bool 79 HasSHA1 bool 80 HasSHA2 bool 81 HasSHA512 bool 82 HasSHA3 bool 83 HasCRC32 bool 84 HasATOMICS bool 85 HasCPUID bool 86 HasDIT bool 87 IsNeoverse bool 88 _ CacheLinePad 89 } 90 91 // The booleans in Loong64 contain the correspondingly named cpu feature bit. 92 // The struct is padded to avoid false sharing. 93 var Loong64 struct { 94 _ CacheLinePad 95 HasLSX bool // support 128-bit vector extension 96 HasLASX bool // support 256-bit vector extension 97 HasCRC32 bool // support CRC instruction 98 HasLAMCAS bool // support AMCAS[_DB].{B/H/W/D} 99 HasLAM_BH bool // support AM{SWAP/ADD}[_DB].{B/H} instruction 100 _ CacheLinePad 101 } 102 103 var MIPS64X struct { 104 _ CacheLinePad 105 HasMSA bool // MIPS SIMD architecture 106 _ CacheLinePad 107 } 108 109 // For ppc64(le), it is safe to check only for ISA level starting on ISA v3.00, 110 // since there are no optional categories. There are some exceptions that also 111 // require kernel support to work (darn, scv), so there are feature bits for 112 // those as well. The minimum processor requirement is POWER8 (ISA 2.07). 113 // The struct is padded to avoid false sharing. 114 var PPC64 struct { 115 _ CacheLinePad 116 HasDARN bool // Hardware random number generator (requires kernel enablement) 117 HasSCV bool // Syscall vectored (requires kernel enablement) 118 IsPOWER8 bool // ISA v2.07 (POWER8) 119 IsPOWER9 bool // ISA v3.00 (POWER9) 120 IsPOWER10 bool // ISA v3.1 (POWER10) 121 _ CacheLinePad 122 } 123 124 var S390X struct { 125 _ CacheLinePad 126 HasZARCH bool // z architecture mode is active [mandatory] 127 HasSTFLE bool // store facility list extended [mandatory] 128 HasLDISP bool // long (20-bit) displacements [mandatory] 129 HasEIMM bool // 32-bit immediates [mandatory] 130 HasDFP bool // decimal floating point 131 HasETF3EH bool // ETF-3 enhanced 132 HasMSA bool // message security assist (CPACF) 133 HasAES bool // KM-AES{128,192,256} functions 134 HasAESCBC bool // KMC-AES{128,192,256} functions 135 HasAESCTR bool // KMCTR-AES{128,192,256} functions 136 HasAESGCM bool // KMA-GCM-AES{128,192,256} functions 137 HasGHASH bool // KIMD-GHASH function 138 HasSHA1 bool // K{I,L}MD-SHA-1 functions 139 HasSHA256 bool // K{I,L}MD-SHA-256 functions 140 HasSHA512 bool // K{I,L}MD-SHA-512 functions 141 HasSHA3 bool // K{I,L}MD-SHA3-{224,256,384,512} and K{I,L}MD-SHAKE-{128,256} functions 142 HasVX bool // vector facility. Note: the runtime sets this when it processes auxv records. 143 HasVXE bool // vector-enhancements facility 1 144 HasKDSA bool // elliptic curve functions 145 HasECDSA bool // NIST curves 146 HasEDDSA bool // Edwards curves 147 _ CacheLinePad 148 } 149 150 // RISCV64 contains the supported CPU features and performance characteristics for riscv64 151 // platforms. The booleans in RISCV64, with the exception of HasFastMisaligned, indicate 152 // the presence of RISC-V extensions. 153 // The struct is padded to avoid false sharing. 154 var RISCV64 struct { 155 _ CacheLinePad 156 HasFastMisaligned bool // Fast misaligned accesses 157 HasV bool // Vector extension compatible with RVV 1.0 158 HasZbb bool // Basic bit-manipulation extension 159 _ CacheLinePad 160 } 161 162 // CPU feature variables are accessed by assembly code in various packages. 163 //go:linkname X86 164 //go:linkname ARM 165 //go:linkname ARM64 166 //go:linkname Loong64 167 //go:linkname MIPS64X 168 //go:linkname PPC64 169 //go:linkname S390X 170 //go:linkname RISCV64 171 172 // doDerived, if non-nil, is called after processing GODEBUG to set "derived" 173 // feature flags. 174 var doDerived func() 175 176 // Initialize examines the processor and sets the relevant variables above. 177 // This is called by the runtime package early in program initialization, 178 // before normal init functions are run. env is set by runtime if the OS supports 179 // cpu feature options in GODEBUG. 180 func Initialize(env string) { 181 doinit() 182 processOptions(env) 183 if doDerived != nil { 184 doDerived() 185 } 186 } 187 188 // options contains the cpu debug options that can be used in GODEBUG. 189 // Options are arch dependent and are added by the arch specific doinit functions. 190 // Features that are mandatory for the specific GOARCH should not be added to options 191 // (e.g. SSE2 on amd64). 192 var options []option 193 194 // Option names should be lower case. e.g. avx instead of AVX. 195 type option struct { 196 Name string 197 Feature *bool 198 Specified bool // whether feature value was specified in GODEBUG 199 Enable bool // whether feature should be enabled 200 } 201 202 // processOptions enables or disables CPU feature values based on the parsed env string. 203 // The env string is expected to be of the form cpu.feature1=value1,cpu.feature2=value2... 204 // where feature names is one of the architecture specific list stored in the 205 // cpu packages options variable and values are either 'on' or 'off'. 206 // If env contains cpu.all=off then all cpu features referenced through the options 207 // variable are disabled. Other feature names and values result in warning messages. 208 func processOptions(env string) { 209 field: 210 for env != "" { 211 field := "" 212 i := indexByte(env, ',') 213 if i < 0 { 214 field, env = env, "" 215 } else { 216 field, env = env[:i], env[i+1:] 217 } 218 if len(field) < 4 || field[:4] != "cpu." { 219 continue 220 } 221 i = indexByte(field, '=') 222 if i < 0 { 223 print("GODEBUG: no value specified for \"", field, "\"\n") 224 continue 225 } 226 key, value := field[4:i], field[i+1:] // e.g. "SSE2", "on" 227 228 var enable bool 229 switch value { 230 case "on": 231 enable = true 232 case "off": 233 enable = false 234 default: 235 print("GODEBUG: value \"", value, "\" not supported for cpu option \"", key, "\"\n") 236 continue field 237 } 238 239 if key == "all" { 240 for i := range options { 241 options[i].Specified = true 242 options[i].Enable = enable 243 } 244 continue field 245 } 246 247 for i := range options { 248 if options[i].Name == key { 249 options[i].Specified = true 250 options[i].Enable = enable 251 continue field 252 } 253 } 254 255 print("GODEBUG: unknown cpu feature \"", key, "\"\n") 256 } 257 258 for _, o := range options { 259 if !o.Specified { 260 continue 261 } 262 263 if o.Enable && !*o.Feature { 264 print("GODEBUG: can not enable \"", o.Name, "\", missing CPU support\n") 265 continue 266 } 267 268 *o.Feature = o.Enable 269 } 270 } 271 272 // indexByte returns the index of the first instance of c in s, 273 // or -1 if c is not present in s. 274 // indexByte is semantically the same as [strings.IndexByte]. 275 // We copy this function because "internal/cpu" should not have external dependencies. 276 func indexByte(s string, c byte) int { 277 for i := 0; i < len(s); i++ { 278 if s[i] == c { 279 return i 280 } 281 } 282 return -1 283 } 284