Skip to content

Add target_feature_available_at_call_site intrinsic#158713

Open
calebzulawski wants to merge 9 commits into
rust-lang:mainfrom
calebzulawski:call-site-target-features
Open

Add target_feature_available_at_call_site intrinsic#158713
calebzulawski wants to merge 9 commits into
rust-lang:mainfrom
calebzulawski:call-site-target-features

Conversation

@calebzulawski

@calebzulawski calebzulawski commented Jul 3, 2026

Copy link
Copy Markdown
Member

View all comments

This intrinsic allows writing intrinsic-like functions in plain Rust, that can be aware of which target features are available post-inlining.

r? @RalfJung
Feel free to pass this review on to anyone else, I just remember that we talked about this concept a while back and you might be interested.

Motivation

For a very simple example:

#[inline(always)]
fn fast_fma(a: f32, b: f32, c: f32) -> f32 {
    let has_fma = unsafe { core::intrinsics::target_feature_available_at_call_site("fma") };
    if has_fma {
        a.mul_add(b, c)
    } else {
        a * b + c
    }
}

For a more concrete example, see std::simd's swizzle_dyn. This function heavily demands target features, but:

  • cfg!(target_feature = "ssse3") doesn't work without build-std (and you lose compatibility with old CPUs)
  • is_x86_feature_detected is much too slow
  • the default case without SSSE3 is terrible!

This function requires a low-overhead method of determining the target features available at the call site.

How it works

In rustc, we replace the intrinsic with true (if the feature is already known to be enabled), false (some specific cases, e.g. compiling without optimizations), or a special marker function (e.g. rust.target_feature_available_at_call_site.avx).

A post-inlining LLVM pass replaces instances of the marker with true or false based on the caller. Then it runs instruction and CFG simplification passes to remove any evidence of branches relying on the intrinsic. This is the same mechanism Julia uses for fma. For GCC and Cranelift, no post-inlining pass is done, so the intrinsic only returns based on the global features and function attribute in MIR.

@rustbot

rustbot commented Jul 3, 2026

Copy link
Copy Markdown
Collaborator

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 the A-LLVM Area: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues. label Jul 3, 2026
@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 Jul 3, 2026
@rustbot

rustbot commented Jul 3, 2026

Copy link
Copy Markdown
Collaborator

RalfJung is not on the review rotation at the moment.
They may take a while to respond.

@rust-log-analyzer

This comment has been minimized.

@calebzulawski calebzulawski force-pushed the call-site-target-features branch from e79630d to a9b4711 Compare July 3, 2026 03:37
@rust-log-analyzer

This comment has been minimized.

@calebzulawski calebzulawski force-pushed the call-site-target-features branch from a9b4711 to a6fead8 Compare July 3, 2026 03:48
@rustbot

rustbot commented Jul 3, 2026

Copy link
Copy Markdown
Collaborator

rustc_codegen_gcc is developed in its own repository. If possible, consider making this change to rust-lang/rustc_codegen_gcc instead.

cc @antoyo, @GuillaumeGomez

@rust-log-analyzer

This comment has been minimized.

@calebzulawski calebzulawski force-pushed the call-site-target-features branch from a6fead8 to 20f5b84 Compare July 3, 2026 04:02
@rust-log-analyzer

This comment has been minimized.

@calebzulawski calebzulawski force-pushed the call-site-target-features branch from 20f5b84 to 9eb4339 Compare July 3, 2026 04:34
@rust-lang rust-lang deleted a comment from krishpinto Jul 3, 2026

@programmerjake programmerjake left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

looks good to me, though definitely get someone more familiar with the compiler to review it.

View changes since this review

@rust-log-analyzer

This comment has been minimized.

@RalfJung

RalfJung commented Jul 3, 2026

Copy link
Copy Markdown
Member

I won't be able to review the implementation, but can give feedback on design.
However, we don't usually design in the implementation PR. Presumably this won't remain just an intrinsic, but the intrinsic will be exposed in a stable wrapper or so? That'd be a new language + libs-api feature, which seems RFC-worthy. Even if we don't need an RFC for a lang experiment, we need enough of a clear problem statement and rough design idea for what this will look like to our users that the lang team can sign off on this becoming a lang experiment. (I can be the liasion or champion or whatever it is called these days for that experiment.)

Comment thread library/core/src/intrinsics/mod.rs Outdated
///
/// # Safety
///
/// Code relying on the result of this intrinsic must be sound for both `true` and `false`.

@RalfJung RalfJung Jul 3, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This can't be correct. Clearly, having the intrinsic randomly return true cannot go well.

I think what you mean is:

  • If the intrinsic returns true, then the feature is definitely available, and it is sound to call other functions that need the feature.
  • If the intrinsic returns false, that conveys no information whatsoever.

View changes since the review

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Yes, probably something like "this intrinsic can return false even if the call site does have the feature statically available because this depends on the vagaries of optimization passes and inlining".

MAM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();
FunctionPassManager FPM;
FPM.addPass(InstSimplifyPass());
FPM.addPass(SimplifyCFGPass());

@nikic nikic Jul 3, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Why not do this in OptimizerEarly instead, so more passes run afterwards?

View changes since the review

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

