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