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

View as plain text