Source file src/simd/internal/spec/doc.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  // Package spec describes all possible operations in the SIMD API.
     6  //
     7  // The SIMD spec describes the function and method signatures, documentation
     8  // comments, and behavior (written as a reference Go implementation) of all
     9  // possible Go SIMD APIs. The archsimd and simd packages are subsets of this
    10  // specified API. This approach enforces that "one name means one thing" across
    11  // all platforms and both packages.
    12  //
    13  // The spec is written as buildable and executable Go code, but isn't meant to
    14  // be called directly. Rather, the specgen package interprets this spec package
    15  // into a full API description, which can then be fed into other generators for
    16  // the actual SIMD packages. The executable part of the spec serves to precisely
    17  // specify the semantics of operations, and is intended for conformance testing.
    18  //
    19  // To see the spec-generated API and debug issues with it, use [cmd/specls].
    20  //
    21  // ## Basic operation specifications
    22  //
    23  // Spec operations are written in a stylized form that makes heavy use of type
    24  // parameters so a single function can describe an operation generalized across
    25  // many vector types. This is in contrast with the public SIMD API, where every
    26  // function and method operates on concrete types. The specgen generator bridges
    27  // this gap, instantiating a single parameterized spec function into many
    28  // concrete methods.
    29  //
    30  // Consider a simple example, the Add operation:
    31  //
    32  //	// Add adds corresponding elements of two vectors.
    33  //	func Add[E Nums, W Width](x, y Vec[E, W]) (z Vec[E, W]) {
    34  //	    ...
    35  //	}
    36  //
    37  // All spec operations are written as functions, but if the first parameter has
    38  // type Vec, then they specify a method of a vector type. Since Add's first
    39  // parameter (x) is a Vec, this describes a method on vector types.
    40  //
    41  // The "E Nums" type parameter controls the allowed element types of the three
    42  // vector types. Here, it can be any numeric type of any size (uint8, float64,
    43  // etc). The "W Width" type parameter controls the total bit width of the three
    44  // vector types. The types that implement Width stand in for 128, 256, or 512
    45  // bits, or "scalable", which can represent any power of two >= 128. The number
    46  // of lanes of a vector is derived from the element size and the total vector
    47  // width.
    48  //
    49  // The Add spec expands to all possible types that satisfy the E and W type
    50  // parameters, which are in turn translated to types in the public API:
    51  //
    52  //	func (Int8x16) Add(Int8x16) Int8x16
    53  //	func (Int8x32) Add(Int8x32) Int8x32
    54  //	func (Int8x64) Add(Int8x64) Int8x64
    55  //	func (Int8s) Add(Int8s) Int8s
    56  //	...
    57  //	func (Float64x8) Add(Float64x8) Float64x8
    58  //	func (Float64s) Add(Float64s) Float64s
    59  //
    60  // ## Spec constraints
    61  //
    62  // For many operations, all possible combinations of their type parameters are
    63  // valid, but some need to express constraints between type parameters that
    64  // can't easily be described in the Go type system. For these, we support a
    65  // `//specgen:requires` directive. Consider DotProductPairs:
    66  //
    67  //	// DotProductPairs computes the dot product of x and y.
    68  //	//
    69  //	//specgen:require z={xB}{xN*2}x{xL/2}
    70  //	func DotProductPairs[E Nums, W Width, zE Nums](x, y Vec[E, W]) (z Vec[zE, W]) {
    71  //	    ...
    72  //	}
    73  //
    74  // The require expression refers to the types of each parameter and result by
    75  // name. For Vec (and Array) arguments, each parameter and result also get
    76  // several related variables:
    77  //
    78  //	v  = The whole vector type (e.g., Uint32x8)
    79  //	vE = The element type (e.g., uint32)
    80  //	vB = The base type (e.g., uint)
    81  //	vN = The base type size (e.g., 32)
    82  //	vL = The number of lanes in the vector or elements in the array (e.g., 8)
    83  //	vW = The total bit width of the vector or array (e.g., 256)
    84  //
    85  // The full syntax for constraints is described in the [specgen/specexpr]
    86  // package, but they often describe vector shapes like those in the
    87  // DotProductPairs example. The form of these is:
    88  //
    89  //   - BaseNxL, which describes a vector with L elements of type BaseN;
    90  //   - BaseNwW, which describes a vector of total width W; or
    91  //   - BaseNs, which describes a scalable vector of BaseN elements.
    92  //
    93  // Base, N, L, or W can be either a literal or an expression in {}'s. For
    94  // example, Uint32x{vL} or {zB}{zN}w128.
    95  //
    96  // For DotProductPairs, the constraint "z={vB}{vN*2}x{vL/2}" says the result z
    97  // must have the same base type as v, but z's element type must be twice as
    98  // wide, and z must have half the number of lanes of v.
    99  //
   100  // The DotProductPairs constraint could also have been written in any of the
   101  // following equivalent ways:
   102  //
   103  //	z={vB}{vN*2}w{vW}       Constrain the total vector width
   104  //	zB=vB zN=vN*2 zL=vL/2   Constrain each component separately
   105  //	zE={vB}{vN*2} zW=vW     Constrain the element type and width separately
   106  //
   107  // ## Name and doc templates
   108  //
   109  // For some operations, the API name or documentation depends on type
   110  // parameters. For these we support a simple template system where constraint
   111  // variables can be referenced in curly braces, like {vE}, similar to {}
   112  // expressions in shape constraints. For doc comments, these can be included
   113  // directly in the doc comment. For names, we use a `//specgen:name` directive,
   114  // such as
   115  //
   116  //	//specgen:name Load{z}
   117  //	func LoadZ[E Elt, W Width](s []E) (z Vec[E, W]) {
   118  //
   119  // In this case, the spec function itself can be named anything (as long as it's
   120  // exported), and the API name is generated from the directive. For example,
   121  // when LoadZ is instantiated on uint32 and Width128, the API name generated
   122  // from the template will be LoadUint32x4. This is particularly useful for
   123  // constructor functions and conversion functions where types must appear in the
   124  // name, such as LoadZ.
   125  //
   126  // ## The spec type system
   127  //
   128  // This package defines a set of types that translate to API types. We saw the
   129  // [Vec] type above, which translates to a concrete BNxL (or BNs) vector type in
   130  // the API, where L is determined from E and W.
   131  //
   132  // Masks are also represented using the [Vec] type, but with an element type
   133  // from the [MaskElt] interface, such as Mask8, Mask16, etc. The generator
   134  // translates these to Mask types in the API. Internal to the spec package,
   135  // these are like a wide mask, where only 0 and ^0 are legal values for these
   136  // elements.
   137  //
   138  // Similar to [Vec], there an [Array[E,W]] type that translates into a [L]E Go
   139  // array type in the API.
   140  //
   141  // The type [UintN] stands for a uint type whose bit width is determined by spec
   142  // constraints.
   143  //
   144  // Pointer and slice types translate directly to the API.
   145  package spec
   146  

View as plain text