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

View as plain text