Source file src/simd/midway_common.go

     1  // Copyright 2026 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  //go:build goexperiment.simd && (amd64 || arm64 || wasm)
     6  
     7  package simd
     8  
     9  import (
    10  	"fmt"
    11  	"internal/godebug"
    12  	"strconv"
    13  )
    14  
    15  // The `simd` package provides an architecture and vector-length agnostic API
    16  // for single-instruction-multiple-data "SIMD" vectors and operations. The
    17  // functions and methods in this package are those that can be mostly supported
    18  // in hardware, combined with an emulation for those platforms that are not yet
    19  // supported.
    20  //
    21  // Users can also control emulation and vector length with the 'simd' GODEBUG
    22  // setting.  GODEBUG=simd=0 requests emulation, not hardware SIMD, even if
    23  // hardware is available.  On platforms that may support multiple vector
    24  // lengths, GODEBUG=simd=N (N=128, 256, or 512) requests a specific vector
    25  // length.  If the request cannot be satisfied, the simd package panics
    26  // informatively.
    27  //
    28  // Some platforms may support vectors of a particular length, but not all of the
    29  // expected operations (those appearing in this package) are available at that
    30  // length.  In that case, the default is to automatically downgrade to a length
    31  // where the operations are supported, perhaps even to emulated-only
    32  // (size=0).  If a size is requested that is not compatible with the available
    33  // features, the simd package will panic (and note the reason).  To override
    34  // the feature check, in the case that the user knows that the missing
    35  // operations will not be used, prefix the size request with a '+', for
    36  // example "GODEBUG=simd=+256".  A plain '+' will override the feature check at
    37  // whatever the hardware's default vector size happens to be.
    38  
    39  var simd = godebug.New("#simd")
    40  
    41  var maxVectorSize int
    42  var emulated = false
    43  var hwClmul = true
    44  
    45  func init() {
    46  	actualMax, allFeatureSize := archMaxVectorSize() // zero == no simd, zero == features unavailable
    47  	gosimd := simd.Value()
    48  	explicitRequest := false
    49  
    50  	// No SIMD, must emulate
    51  	if actualMax == 0 {
    52  		maxVectorSize = 128
    53  		emulated = true
    54  		hwClmul = false
    55  		return
    56  	}
    57  
    58  	maxVectorSize = actualMax
    59  
    60  	// If gosimd begins with a '+' or is a single '1' then override
    61  	// any hardware feature check disabling of hardware SIMD.
    62  	// The '+' may be followed by a size, expected to be 0, 128, 256, 512.
    63  	// If it is zero (e.g., "0" or +0") then hardware SIMD is still disabled.
    64  	if len(gosimd) > 0 && gosimd[0] == '+' {
    65  		// override feature reduction
    66  		// keep maxVectorSize
    67  		// emulated remains false
    68  		// note if features missing.
    69  		hwClmul = allFeatureSize < actualMax
    70  		gosimd = gosimd[1:]
    71  		explicitRequest = true
    72  
    73  	} else if allFeatureSize < actualMax {
    74  		if allFeatureSize > 0 {
    75  			maxVectorSize = allFeatureSize
    76  			hwClmul = true
    77  			emulated = false
    78  		} else {
    79  			maxVectorSize = 128
    80  			hwClmul = false
    81  			emulated = true
    82  		}
    83  	}
    84  
    85  	if gosimd == "" {
    86  		return
    87  	}
    88  
    89  	// possible adjustment to chosen size
    90  	val, err := strconv.Atoi(gosimd)
    91  	if err != nil {
    92  		panic(fmt.Errorf("Could not parse GODEBUG=gosimd='%s' as a decimal number, %v", gosimd, err))
    93  	}
    94  	if val > actualMax {
    95  		panic(fmt.Errorf("Requested GODEBUG=gosimd=%d is larger than the simd length (%d) supported on this cpu ", val, actualMax))
    96  	}
    97  	if !explicitRequest && val > allFeatureSize {
    98  		panic(fmt.Errorf("Requested GODEBUG=gosimd=%d is larger than the simd length required for expected features (%d) on this cpu. GODEBUG=gosimd='+%d' will skip this check.", val, allFeatureSize, val))
    99  	}
   100  	if val < 0 {
   101  		panic(fmt.Errorf("Requested GODEBUG=gosimd=%d is negative", val))
   102  	}
   103  	// user-requested emulation
   104  	if val == 0 {
   105  		maxVectorSize = 128
   106  		hwClmul = false
   107  		emulated = true
   108  		return
   109  	}
   110  
   111  	hwClmul = allFeatureSize >= val
   112  	maxVectorSize = val
   113  	emulated = false
   114  	return
   115  }
   116  
   117  // VectorBitSize returns the bit length of the longest vector available
   118  // on the current hardware.  It can be artificially reduced by setting
   119  // GODEBUG=simd=<smaller size> environment variable before running a program.
   120  func VectorBitSize() int {
   121  	return maxVectorSize
   122  }
   123  
   124  // Emulated returns whether simd operations are emulated or
   125  // running on actual vector hardware.
   126  func Emulated() bool {
   127  	return emulated
   128  }
   129  
   130  // HasHardwareCarrylessMultiply returns whether this platform
   131  // as a hardware-implemented version of carryless multiply.
   132  // With default GODEBUG=simd settings, if this is false,
   133  // it is emulated and merely slow, but with non-default settings
   134  // this can indicate the possibility of a missing instruction
   135  // that will fail ("SIGILL") if it is executed.
   136  func HasHardwareCarrylessMultiply() bool {
   137  	return hwClmul && archHasHwClmul
   138  }
   139  

View as plain text