github.com/primecitizens/pcz/std@v0.2.1/core/cpu/cpu.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright 2023 The Prime Citizens 3 // 4 // Copyright 2017 The Go Authors. All rights reserved. 5 // Use of this source code is governed by a BSD-style 6 // license that can be found in the LICENSE file. 7 8 // Package cpu implements processor feature detection 9 // used by the Go standard library. 10 package cpu 11 12 import ( 13 "github.com/primecitizens/pcz/std/core/os" 14 ) 15 16 // DebugOptions is set to true by the runtime if the OS supports reading 17 // GODEBUG early in runtime startup. 18 // This should not be changed after it is initialized. 19 const DebugOptions = 0| 20 os.IsAix| 21 os.IsDarwin| 22 os.IsIos| 23 os.IsDragonfly| 24 os.IsFreebsd| 25 os.IsNetbsd| 26 os.IsOpenbsd| 27 os.IsIllumos| 28 os.IsSolaris| 29 os.IsLinux| 30 0 != 0 31 32 type FeatureChecker[Self any] interface { 33 // HasAll checks whether wanted features are all present 34 HasAll(want Self) bool 35 } 36 37 type FeatureSet[Self any] interface { 38 // Set `feat` state to `enable` 39 // 40 // known = false when the feat is unknown to this feature set 41 // enabled = true 42 Set(feat string, enable bool) (enabled, found bool) 43 } 44 45 var ( 46 ARM ARMFeatures 47 X86 X86Features 48 ARM64 ARM64Features 49 MIPS64 MIPS64Features 50 PPC64 PPC64Features 51 S390X S390XFeatures 52 WASM WASMFeatures 53 ) 54 55 type ARMFeatures uint32 56 57 const ( 58 ARMFeature_vfpv4 ARMFeatures = 1 << iota 59 ARMFeature_idiva 60 ) 61 62 func (x ARMFeatures) HasAll(want ARMFeatures) bool { 63 return x&want == want 64 } 65 66 func (x *ARMFeatures) Set(feat string, enable bool) (enabled bool, found bool) { 67 var want ARMFeatures 68 switch feat { 69 case "vfpv4": 70 want = ARMFeature_vfpv4 71 case "idiva": 72 want = ARMFeature_idiva 73 default: 74 return 75 } 76 77 found = true 78 if *x&want != 0 /* has this feat */ { 79 if enable { 80 enabled = true 81 } else { 82 *x &= ^want 83 } 84 } 85 86 return 87 } 88 89 type X86Features uint32 90 91 const ( 92 X86Feature_adx = 1 << iota 93 X86Feature_aes 94 X86Feature_erms 95 X86Feature_pclmulqdq 96 X86Feature_rdtscp 97 X86Feature_popcnt 98 X86Feature_sse3 99 X86Feature_sse41 100 X86Feature_sse42 101 X86Feature_ssse3 102 X86Feature_avx 103 X86Feature_avx2 104 X86Feature_bmi1 105 X86Feature_bmi2 106 X86Feature_fma 107 ) 108 109 func (x X86Features) HasAll(want X86Features) bool { 110 return x&want == want 111 } 112 113 func (x *X86Features) Set(feat string, enable bool) (enabled, found bool) { 114 var want X86Features 115 switch feat { 116 case "adx": 117 want = X86Feature_adx 118 case "aes": 119 want = X86Feature_aes 120 case "erms": 121 want = X86Feature_erms 122 case "pclmulqdq": 123 want = X86Feature_pclmulqdq 124 case "rdtscp": 125 want = X86Feature_rdtscp 126 case "popcnt": 127 want = X86Feature_popcnt 128 case "sse3": 129 want = X86Feature_sse3 130 case "sse41": 131 want = X86Feature_sse41 132 case "sse42": 133 want = X86Feature_sse42 134 case "ssse3": 135 want = X86Feature_ssse3 136 case "avx": 137 want = X86Feature_avx 138 case "avx2": 139 want = X86Feature_avx2 140 case "bmi1": 141 want = X86Feature_bmi1 142 case "bmi2": 143 want = X86Feature_bmi2 144 case "fma": 145 want = X86Feature_fma 146 default: 147 return 148 } 149 150 found = true 151 if *x&want != 0 /* has this feat */ { 152 if enable { 153 enabled = true 154 } else { 155 *x &= ^want 156 } 157 } 158 159 return 160 } 161 162 type ARM64Features uint32 163 164 const ( 165 ARM64Feature_aes ARM64Features = 1 << iota 166 ARM64Feature_pmull 167 ARM64Feature_sha1 168 ARM64Feature_sha2 169 ARM64Feature_sha512 170 ARM64Feature_crc32 171 ARM64Feature_atomics 172 ARM64Feature_cpuid 173 ARM64Feature_is_neoversen1 174 ARM64Feature_is_zeus 175 ) 176 177 func (x ARM64Features) HasAll(want ARM64Features) bool { 178 return x&want == want 179 } 180 181 func (x *ARM64Features) Set(feat string, enable bool) (enabled bool, found bool) { 182 var want ARM64Features 183 switch feat { 184 case "aes": 185 want = ARM64Feature_aes 186 case "pmull": 187 want = ARM64Feature_pmull 188 case "sha1": 189 want = ARM64Feature_sha1 190 case "sha2": 191 want = ARM64Feature_sha2 192 case "sha512": 193 want = ARM64Feature_sha512 194 case "crc32": 195 want = ARM64Feature_crc32 196 case "atomics": 197 want = ARM64Feature_atomics 198 case "cpuid": 199 want = ARM64Feature_cpuid 200 case "isNeoverseN1": 201 want = ARM64Feature_is_neoversen1 202 case "isZeus": 203 want = ARM64Feature_is_zeus 204 default: 205 return 206 } 207 208 found = true 209 if *x&want != 0 /* has this feat */ { 210 if enable { 211 enabled = true 212 } else { 213 *x &= ^want 214 } 215 } 216 217 return 218 } 219 220 type MIPS64Features uint32 221 222 const ( 223 MIPS64Feature_msa MIPS64Features = 1 << iota // MIPS SIMD architecture 224 ) 225 226 func (x MIPS64Features) HasAll(want MIPS64Features) bool { 227 return x&want == want 228 } 229 230 func (x *MIPS64Features) Set(feat string, enable bool) (enabled bool, found bool) { 231 var want MIPS64Features 232 switch feat { 233 case "msa": 234 want = MIPS64Feature_msa 235 default: 236 return 237 } 238 239 found = true 240 if *x&want != 0 /* has this feat */ { 241 if enable { 242 enabled = true 243 } else { 244 *x &= ^want 245 } 246 } 247 248 return 249 } 250 251 // For ppc64(le), it is safe to check only for ISA level starting on ISA v3.00, 252 // since there are no optional categories. There are some exceptions that also 253 // require kernel support to work (darn, scv), so there are feature bits for 254 // those as well. The minimum processor requirement is POWER8 (ISA 2.07). 255 // The struct is padded to avoid false sharing. 256 type PPC64Features uint32 257 258 const ( 259 PPC64Feature_darn PPC64Features = 1 << iota // Hardware random number generator (requires kernel enablement) 260 PPC64Feature_scv // Syscall vectored (requires kernel enablement) 261 PPC64Feature_is_power8 // ISA v2.07 (POWER8) 262 PPC64Feature_is_power9 // ISA v3.00 (POWER9) 263 PPC64Feature_is_power10 // ISA v3.1 (POWER10) 264 ) 265 266 func (x PPC64Features) HasAll(want PPC64Features) bool { 267 return x&want == want 268 } 269 270 func (x *PPC64Features) Set(feat string, enable bool) (enabled bool, found bool) { 271 var want PPC64Features 272 switch feat { 273 case "darn": 274 want = PPC64Feature_darn 275 case "scv": 276 want = PPC64Feature_scv 277 case "power8": 278 want = PPC64Feature_is_power8 279 case "power9": 280 want = PPC64Feature_is_power9 281 case "power10": 282 want = PPC64Feature_is_power10 283 default: 284 return 285 } 286 287 found = true 288 if *x&want != 0 /* has this feat */ { 289 if enable { 290 enabled = true 291 } else { 292 *x &= ^want 293 } 294 } 295 296 return 297 } 298 299 type S390XFeatures uint32 300 301 const ( 302 S390XFeature_zarch S390XFeatures = 1 << iota // z architecture mode is active [mandatory] 303 S390XFeature_stfle // store facility list extended [mandatory] 304 S390XFeature_ldisp // long (20-bit) displacements [mandatory] 305 S390XFeature_eimm // 32-bit immediates [mandatory] 306 S390XFeature_dfp // decimal floating point 307 S390XFeature_etf3eh // ETF-3 enhanced 308 S390XFeature_msa // message security assist (CPACF) 309 S390XFeature_aes // KM-AES{128,192,256} functions 310 S390XFeature_aescbc // KMC-AES{128,192,256} functions 311 S390XFeature_aesctr // KMCTR-AES{128,192,256} functions 312 S390XFeature_aesgcm // KMA-GCM-AES{128,192,256} functions 313 S390XFeature_ghash // KIMD-GHASH function 314 S390XFeature_sha1 // K{I,L}MD-SHA-1 functions 315 S390XFeature_sha256 // K{I,L}MD-SHA-256 functions 316 S390XFeature_sha512 // K{I,L}MD-SHA-512 functions 317 S390XFeature_sha3 // K{I,L}MD-SHA3-{224,256,384,512} and K{I,L}MD-SHAKE-{128,256} functions 318 S390XFeature_vx // vector facility. Note: the runtime sets this when it processes auxv records. 319 S390XFeature_vxe // vector-enhancements facility 1 320 S390XFeature_kdsa // elliptic curve functions 321 S390XFeature_ecdsa // NIST curves 322 S390XFeature_eddsa // Edwards curves 323 ) 324 325 func (x S390XFeatures) HasAll(want S390XFeatures) bool { 326 return x&want == want 327 } 328 329 func (x *S390XFeatures) Set(feat string, enable bool) (enabled bool, found bool) { 330 var want S390XFeatures 331 switch feat { 332 case "zarch": 333 want = S390XFeature_zarch 334 case "stfle": 335 want = S390XFeature_stfle 336 case "ldisp": 337 want = S390XFeature_ldisp 338 case "eimm": 339 want = S390XFeature_eimm 340 case "dfp": 341 want = S390XFeature_dfp 342 case "etf3eh": 343 want = S390XFeature_etf3eh 344 case "msa": 345 want = S390XFeature_msa 346 case "aes": 347 want = S390XFeature_aes 348 case "aescbc": 349 want = S390XFeature_aescbc 350 case "aesctr": 351 want = S390XFeature_aesctr 352 case "aesgcm": 353 want = S390XFeature_aesgcm 354 case "ghash": 355 want = S390XFeature_ghash 356 case "sha1": 357 want = S390XFeature_sha1 358 case "sha256": 359 want = S390XFeature_sha256 360 case "sha512": 361 want = S390XFeature_sha512 362 case "sha3": 363 want = S390XFeature_sha3 364 case "vx": 365 want = S390XFeature_vx 366 case "vxe": 367 want = S390XFeature_vxe 368 case "kdsa": 369 want = S390XFeature_kdsa 370 case "ecdsa": 371 want = S390XFeature_ecdsa 372 case "eddsa": 373 want = S390XFeature_eddsa 374 default: 375 return 376 } 377 378 found = true 379 if *x&want != 0 /* has this feat */ { 380 if enable { 381 enabled = true 382 } else { 383 *x &= ^want 384 } 385 } 386 387 return 388 } 389 390 type WASMFeatures uint32 391 392 func (x WASMFeatures) HasAll(want WASMFeatures) bool { 393 return x&want == want 394 } 395 396 func (x *WASMFeatures) Set(feat string, enable bool) (enabled, found bool) { 397 return 398 } 399 400 // Initialize examines the processor and sets the relevant variables above. 401 // This is called by the runtime package early in program initialization, 402 // before normal init functions are run. env is set by runtime if the OS supports 403 // cpu feature options in GODEBUG. 404 func Initialize(env string) { 405 processOptions(doinit(), env) 406 } 407 408 // processOptions enables or disables CPU feature values based on the parsed env string. 409 // The env string is expected to be of the form cpu.feature1=value1,cpu.feature2=value2... 410 // where feature names is one of the architecture specific list stored in the 411 // cpu packages options variable and values are either 'on' or 'off'. 412 // If env contains cpu.all=off then all cpu features referenced through the options 413 // variable are disabled. Other feature names and values result in warning messages. 414 func processOptions[T FeatureSet[T]](fset T, godebug string) { 415 for len(godebug) != 0 { 416 field := "" 417 i := indexByte(godebug, ',') 418 if i < 0 { 419 field, godebug = godebug, "" 420 } else { 421 field, godebug = godebug[:i], godebug[i+1:] 422 } 423 if len(field) < 4 || field[:4] != "cpu." { 424 continue 425 } 426 i = indexByte(field, '=') 427 if i < 0 { 428 print("GODEBUG: no value specified for \"", field, "\"\n") 429 continue 430 } 431 key, value := field[4:i], field[i+1:] // e.g. "SSE2", "on" 432 433 var enable bool 434 switch value { 435 case "on": 436 enable = true 437 case "off": 438 enable = false 439 default: 440 print("GODEBUG: value \"", value, "\" not supported for cpu option \"", key, "\"\n") 441 continue 442 } 443 444 enabled, found := fset.Set(key, enable) 445 if !found { 446 print("GODEBUG: unknown cpu feature \"", key, "\"\n") 447 continue 448 } 449 450 if enable && !enabled { 451 print("GODEBUG: can not enable \"", key, "\", missing CPU support\n") 452 } 453 } 454 } 455 456 // indexByte returns the index of the first instance of c in s, 457 // or -1 if c is not present in s. 458 func indexByte(s string, c byte) int { 459 for i := 0; i < len(s); i++ { 460 if s[i] == c { 461 return i 462 } 463 } 464 return -1 465 }