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