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