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

View as plain text