Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tracking Issue for RFC 2948: Portable SIMD #86656

Open
1 of 9 tasks
calebzulawski opened this issue Jun 27, 2021 · 29 comments
Open
1 of 9 tasks

Tracking Issue for RFC 2948: Portable SIMD #86656

calebzulawski opened this issue Jun 27, 2021 · 29 comments
Labels
A-simd Area: SIMD (Single Instruction Multiple Data) A-target-feature Area: Enabling/disabling target features like AVX, Neon, etc. C-tracking-issue Category: A tracking issue for an RFC or an unstable feature. needs-rfc This change is large or controversial enough that it should have an RFC accepted before doing it. PG-portable-simd Project group: Portable SIMD (https://github.com/rust-lang/project-portable-simd) T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.

Comments

@calebzulawski
Copy link
Member

calebzulawski commented Jun 27, 2021

Feature gate: #![feature(portable_simd)]

This is a tracking issue for the future feature chartered in RFC 2977, with the intent of creating something akin to the design in RFC 2948 (rust-lang/rfcs#2948): a portable SIMD library (std::simd).

Portable SIMD project group: https://github.com/rust-lang/project-portable-simd
Implementation: https://github.com/rust-lang/portable-simd

More discussion can be found in the #project-portable-simd zulip stream.

Steps

Unresolved Questions

  • What will the overall design be?
  • What are the ideal semantics for Masks?
  • Are there any limits or vector sizes we should not support?
  • How should these types interop with types like Saturating, NonZero, etc.?

Implementation History

@calebzulawski calebzulawski added C-tracking-issue Category: A tracking issue for an RFC or an unstable feature. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue. labels Jun 27, 2021
@jonas-schievink jonas-schievink added A-simd Area: SIMD (Single Instruction Multiple Data) PG-portable-simd Project group: Portable SIMD (https://github.com/rust-lang/project-portable-simd) labels Jun 27, 2021
workingjubilee added a commit to workingjubilee/rustc that referenced this issue Nov 13, 2021
This enables programmers to use a safe alternative to the current
`extern "platform-intrinsics"` API for writing portable SIMD code.
This is `#![feature(portable_simd)]` as tracked in rust-lang#86656
bors added a commit to rust-lang-ci/rust that referenced this issue Nov 13, 2021
…crum

pub use core::simd;

A portable abstraction over SIMD has been a major pursuit in recent years for several programming languages. In Rust, `std::arch` offers explicit SIMD acceleration via compiler intrinsics, but it does so at the cost of having to individually maintain each and every single such API, and is almost completely `unsafe` to use.  `core::simd` offers safe abstractions that are resolved to the appropriate SIMD instructions by LLVM during compilation, including scalar instructions if that is all that is available.

`core::simd` is enabled by the `#![portable_simd]` nightly feature tracked in rust-lang#86656 and is introduced here by pulling in the https://github.com/rust-lang/portable-simd repository as a subtree. We built the repository out-of-tree to allow faster compilation and a stochastic test suite backed by the proptest crate to verify that different targets, features, and optimizations produce the same result, so that using this library does not introduce any surprises. As these tests are technically non-deterministic, and thus can introduce overly interesting Heisenbugs if included in the rustc CI, they are visible in the commit history of the subtree but do nothing here. Some tests **are** introduced via the documentation, but these use deterministic asserts.

There are multiple unsolved problems with the library at the current moment, including a want for better documentation, technical issues with LLVM scalarizing and lowering to libm, room for improvement for the APIs, and so far I have not added the necessary plumbing for allowing the more experimental or libm-dependent APIs to be used. However, I thought it would be prudent to open this for review in its current condition, as it is both usable and it is likely I am going to learn something else needs to be fixed when bors tries this out.

The major types are
- `core::simd::Simd<T, N>`
- `core::simd::Mask<T, N>`

There is also the `LaneCount` struct, which, together with the SimdElement and SupportedLaneCount traits, limit the implementation's maximum support to vectors we know will actually compile and provide supporting logic for bitmasks. I'm hoping to simplify at least some of these out of the way as the compiler and library evolve.
@workingjubilee workingjubilee added the needs-rfc This change is large or controversial enough that it should have an RFC accepted before doing it. label Dec 1, 2021
@HannesGitH
Copy link

Feature gate: #![feature(portable_simd)]

i'm sorry if this is the wrong place to ask but im rather new to rust and stumbled upon this issues as my compiler told me to

if i want to use this feature as soon as my compiler supports it can i gate it like:

#[cfg(feature = "portable_simd")]
use std::simd::Simd;

or is that only for feautures regarding my package (set in toml or passed to cargo?) if so what would be the appropriate way to use simd as soon as this issue is resolved?

@Lokathor
Copy link
Contributor

The #![feature(portable_simd)] part goes at the top of a binary or library.

It's a language feature not a cargo feature so it works a little differently.

It's unfortunate that they're both just "feature". Rust is often too terse when it counts.

@HannesGitH
Copy link

HannesGitH commented Feb 21, 2023

ok thanks a lot!

just to make sure this means there is no (easy*) way to use this language feature if my compiler supports it and fall back to a custom implementation otherwise?

*easy as in compile time guards / attribute-like macros or creating a custom wrapper module that either provides rusts simd or my own fallback or something else in that level of skill


for anyone else stumbling upon this:

language features are (unstable) features you can opt-in when using nightly rust (by putting the specified flag in your library root, the whole project will then be compiled with a compiler that uses this feature)

@erwanvivien
Copy link

Is there any work done doday to use simd ? I see we are 1/9 and there is not much activity at portable_simd.

Does this part of Rust requires help ?

@calebzulawski
Copy link
Member Author

That first task was most of the work--with the nightly compiler you can use std::simd today. Most of the improvements being worked on now are relatively minor in comparison, but we are always open to contributions.

At this point we are mostly focusing on usability rather than features, which really means two things: ease of use of the API, and quality of the code generation. Once a base set of features is in a good state, we can begin the RFC process.

@erwanvivien
Copy link

Thanks for info and the kind reply!

@workingjubilee workingjubilee added the A-target-feature Area: Enabling/disabling target features like AVX, Neon, etc. label Mar 3, 2023
@safinaskar
Copy link
Contributor

@agausmann

  • To enable the experimental feature flag on nightly,
#![rustversion::attr(nightly, feature(portable_simd))]

Unfortunately, this particular code doesn't work

@Inspirateur
Copy link

Do you think this has a chance to get stabilized ? It seems like activity has been very low recently, despite being a cool feature

@programmerjake
Copy link
Member

Do you think this has a chance to get stabilized ? It seems like activity has been very low recently, despite being a cool feature

I think it will be stabilized but not right away, afaict that still needs a RFC with the full detailed design.

@scottmcm
Copy link
Member

@Inspirateur I think there's two big things needed:

  1. Confidence that the overall shape of things is good enough to stabilize -- questions like whether the lanecount trait is worth having, whether the structure will work tolerably with vscale, etc
  2. Someone carving out a subset in which people are confident and writing an RFC for it. Maybe that's the types, the basic lanewise ops, and conversions/layout stuff to start with. (Notably, if for some time non-trivial things require converting to platform-specific types like __m256 and using intrinsics, that's fine. We could do, say, aggregations and masks in a v2, shuffles and swizzles in a v3, or something.)

@CarlKCarlK
Copy link

CarlKCarlK commented Nov 22, 2023

@agausmann

  • To enable the experimental feature flag on nightly,
#![rustversion::attr(nightly, feature(portable_simd))]

@safinaskar

Unfortunately, this particular code doesn't work

This worked for me:

#![cfg_attr(feature = "from_slice", feature(portable_simd))]

where "from_slice" is the name of my the-other-kind-of-feature, defined in Cargo.toml, that uses portable_simd.

[features]
from_slice = []

So, I run tests, for example, via cargo test --features=from_slice.

@GlenDC
Copy link
Contributor

GlenDC commented Dec 7, 2023

Is this on the 2024 edition roadmap, or will it be only for after that? I know it’s not related, but gives me a timeline range.

@calebzulawski
Copy link
Member Author

I don't think anyone has a specific timeline, but we still need to draft a new RFC and go through the approval process, which can take some time.

@jhpratt
Copy link
Member

jhpratt commented Mar 8, 2024

Is there a particular reason that Simd does not implement Deref and DerefMut? I don't see any reason the impls would restrict the ability to do anything.

@Lokathor
Copy link
Contributor

Lokathor commented Mar 8, 2024

Like deref into a slice? Usually that's not done because it's a huge performance footgun.

@Firstyear
Copy link
Contributor

It may be good to document what that footgun is and why the choice was made because people will ask this again in future.

@Lokathor
Copy link
Contributor

Lokathor commented Mar 8, 2024

So, to add more detail: the problem is that (depending on SIMD used) you can't in general index to a particular lane of a SIMD register. So if you view the SIMD data as a slice and operate on an element of the slice, what the hardware must do is have the CPU stop the current SIMD processing, write the register to the stack, work on the stack value (however the slice is adjusted), and then load that back into a SIMD register. This is, in general, a performance disaster. As usual, the optimizer might be able to cut out this stall in the pipeline, in some cases, depending on circumstances, etc etc. But you should expect that the SIMD handling is totally stalled when trying to treat the data as a slice.

@jhpratt
Copy link
Member

jhpratt commented Mar 9, 2024

I figured there was a reason, but I'm not familiar with how SIMD works under the hood. Given that indexing is the problem, why implement Index and IndexMut then?

@Lokathor
Copy link
Contributor

Lokathor commented Mar 9, 2024

Oh, uh, well I haven't looked in a while! I guess I'm out of the loop on the current API details.

I'm surprised that Index is in if Deref is out. Either both should be in or both should be out, would be my expectation.

@calebzulawski
Copy link
Member Author

calebzulawski commented Mar 9, 2024

The basic idea is that we want a clear marker of the boundary between SIMD and non-SIMD operations. When using Index (vector[i]) there is an obvious sign that you are no longer using SIMD operations. Likewise with arrays and slices, we implement AsRef and the to_array function because these are explicit. The concern with Deref is that the automatic inclusion of all slice functions makes it harder to tell which operations are SIMD. For example, you may expect is_ascii to be vectorized, but instead it is simply a scalar implementation inherited from slices.

@Lokathor
Copy link
Contributor

Lokathor commented Mar 9, 2024

vector[i] isn't particularly more obvious, I would say.

Maybe we should just always make people convert to an array to index elements?

@calebzulawski
Copy link
Member Author

A while ago we didn't implement Index and we got requests for it, but this is the first time Deref has come up, so I think it's a good compromise. Maybe it's not particularly obvious that Index is the boundary, but Deref is completely invisible without consulting the docs.

@ZagButNoZig
Copy link

ZagButNoZig commented Apr 22, 2024

There are certain types of instructions where the output data type is different from the input data type like: _mm256_maddubs_epi16. I don't think there is a way to do that in portable simd without casting first which is slower? Are there any plans to support these instructions. Similar instructions also exist on arch: vdotq_s32

@abysssol
Copy link

Hi, I was wondering if there had been any discussion or consideration of making a dynamically sized api for vector operations. The current api seems to be analogous to arrays, but perhaps a more elegant and convenient solution would be analogous to slices.

I learned about this idea when researching risc-v's vector extension. Both this article and this one (fully rendered here) are good references on the motivation, from the perspective of an ISA.

While the current api is already much better than traditional simd instructions, it seems to me that the logical conclusion is a runtime sized type; maybe a wrapper around &mut [T], or a type like Vec<T>, or perhaps a modification to Vec<T> that guarantees simd optimization if T is a numeric primitive.

Hopefully this can spark a useful discussion on the best design of simd/vector types and operations. Thank you for your consideration.

@Lokathor
Copy link
Contributor

That could be some additional API that lives along aside the fixed sized SIMD types, but for the main CPU arches a fixed sized simd type is what generally works best with optimizations.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-simd Area: SIMD (Single Instruction Multiple Data) A-target-feature Area: Enabling/disabling target features like AVX, Neon, etc. C-tracking-issue Category: A tracking issue for an RFC or an unstable feature. needs-rfc This change is large or controversial enough that it should have an RFC accepted before doing it. PG-portable-simd Project group: Portable SIMD (https://github.com/rust-lang/project-portable-simd) T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests