Proposal Details
In Go 1.26, we introduced AMD64 architecture-specific SIMD intrinsics in the simd/archsimd package under GOEXPERIMENT=simd.
Thanks to users trying out the experiment, we've received valuable feedback. The feedback is very positive, and we did not find major flaws in the API. While there are opportunities for further optimizations and the addition of new features, these improvements can be implemented without necessitating revisions to the existing API.
The architecture-specific SIMD API is the first step and the lower level of our Two-level approach. It serves as the building block for the upper-level, portable, size-agnostic vector API. We now have sketched out a draft of the high-level API. Our analysis confirms that the simd/archsimd package is compatible with the high-level API, provides a good foundation, and facilitates efficient interoperability (see #78902 for details).
Further, CL 745080 demonstrates that this approach can be adapted well to WebAssembly (128-bit fixed-size vectors), and the ongoing discussions shows that a similar, but scalable, API is emerging to support scalable vectors with ARM64 SVE. This suggests that the current approach can work reasonably well on a variety of architectures.
Based on these findings, we propose to enable the AMD64 simd/archsimd API by default, without requiring GOEXPERIMENT=simd.
API changes
So far the only API we'd want to change from Go 1.26 experimental API is to change ShiftAll{Left,Right} operations to take an uint8 instead of uint64. This is to make it consistent with the RotateAll{Left,Right} and ShiftAll{Left,Right}Concat operations. (CL 767560)
API additions
Based on the discussions and feedback on #73787, we plan to add the following APIs to AMD64 simd/archsimd.
- More operations on masks: bit operations
AndNot, Not, Xor; testing operations All, Any, None, which check if all/any/no elements are selected; and the String method.
func (MaskMxN) AndNot(MaskMxN) MaskMxN
func (MaskMxN) Not() MaskMxN
func (MaskMxN) Xor(MaskMxN) MaskMxN
func (MaskMxN) All() bool
func (MaskMxN) Any() bool
func (MaskMxN) None() bool
func (MaskMxN) String() string
- Broadcasting a vector to a wider vector:
BoradcastAllTo{4,8,...}
func (Int64x2) BroadcastAllTo4() Int64x4
func (Int64x2) BroadcastAllTo8() Int64x8
func (Int64x4) BroadcastAllTo8() Int64x8
func (Int32x4) BroadcastAllTo8() Int32x8
func (Int32x4) BroadcastAllTo16() Int32x16
func (Int32x8) BroadcastAllTo16() Int32x16
and also for Uint and Float elements.
- Quadruple dot products:
DotProductQuadruple{Signed,Unsigned} (discussion)
func (Int8x16) DotProductQuadrupleSigned(Int8x16) Int32x4
func (Int8x16) DotProductQuadrupleUnsigned(Uint8x16) Int32x4
func (Uint8x16) DotProductQuadrupleSigned(Int8x16) Int32x4
func (Uint8x16) DotProductQuadrupleUnsigned(Uint8x16) Uint32x4
- Convenient methods (see below)
Convenient methods
We plan to add a few more convenient methods, which may not necessarily map to a single machine instruction, but still simple, usually a small number of instructions.
During the development of the high-level, portable API, we found that there are some operations on one architecture that can be easily implemented on another. For example, on WebAssembly, there is an instruction that negates the integer elements of a vector. On AMD64, there is no such an instruction, but it can be done with a Sub from a zero vector. Adding this convenient method makes it easy to support the operation in the portable layer. And it can also be handy to users.
We currently already have some convenient methods, for instance, Not is Xor with an all-one vector, and some comparison operations are a logical combination of other, native comparison operations. We plan to extend this list with Neg on integer vectors.
func (IntMxN) Neg() IntMxN
API summary
A compact summary of the API is at #73787 (comment). The full list of the current experimental API can be found at https://pkg.go.dev/simd/archsimd@master. The new API will be the experimental API with the adjustments mentioned above.
Related/future work
- #76175: a static checker of SIMD CPU features. This ensures that SIMD API is used only when the corresponding CPU feature is supported, preventing illegal instruction crashes.
- #78902: A proposal for high-level portable SIMD API
- CL 745080: An implementation of 128-bit
simd/archsimd API for Wasm
- Ongoing discussion about the
simd/archsimd API for ARM64 SVE
Proposal Details
In Go 1.26, we introduced AMD64 architecture-specific SIMD intrinsics in the
simd/archsimdpackage underGOEXPERIMENT=simd.Thanks to users trying out the experiment, we've received valuable feedback. The feedback is very positive, and we did not find major flaws in the API. While there are opportunities for further optimizations and the addition of new features, these improvements can be implemented without necessitating revisions to the existing API.
The architecture-specific SIMD API is the first step and the lower level of our Two-level approach. It serves as the building block for the upper-level, portable, size-agnostic vector API. We now have sketched out a draft of the high-level API. Our analysis confirms that the
simd/archsimdpackage is compatible with the high-level API, provides a good foundation, and facilitates efficient interoperability (see #78902 for details).Further, CL 745080 demonstrates that this approach can be adapted well to WebAssembly (128-bit fixed-size vectors), and the ongoing discussions shows that a similar, but scalable, API is emerging to support scalable vectors with ARM64 SVE. This suggests that the current approach can work reasonably well on a variety of architectures.
Based on these findings, we propose to enable the AMD64
simd/archsimdAPI by default, without requiringGOEXPERIMENT=simd.API changes
So far the only API we'd want to change from Go 1.26 experimental API is to change
ShiftAll{Left,Right}operations to take anuint8instead ofuint64. This is to make it consistent with theRotateAll{Left,Right}andShiftAll{Left,Right}Concatoperations. (CL 767560)API additions
Based on the discussions and feedback on #73787, we plan to add the following APIs to AMD64
simd/archsimd.AndNot,Not,Xor; testing operationsAll,Any,None, which check if all/any/no elements are selected; and theStringmethod.BoradcastAllTo{4,8,...}and also for Uint and Float elements.
DotProductQuadruple{Signed,Unsigned}(discussion)Convenient methods
We plan to add a few more convenient methods, which may not necessarily map to a single machine instruction, but still simple, usually a small number of instructions.
During the development of the high-level, portable API, we found that there are some operations on one architecture that can be easily implemented on another. For example, on WebAssembly, there is an instruction that negates the integer elements of a vector. On AMD64, there is no such an instruction, but it can be done with a
Subfrom a zero vector. Adding this convenient method makes it easy to support the operation in the portable layer. And it can also be handy to users.We currently already have some convenient methods, for instance,
NotisXorwith an all-one vector, and some comparison operations are a logical combination of other, native comparison operations. We plan to extend this list withNegon integer vectors.API summary
A compact summary of the API is at #73787 (comment). The full list of the current experimental API can be found at https://pkg.go.dev/simd/archsimd@master. The new API will be the experimental API with the adjustments mentioned above.
Related/future work
simd/archsimdAPI for Wasmsimd/archsimdAPI for ARM64 SVE