Skip to content

Conversation

sayantn
Copy link
Contributor

@sayantn sayantn commented Sep 15, 2025

Ported the implementation of most SIMD intrinsics from Miri to rustc_const_eval. Remaining are

  • Math functions (as per @RalfJung's suggestions)
  • FMA (non-deterministic)
  • Funnel Shifts (not implemented in Miri yet)
  • Unordered reduction intrinsics (not implemented in Miri yet)

@rustbot
Copy link
Collaborator

rustbot commented Sep 15, 2025

Some changes occurred to the platform-builtins intrinsics. Make sure the
LLVM backend as well as portable-simd gets adapted for the changes.

cc @antoyo, @GuillaumeGomez, @bjorn3, @calebzulawski, @programmerjake

Some changes occurred to the CTFE / Miri interpreter

cc @rust-lang/miri

Some changes occurred to the CTFE machinery

cc @RalfJung, @oli-obk, @lcnr

Some changes occurred to the intrinsics. Make sure the CTFE / Miri interpreter
gets adapted for the changes, if necessary.

cc @rust-lang/miri, @RalfJung, @oli-obk, @lcnr

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-libs Relevant to the library team, which will review and decide on the PR/issue. labels Sep 15, 2025
@rustbot
Copy link
Collaborator

rustbot commented Sep 15, 2025

r? @davidtwco

rustbot has assigned @davidtwco.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

@rustbot
Copy link
Collaborator

rustbot commented Sep 15, 2025

workingjubilee is currently at their maximum review capacity.
They may take a while to respond.

}

fn main() {
const X2: i32x2 = i32x2::from_array([20, 21]);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please add checks for length 3 and 6 since portable-simd wants to support non-powers-of-2. length 3 since it's odd and length 6 because it's the smallest where the simd type's alignment is not equal to either the simd type's size or to the element's size.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should I also add these to the tests/ui/simd file, I just copied the test cases from there?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure if you like. I mostly just figured while you're writing the code is a good time to add it to the code you're changing. I'll leave it up to the const-eval people to decide if they want it everywhere. shuffles do get a bunch of testing in portable-simd for miri (and normal compilation), but we don't explicitly test const-eval shuffles in portable-simd because they didn't exist yet.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Miri and const-eval will use the same implementation so in principle it is covered.

Instead of duplicating tests we usually prefer making the existing tests run both inside and outside consts. We have some infrastructure for that in the std test suite -- is there a reason this has to be a ui test?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Idts, this should be in coretests, but the tests for simd_insert and simd_extract was in this directory so I just put these there. I will port these to coretests

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have moved all the tests to coretests, and enabled const-eval tests for them

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, moving them to coretests is problematic because apparently there is no way to disable tests inside coretests (even for backends), so I undid the move, and modified the files in place to make them const-compatible

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you mean by this? There's tons of ways to disable tests inside coretests, depending on what exactly you want to do.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wanted to disable them based on the backend (clif and gcc has broken support, and I don't want this PR to be the one to fix them), couldn't figure it out, and then realized that the current design "works" 😅

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have moved a lot of tests from ui to coretests so this feels like a step in the wrong direction. I don't know how we deal with backend issues, maybe we have cfg flags for that?

We'll have to find another reviewer for the tests anyway, a 4k diffstat is just way more than I can handle currently.

@RalfJung
Copy link
Member

Make simd_shuffle usable in const-contexts (I am also working on other simd intrinsics, but want to get this one over fast because a stdarch PR depends on it)

Which PR is that? Always good to cross-reference things. :) Or if the PR doesn't exist yet, what are your stdarch plans that need this?

@sayantn
Copy link
Contributor Author

sayantn commented Sep 15, 2025

