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