github.com/sandwichdev/go-internals@v0.0.0-20210605002614-12311ac6b2c5/cpu/cpu.go (about)

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