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

View as plain text