blob: 35b867577efd1b93ee37681b51debbfe06c4f049 [file]
// Copyright 2026 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package spec describes all possible operations in the SIMD API.
//
// The SIMD spec describes the function and method signatures, documentation
// comments, and behavior (written as a reference Go implementation) of all
// possible Go SIMD APIs. The archsimd and simd packages are subsets of this
// specified API. This approach enforces that "one name means one thing" across
// all platforms and both packages.
//
// The spec is written as buildable and executable Go code, but isn't meant to
// be called directly. Rather, the specgen package interprets this spec package
// into a full API description, which can then be fed into other generators for
// the actual SIMD packages. The executable part of the spec serves to precisely
// specify the semantics of operations, and is intended for conformance testing.
//
// To see the spec-generated API and debug issues with it, use [cmd/specls].
//
// ## Basic operation specifications
//
// Spec operations are written in a stylized form that makes heavy use of type
// parameters so a single function can describe an operation generalized across
// many vector types. This is in contrast with the public SIMD API, where every
// function and method operates on concrete types. The specgen generator bridges
// this gap, instantiating a single parameterized spec function into many
// concrete methods.
//
// Consider a simple example, the Add operation:
//
// // Add adds corresponding elements of two vectors.
// func Add[E Nums, W Width](x, y Vec[E, W]) (z Vec[E, W]) {
// ...
// }
//
// All spec operations are written as functions, but if the first parameter has
// type Vec, then they specify a method of a vector type. Since Add's first
// parameter (x) is a Vec, this describes a method on vector types.
//
// The "E Nums" type parameter controls the allowed element types of the three
// vector types. Here, it can be any numeric type of any size (uint8, float64,
// etc). The "W Width" type parameter controls the total bit width of the three
// vector types. The types that implement Width stand in for 128, 256, or 512
// bits, or "scalable", which can represent any power of two >= 128. The number
// of lanes of a vector is derived from the element size and the total vector
// width.
//
// The Add spec expands to all possible types that satisfy the E and W type
// parameters, which are in turn translated to types in the public API:
//
// func (Int8x16) Add(Int8x16) Int8x16
// func (Int8x32) Add(Int8x32) Int8x32
// func (Int8x64) Add(Int8x64) Int8x64
// func (Int8s) Add(Int8s) Int8s
// ...
// func (Float64x8) Add(Float64x8) Float64x8
// func (Float64s) Add(Float64s) Float64s
//
// ## Spec constraints
//
// For many operations, all possible combinations of their type parameters are
// valid, but some need to express constraints between type parameters that
// can't easily be described in the Go type system. For these, we support a
// `//specgen:requires` directive. Consider DotProductPairs:
//
// // DotProductPairs computes the dot product of x and y.
// //
// //specgen:require z={xB}{xN*2}x{xL/2}
// func DotProductPairs[E Nums, W Width, zE Nums](x, y Vec[E, W]) (z Vec[zE, W]) {
// ...
// }
//
// The require expression refers to the types of each parameter and result by
// name. For Vec (and Array) arguments, each parameter and result also get
// several related variables:
//
// v = The whole vector type (e.g., Uint32x8)
// vE = The element type (e.g., uint32)
// vB = The base type (e.g., uint)
// vN = The base type size (e.g., 32)
// vL = The number of lanes in the vector or elements in the array (e.g., 8)
// vW = The total bit width of the vector or array (e.g., 256)
//
// The full syntax for constraints is described in the [specgen/specexpr]
// package, but they often describe vector shapes like those in the
// DotProductPairs example. The form of these is:
//
// - BaseNxL, which describes a vector with L elements of type BaseN;
// - BaseNwW, which describes a vector of total width W; or
// - BaseNs, which describes a scalable vector of BaseN elements.
//
// Base, N, L, or W can be either a literal or an expression in {}'s. For
// example, Uint32x{vL} or {zB}{zN}w128.
//
// For DotProductPairs, the constraint "z={vB}{vN*2}x{vL/2}" says the result z
// must have the same base type as v, but z's element type must be twice as
// wide, and z must have half the number of lanes of v.
//
// The DotProductPairs constraint could also have been written in any of the
// following equivalent ways:
//
// z={vB}{vN*2}w{vW} Constrain the total vector width
// zB=vB zN=vN*2 zL=vL/2 Constrain each component separately
// zE={vB}{vN*2} zW=vW Constrain the element type and width separately
//
// ## Name and doc templates
//
// For some operations, the API name or documentation depends on type
// parameters. For these we support a simple template system where constraint
// variables can be referenced in curly braces, like {vE}, similar to {}
// expressions in shape constraints. For doc comments, these can be included
// directly in the doc comment. For names, we use a `//specgen:name` directive,
// such as
//
// //specgen:name Load{z}
// func LoadZ[E Elt, W Width](s []E) (z Vec[E, W]) {
//
// In this case, the spec function itself can be named anything (as long as it's
// exported), and the API name is generated from the directive. For example,
// when LoadZ is instantiated on uint32 and Width128, the API name generated
// from the template will be LoadUint32x4. This is particularly useful for
// constructor functions and conversion functions where types must appear in the
// name, such as LoadZ.
//
// ## The spec type system
//
// This package defines a set of types that translate to API types. We saw the
// [Vec] type above, which translates to a concrete BNxL (or BNs) vector type in
// the API, where L is determined from E and W.
//
// Masks are also represented using the [Vec] type, but with an element type
// from the [MaskElt] interface, such as Mask8, Mask16, etc. The generator
// translates these to Mask types in the API. Internal to the spec package,
// these are like a wide mask, where only 0 and ^0 are legal values for these
// elements.
//
// Similar to [Vec], there an [Array[E,W]] type that translates into a [L]E Go
// array type in the API.
//
// The type [UintN] stands for a uint type whose bit width is determined by spec
// constraints.
//
// Pointer and slice types translate directly to the API.
package spec