Skip to content

proposal: simd/archsimd: enable AMD64 architecture-specific SIMD by default #78979

Description

@cherrymui

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    LibraryProposalIssues describing a requested change to the Go standard library or x/ libraries, but not to a toolProposalProposal-Hold

    Type

    No type

    Projects

    Status
    Hold

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions