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