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