Source file src/simd/internal/spec/reductions.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 //specgen:category Reductions 6 7 package spec 8 9 // ReduceSumInts returns the scalar sum of the elements of x. 10 // 11 // z = x[0] + x[1] + ... 12 // 13 //specgen:name ReduceSum 14 func ReduceSumInts[E Ints | Uints, W Width](x Vec[E, W]) (z E) { 15 // Integer addition wraps and is associative, so the order doesn't matter. 16 for _, xi := range x { 17 z += xi 18 } 19 return z 20 } 21 22 // ReduceSumFloats returns the scalar sum of the elements of x. 23 // 24 // {{if eq .xL 2}} 25 // 26 // z = x[0] + x[1] 27 // 28 // {{else}} 29 // 30 // This uses repeated pairwise summation, which may affect the final precision 31 // of the result. 32 // 33 // {{if eq .xL 4}} 34 // 35 // z = (x[0] + x[1]) + (x[2] + x[3]) 36 // 37 // {{else}} 38 // 39 // z = ((x[0] + x[1]) + (x[2] + x[3])) + ... 40 // 41 // {{end}} 42 // 43 // {{end}} 44 // 45 //specgen:name ReduceSum 46 func ReduceSumFloats[E Floats, W Width](x Vec[E, W]) (z E) { 47 // Vector lengths are powers of two, so every level pairs up evenly. 48 tmp := make([]E, x.len()/2, maxScalableWidth/elemBits[E]()/2) 49 for i := range tmp { 50 tmp[i] = x[2*i] + x[2*i+1] 51 } 52 for len(tmp) > 1 { 53 half := len(tmp) / 2 54 for i := range half { 55 tmp[i] = tmp[2*i] + tmp[2*i+1] 56 } 57 tmp = tmp[:half] 58 } 59 return tmp[0] 60 } 61 62 // ReduceMax returns the largest element of x. 63 // 64 // z = max(x[0], x[1], ...) 65 func ReduceMax[E Elt, W Width](x Vec[E, W]) (z E) { 66 // TODO: Do we need per-platform handling of non-finites? Since AMD64 is the 67 // only platform that's weird about non-finite values and it doesn't have 68 // ReduceMax, maybe we don't have to, but if we ever want to emulate this on 69 // AMD64, we'd have to decide whether to match AMD64's Max or Go/IEEE Max. 70 z = x[0] 71 for _, xi := range x[1:] { 72 z = max(z, xi) 73 } 74 return z 75 } 76 77 // ReduceMin returns the smallest element of x. 78 // 79 // z = min(x[0], x[1], ...) 80 func ReduceMin[E Elt, W Width](x Vec[E, W]) (z E) { 81 // See ReduceMax about the handling of non-finite values. 82 z = x[0] 83 for _, xi := range x[1:] { 84 z = min(z, xi) 85 } 86 return z 87 } 88