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

View as plain text