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