Skip to content

Commit

Permalink
Expose C versions of libm functions in the cb crate
Browse files Browse the repository at this point in the history
`compiler_builtins` exposes an `extern "C"` version of `libm` routines,
so add the same here. There really isn't much to test here (unless we
later add tests against C `libm` suites), but one nice benefit is this
gives us a library with unmangled names that is easy to `objdump`. In
accordance with that, also update `cb` to be a `staticlib`.

Unfortunately this also means we have to remove it from the workspace,
since Cargo doesn't allow setting `panic = "abort"` for a single crate.
  • Loading branch information
tgross35 committed Jan 12, 2025
1 parent 233700c commit 5eda282
Show file tree
Hide file tree
Showing 6 changed files with 200 additions and 6 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ jobs:
- name: Install Rust
run: rustup update nightly --no-self-update && rustup default nightly
- uses: Swatinem/rust-cache@v2
- run: cargo build -p cb
- run: cargo test --manifest-path crates/compiler-builtins-smoke-test/Cargo.toml

benchmarks:
name: Benchmarks
Expand Down
3 changes: 1 addition & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@
.#*
/bin
/math/src
/math/target
/target
target
Cargo.lock
musl/
**.tar.gz
5 changes: 4 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ force-soft-floats = []
[workspace]
resolver = "2"
members = [
"crates/compiler-builtins-smoke-test",
"crates/libm-macros",
"crates/libm-test",
"crates/musl-math-sys",
Expand All @@ -53,6 +52,10 @@ default-members = [
"crates/libm-macros",
"crates/libm-test",
]
exclude = [
# Requires `panic = abort` so can't be a member of the workspace
"crates/compiler-builtins-smoke-test",
]

[dev-dependencies]
no-panic = "0.1.30"
Expand Down
18 changes: 16 additions & 2 deletions crates/compiler-builtins-smoke-test/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,33 @@ edition = "2021"
publish = false

[lib]
crate-type = ["staticlib"]
test = false
bench = false

[features]
default = ["arch", "unstable-float"]

# Copied from `libm`'s root `Cargo.toml`'
unstable-float = []
arch = []

[lints.rust]
unexpected_cfgs = { level = "warn", check-cfg = [
"cfg(arch_enabled)",
"cfg(assert_no_panic)",
"cfg(f128_enabled)",
"cfg(f16_enabled)",
"cfg(intrinsics_enabled)",
'cfg(feature, values("checked"))',
'cfg(feature, values("force-soft-floats"))',
'cfg(feature, values("unstable"))',
'cfg(feature, values("unstable-intrinsics"))',
'cfg(feature, values("unstable-public-internals"))',
] }

[profile.dev]
panic = "abort"

[profile.release]
panic = "abort"
codegen-units = 1
lto = "fat"
7 changes: 7 additions & 0 deletions crates/compiler-builtins-smoke-test/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#[path = "../../configure.rs"]
mod configure;

fn main() {
let cfg = configure::Config::from_env();
configure::emit_libm_config(&cfg);
}
171 changes: 171 additions & 0 deletions crates/compiler-builtins-smoke-test/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,183 @@
//! Fake compiler-builtins crate
//!
//! This is used to test that we can source import `libm` into the compiler-builtins crate.
//! Additionally, it provides a `#[no_mangle]` C API that can be easier to inspect than the
//! default `.rlib`.
#![feature(core_intrinsics)]
#![feature(f16)]
#![feature(f128)]
#![allow(internal_features)]
#![no_std]

#[allow(dead_code)]
#[allow(clippy::all)] // We don't get `libm`'s list of `allow`s, so just ignore Clippy.
#[path = "../../../src/math/mod.rs"]
pub mod libm;

use core::ffi::c_int;

/// Mark functions `#[no_mangle]` and with the C ABI.
macro_rules! no_mangle {
($( $name:ident( $($tt:tt)+ ) -> $ret:ty; )+) => {
$( no_mangle!(@inner $name( $($tt)+ ) -> $ret); )+
};

// Handle simple functions with single return types
(@inner $name:ident( $($arg:ident: $aty:ty),+ ) -> $ret:ty) => {
#[no_mangle]
extern "C" fn $name($($arg: $aty),+) -> $ret {
libm::$name($($arg),+)
}
};


// Functions with `&mut` return values need to be handled differently, use `|` to
// separate inputs vs. outputs.
(
@inner $name:ident( $($arg:ident: $aty:ty),+ | $($rarg:ident: $rty:ty),+) -> $ret:ty
) => {
#[no_mangle]
extern "C" fn $name($($arg: $aty,)+ $($rarg: $rty),+) -> $ret {
let ret;
(ret, $(*$rarg),+) = libm::$name($($arg),+);
ret
}
};
}

no_mangle! {
frexp(x: f64 | y: &mut c_int) -> f64;
frexpf(x: f32 | y: &mut c_int) -> f32;
acos(x: f64) -> f64;
acosf(x: f32) -> f32;
acosh(x: f64) -> f64;
acoshf(x: f32) -> f32;
asin(x: f64) -> f64;
asinf(x: f32) -> f32;
asinh(x: f64) -> f64;
asinhf(x: f32) -> f32;
atan(x: f64) -> f64;
atan2(x: f64, y: f64) -> f64;
atan2f(x: f32, y: f32) -> f32;
atanf(x: f32) -> f32;
atanh(x: f64) -> f64;
atanhf(x: f32) -> f32;
cbrt(x: f64) -> f64;
cbrtf(x: f32) -> f32;
ceil(x: f64) -> f64;
ceilf(x: f32) -> f32;
copysign(x: f64, y: f64) -> f64;
copysignf(x: f32, y: f32) -> f32;
copysignf128(x: f128, y: f128) -> f128;
copysignf16(x: f16, y: f16) -> f16;
cos(x: f64) -> f64;
cosf(x: f32) -> f32;
cosh(x: f64) -> f64;
coshf(x: f32) -> f32;
erf(x: f64) -> f64;
erfc(x: f64) -> f64;
erfcf(x: f32) -> f32;
erff(x: f32) -> f32;
exp(x: f64) -> f64;
exp10(x: f64) -> f64;
exp10f(x: f32) -> f32;
exp2(x: f64) -> f64;
exp2f(x: f32) -> f32;
expf(x: f32) -> f32;
expm1(x: f64) -> f64;
expm1f(x: f32) -> f32;
fabs(x: f64) -> f64;
fabsf(x: f32) -> f32;
fabsf128(x: f128) -> f128;
fabsf16(x: f16) -> f16;
fdim(x: f64, y: f64) -> f64;
fdimf(x: f32, y: f32) -> f32;
floor(x: f64) -> f64;
floorf(x: f32) -> f32;
fma(x: f64, y: f64, z: f64) -> f64;
fmaf(x: f32, y: f32, z: f32) -> f32;
fmax(x: f64, y: f64) -> f64;
fmaxf(x: f32, y: f32) -> f32;
fmin(x: f64, y: f64) -> f64;
fminf(x: f32, y: f32) -> f32;
fmod(x: f64, y: f64) -> f64;
fmodf(x: f32, y: f32) -> f32;
hypot(x: f64, y: f64) -> f64;
hypotf(x: f32, y: f32) -> f32;
ilogb(x: f64) -> c_int;
ilogbf(x: f32) -> c_int;
j0(x: f64) -> f64;
j0f(x: f32) -> f32;
j1(x: f64) -> f64;
j1f(x: f32) -> f32;
jn(x: c_int, y: f64) -> f64;
jnf(x: c_int, y: f32) -> f32;
ldexp(x: f64, y: c_int) -> f64;
ldexpf(x: f32, y: c_int) -> f32;
lgamma(x: f64) -> f64;
lgamma_r(x: f64 | r: &mut c_int) -> f64;
lgammaf(x: f32) -> f32;
lgammaf_r(x: f32 | r: &mut c_int) -> f32;
log(x: f64) -> f64;
log10(x: f64) -> f64;
log10f(x: f32) -> f32;
log1p(x: f64) -> f64;
log1pf(x: f32) -> f32;
log2(x: f64) -> f64;
log2f(x: f32) -> f32;
logf(x: f32) -> f32;
modf(x: f64 | r: &mut f64) -> f64;
modff(x: f32 | r: &mut f32) -> f32;
nextafter(x: f64, y: f64) -> f64;
nextafterf(x: f32, y: f32) -> f32;
pow(x: f64, y: f64) -> f64;
powf(x: f32, y: f32) -> f32;
remainder(x: f64, y: f64) -> f64;
remainderf(x: f32, y: f32) -> f32;
remquo(x: f64, y: f64 | q: &mut c_int) -> f64;
remquof(x: f32, y: f32 | q: &mut c_int) -> f32;
rint(x: f64) -> f64;
rintf(x: f32) -> f32;
round(x: f64) -> f64;
roundf(x: f32) -> f32;
scalbn(x: f64, y: c_int) -> f64;
scalbnf(x: f32, y: c_int) -> f32;
sin(x: f64) -> f64;
sinf(x: f32) -> f32;
sinh(x: f64) -> f64;
sinhf(x: f32) -> f32;
sqrt(x: f64) -> f64;
sqrtf(x: f32) -> f32;
tan(x: f64) -> f64;
tanf(x: f32) -> f32;
tanh(x: f64) -> f64;
tanhf(x: f32) -> f32;
tgamma(x: f64) -> f64;
tgammaf(x: f32) -> f32;
trunc(x: f64) -> f64;
truncf(x: f32) -> f32;
y0(x: f64) -> f64;
y0f(x: f32) -> f32;
y1(x: f64) -> f64;
y1f(x: f32) -> f32;
yn(x: c_int, y: f64) -> f64;
ynf(x: c_int, y: f32) -> f32;
}

/* sincos has no direct return type, not worth handling in the macro */

#[no_mangle]
extern "C" fn sincos(x: f64, s: &mut f64, c: &mut f64) {
(*s, *c) = libm::sincos(x);
}

#[no_mangle]
extern "C" fn sincosf(x: f32, s: &mut f32, c: &mut f32) {
(*s, *c) = libm::sincosf(x);
}

#[panic_handler]
fn panic(_info: &core::panic::PanicInfo) -> ! {
loop {}
}

0 comments on commit 5eda282

Please sign in to comment.