-
Notifications
You must be signed in to change notification settings - Fork 58
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How to standardize function calls LLVM lowers to? #84
Comments
cc @sunfishcode |
Also related to https://github.com/rust-lang-nursery/rust-wasm/issues/16, but not so much about I/O per se |
Discussed a bit with @sunfishcode, and the "port all math to Rust" may not be as difficult as originally thought. Additionally the intrinsics may not be too large, for example MUSL's implementations are relatively reasonably sized. We may be able to lift those or also work off https://github.com/nagisa/math.rs as well |
Let me know if y'all plan to implement libm in Rust. The embedded community, and likely the no-std community in general (e.g. Redox), is interested in having pure Rust math so we are very likely to contribute to such effort. |
Oh an excellent point @japaric, nice thinking! I'm not entirely decided what to do about this personally, but I think having a Rust-based solution in our back pocket is probably a good idea no matter what. @japaric perhaps I could itemize what we need in wasm (currently at least) as well as perhaps find the musl implementation of each, and then post a checklist to the compiler-builtins repo? (we'd have all the intrinsics in an off-by-default feature probably there) |
@alexcrichton Sounds like a plan to me!
Will the math functions live in the compiler-builtins repo though? I would prefer them to live in a separate crate because:
If wasm needs the unmangled symbols in compiler-builtins we can structure things like this: // crate: (lib)m -- the port of MUSL stuff lives here
#![no_std] // stable (no unstable features)
pub fn sinf(x: f32) -> f32 {
// ..
} // crate: compiler-builtins
#![compiler_builtins] // perma-unstable
extern crate m;
// shims for wasm compatibility
// "C" or "aapcs" or w/e makes sense
#[no_mangle]
pub extern "C" fn sinf(x: f32) -> f32 {
m::sinf(x)
} // crate: float-core -- for use in no-std crates (i.e. use float_core::FloatExt;)
#![no_std] // stable (no unstable features)
extern crate m;
pub trait FloatExt {
fn sin(self) -> Self;
// ..
}
impl FloatExt for f32 {
fn sin(self) -> Self {
m::sinf(self)
}
} And if it makes sense |
@japaric hm an interesting idea! I'd assumed compiler-builtins due to its extensive CI, but you bring up some excellent points. There's certianly no need for these intrinsics to be so unstable! I do think though that they may still participate in linker shenanigans and not be available for LTO (or at least not all of them). For example I don't think that LLVM knows that the I'm also not sure if LLVM's smart enough to draw a connection between the In any case doing this all in a separate crate is a great way to start. We can always figure out weird integration bugs later down the road once we've actually got a body of code. |
Er, above is a list of what wasm needs (although embedded targets probably need more like sqrt) |
Julia has native versions of most of libm. Much of that is in this directory. It's all MIT-licensed code. That may help when writing Rust versions. The Julia community is also slowly working on wasm support, so eventually, it may be possible to use basic Julia functions like these compiled to wasm. |
I finally got around starting a port of MUSL libm. The repo lives here. The test infrastructure is To cover what WASM needs I think we should add that repo as a submodule There are still lots of function that need to be ported. Happy to add more reviewers to the repo and P.S. long term we may want to provide (overridable (*)) math support in (*) Some people may want to override the Rust implementation with assembly tuned ones. |
@japaric that's awesome! Thanks for the pointer! Your proposed integration sounds spot on for compiler-builtins as well. |
With https://github.com/japaric/libm, rust-lang/compiler-builtins#248, rust-lang/rust#52499, @japaric, and an awesome amount of elbow grease from the community, I think we can safely say this is done now! |
LLVM will intrinsically lower some operations to a function call at runtime, for example this program:
generates IR that looks like:
note the lack of call to a function named
log2
, it's just an LLVM intrinsic. On Linux, however, at runtime this function is compiled as calling the symbollog2f
, usually found in libm.It can be important in some situations to use the intrinsics rather than explicit functions themselves as LLVM may optimize better, but other times LLVM may optimize a program to using an intrinsic without the original source mentioning the intrinsic. In other words, these function calls can sometimes run a risk of being inserted even if they're not used!
Currently LLVM will translate this in wasm as an import from the
env
module with the same name as these functions have in C. Additionally the standard library has a set of symbols that it imports and uses. (if the associated functions are called).Today projects like wasm-bindgen will automatically fill in these imports so users don't have to worry about them, but that's not necessarily great! The method in which these intrinsics are exposed today may not be stable and could change tomorrow.
Ok so that brings us to the question, what do we do about these math-related intrinsics? some options:
a % b
wouldn't work for floats. Additionally I'm not sure that if we forbid access that it'd actually work, for example are we sure that LLVM won't optimize otherwise normal code to have these imports?atan
) and rustc would inject an implementation into the wasm. The good news here is that everything's "always taken care of", the bad news is we're probably filling in a much worse implementation ofsin
thanMath.sin
, not to mention that it's probably pretty big code-size-wise.I'm curious to hear what others think! I'm sort of tempted to take the second route here, defining these functions for bundlers/wasm instantiators. We could, for example, define that these functions will always be imported from something like
__rust_math
(requiring rustc to postprocess the wasm file) and they've all got their C-like names (reverting libstd-specific names)The text was updated successfully, but these errors were encountered: