github.com/primecitizens/pcz/std@v0.2.1/core/cpu/cpu.go (about)

     1  // SPDX-License-Identifier: Apache-2.0
     2  // Copyright 2023 The Prime Citizens
     3  //
     4  // Copyright 2017 The Go Authors. All rights reserved.
     5  // Use of this source code is governed by a BSD-style
     6  // license that can be found in the LICENSE file.
     7  
     8  // Package cpu implements processor feature detection
     9  // used by the Go standard library.
    10  package cpu
    11  
    12  import (
    13  	"github.com/primecitizens/pcz/std/core/os"
    14  )
    15  
    16  // DebugOptions is set to true by the runtime if the OS supports reading
    17  // GODEBUG early in runtime startup.
    18  // This should not be changed after it is initialized.
    19  const DebugOptions = 0|
    20  	os.IsAix|
    21  	os.IsDarwin|
    22  	os.IsIos|
    23  	os.IsDragonfly|
    24  	os.IsFreebsd|
    25  	os.IsNetbsd|
    26  	os.IsOpenbsd|
    27  	os.IsIllumos|
    28  	os.IsSolaris|
    29  	os.IsLinux|
    30  	0 != 0
    31  
    32  type FeatureChecker[Self any] interface {
    33  	// HasAll checks whether wanted features are all present
    34  	HasAll(want Self) bool
    35  }
    36  
    37  type FeatureSet[Self any] interface {
    38  	// Set `feat` state to `enable`
    39  	//
    40  	// known = false when the feat is unknown to this feature set
    41  	// enabled = true
    42  	Set(feat string, enable bool) (enabled, found bool)
    43  }
    44  
    45  var (
    46  	ARM    ARMFeatures
    47  	X86    X86Features
    48  	ARM64  ARM64Features
    49  	MIPS64 MIPS64Features
    50  	PPC64  PPC64Features
    51  	S390X  S390XFeatures
    52  	WASM   WASMFeatures
    53  )
    54  
    55  type ARMFeatures uint32
    56  
    57  const (
    58  	ARMFeature_vfpv4 ARMFeatures = 1 << iota
    59  	ARMFeature_idiva
    60  )
    61  
    62  func (x ARMFeatures) HasAll(want ARMFeatures) bool {
    63  	return x&want == want
    64  }
    65  
    66  func (x *ARMFeatures) Set(feat string, enable bool) (enabled bool, found bool) {
    67  	var want ARMFeatures
    68  	switch feat {
    69  	case "vfpv4":
    70  		want = ARMFeature_vfpv4
    71  	case "idiva":
    72  		want = ARMFeature_idiva
    73  	default:
    74  		return
    75  	}
    76  
    77  	found = true
    78  	if *x&want != 0 /* has this feat */ {
    79  		if enable {
    80  			enabled = true
    81  		} else {
    82  			*x &= ^want
    83  		}
    84  	}
    85  
    86  	return
    87  }
    88  
    89  type X86Features uint32
    90  
    91  const (
    92  	X86Feature_adx = 1 << iota
    93  	X86Feature_aes
    94  	X86Feature_erms
    95  	X86Feature_pclmulqdq
    96  	X86Feature_rdtscp
    97  	X86Feature_popcnt
    98  	X86Feature_sse3
    99  	X86Feature_sse41
   100  	X86Feature_sse42
   101  	X86Feature_ssse3
   102  	X86Feature_avx
   103  	X86Feature_avx2
   104  	X86Feature_bmi1
   105  	X86Feature_bmi2
   106  	X86Feature_fma
   107  )
   108  
   109  func (x X86Features) HasAll(want X86Features) bool {
   110  	return x&want == want
   111  }
   112  
   113  func (x *X86Features) Set(feat string, enable bool) (enabled, found bool) {
   114  	var want X86Features
   115  	switch feat {
   116  	case "adx":
   117  		want = X86Feature_adx
   118  	case "aes":
   119  		want = X86Feature_aes
   120  	case "erms":
   121  		want = X86Feature_erms
   122  	case "pclmulqdq":
   123  		want = X86Feature_pclmulqdq
   124  	case "rdtscp":
   125  		want = X86Feature_rdtscp
   126  	case "popcnt":
   127  		want = X86Feature_popcnt
   128  	case "sse3":
   129  		want = X86Feature_sse3
   130  	case "sse41":
   131  		want = X86Feature_sse41
   132  	case "sse42":
   133  		want = X86Feature_sse42
   134  	case "ssse3":
   135  		want = X86Feature_ssse3
   136  	case "avx":
   137  		want = X86Feature_avx
   138  	case "avx2":
   139  		want = X86Feature_avx2
   140  	case "bmi1":
   141  		want = X86Feature_bmi1
   142  	case "bmi2":
   143  		want = X86Feature_bmi2
   144  	case "fma":
   145  		want = X86Feature_fma
   146  	default:
   147  		return
   148  	}
   149  
   150  	found = true
   151  	if *x&want != 0 /* has this feat */ {
   152  		if enable {
   153  			enabled = true
   154  		} else {
   155  			*x &= ^want
   156  		}
   157  	}
   158  
   159  	return
   160  }
   161  
   162  type ARM64Features uint32
   163  
   164  const (
   165  	ARM64Feature_aes ARM64Features = 1 << iota
   166  	ARM64Feature_pmull
   167  	ARM64Feature_sha1
   168  	ARM64Feature_sha2
   169  	ARM64Feature_sha512
   170  	ARM64Feature_crc32
   171  	ARM64Feature_atomics
   172  	ARM64Feature_cpuid
   173  	ARM64Feature_is_neoversen1
   174  	ARM64Feature_is_zeus
   175  )
   176  
   177  func (x ARM64Features) HasAll(want ARM64Features) bool {
   178  	return x&want == want
   179  }
   180  
   181  func (x *ARM64Features) Set(feat string, enable bool) (enabled bool, found bool) {
   182  	var want ARM64Features
   183  	switch feat {
   184  	case "aes":
   185  		want = ARM64Feature_aes
   186  	case "pmull":
   187  		want = ARM64Feature_pmull
   188  	case "sha1":
   189  		want = ARM64Feature_sha1
   190  	case "sha2":
   191  		want = ARM64Feature_sha2
   192  	case "sha512":
   193  		want = ARM64Feature_sha512
   194  	case "crc32":
   195  		want = ARM64Feature_crc32
   196  	case "atomics":
   197  		want = ARM64Feature_atomics
   198  	case "cpuid":
   199  		want = ARM64Feature_cpuid
   200  	case "isNeoverseN1":
   201  		want = ARM64Feature_is_neoversen1
   202  	case "isZeus":
   203  		want = ARM64Feature_is_zeus
   204  	default:
   205  		return
   206  	}
   207  
   208  	found = true
   209  	if *x&want != 0 /* has this feat */ {
   210  		if enable {
   211  			enabled = true
   212  		} else {
   213  			*x &= ^want
   214  		}
   215  	}
   216  
   217  	return
   218  }
   219  
   220  type MIPS64Features uint32
   221  
   222  const (
   223  	MIPS64Feature_msa MIPS64Features = 1 << iota // MIPS SIMD architecture
   224  )
   225  
   226  func (x MIPS64Features) HasAll(want MIPS64Features) bool {
   227  	return x&want == want
   228  }
   229  
   230  func (x *MIPS64Features) Set(feat string, enable bool) (enabled bool, found bool) {
   231  	var want MIPS64Features
   232  	switch feat {
   233  	case "msa":
   234  		want = MIPS64Feature_msa
   235  	default:
   236  		return
   237  	}
   238  
   239  	found = true
   240  	if *x&want != 0 /* has this feat */ {
   241  		if enable {
   242  			enabled = true
   243  		} else {
   244  			*x &= ^want
   245  		}
   246  	}
   247  
   248  	return
   249  }
   250  
   251  // For ppc64(le), it is safe to check only for ISA level starting on ISA v3.00,
   252  // since there are no optional categories. There are some exceptions that also
   253  // require kernel support to work (darn, scv), so there are feature bits for
   254  // those as well. The minimum processor requirement is POWER8 (ISA 2.07).
   255  // The struct is padded to avoid false sharing.
   256  type PPC64Features uint32
   257  
   258  const (
   259  	PPC64Feature_darn       PPC64Features = 1 << iota // Hardware random number generator (requires kernel enablement)
   260  	PPC64Feature_scv                                  // Syscall vectored (requires kernel enablement)
   261  	PPC64Feature_is_power8                            // ISA v2.07 (POWER8)
   262  	PPC64Feature_is_power9                            // ISA v3.00 (POWER9)
   263  	PPC64Feature_is_power10                           // ISA v3.1  (POWER10)
   264  )
   265  
   266  func (x PPC64Features) HasAll(want PPC64Features) bool {
   267  	return x&want == want
   268  }
   269  
   270  func (x *PPC64Features) Set(feat string, enable bool) (enabled bool, found bool) {
   271  	var want PPC64Features
   272  	switch feat {
   273  	case "darn":
   274  		want = PPC64Feature_darn
   275  	case "scv":
   276  		want = PPC64Feature_scv
   277  	case "power8":
   278  		want = PPC64Feature_is_power8
   279  	case "power9":
   280  		want = PPC64Feature_is_power9
   281  	case "power10":
   282  		want = PPC64Feature_is_power10
   283  	default:
   284  		return
   285  	}
   286  
   287  	found = true
   288  	if *x&want != 0 /* has this feat */ {
   289  		if enable {
   290  			enabled = true
   291  		} else {
   292  			*x &= ^want
   293  		}
   294  	}
   295  
   296  	return
   297  }
   298  
   299  type S390XFeatures uint32
   300  
   301  const (
   302  	S390XFeature_zarch  S390XFeatures = 1 << iota // z architecture mode is active [mandatory]
   303  	S390XFeature_stfle                            // store facility list extended [mandatory]
   304  	S390XFeature_ldisp                            // long (20-bit) displacements [mandatory]
   305  	S390XFeature_eimm                             // 32-bit immediates [mandatory]
   306  	S390XFeature_dfp                              // decimal floating point
   307  	S390XFeature_etf3eh                           // ETF-3 enhanced
   308  	S390XFeature_msa                              // message security assist (CPACF)
   309  	S390XFeature_aes                              // KM-AES{128,192,256} functions
   310  	S390XFeature_aescbc                           // KMC-AES{128,192,256} functions
   311  	S390XFeature_aesctr                           // KMCTR-AES{128,192,256} functions
   312  	S390XFeature_aesgcm                           // KMA-GCM-AES{128,192,256} functions
   313  	S390XFeature_ghash                            // KIMD-GHASH function
   314  	S390XFeature_sha1                             // K{I,L}MD-SHA-1 functions
   315  	S390XFeature_sha256                           // K{I,L}MD-SHA-256 functions
   316  	S390XFeature_sha512                           // K{I,L}MD-SHA-512 functions
   317  	S390XFeature_sha3                             // K{I,L}MD-SHA3-{224,256,384,512} and K{I,L}MD-SHAKE-{128,256} functions
   318  	S390XFeature_vx                               // vector facility. Note: the runtime sets this when it processes auxv records.
   319  	S390XFeature_vxe                              // vector-enhancements facility 1
   320  	S390XFeature_kdsa                             // elliptic curve functions
   321  	S390XFeature_ecdsa                            // NIST curves
   322  	S390XFeature_eddsa                            // Edwards curves
   323  )
   324  
   325  func (x S390XFeatures) HasAll(want S390XFeatures) bool {
   326  	return x&want == want
   327  }
   328  
   329  func (x *S390XFeatures) Set(feat string, enable bool) (enabled bool, found bool) {
   330  	var want S390XFeatures
   331  	switch feat {
   332  	case "zarch":
   333  		want = S390XFeature_zarch
   334  	case "stfle":
   335  		want = S390XFeature_stfle
   336  	case "ldisp":
   337  		want = S390XFeature_ldisp
   338  	case "eimm":
   339  		want = S390XFeature_eimm
   340  	case "dfp":
   341  		want = S390XFeature_dfp
   342  	case "etf3eh":
   343  		want = S390XFeature_etf3eh
   344  	case "msa":
   345  		want = S390XFeature_msa
   346  	case "aes":
   347  		want = S390XFeature_aes
   348  	case "aescbc":
   349  		want = S390XFeature_aescbc
   350  	case "aesctr":
   351  		want = S390XFeature_aesctr
   352  	case "aesgcm":
   353  		want = S390XFeature_aesgcm
   354  	case "ghash":
   355  		want = S390XFeature_ghash
   356  	case "sha1":
   357  		want = S390XFeature_sha1
   358  	case "sha256":
   359  		want = S390XFeature_sha256
   360  	case "sha512":
   361  		want = S390XFeature_sha512
   362  	case "sha3":
   363  		want = S390XFeature_sha3
   364  	case "vx":
   365  		want = S390XFeature_vx
   366  	case "vxe":
   367  		want = S390XFeature_vxe
   368  	case "kdsa":
   369  		want = S390XFeature_kdsa
   370  	case "ecdsa":
   371  		want = S390XFeature_ecdsa
   372  	case "eddsa":
   373  		want = S390XFeature_eddsa
   374  	default:
   375  		return
   376  	}
   377  
   378  	found = true
   379  	if *x&want != 0 /* has this feat */ {
   380  		if enable {
   381  			enabled = true
   382  		} else {
   383  			*x &= ^want
   384  		}
   385  	}
   386  
   387  	return
   388  }
   389  
   390  type WASMFeatures uint32
   391  
   392  func (x WASMFeatures) HasAll(want WASMFeatures) bool {
   393  	return x&want == want
   394  }
   395  
   396  func (x *WASMFeatures) Set(feat string, enable bool) (enabled, found bool) {
   397  	return
   398  }
   399  
   400  // Initialize examines the processor and sets the relevant variables above.
   401  // This is called by the runtime package early in program initialization,
   402  // before normal init functions are run. env is set by runtime if the OS supports
   403  // cpu feature options in GODEBUG.
   404  func Initialize(env string) {
   405  	processOptions(doinit(), env)
   406  }
   407  
   408  // processOptions enables or disables CPU feature values based on the parsed env string.
   409  // The env string is expected to be of the form cpu.feature1=value1,cpu.feature2=value2...
   410  // where feature names is one of the architecture specific list stored in the
   411  // cpu packages options variable and values are either 'on' or 'off'.
   412  // If env contains cpu.all=off then all cpu features referenced through the options
   413  // variable are disabled. Other feature names and values result in warning messages.
   414  func processOptions[T FeatureSet[T]](fset T, godebug string) {
   415  	for len(godebug) != 0 {
   416  		field := ""
   417  		i := indexByte(godebug, ',')
   418  		if i < 0 {
   419  			field, godebug = godebug, ""
   420  		} else {
   421  			field, godebug = godebug[:i], godebug[i+1:]
   422  		}
   423  		if len(field) < 4 || field[:4] != "cpu." {
   424  			continue
   425  		}
   426  		i = indexByte(field, '=')
   427  		if i < 0 {
   428  			print("GODEBUG: no value specified for \"", field, "\"\n")
   429  			continue
   430  		}
   431  		key, value := field[4:i], field[i+1:] // e.g. "SSE2", "on"
   432  
   433  		var enable bool
   434  		switch value {
   435  		case "on":
   436  			enable = true
   437  		case "off":
   438  			enable = false
   439  		default:
   440  			print("GODEBUG: value \"", value, "\" not supported for cpu option \"", key, "\"\n")
   441  			continue
   442  		}
   443  
   444  		enabled, found := fset.Set(key, enable)
   445  		if !found {
   446  			print("GODEBUG: unknown cpu feature \"", key, "\"\n")
   447  			continue
   448  		}
   449  
   450  		if enable && !enabled {
   451  			print("GODEBUG: can not enable \"", key, "\", missing CPU support\n")
   452  		}
   453  	}
   454  }
   455  
   456  // indexByte returns the index of the first instance of c in s,
   457  // or -1 if c is not present in s.
   458  func indexByte(s string, c byte) int {
   459  	for i := 0; i < len(s); i++ {
   460  		if s[i] == c {
   461  			return i
   462  		}
   463  	}
   464  	return -1
   465  }