intrinsics: Add a fallback for non-const libm float functions#150946
intrinsics: Add a fallback for non-const libm float functions#150946tgross35 wants to merge 3 commits into
Conversation
| #[rustc_intrinsic_const_stable_indirect] | ||
| #[rustc_intrinsic] | ||
| #[rustc_nounwind] | ||
| pub const fn fmaf128(a: f128, b: f128, c: f128) -> f128; |
There was a problem hiding this comment.
Is there a way to provide a non-const fallback for const intrinsics? In cases where CTFE definitely has to hook it rather than using the fallback, like here.
Not the worst thing if not.
There was a problem hiding this comment.
I don't think there is -- please file an issue.
This comment has been minimized.
This comment has been minimized.
d533ef5 to
90b9d6a
Compare
This comment has been minimized.
This comment has been minimized.
Huh - so |
|
At a glance, your reasoning is completely backwards. The fallback body for |
|
It shouldn't be; the |
|
The changes LGTM. However I can't actually check whether what you say about what is available where is correct -- you would be the person I ask about things like that. ;) |
|
https://github.com/rust-lang/compiler-builtins/blob/65624df7f55db9b7b494fbe3aa9dcea0a743eea4/compiler-builtins/src/math/mod.rs is what controls what we sometimes/always provide, so the module root symbols and |
Yes, that's the problem. The body for the function is not available in the crate compiler-builtins when compiling compiler-builtins. Remember the the rule is to ban linkage against other crates and the point of these extern declarations is to use linkage. |
This comment has been minimized.
This comment has been minimized.
Forgot to follow up here. In this case it there isn't anything technically incorrect right, and instead it's a limitation of the knowledge the compiler has to emit that error? Because c-b itself provides the It probably goes without saying but libm isn't calling the |
|
Oh I see, thanks for clarifying. I think this is actually a limitation of the check logic itself. The problem is that you have an item defined in an upstream crate, which is not So the missing check is whether the |
|
I threw this together to convince myself that this can work, and it seems to work. diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs
index c8aa7c04585..3fc0411d2be 100644
--- a/compiler/rustc_codegen_ssa/src/base.rs
+++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -867,6 +867,10 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
/// unlinkable calls.
///
/// Note that calls to LLVM intrinsics are uniquely okay because they won't make it to the linker.
+/// Note also that calls to foreign items that are actually exported by the local crate are also
+/// okay. This situation arises because compiler-builtins calls functions in core that are #[inline]
+/// wrappers for extern "C" declarations in core, which resolve to a symbol exported by
+/// compiler-builtins.
pub fn is_call_from_compiler_builtins_to_upstream_monomorphization<'tcx>(
tcx: TyCtxt<'tcx>,
instance: Instance<'tcx>,
@@ -879,11 +883,19 @@ fn is_llvm_intrinsic(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
}
}
+ fn is_extern_call_to_local_crate<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> bool {
+ tcx.is_foreign_item(instance.def_id())
+ && tcx.exported_non_generic_symbols(LOCAL_CRATE).iter().any(|(sym, _info)| {
+ sym.symbol_name_for_local_instance(tcx) == tcx.symbol_name(instance)
+ })
+ }
+
let def_id = instance.def_id();
!def_id.is_local()
&& tcx.is_compiler_builtins(LOCAL_CRATE)
&& !is_llvm_intrinsic(tcx, def_id)
&& !tcx.should_codegen_locally(instance)
+ && !is_extern_call_to_local_crate(tcx, instance)
}
impl CrateInfo {The linear search of all exported non-generic symbols seems bad. It's only done a handful of times so it doesn't have a visible impact on compile time of compiler-builtins... yet. |
|
@rustbot author |
|
Reminder, once the PR becomes ready for a review, use |
90b9d6a to
176fd06
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. |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
A number of float operations from libm have intrinsics for optimization, but it is also okay to just call the libm functions directly. Add a fallback for these cases, including converting to/from another float size where needed, so the backends don't need to override these.
in `is_call_from_compiler_builtins_to_upstream_monomorphization`, suggested by Seathlin
69882f0 to
21d67bf
Compare
This comment has been minimized.
This comment has been minimized.
|
@RalfJung we're running into We could manually disable the failing tests but maybe a list of "never use the fallback for these" intrinsics would be better? or some sort of attribute? |
|
cc @rust-lang/miri |
|
The job Click to see the possible cause of the failure (guessed by this bot) |
|
I don't think those would be better than the Can you make it so it only skips the nondet tests rather than skipping the entire test? Also please add comments explaining why this gets skipped. |
| pub fn sqrtf16(x: f16) -> f16; | ||
| pub fn sqrtf16(x: f16) -> f16 { | ||
| libm::sqrtf16(x) | ||
| } |
There was a problem hiding this comment.
Adding a fallback body now will make it harder to constify these intrinsics later due to #150961. So -- is that really worth it? At least for intrinsics that we already have softfloat impls for, maybe it'd be better to not have fallback bodies.
Well, it's tricky to deal with the errors in the tokio tests from They assert on the output too, so we can't just skip the test. We can fake the output? Idk this just seems really fragile. |
|
Ah, yeah that's annoying. Can we have something in the rustc test suite that tests the fallback bodies? That might be more robust / easier to maintain than doing that via Miri. |
|
Well we can add And then some sort of |
Yeah something like that -- but it may need its own sysroot build.
What purpose does that serve? We already default to requiring a Miri override for every intrinsic that does not have I added this Miri intrinsic fallback body test to let us catch bugs in the fallback intrinsics as some of those have complicated bodies. We should ensure we have test coverage for the stuff in |
View all comments
A number of float operations from libm have intrinsics for optimization, but it is also okay to just call the libm functions directly. Add a fallback for these cases, including converting to/from another float size where needed, so the backends don't need to override these.
r? @RalfJung