Source file src/simd/internal/spec/math.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  //simdgen:category Math
     6  
     7  package spec
     8  
     9  // Add adds corresponding elements of two vectors.
    10  //
    11  //	z[i] = x[i] + y[i]
    12  //
    13  //specgen:commutative
    14  func Add[E Nums, W Width](x, y Vec[E, W]) (z Vec[E, W]) {
    15  	return map2[E, W, E, W](x, y, func(x, y E) E { return x + y })
    16  }
    17  
    18  // DotProductPairs multiplies corresponding elements of x and y, and sums
    19  // adjacent pairs, yielding a vector of half as many elements with twice the
    20  // input element size.
    21  //
    22  //	w[i] = x[i] * y[i]        // Double width
    23  //	z[i] = w[2*i] + w[2*i+1]
    24  //
    25  //specgen:commutative
    26  //specgen:require z={xB}{xN*2}x{xL/2}
    27  func DotProductPairs[E Nums, W Width, zE Nums](x, y Vec[E, W]) (z Vec[zE, W]) {
    28  	// TODO: How do we handle/specify overflow? x86 only supports this on signed
    29  	// types, and the only case that can overflow is if all four elements are
    30  	// MinInt16 (in which case the true result is MaxInt32+1, which wraps around
    31  	// to MinInt32). Unsigned types can overflow much more readily.
    32  	//
    33  	// Maybe we just leave overflow unspecified (or "architecture dependent").
    34  	// In which case, we probably need a way to communicate that in the spec
    35  	// (designated panic?).
    36  	//
    37  	// We might also need a way to constraint this to same-signed E and zE,
    38  	// which the constraint language doesn't currently have a way to say, but we
    39  	// could add as a built-in projection function in the syntax.
    40  	z = makeVec[zE, W]()
    41  	for i := range z {
    42  		z[i] = zE(x[2*i])*zE(y[2*i]) + zE(x[2*i+1])*zE(y[2*i+1])
    43  	}
    44  	return z
    45  }
    46  
    47  // DotProductPairsSaturated multiplies corresponding elements of x and y, and
    48  // sums adjacent pairs, all with saturation. It yields a vector of half as many
    49  // elements with twice the input element size.
    50  //
    51  //	w[i] = x[i] * y[i]        // Double width, saturated
    52  //	z[i] = w[2*i] + w[2*i+1]  // Saturated
    53  //
    54  //specgen:commutative
    55  //specgen:require y=Int{xN}x{xL} z=Int{xN*2}x{xL/2}
    56  func DotProductPairsSaturated[xE Uints, xW Width, yE Ints, zE Ints](x Vec[xE, xW], y Vec[yE, xW]) (z Vec[zE, xW]) {
    57  	z = makeVec[zE, xW]()
    58  	for i := range z {
    59  		a := mulSaturatedUSS64(uint64(x[2*i]), int64(y[2*i]))
    60  		b := mulSaturatedUSS64(uint64(x[2*i+1]), int64(y[2*i+1]))
    61  		z[i] = saturateS[zE](addSaturatedSSS64(a, b))
    62  	}
    63  	return z
    64  }
    65  

View as plain text