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

View as plain text