github.com/icodeface/tls@v0.0.0-20230910023335-34df9250cd12/internal/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  var X86 x86
    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  type x86 struct {
    29  	_            CacheLinePad
    30  	HasAES       bool
    31  	HasADX       bool
    32  	HasAVX       bool
    33  	HasAVX2      bool
    34  	HasBMI1      bool
    35  	HasBMI2      bool
    36  	HasERMS      bool
    37  	HasFMA       bool
    38  	HasOSXSAVE   bool
    39  	HasPCLMULQDQ bool
    40  	HasPOPCNT    bool
    41  	HasSSE2      bool
    42  	HasSSE3      bool
    43  	HasSSSE3     bool
    44  	HasSSE41     bool
    45  	HasSSE42     bool
    46  	_            CacheLinePad
    47  }
    48  
    49  var PPC64 ppc64
    50  
    51  // For ppc64(le), it is safe to check only for ISA level starting on ISA v3.00,
    52  // since there are no optional categories. There are some exceptions that also
    53  // require kernel support to work (darn, scv), so there are feature bits for
    54  // those as well. The minimum processor requirement is POWER8 (ISA 2.07).
    55  // The struct is padded to avoid false sharing.
    56  type ppc64 struct {
    57  	_        CacheLinePad
    58  	HasDARN  bool // Hardware random number generator (requires kernel enablement)
    59  	HasSCV   bool // Syscall vectored (requires kernel enablement)
    60  	IsPOWER8 bool // ISA v2.07 (POWER8)
    61  	IsPOWER9 bool // ISA v3.00 (POWER9)
    62  	_        CacheLinePad
    63  }
    64  
    65  var ARM arm
    66  
    67  // The booleans in arm contain the correspondingly named cpu feature bit.
    68  // The struct is padded to avoid false sharing.
    69  type arm struct {
    70  	_        CacheLinePad
    71  	HasVFPv4 bool
    72  	HasIDIVA bool
    73  	_        CacheLinePad
    74  }
    75  
    76  var ARM64 arm64
    77  
    78  // The booleans in arm64 contain the correspondingly named cpu feature bit.
    79  // The struct is padded to avoid false sharing.
    80  type arm64 struct {
    81  	_           CacheLinePad
    82  	HasFP       bool
    83  	HasASIMD    bool
    84  	HasEVTSTRM  bool
    85  	HasAES      bool
    86  	HasPMULL    bool
    87  	HasSHA1     bool
    88  	HasSHA2     bool
    89  	HasCRC32    bool
    90  	HasATOMICS  bool
    91  	HasFPHP     bool
    92  	HasASIMDHP  bool
    93  	HasCPUID    bool
    94  	HasASIMDRDM bool
    95  	HasJSCVT    bool
    96  	HasFCMA     bool
    97  	HasLRCPC    bool
    98  	HasDCPOP    bool
    99  	HasSHA3     bool
   100  	HasSM3      bool
   101  	HasSM4      bool
   102  	HasASIMDDP  bool
   103  	HasSHA512   bool
   104  	HasSVE      bool
   105  	HasASIMDFHM bool
   106  	_           CacheLinePad
   107  }
   108  
   109  var S390X s390x
   110  
   111  type s390x struct {
   112  	_               CacheLinePad
   113  	HasZArch        bool // z architecture mode is active [mandatory]
   114  	HasSTFLE        bool // store facility list extended [mandatory]
   115  	HasLDisp        bool // long (20-bit) displacements [mandatory]
   116  	HasEImm         bool // 32-bit immediates [mandatory]
   117  	HasDFP          bool // decimal floating point
   118  	HasETF3Enhanced bool // ETF-3 enhanced
   119  	HasMSA          bool // message security assist (CPACF)
   120  	HasAES          bool // KM-AES{128,192,256} functions
   121  	HasAESCBC       bool // KMC-AES{128,192,256} functions
   122  	HasAESCTR       bool // KMCTR-AES{128,192,256} functions
   123  	HasAESGCM       bool // KMA-GCM-AES{128,192,256} functions
   124  	HasGHASH        bool // KIMD-GHASH function
   125  	HasSHA1         bool // K{I,L}MD-SHA-1 functions
   126  	HasSHA256       bool // K{I,L}MD-SHA-256 functions
   127  	HasSHA512       bool // K{I,L}MD-SHA-512 functions
   128  	HasVX           bool // vector facility. Note: the runtime sets this when it processes auxv records.
   129  	HasVE1          bool // vector-enhancement 1
   130  	_               CacheLinePad
   131  }
   132  
   133  // Initialize examines the processor and sets the relevant variables above.
   134  // This is called by the runtime package early in program initialization,
   135  // before normal init functions are run. env is set by runtime if the OS supports
   136  // cpu feature options in GODEBUG.
   137  func Initialize(env string) {
   138  	doinit()
   139  	processOptions(env)
   140  }
   141  
   142  // options contains the cpu debug options that can be used in GODEBUG.
   143  // Options are arch dependent and are added by the arch specific doinit functions.
   144  // Features that are mandatory for the specific GOARCH should not be added to options
   145  // (e.g. SSE2 on amd64).
   146  var options []option
   147  
   148  // Option names should be lower case. e.g. avx instead of AVX.
   149  type option struct {
   150  	Name      string
   151  	Feature   *bool
   152  	Specified bool // whether feature value was specified in GODEBUG
   153  	Enable    bool // whether feature should be enabled
   154  	Required  bool // whether feature is mandatory and can not be disabled
   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 specifc 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 || options[i].Required
   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  		if !o.Enable && o.Required {
   224  			print("GODEBUG: can not disable \"", o.Name, "\", required CPU feature\n")
   225  			continue
   226  		}
   227  
   228  		*o.Feature = o.Enable
   229  	}
   230  }
   231  
   232  // indexByte returns the index of the first instance of c in s,
   233  // or -1 if c is not present in s.
   234  func indexByte(s string, c byte) int {
   235  	for i := 0; i < len(s); i++ {
   236  		if s[i] == c {
   237  			return i
   238  		}
   239  	}
   240  	return -1
   241  }