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