That makes sense, I moved it

continue;

StringRef Feature = MarkerDecl.getName().drop_front(
TargetFeatureAvailableAtCallSitePrefix.size());

@nikic nikic Jul 3, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This should be a metadata string argument instead.

View changes since the review

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I didn't know you could do this! Much better

Comment thread library/core/src/intrinsics/mod.rs Outdated
@nikic

nikic commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Doing this in a custom pass is okay for experimentation purposes, but this should really be proposed as an LLVM intrinsic upstream.

Comment thread library/core/src/intrinsics/mod.rs Outdated
Comment thread compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
@workingjubilee

workingjubilee commented Jul 3, 2026

Copy link
Copy Markdown
Member

I think currently Caleb's intent is to experiment with this for internal usage for std::simd APIs which would like to be able to select an implementation that is "feature aware" with respect to, effectively, where we expect to be inlined, so that it can resolve to the preferred instruction. There are a few functions where the fact that we can't enable features on the function is extremely brutal because we're already compiled into std.

The alternative is to tell people to recompile std with the features they have available which... well, I can't throw stones about slow progress but -Zbuild-std isn't already-solved for a reason.

@programmerjake

Copy link
Copy Markdown
Member

Doing this in a custom pass is okay for experimentation purposes, but this should really be proposed as an LLVM intrinsic upstream.

yes, that has additional benefits such as still working correctly when no LLVM optimization passes are run and then it's compiled the rest of the way using clang or something to compile the LLVM IR.

Comment thread compiler/rustc_codegen_gcc/src/intrinsic/mod.rs Outdated
@calebzulawski

Copy link
Copy Markdown
Member Author

I won't be able to review the implementation, but can give feedback on design. However, we don't usually design in the implementation PR. Presumably this won't remain just an intrinsic, but the intrinsic will be exposed in a stable wrapper or so? That'd be a new language + libs-api feature, which seems RFC-worthy. Even if we don't need an RFC for a lang experiment, we need enough of a clear problem statement and rough design idea for what this will look like to our users that the lang team can sign off on this becoming a lang experiment. (I can be the liasion or champion or whatever it is called these days for that experiment.)

I would certainly eventually like a public interface which would certainly need an RFC/experiment, but more urgently I think the intrinsic is useful within std::simd. I'm happy to write an RFC or problem statement or whatever is necessary. Thanks :)

@calebzulawski

calebzulawski commented Jul 3, 2026

Copy link
Copy Markdown
Member Author

Doing this in a custom pass is okay for experimentation purposes, but this should really be proposed as an LLVM intrinsic upstream.

Agreed that I would like to eventually move this to LLVM. I haven't personally had much luck getting simple bugfixes merged there

@RalfJung

RalfJung commented Jul 3, 2026

Copy link
Copy Markdown
Member

Doing this in a custom pass is okay for experimentation purposes, but this should really be proposed as an LLVM intrinsic upstream.

Agreed that I would like to eventually move this to LLVM. I haven't personally had much luck getting simple bugfixes merged there

@nikic is the head LLVM maintainer, I'm sure he can give you some guidance. :)

@RalfJung

RalfJung commented Jul 3, 2026

Copy link
Copy Markdown
Member

I would certainly eventually like a public interface which would certainly need an RFC/experiment, but more urgently I think the intrinsic is useful within std::simd. I'm happy to write an RFC or problem statement or whatever is necessary. Thanks :)

If it's just for internal use for now, then... maybe make it a t-compiler MCP where we also ping t-opsem? It's a new compiler feature with opsem considerations so that seems like a reasonable use of our process to me.

We should be sure to get some sort of t-lang vibes before any stable part of libcore/libstd relies on this, though. But for experimentation that shouldn't be needed.

@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

Comment thread library/core/src/intrinsics/mod.rs Outdated
@calebzulawski calebzulawski force-pushed the call-site-target-features branch from 8ac5989 to 7b44636 Compare July 4, 2026 03:06
@rust-log-analyzer

This comment has been minimized.

Comment thread library/core/src/intrinsics/mod.rs Outdated
@rustbot

rustbot commented Jul 5, 2026

Copy link
Copy Markdown
Collaborator

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, @programmerjake

Comment thread compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
@rust-bors

This comment has been minimized.

@rustbot

rustbot commented Jul 6, 2026

Copy link
Copy Markdown
Collaborator

rustc_codegen_cranelift is developed in its own repository. If possible, consider making this change to rust-lang/rustc_codegen_cranelift instead.

cc @bjorn3

@calebzulawski calebzulawski force-pushed the call-site-target-features branch from 6455b1a to 81bc0ad Compare July 6, 2026 03:14
@rustbot

rustbot commented Jul 6, 2026

Copy link
Copy Markdown
Collaborator

This PR was rebased onto a different main 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.

generic_args,
) {
target_features::TargetFeatureAvailableAtCallSite::Known(enabled) => enabled,
// SSA already handles the easy case where the caller function has the feature enabled.

@bjorn3 bjorn3 Jul 6, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Per-function target features aren't supported by cg_clif yet. The TargetIsa is fixed for a Module. Would need Cranelift changes to implement.

View changes since the review

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-LLVM Area: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues. 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.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants