Add target_feature_available_at_call_site intrinsic#158713
Add target_feature_available_at_call_site intrinsic#158713calebzulawski wants to merge 9 commits into
Conversation
|
|
This comment has been minimized.
This comment has been minimized.
e79630d to
a9b4711
Compare
This comment has been minimized.
This comment has been minimized.
a9b4711 to
a6fead8
Compare
|
|
This comment has been minimized.
This comment has been minimized.
a6fead8 to
20f5b84
Compare
This comment has been minimized.
This comment has been minimized.
20f5b84 to
9eb4339
Compare
This comment has been minimized.
This comment has been minimized.
|
I won't be able to review the implementation, but can give feedback on design. |
| /// | ||
| /// # Safety | ||
| /// | ||
| /// Code relying on the result of this intrinsic must be sound for both `true` and `false`. |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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()); |
There was a problem hiding this comment.
Why not do this in OptimizerEarly instead, so more passes run afterwards?
There was a problem hiding this comment.
That makes sense, I moved it
| continue; | ||
|
|
||
| StringRef Feature = MarkerDecl.getName().drop_front( | ||
| TargetFeatureAvailableAtCallSitePrefix.size()); |
There was a problem hiding this comment.
This should be a metadata string argument instead.
There was a problem hiding this comment.
I didn't know you could do this! Much better
|
Doing this in a custom pass is okay for experimentation purposes, but this should really be proposed as an LLVM intrinsic upstream. |
|
I think currently Caleb's intent is to experiment with this for internal usage for The alternative is to tell people to recompile |
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 |
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 :) |
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. :) |
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. |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
8ac5989 to
7b44636
Compare
This comment has been minimized.
This comment has been minimized.
|
Some changes occurred to the platform-builtins intrinsics. Make sure the |
This comment has been minimized.
This comment has been minimized.
|
cc @bjorn3 |
6455b1a to
81bc0ad
Compare
|
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. |
There was a problem hiding this comment.
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 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:
For a more concrete example, see
std::simd'sswizzle_dyn. This function heavily demands target features, but:cfg!(target_feature = "ssse3")doesn't work withoutbuild-std(and you lose compatibility with old CPUs)is_x86_feature_detectedis much too slowThis 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.