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

View as plain text