I want to make some stdarch functions available on const-contexts (for now, we are doing mostly constructors, but the _mm_set1 constructors use simd_shuffle, hence this. For some reason a simple Type([value; N]) doesn't optimize in darwin and ios (see #60637 (comment))

@workingjubilee
Copy link
Member

I think we discussed creating a simd_splat intrinsic of some kind for simple initialization of vectors because it would optimize better.

@workingjubilee
Copy link
Member

workingjubilee commented Sep 15, 2025

Also I know I mentioned it but please do not get into introducing such a new intrinsic here (a new PR, maybe!), as there are other good reasons to make this const so that we don't have to haggle over the many possible reasons (it is a truth universally acknowledged that std::arch is... a tad big) someone might want to use the simd_shuffle operation in their runtime API yet also const-evaluate it. At const time it's just boring operations on an array, after all, and you can already do that.

@workingjubilee
Copy link
Member

Anyways, that aside, I'm basically good with this so it's mostly going to be haggling with Ralf, so

r? RalfJung

@rustbot
Copy link
Collaborator

rustbot commented Sep 15, 2025

The Miri subtree was changed

cc @rust-lang/miri

@sayantn sayantn changed the title Implement simd_shuffle in const_eval Implement most SIMD intrinsics in const-eval Sep 15, 2025
Comment on lines 36 to 45
pub const fn from_array(a: [T; N]) -> Self {
Simd(a)
}

pub const fn splat(value: T) -> Self
where
T: Copy,
{
Self([value; N])
}
Copy link
Member

@programmerjake programmerjake Sep 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you need to use mem::transmute instead of accessing the field inside a repr(simd) struct, since last I knew the compiler doesn't properly handle the field accesses in all cases

Suggested change
pub const fn from_array(a: [T; N]) -> Self {
Simd(a)
}
pub const fn splat(value: T) -> Self
where
T: Copy,
{
Self([value; N])
}
pub const fn from_array(a: [T; N]) -> Self {
// Safety: same shape
unsafe { mem::transmute(a) }
}
pub const fn splat(value: T) -> Self
where
T: Copy,
{
// Safety: same shape
unsafe { mem::transmute([value; N]) }
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

afaik constructing them is fine, projecting is the problematic part

@rust-log-analyzer

This comment has been minimized.

@sayantn sayantn force-pushed the simd-shuffle branch 2 times, most recently from 85efca6 to de2aa11 Compare September 16, 2025 05:54
@rust-log-analyzer

This comment has been minimized.

@sayantn

This comment was marked as outdated.

@rust-log-analyzer

This comment has been minimized.

@sayantn
Copy link
Contributor Author

sayantn commented Sep 25, 2025

seems spurious, let's retry

edit: huh 😕

@bors
Copy link
Collaborator

bors commented Sep 25, 2025

☔ The latest upstream changes (presumably #147019) made this pull request unmergeable. Please resolve the merge conflicts.

@sayantn
Copy link
Contributor Author

sayantn commented Sep 25, 2025

@RalfJung as #146735 is merged now, should I also make simd_fma const in this pr, or should I postpone it for the next PR?

@RalfJung
Copy link
Member

I'd prefer not expanding the scope of this PR.

@rustbot
Copy link
Collaborator

rustbot commented Sep 25, 2025

This PR was rebased onto a different master commit. Here's a range-diff highlighting what actually changed.

Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers.

@clarfonthey
Copy link
Contributor

This is probably far better performance-wise, but is there a particular reason why these are implemented directly in miri/const-eval instead of via fallback bodies? Since I had also been investigating that path to doing this, although it's clear that some versions like simd_relaxed_fma would require a direct MIRI implementation to ensure nondeterminism.

@sayantn
Copy link
Contributor Author

sayantn commented Oct 5, 2025

The arguments are just random type parameters. If repr(simd) gets removed in favor of a Simd<T, N> type, then probably we can have a fallback implementation. This is in contrast to the scalar intrinsics, where we know all the possible types, and so use an extension trait or sth else to implement the fallback body

@clarfonthey
Copy link
Contributor

I thought that repr(simd) was perma-unstable, and so, you would be able to know all possible types? I know that it's more than just Simd and also includes stuff like __m128, but I figured that you didn't have to account for some random repr(simd) struct being implemented downstream.

@sayantn
Copy link
Contributor Author

sayantn commented Oct 5, 2025

Even if it is perma-unstable, there are a lot more of such structs lying around. Grepping the rustc repo I could find ~300 instances of #[repr(simd, a lot of them being in the tests

@clarfonthey
Copy link
Contributor

Fair enough!

Sorry for interrupting, mostly just wanting to verify that this is the correct path for the implementation. While it doesn't seem unreasonable to just implement the fallback traits in those instances, you're right that it'd be a load of extra work when we could just rely on repr(simd) instead, especially when it'll probably be much more performant to directly compute things than do five loops through the traits system first.

@sayantn sayantn changed the title Implement most SIMD intrinsics in const-eval Port the implemention of SIMD intrinsics from Miri to const-eval Oct 8, 2025
@sayantn
Copy link
Contributor Author

sayantn commented Oct 8, 2025

I (on suggestions from @RalfJung) have decided to split this PR into 2 - this one will just port the implementations, and another PR after this will update the definitions and the tests to actually make them const. So now this can be merged quickly to unblock other work such as #147355

r? @RalfJung

@rustbot rustbot assigned RalfJung and unassigned tgross35 Oct 8, 2025
@RalfJung
Copy link
Member

RalfJung commented Oct 8, 2025

LGTM, thanks!
@bors r+

@bors
Copy link
Collaborator

bors commented Oct 8, 2025

📌 Commit 45ca537 has been approved by RalfJung

It is now in the queue for this repository.

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Oct 8, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-libs Relevant to the library team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

10 participants