Skip to content

intrinsics: Add a fallback for non-const libm float functions#150946

Open
tgross35 wants to merge 6 commits into
rust-lang:mainfrom
tgross35:float-intrinsic-fallback
Open

intrinsics: Add a fallback for non-const libm float functions#150946
tgross35 wants to merge 6 commits into
rust-lang:mainfrom
tgross35:float-intrinsic-fallback

Conversation

@tgross35

@tgross35 tgross35 commented Jan 10, 2026

Copy link
Copy Markdown
Contributor

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

@rustbot

rustbot commented Jan 10, 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 S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-libs Relevant to the library team, which will review and decide on the PR/issue. labels Jan 10, 2026
Comment on lines 1410 to 1413
#[rustc_intrinsic_const_stable_indirect]
#[rustc_intrinsic]
#[rustc_nounwind]
pub const fn fmaf128(a: f128, b: f128, c: f128) -> f128;

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

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.

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.

I don't think there is -- please file an issue.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Opened #150961

@rust-log-analyzer

This comment has been minimized.

@tgross35 tgross35 force-pushed the float-intrinsic-fallback branch from d533ef5 to 90b9d6a Compare January 11, 2026 01:59
@rust-log-analyzer

This comment has been minimized.

@tgross35

Copy link
Copy Markdown
Contributor Author
error: `compiler_builtins` cannot call functions through upstream monomorphizations; encountered invalid call from `core::intrinsics::sqrtf64` to `core::num::libm::sqrt`
    --> library/core/src/intrinsics/mod.rs:1047:1
     |
1047 | pub fn sqrtf64(x: f64) -> f64 {
     | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Huh - so #[inline] doesn't make a difference here. The body itself shouldn't be a problem since it's calling an extern function. @saethlin any idea what is going on here?

@saethlin

Copy link
Copy Markdown
Member

At a glance, your reasoning is completely backwards. The fallback body for sqrtf64 is being monomorphized, which is disallowed because it calls a libm function that is upstream.

@tgross35

Copy link
Copy Markdown
Contributor Author

It shouldn't be; the libm module in core is only bindings to libm, the function call is just an extern.

@RalfJung

Copy link
Copy Markdown
Member

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. ;)
Is there anyone else who knows those details of libm and our compiler-builtins? If not, I'm also fine with approving this based on your judgment.

@tgross35

