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 HasVPCLMULQDQ bool 61 _ CacheLinePad 62 } 63 64 // The booleans in ARM contain the correspondingly named cpu feature bit. 65 // The struct is padded to avoid false sharing. 66 var ARM struct { 67 _ CacheLinePad 68 HasVFPv4 bool 69 HasIDIVA bool 70 HasV7Atomics bool 71 _ CacheLinePad 72 } 73 74 // The booleans in ARM64 contain the correspondingly named cpu feature bit. 75 // The struct is padded to avoid false sharing. 76 var ARM64 struct { 77 _ CacheLinePad 78 HasAES bool 79 HasPMULL bool 80 HasSHA1 bool 81 HasSHA2 bool 82 HasSHA512 bool 83 HasSHA3 bool 84 HasCRC32 bool 85 HasATOMICS bool 86 HasCPUID bool 87 HasDIT bool 88 HasSB bool 89 IsNeoverse bool 90 HasSVE bool 91 HasSVE2 bool 92 _ CacheLinePad 93 } 94 95 // The booleans in Loong64 contain the correspondingly named cpu feature bit. 96 // The struct is padded to avoid false sharing. 97 var Loong64 struct { 98 _ CacheLinePad 99 HasLSX bool // support 128-bit vector extension 100 HasLASX bool // support 256-bit vector extension 101 HasCRC32 bool // support CRC instruction 102 HasLAMCAS bool // support AMCAS[_DB].{B/H/W/D} 103 HasLAM_BH bool // support AM{SWAP/ADD}[_DB].{B/H} instruction 104 HasLLACQ_SCREL bool // support LLACQ.{W/D}, SCREL.{W/D} instruction 105 HasSCQ bool // support SC.Q instruction 106 HasDBAR_HINTS bool // supports finer-grained DBAR hints 107 _ CacheLinePad 108 } 109 110 var MIPS64X struct { 111 _ CacheLinePad 112 HasMSA bool // MIPS SIMD architecture 113 _ CacheLinePad 114 } 115 116 // For ppc64(le), it is safe to check only for ISA level starting on ISA v3.00, 117 // since there are no optional categories. There are some exceptions that also 118 // require kernel support to work (darn, scv), so there are feature bits for 119 // those as well. The minimum processor requirement is POWER8 (ISA 2.07). 120 // The struct is padded to avoid false sharing. 121 var PPC64 struct { 122 _ CacheLinePad 123 HasDARN bool // Hardware random number generator (requires kernel enablement) 124 HasSCV bool // Syscall vectored (requires kernel enablement) 125 IsPOWER8 bool // ISA v2.07 (POWER8) 126 IsPOWER9 bool // ISA v3.00 (POWER9) 127 IsPOWER10 bool // ISA v3.1 (POWER10) 128 _ CacheLinePad 129 } 130 131 var S390X struct { 132 _ CacheLinePad 133 HasZARCH bool // z architecture mode is active [mandatory] 134 HasSTFLE bool // store facility list extended [mandatory] 135 HasLDISP bool // long (20-bit) displacements [mandatory] 136 HasEIMM bool // 32-bit immediates [mandatory] 137 HasDFP bool // decimal floating point 138 HasETF3EH bool // ETF-3 enhanced 139 HasMSA bool // message security assist (CPACF) 140 HasAES bool // KM-AES{128,192,256} functions 141 HasAESCBC bool // KMC-AES{128,192,256} functions 142 HasAESCTR bool // KMCTR-AES{128,192,256} functions 143 HasAESGCM bool // KMA-GCM-AES{128,192,256} functions 144 HasGHASH bool // KIMD-GHASH function 145 HasSHA1 bool // K{I,L}MD-SHA-1 functions 146 HasSHA256 bool // K{I,L}MD-SHA-256 functions 147 HasSHA512 bool // K{I,L}MD-SHA-512 functions 148 HasSHA3 bool // K{I,L}MD-SHA3-{224,256,384,512} and K{I,L}MD-SHAKE-{128,256} functions 149 HasVX bool // vector facility. Note: the runtime sets this when it processes auxv records. 150 HasVXE bool // vector-enhancements facility 1 151 HasKDSA bool // elliptic curve functions 152 HasECDSA bool // NIST curves 153 HasEDDSA bool // Edwards curves 154 _ CacheLinePad 155 } 156 157 // RISCV64 contains the supported CPU features and performance characteristics for riscv64 158 // platforms. The booleans in RISCV64, with the exception of HasFastMisaligned, indicate 159 // the presence of RISC-V extensions. 160 // The struct is padded to avoid false sharing. 161 var RISCV64 struct { 162 _ CacheLinePad 163 HasFastMisaligned bool // Fast misaligned accesses 164 HasV bool // Vector extension compatible with RVV 1.0 165 HasZbb bool // Basic bit-manipulation extension 166 HasZbc bool // Carryless multiplication extension 167 HasZvbb bool // Vector Basic Bit-manipulation 168 HasZvbc bool // Vector Carryless Multiplication 169 HasZvkg bool // Vector GCM/GMAC 170 HasZvkned bool // NIST Suite: Vector AES Block Cipher 171 HasZvknha bool // NIST Suite: Vector SHA-2 Secure Hash 172 HasZvknhb bool // NIST Suite: Vector SHA-2 Secure Hash 173 HasZvksed bool // ShangMi Suite: SM4 Block Cipher 174 HasZvksh bool // ShangMi Suite: SM3 Secure Hash 175 HasZvkt bool // Vector Data-Independent Execution Latency 176 VLENB uint // Vector register length in bytes, 0 if undetected 177 _ CacheLinePad 178 } 179 180 // CPU feature variables are accessed by assembly code in various packages. 181 //go:linkname X86 182 //go:linkname ARM 183 //go:linkname ARM64 184 //go:linkname Loong64 185 //go:linkname MIPS64X 186 //go:linkname PPC64 187 //go:linkname S390X 188 //go:linkname RISCV64 189 190 // doDerived, if non-nil, is called after processing GODEBUG to set "derived" 191 // feature flags. 192 var doDerived func() 193 194 // Initialize examines the processor and sets the relevant variables above. 195 // This is called by the runtime package early in program initialization, 196 // before normal init functions are run. env is set by runtime if the OS supports 197 // cpu feature options in GODEBUG. 198 func Initialize(env string) { 199 doinit() 200 processOptions(env) 201 if doDerived != nil { 202 doDerived() 203 } 204 } 205 206 // options contains the cpu debug options that can be used in GODEBUG. 207 // Options are arch dependent and are added by the arch specific doinit functions. 208 // Features that are mandatory for the specific GOARCH should not be added to options 209 // (e.g. SSE2 on amd64). 210 var options []option 211 212 // Option names should be lower case. e.g. avx instead of AVX. 213 type option struct { 214 Name string 215 Feature *bool 216 Specified bool // whether feature value was specified in GODEBUG 217 Enable bool // whether feature should be enabled 218 } 219 220 // processOptions enables or disables CPU feature values based on the parsed env string. 221 // The env string is expected to be of the form cpu.feature1=value1,cpu.feature2=value2... 222 // where feature names is one of the architecture specific list stored in the 223 // cpu packages options variable and values are either 'on' or 'off'. 224 // If env contains cpu.all=off then all cpu features referenced through the options 225 // variable are disabled. Other feature names and values result in warning messages. 226 func processOptions(env string) { 227 field: 228 for env != "" { 229 field := "" 230 i := indexByte(env, ',') 231 if i < 0 { 232 field, env = env, "" 233 } else { 234 field, env = env[:i], env[i+1:] 235 } 236 if len(field) < 4 || field[:4] != "cpu." { 237 continue 238 } 239 i = indexByte(field, '=') 240 if i < 0 { 241 print("GODEBUG: no value specified for \"", field, "\"\n") 242 continue 243 } 244 key, value := field[4:i], field[i+1:] // e.g. "SSE2", "on" 245 246 var enable bool 247 switch value { 248 case "on": 249 enable = true 250 case "off": 251 enable = false 252 default: 253 print("GODEBUG: value \"", value, "\" not supported for cpu option \"", key, "\"\n") 254 continue field 255 } 256 257 if key == "all" { 258 for i := range options { 259 options[i].Specified = true 260 options[i].Enable = enable 261 } 262 continue field 263 } 264 265 for i := range options { 266 if options[i].Name == key { 267 options[i].Specified = true 268 options[i].Enable = enable 269 continue field 270 } 271 } 272 273 print("GODEBUG: unknown cpu feature \"", key, "\"\n") 274 } 275 276 for _, o := range options { 277 if !o.Specified { 278 continue 279 } 280 281 if o.Enable && !*o.Feature { 282 print("GODEBUG: can not enable \"", o.Name, "\", missing CPU support\n") 283 continue 284 } 285 286 *o.Feature = o.Enable 287 } 288 } 289 290 // indexByte returns the index of the first instance of c in s, 291 // or -1 if c is not present in s. 292 // indexByte is semantically the same as [strings.IndexByte]. 293 // We copy this function because "internal/cpu" should not have external dependencies. 294 func indexByte(s string, c byte) int { 295 for i := 0; i < len(s); i++ { 296 if s[i] == c { 297 return i 298 } 299 } 300 return -1 301 } 302