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