Copy link
Copy Markdown
Contributor Author

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 likely_available match that. Then the remaining maybe_available symbols are part of glibc (e.g. https://github.com/bminor/glibc/blob/e539a269990dac3ff4d2432c0eb6966a5ee4f274/sysdeps/unix/sysv/linux/i386/libm.abilist#L590), but not too much else.

@saethlin

saethlin commented Jan 11, 2026

Copy link
Copy Markdown
Member

It shouldn't be; the libm module in core is only bindings to libm, the function call is just an extern.

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.

@rust-bors

This comment has been minimized.

@tgross35

Copy link
Copy Markdown
Contributor Author

It shouldn't be; the libm module in core is only bindings to libm, the function call is just an extern.

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.

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 sqrt symbol so it will be available to link. I can drop the sqrt fallbacks for now since the status quo is fine anyway, but it seems like maybe the ideal solution would be something like an #[allow_compiler_builtins_link] attribute on the extern "C" block?

It probably goes without saying but libm isn't calling the sqrt intrinsic in fn sqrt itself, it's used elsewhere so we get the asm lowering if available.

@saethlin

saethlin commented Feb 13, 2026

Copy link
Copy Markdown
Member

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 should_codegen_locally... except that it is codegenned in the local crate in this one case because of the linkage relationship.

So the missing check is whether the Instance inside is_call_from_compiler_builtins_to_upstream_monomorphization is actually an extern declaration of a symbol name that is in the current crate's exported_symbols. I think this is a feasible check for you to write if you want. I'm a bit busy for a bit or I'd try to slap it together. @bjorn3 since this is fiddly linkage stuff.

@saethlin

saethlin commented Feb 14, 2026

Copy link
Copy Markdown
Member

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.

@RalfJung

Copy link
Copy Markdown
Member

@rustbot author

@rustbot rustbot removed the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Feb 21, 2026
@rustbot

rustbot commented Feb 21, 2026

Copy link
Copy Markdown
Collaborator

Reminder, once the PR becomes ready for a review, use @rustbot ready.

@rustbot rustbot added the S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. label Feb 21, 2026
@folkertdev folkertdev force-pushed the float-intrinsic-fallback branch from 90b9d6a to 176fd06 Compare June 23, 2026 21:17
@rustbot

This comment has been minimized.

@rust-bors rust-bors Bot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. labels Jul 8, 2026
@rust-bors

rust-bors Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

This pull request was unapproved.

This PR was contained in a rollup (#158958), which was unapproved.

View changes since this unapproval

@rust-bors

This comment has been minimized.

rust-bors Bot pushed a commit that referenced this pull request Jul 8, 2026
intrinsics: Add a fallback for non-const libm float functions


try-job: i686-msvc-1
@folkertdev

Copy link
Copy Markdown
Contributor

I actually suspect this is an interaction with #158927 (part of that same rollup), so the bors job here will likely be fine.

But apparently we should go via f64 in msvc.

@rust-bors

rust-bors Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

⚠️ A new commit a6f8d095786c2e5b523ee1a6429411b9a9ec6fe4 was pushed.

This PR was contained in a rollup (#158958), which was closed.

libm::likely_available::sinf(x)
cfg_select! {
target_env = "msvc" => sinf64(x as f64) as f32,
_ => libm::likely_available::sinf(x),

@RalfJung RalfJung Jul 8, 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.

Looks like we should remove the sinf import on Windows as well to avoid accidentally calling it? (Same for the others)

View changes since the review

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.

Well they are already marked as likely available, but I can just cfg them out on x86 msvc?

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.

Seems wrong to call them likely available if we know them to be unavailable. ;)

@rust-log-analyzer

This comment has been minimized.

@folkertdev folkertdev force-pushed the float-intrinsic-fallback branch 2 times, most recently from 8759054 to 109180e Compare July 8, 2026 21:56
@folkertdev

Copy link
Copy Markdown
Contributor

@bors try jobs=i686-msvc-1,x86_64-msvc-1,aarch64-msvc-1,x86_64-mingw-1

@rust-bors

This comment has been minimized.

rust-bors Bot pushed a commit that referenced this pull request Jul 8, 2026
intrinsics: Add a fallback for non-const libm float functions


try-job: i686-msvc-1
try-job: x86_64-msvc-1
try-job: aarch64-msvc-1
try-job: x86_64-mingw-1
@rust-log-analyzer

This comment has been minimized.

the 32-bit symbols are not available on msvc
@folkertdev folkertdev force-pushed the float-intrinsic-fallback branch from 109180e to 58c2c07 Compare July 8, 2026 22:49
@rust-log-analyzer

This comment has been minimized.

@folkertdev

Copy link
Copy Markdown
Contributor

@bors try jobs=i686-msvc-1,x86_64-msvc-1,aarch64-msvc-1,x86_64-mingw-1

@rust-bors

This comment has been minimized.

rust-bors Bot pushed a commit that referenced this pull request Jul 8, 2026
intrinsics: Add a fallback for non-const libm float functions


try-job: i686-msvc-1
try-job: x86_64-msvc-1
try-job: aarch64-msvc-1
try-job: x86_64-mingw-1
@rust-log-analyzer

This comment has been minimized.

@rust-bors

rust-bors Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

☀️ Try build successful (CI)
Build commit: b0486e8 (b0486e8097bf7dbf95d5f24371c08c38f3985623)
Base parent: 7ef36ed (7ef36edc23ac10760eb9f097d32edbab2e1e8928)

we know that the symbols are not available there
Comment on lines +81 to +86
cfg_select! {
all(target_env = "msvc", target_arch = "x86") => {
/* these symbols are not available on x86 msvc */
}
_ => {
#[allow(dead_code)]

@folkertdev folkertdev Jul 9, 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.

The cfg_select is to work around

tidy [pal (library)]: library/core/src/num/imp/libm.rs:82: platform-specific cfg: cfg(not(all(target_env = "msvc", target_arch = "x86")))
tidy [pal (library)]: FAIL

but it gives a good place for a comment so it's probably fine this way.

View changes since the review

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.

Anyhow, there might be some nicer refactor that can be done, but this PR means we can drop one of the cranelift patch files, so I think we can defer that additional work.

@RalfJung

RalfJung commented Jul 9, 2026

Copy link
Copy Markdown
Member

r=RalfJung,saethlin when CI is happy.
@bors rollup=iffy

@folkertdev

Copy link
Copy Markdown
Contributor

better safe than sorry etc

@bors try jobs=i686-msvc-1,x86_64-msvc-1,aarch64-msvc-1,x86_64-mingw-1

@rust-bors

rust-bors Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

⌛ Trying commit e732dd1 with merge 5d627ac

To cancel the try build, run the command @bors try cancel.

Workflow: https://github.com/rust-lang/rust/actions/runs/29009736809

rust-bors Bot pushed a commit that referenced this pull request Jul 9, 2026
intrinsics: Add a fallback for non-const libm float functions


try-job: i686-msvc-1
try-job: x86_64-msvc-1
try-job: aarch64-msvc-1
try-job: x86_64-mingw-1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-CI Area: Our Github Actions CI A-testsuite Area: The testsuite used to check the correctness of rustc S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. T-infra Relevant to the infrastructure 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.

7 participants