// Copyright 2017 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Package cpu implements processor feature detection // used by the Go standard library. package cpu import _ "unsafe" // for linkname // DebugOptions is set to true by the runtime if the OS supports reading // GODEBUG early in runtime startup. // This should not be changed after it is initialized. var DebugOptions bool // CacheLinePad is used to pad structs to avoid false sharing. type CacheLinePad struct{ _ [CacheLinePadSize]byte } // CacheLineSize is the CPU's assumed cache line size. // There is currently no runtime detection of the real cache line size // so we use the constant per GOARCH CacheLinePadSize as an approximation. var CacheLineSize uintptr = CacheLinePadSize // The booleans in X86 contain the correspondingly named cpuid feature bit. // HasAVX and HasAVX2 are only set if the OS does support XMM and YMM registers // in addition to the cpuid feature bit being set. // The struct is padded to avoid false sharing. var X86 struct { _ CacheLinePad HasAES bool HasADX bool HasAVX bool HasAVX2 bool HasAVX512F bool HasAVX512BW bool HasAVX512VL bool HasBMI1 bool HasBMI2 bool HasERMS bool HasFSRM bool HasFMA bool HasOSXSAVE bool HasPCLMULQDQ bool HasPOPCNT bool HasRDTSCP bool HasSHA bool HasSSE3 bool HasSSSE3 bool HasSSE41 bool HasSSE42 bool _ CacheLinePad } // The booleans in ARM contain the correspondingly named cpu feature bit. // The struct is padded to avoid false sharing. var ARM struct { _ CacheLinePad HasVFPv4 bool HasIDIVA bool HasV7Atomics bool _ CacheLinePad } // The booleans in ARM64 contain the correspondingly named cpu feature bit. // The struct is padded to avoid false sharing. var ARM64 struct { _ CacheLinePad HasAES bool HasPMULL bool HasSHA1 bool HasSHA2 bool HasSHA512 bool HasCRC32 bool HasATOMICS bool HasCPUID bool HasDIT bool IsNeoverse bool _ CacheLinePad } // The booleans in Loong64 contain the correspondingly named cpu feature bit. // The struct is padded to avoid false sharing. var Loong64 struct { _ CacheLinePad HasLSX bool // support 128-bit vector extension HasCRC32 bool // support CRC instruction HasLAMCAS bool // support AMCAS[_DB].{B/H/W/D} HasLAM_BH bool // support AM{SWAP/ADD}[_DB].{B/H} instruction _ CacheLinePad } var MIPS64X struct { _ CacheLinePad HasMSA bool // MIPS SIMD architecture _ CacheLinePad } // For ppc64(le), it is safe to check only for ISA level starting on ISA v3.00, // since there are no optional categories. There are some exceptions that also // require kernel support to work (darn, scv), so there are feature bits for // those as well. The minimum processor requirement is POWER8 (ISA 2.07). // The struct is padded to avoid false sharing. var PPC64 struct { _ CacheLinePad HasDARN bool // Hardware random number generator (requires kernel enablement) HasSCV bool // Syscall vectored (requires kernel enablement) IsPOWER8 bool // ISA v2.07 (POWER8) IsPOWER9 bool // ISA v3.00 (POWER9) IsPOWER10 bool // ISA v3.1 (POWER10) _ CacheLinePad } var S390X struct { _ CacheLinePad HasZARCH bool // z architecture mode is active [mandatory] HasSTFLE bool // store facility list extended [mandatory] HasLDISP bool // long (20-bit) displacements [mandatory] HasEIMM bool // 32-bit immediates [mandatory] HasDFP bool // decimal floating point HasETF3EH bool // ETF-3 enhanced HasMSA bool // message security assist (CPACF) HasAES bool // KM-AES{128,192,256} functions HasAESCBC bool // KMC-AES{128,192,256} functions HasAESCTR bool // KMCTR-AES{128,192,256} functions HasAESGCM bool // KMA-GCM-AES{128,192,256} functions HasGHASH bool // KIMD-GHASH function HasSHA1 bool // K{I,L}MD-SHA-1 functions HasSHA256 bool // K{I,L}MD-SHA-256 functions HasSHA512 bool // K{I,L}MD-SHA-512 functions HasSHA3 bool // K{I,L}MD-SHA3-{224,256,384,512} and K{I,L}MD-SHAKE-{128,256} functions HasVX bool // vector facility. Note: the runtime sets this when it processes auxv records. HasVXE bool // vector-enhancements facility 1 HasKDSA bool // elliptic curve functions HasECDSA bool // NIST curves HasEDDSA bool // Edwards curves _ CacheLinePad } // CPU feature variables are accessed by assembly code in various packages. //go:linkname X86 //go:linkname ARM //go:linkname ARM64 //go:linkname Loong64 //go:linkname MIPS64X //go:linkname PPC64 //go:linkname S390X // Initialize examines the processor and sets the relevant variables above. // This is called by the runtime package early in program initialization, // before normal init functions are run. env is set by runtime if the OS supports // cpu feature options in GODEBUG. func Initialize(env string) { doinit() processOptions(env) } // options contains the cpu debug options that can be used in GODEBUG. // Options are arch dependent and are added by the arch specific doinit functions. // Features that are mandatory for the specific GOARCH should not be added to options // (e.g. SSE2 on amd64). var options []option // Option names should be lower case. e.g. avx instead of AVX. type option struct { Name string Feature *bool Specified bool // whether feature value was specified in GODEBUG Enable bool // whether feature should be enabled } // processOptions enables or disables CPU feature values based on the parsed env string. // The env string is expected to be of the form cpu.feature1=value1,cpu.feature2=value2... // where feature names is one of the architecture specific list stored in the // cpu packages options variable and values are either 'on' or 'off'. // If env contains cpu.all=off then all cpu features referenced through the options // variable are disabled. Other feature names and values result in warning messages. func processOptions(env string) { field: for env != "" { field := "" i := indexByte(env, ',') if i < 0 { field, env = env, "" } else { field, env = env[:i], env[i+1:] } if len(field) < 4 || field[:4] != "cpu." { continue } i = indexByte(field, '=') if i < 0 { print("GODEBUG: no value specified for \"", field, "\"\n") continue } key, value := field[4:i], field[i+1:] // e.g. "SSE2", "on" var enable bool switch value { case "on": enable = true case "off": enable = false default: print("GODEBUG: value \"", value, "\" not supported for cpu option \"", key, "\"\n") continue field } if key == "all" { for i := range options { options[i].Specified = true options[i].Enable = enable } continue field } for i := range options { if options[i].Name == key { options[i].Specified = true options[i].Enable = enable continue field } } print("GODEBUG: unknown cpu feature \"", key, "\"\n") } for _, o := range options { if !o.Specified { continue } if o.Enable && !*o.Feature { print("GODEBUG: can not enable \"", o.Name, "\", missing CPU support\n") continue } *o.Feature = o.Enable } } // indexByte returns the index of the first instance of c in s, // or -1 if c is not present in s. // indexByte is semantically the same as [strings.IndexByte]. // We copy this function because "internal/cpu" should not have external dependencies. func indexByte(s string, c byte) int { for i := 0; i < len(s); i++ { if s[i] == c { return i } } return -1 }