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

View as plain text