cpu.mx raw

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