Introduce musl-math-sys for bindings to musl math symbols
This crate builds math symbols from a musl checkout and provides a Rust interface. The intent is that we will be able to compare our implementations against musl on more than just linux (which are the only currently the only targets we run `*-musl` targets against for comparison). Musl libc can't compile on anything other than Linux; however, the routines in `src/math` are cross platform enough to build on MacOS and windows-gnu with only minor adjustments. We take advantage of this and build only needed files using `cc`. The build script also performs remapping (via defines) so that e.g. `cos` gets defined as `musl_cos`. This gives us more certainty that we are actually testing against the intended symbol; without it, it is easy to unknowingly link to system libraries or even Rust's `libm` itself and wind up with an ineffective test. There is also a small procedure to verify remapping worked correctly by checking symbols in object files.
This commit is contained in:
parent
750027cbbe
commit
36b52c7d1b
7 changed files with 703 additions and 2 deletions
5
library/compiler-builtins/libm/.gitignore
vendored
5
library/compiler-builtins/libm/.gitignore
vendored
|
|
@ -1,8 +1,9 @@
|
|||
**/*.rs.bk
|
||||
**.bk
|
||||
.#*
|
||||
/bin
|
||||
/math/src
|
||||
/math/target
|
||||
/target
|
||||
/tests
|
||||
Cargo.lock
|
||||
musl/
|
||||
**.tar.gz
|
||||
|
|
|
|||
|
|
@ -24,10 +24,12 @@ unstable = []
|
|||
force-soft-floats = []
|
||||
|
||||
[workspace]
|
||||
resolver = "2"
|
||||
members = [
|
||||
"crates/compiler-builtins-smoke-test",
|
||||
"crates/libm-bench",
|
||||
"crates/libm-test",
|
||||
"crates/musl-math-sys",
|
||||
]
|
||||
default-members = [
|
||||
".",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,12 @@
|
|||
[package]
|
||||
name = "musl-math-sys"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
|
||||
[dev-dependencies]
|
||||
libm = { path = "../../" }
|
||||
|
||||
[build-dependencies]
|
||||
cc = "1.1.24"
|
||||
328
library/compiler-builtins/libm/crates/musl-math-sys/build.rs
Normal file
328
library/compiler-builtins/libm/crates/musl-math-sys/build.rs
Normal file
|
|
@ -0,0 +1,328 @@
|
|||
use std::collections::BTreeMap;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::{Command, Stdio};
|
||||
use std::{env, fs, str};
|
||||
|
||||
/// Static library that will be built
|
||||
const LIB_NAME: &str = "musl_math_prefixed";
|
||||
|
||||
/// Files that have more than one symbol. Map of file names to the symbols defined in that file.
|
||||
const MULTIPLE_SYMBOLS: &[(&str, &[&str])] = &[
|
||||
("__invtrigl", &["__invtrigl", "__invtrigl_R", "__pio2_hi", "__pio2_lo"]),
|
||||
("__polevll", &["__polevll", "__p1evll"]),
|
||||
("erf", &["erf", "erfc"]),
|
||||
("erff", &["erff", "erfcf"]),
|
||||
("erfl", &["erfl", "erfcl"]),
|
||||
("exp10", &["exp10", "pow10"]),
|
||||
("exp10f", &["exp10f", "pow10f"]),
|
||||
("exp10l", &["exp10l", "pow10l"]),
|
||||
("exp2f_data", &["exp2f_data", "__exp2f_data"]),
|
||||
("exp_data", &["exp_data", "__exp_data"]),
|
||||
("j0", &["j0", "y0"]),
|
||||
("j0f", &["j0f", "y0f"]),
|
||||
("j1", &["j1", "y1"]),
|
||||
("j1f", &["j1f", "y1f"]),
|
||||
("jn", &["jn", "yn"]),
|
||||
("jnf", &["jnf", "ynf"]),
|
||||
("lgamma", &["lgamma", "__lgamma_r"]),
|
||||
("remainder", &["remainder", "drem"]),
|
||||
("remainderf", &["remainderf", "dremf"]),
|
||||
("lgammaf", &["lgammaf", "lgammaf_r", "__lgammaf_r"]),
|
||||
("lgammal", &["lgammal", "lgammal_r", "__lgammal_r"]),
|
||||
("log2_data", &["log2_data", "__log2_data"]),
|
||||
("log2f_data", &["log2f_data", "__log2f_data"]),
|
||||
("log_data", &["log_data", "__log_data"]),
|
||||
("logf_data", &["logf_data", "__logf_data"]),
|
||||
("pow_data", &["pow_data", "__pow_log_data"]),
|
||||
("powf_data", &["powf_data", "__powf_log2_data"]),
|
||||
("signgam", &["signgam", "__signgam"]),
|
||||
("sqrt_data", &["sqrt_data", "__rsqrt_tab"]),
|
||||
];
|
||||
|
||||
fn main() {
|
||||
let cfg = Config::from_env();
|
||||
|
||||
if cfg.target_env == "msvc"
|
||||
|| cfg.target_family == "wasm"
|
||||
|| cfg.target_features.iter().any(|f| f == "thumb-mode")
|
||||
{
|
||||
println!(
|
||||
"cargo::warning=Musl doesn't compile with the current \
|
||||
target {}; skipping build",
|
||||
&cfg.target_string
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
build_musl_math(&cfg);
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug)]
|
||||
struct Config {
|
||||
manifest_dir: PathBuf,
|
||||
out_dir: PathBuf,
|
||||
musl_dir: PathBuf,
|
||||
musl_arch: String,
|
||||
target_arch: String,
|
||||
target_env: String,
|
||||
target_family: String,
|
||||
target_os: String,
|
||||
target_string: String,
|
||||
target_vendor: String,
|
||||
target_features: Vec<String>,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
fn from_env() -> Self {
|
||||
let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
|
||||
let target_features = env::var("CARGO_CFG_TARGET_FEATURE")
|
||||
.map(|feats| feats.split(',').map(ToOwned::to_owned).collect())
|
||||
.unwrap_or_default();
|
||||
|
||||
// Default to the `{workspace_root}/musl` if not specified
|
||||
let musl_dir = env::var("MUSL_SOURCE_DIR")
|
||||
.map(PathBuf::from)
|
||||
.unwrap_or_else(|_| manifest_dir.parent().unwrap().parent().unwrap().join("musl"));
|
||||
|
||||
let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap();
|
||||
let musl_arch = if target_arch == "x86" { "i386".to_owned() } else { target_arch.clone() };
|
||||
|
||||
println!("cargo::rerun-if-changed={}/c_patches", manifest_dir.display());
|
||||
println!("cargo::rerun-if-env-changed=MUSL_SOURCE_DIR");
|
||||
println!("cargo::rerun-if-changed={}", musl_dir.display());
|
||||
|
||||
Self {
|
||||
manifest_dir,
|
||||
out_dir: PathBuf::from(env::var("OUT_DIR").unwrap()),
|
||||
musl_dir,
|
||||
musl_arch,
|
||||
target_arch,
|
||||
target_env: env::var("CARGO_CFG_TARGET_ENV").unwrap(),
|
||||
target_family: env::var("CARGO_CFG_TARGET_FAMILY").unwrap(),
|
||||
target_os: env::var("CARGO_CFG_TARGET_OS").unwrap(),
|
||||
target_string: env::var("TARGET").unwrap(),
|
||||
target_vendor: env::var("CARGO_CFG_TARGET_VENDOR").unwrap(),
|
||||
target_features,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Build musl math symbols to a static library
|
||||
fn build_musl_math(cfg: &Config) {
|
||||
let musl_dir = &cfg.musl_dir;
|
||||
assert!(
|
||||
musl_dir.exists(),
|
||||
"musl source is missing. it can be downloaded with ./ci/download-musl.sh"
|
||||
);
|
||||
|
||||
let math = musl_dir.join("src/math");
|
||||
let arch_dir = musl_dir.join("arch").join(&cfg.musl_arch);
|
||||
let source_map = find_math_source(&math, cfg);
|
||||
let out_path = cfg.out_dir.join(format!("lib{LIB_NAME}.a"));
|
||||
|
||||
// Run configuration steps. Usually done as part of the musl `Makefile`.
|
||||
let obj_include = cfg.out_dir.join("musl_obj/include");
|
||||
fs::create_dir_all(&obj_include).unwrap();
|
||||
fs::create_dir_all(&obj_include.join("bits")).unwrap();
|
||||
let sed_stat = Command::new("sed")
|
||||
.arg("-f")
|
||||
.arg(musl_dir.join("tools/mkalltypes.sed"))
|
||||
.arg(arch_dir.join("bits/alltypes.h.in"))
|
||||
.arg(musl_dir.join("include/alltypes.h.in"))
|
||||
.stderr(Stdio::inherit())
|
||||
.output()
|
||||
.unwrap();
|
||||
assert!(sed_stat.status.success(), "sed command failed: {:?}", sed_stat.status);
|
||||
|
||||
fs::write(obj_include.join("bits/alltypes.h"), sed_stat.stdout).unwrap();
|
||||
|
||||
let mut cbuild = cc::Build::new();
|
||||
cbuild
|
||||
.extra_warnings(false)
|
||||
.warnings(false)
|
||||
.flag_if_supported("-Wno-bitwise-op-parentheses")
|
||||
.flag_if_supported("-Wno-literal-range")
|
||||
.flag_if_supported("-Wno-parentheses")
|
||||
.flag_if_supported("-Wno-shift-count-overflow")
|
||||
.flag_if_supported("-Wno-shift-op-parentheses")
|
||||
.flag_if_supported("-Wno-unused-but-set-variable")
|
||||
.flag_if_supported("-std=c99")
|
||||
.flag_if_supported("-ffreestanding")
|
||||
.flag_if_supported("-nostdinc")
|
||||
.define("_ALL_SOURCE", "1")
|
||||
.opt_level(3)
|
||||
.define(
|
||||
"ROOT_INCLUDE_FEATURES",
|
||||
Some(musl_dir.join("include/features.h").to_str().unwrap()),
|
||||
)
|
||||
// Our overrides are in this directory
|
||||
.include(cfg.manifest_dir.join("c_patches"))
|
||||
.include(musl_dir.join("arch").join(&cfg.musl_arch))
|
||||
.include(musl_dir.join("arch/generic"))
|
||||
.include(musl_dir.join("src/include"))
|
||||
.include(musl_dir.join("src/internal"))
|
||||
.include(obj_include)
|
||||
.include(musl_dir.join("include"))
|
||||
.file(cfg.manifest_dir.join("c_patches/alias.c"));
|
||||
|
||||
for (sym_name, src_file) in source_map {
|
||||
// Build the source file
|
||||
cbuild.file(src_file);
|
||||
|
||||
// Trickery! Redefine the symbol names to have the prefix `musl_`, which allows us to
|
||||
// differentiate these symbols from whatever we provide.
|
||||
if let Some((_names, syms)) =
|
||||
MULTIPLE_SYMBOLS.iter().find(|(name, _syms)| *name == sym_name)
|
||||
{
|
||||
// Handle the occasional file that defines multiple symbols
|
||||
for sym in *syms {
|
||||
cbuild.define(sym, Some(format!("musl_{sym}").as_str()));
|
||||
}
|
||||
} else {
|
||||
// If the file doesn't define multiple symbols, the file name will be the symbol
|
||||
cbuild.define(&sym_name, Some(format!("musl_{sym_name}").as_str()));
|
||||
}
|
||||
}
|
||||
|
||||
if cfg!(windows) {
|
||||
// On Windows we don't have a good way to check symbols, so skip that step.
|
||||
cbuild.compile(LIB_NAME);
|
||||
return;
|
||||
}
|
||||
|
||||
let objfiles = cbuild.compile_intermediates();
|
||||
|
||||
// We create the archive ourselves with relocations rather than letting `cc` do it so we can
|
||||
// encourage it to resolve symbols now. This should help avoid accidentally linking the wrong
|
||||
// thing.
|
||||
let stat = cbuild
|
||||
.get_compiler()
|
||||
.to_command()
|
||||
.arg("-r")
|
||||
.arg("-o")
|
||||
.arg(&out_path)
|
||||
.args(objfiles)
|
||||
.status()
|
||||
.unwrap();
|
||||
assert!(stat.success());
|
||||
|
||||
println!("cargo::rustc-link-lib={LIB_NAME}");
|
||||
println!("cargo::rustc-link-search=native={}", cfg.out_dir.display());
|
||||
|
||||
validate_archive_symbols(&out_path);
|
||||
}
|
||||
|
||||
/// Build a map of `name -> path`. `name` is typically the symbol name, but this doesn't account
|
||||
/// for files that provide multiple symbols.
|
||||
fn find_math_source(math_root: &Path, cfg: &Config) -> BTreeMap<String, PathBuf> {
|
||||
let mut map = BTreeMap::new();
|
||||
let mut arch_dir = None;
|
||||
|
||||
// Locate all files and directories
|
||||
for item in fs::read_dir(math_root).unwrap() {
|
||||
let path = item.unwrap().path();
|
||||
let meta = fs::metadata(&path).unwrap();
|
||||
|
||||
if meta.is_dir() {
|
||||
// Make note of the arch-specific directory if it exists
|
||||
if path.file_name().unwrap() == cfg.target_arch.as_str() {
|
||||
arch_dir = Some(path);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip non-source files
|
||||
if path.extension().is_some_and(|ext| ext == "h") {
|
||||
continue;
|
||||
}
|
||||
|
||||
let sym_name = path.file_stem().unwrap();
|
||||
map.insert(sym_name.to_str().unwrap().to_owned(), path.to_owned());
|
||||
}
|
||||
|
||||
// If arch-specific versions are available, build those instead.
|
||||
if let Some(arch_dir) = arch_dir {
|
||||
for item in fs::read_dir(arch_dir).unwrap() {
|
||||
let path = item.unwrap().path();
|
||||
let sym_name = path.file_stem().unwrap();
|
||||
|
||||
if path.extension().unwrap() == "s" {
|
||||
// FIXME: we never build assembly versions since we have no good way to
|
||||
// rename the symbol (our options are probably preprocessor or objcopy).
|
||||
continue;
|
||||
}
|
||||
map.insert(sym_name.to_str().unwrap().to_owned(), path);
|
||||
}
|
||||
}
|
||||
|
||||
map
|
||||
}
|
||||
|
||||
/// Make sure we don't have something like a loose unprefixed `_cos` called somewhere, which could
|
||||
/// wind up linking to system libraries rather than the built musl library.
|
||||
fn validate_archive_symbols(out_path: &Path) {
|
||||
const ALLOWED_UNDEF_PFX: &[&str] = &[
|
||||
// PIC and arch-specific
|
||||
".TOC",
|
||||
"_GLOBAL_OFFSET_TABLE_",
|
||||
"__x86.get_pc_thunk",
|
||||
// gcc/compiler-rt/compiler-builtins symbols
|
||||
"__add",
|
||||
"__aeabi_",
|
||||
"__div",
|
||||
"__eq",
|
||||
"__extend",
|
||||
"__fix",
|
||||
"__float",
|
||||
"__gcc_",
|
||||
"__ge",
|
||||
"__gt",
|
||||
"__le",
|
||||
"__lshr",
|
||||
"__lt",
|
||||
"__mul",
|
||||
"__ne",
|
||||
"__stack_chk_fail",
|
||||
"__stack_chk_guard",
|
||||
"__sub",
|
||||
"__trunc",
|
||||
"__undef",
|
||||
// string routines
|
||||
"__bzero",
|
||||
"bzero",
|
||||
// FPENV interfaces
|
||||
"feclearexcept",
|
||||
"fegetround",
|
||||
"feraiseexcept",
|
||||
"fesetround",
|
||||
"fetestexcept",
|
||||
];
|
||||
|
||||
// List global undefined symbols
|
||||
let out =
|
||||
Command::new("nm").arg("-guj").arg(out_path).stderr(Stdio::inherit()).output().unwrap();
|
||||
|
||||
let undef = str::from_utf8(&out.stdout).unwrap();
|
||||
let mut undef = undef.lines().collect::<Vec<_>>();
|
||||
undef.retain(|sym| {
|
||||
// Account for file formats that add a leading `_`
|
||||
!ALLOWED_UNDEF_PFX.iter().any(|pfx| sym.starts_with(pfx) || sym[1..].starts_with(pfx))
|
||||
});
|
||||
|
||||
assert!(undef.is_empty(), "found disallowed undefined symbols: {undef:#?}");
|
||||
|
||||
// Find any symbols that are missing the `_musl_` prefix`
|
||||
let out =
|
||||
Command::new("nm").arg("-gUj").arg(out_path).stderr(Stdio::inherit()).output().unwrap();
|
||||
|
||||
let defined = str::from_utf8(&out.stdout).unwrap();
|
||||
let mut defined = defined.lines().collect::<Vec<_>>();
|
||||
defined.retain(|sym| {
|
||||
!(sym.starts_with("_musl_")
|
||||
|| sym.starts_with("musl_")
|
||||
|| sym.starts_with("__x86.get_pc_thunk"))
|
||||
});
|
||||
|
||||
assert!(defined.is_empty(), "found unprefixed symbols: {defined:#?}");
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
/* On platforms that don't support weak symbols, define required aliases
|
||||
* as wrappers. See comments in `features.h` for more.
|
||||
*/
|
||||
#if defined(__APPLE__) || defined(__MINGW32__)
|
||||
|
||||
double __lgamma_r(double a, int *b);
|
||||
float __lgammaf_r(float a, int *b);
|
||||
long __lgammal_r(long double a, int *b);
|
||||
double exp10(double a);
|
||||
float exp10f(float a);
|
||||
long exp10l(long double a);
|
||||
double remainder(double a, double b);
|
||||
float remainderf(float a, float b);
|
||||
|
||||
double lgamma_r(double a, int *b) {
|
||||
return __lgamma_r(a, b);
|
||||
}
|
||||
float lgammaf_r(float a, int *b) {
|
||||
return __lgammaf_r(a, b);
|
||||
}
|
||||
long double lgammal_r(long double a, int *b) {
|
||||
return __lgammal_r(a, b);
|
||||
}
|
||||
double pow10(double a) {
|
||||
return exp10(a);
|
||||
}
|
||||
float pow10f(float a) {
|
||||
return exp10f(a);
|
||||
}
|
||||
long double pow10l(long double a) {
|
||||
return exp10l(a);
|
||||
}
|
||||
double drem(double a, double b) {
|
||||
return remainder(a, b);
|
||||
}
|
||||
float dremf(float a, float b) {
|
||||
return remainderf(a, b);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
/* This is meant to override Musl's src/include/features.h
|
||||
*
|
||||
* We use a separate file here to redefine some attributes that don't work on
|
||||
* all platforms that we would like to build on.
|
||||
*/
|
||||
|
||||
#ifndef FEATURES_H
|
||||
#define FEATURES_H
|
||||
|
||||
/* Get the required `#include "../../include/features.h"` since we can't use
|
||||
* the relative path. The C macros need double indirection to get a usable
|
||||
* string. */
|
||||
#define _stringify_inner(s) #s
|
||||
#define _stringify(s) _stringify_inner(s)
|
||||
#include _stringify(ROOT_INCLUDE_FEATURES)
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#define weak __attribute__((__weak__))
|
||||
#define hidden __attribute__((__visibility__("hidden")))
|
||||
|
||||
/* We _should_ be able to define this as:
|
||||
* _Pragma(_stringify(weak musl_ ## new = musl_ ## old))
|
||||
* However, weak symbols aren't handled correctly [1]. So we manually write
|
||||
* wrappers, which are in `alias.c`.
|
||||
*
|
||||
* [1]: https://github.com/llvm/llvm-project/issues/111321
|
||||
*/
|
||||
#define weak_alias(old, new) /* nothing */
|
||||
|
||||
#else
|
||||
#define weak __attribute__((__weak__))
|
||||
#define hidden __attribute__((__visibility__("hidden")))
|
||||
#define weak_alias(old, new) \
|
||||
extern __typeof(old) musl_ ## new \
|
||||
__attribute__((__weak__, __alias__(_stringify(musl_ ## old))))
|
||||
|
||||
#endif /* defined(__APPLE__) */
|
||||
|
||||
#endif
|
||||
279
library/compiler-builtins/libm/crates/musl-math-sys/src/lib.rs
Normal file
279
library/compiler-builtins/libm/crates/musl-math-sys/src/lib.rs
Normal file
|
|
@ -0,0 +1,279 @@
|
|||
//! Bindings to Musl math functions (these are built in `build.rs`).
|
||||
|
||||
use std::ffi::{c_char, c_int, c_long};
|
||||
|
||||
/// Macro for creating bindings and exposing a safe function (since the implementations have no
|
||||
/// preconditions). Included functions must have correct signatures, otherwise this will be
|
||||
/// unsound.
|
||||
macro_rules! functions {
|
||||
( $(
|
||||
$pfx_name:ident: $name:ident( $($arg:ident: $aty:ty),+ ) -> $rty:ty;
|
||||
)* ) => {
|
||||
extern "C" {
|
||||
$( fn $pfx_name( $($arg: $aty),+ ) -> $rty; )*
|
||||
}
|
||||
|
||||
$(
|
||||
// Expose a safe version
|
||||
pub fn $name( $($arg: $aty),+ ) -> $rty {
|
||||
// SAFETY: FFI calls with no preconditions
|
||||
unsafe { $pfx_name( $($arg),+ ) }
|
||||
}
|
||||
)*
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use test_support::CallTest;
|
||||
|
||||
$( functions!(
|
||||
@single_test
|
||||
$name($($arg: $aty),+) -> $rty
|
||||
); )*
|
||||
}
|
||||
};
|
||||
|
||||
(@single_test
|
||||
$name:ident( $($arg:ident: $aty:ty),+ ) -> $rty:ty
|
||||
) => {
|
||||
// Run a simple check to ensure we can link and call the function without crashing.
|
||||
#[test]
|
||||
// FIXME(#309): LE PPC crashes calling some musl functions
|
||||
#[cfg_attr(all(target_arch = "powerpc64", target_endian = "little"), ignore)]
|
||||
fn $name() {
|
||||
<fn($($aty),+) -> $rty>::check(super::$name);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test_support {
|
||||
use core::ffi::c_char;
|
||||
|
||||
/// Just verify that we are able to call the function.
|
||||
pub trait CallTest {
|
||||
fn check(f: Self);
|
||||
}
|
||||
|
||||
macro_rules! impl_calltest {
|
||||
($( ($($arg:ty),*) -> $ret:ty; )*) => {
|
||||
$(
|
||||
impl CallTest for fn($($arg),*) -> $ret {
|
||||
fn check(f: Self) {
|
||||
f($(1 as $arg),*);
|
||||
}
|
||||
}
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
impl_calltest! {
|
||||
(f32) -> f32;
|
||||
(f64) -> f64;
|
||||
(f32, f32) -> f32;
|
||||
(f64, f64) -> f64;
|
||||
(i32, f32) -> f32;
|
||||
(i32, f64) -> f64;
|
||||
(f32, f32, f32) -> f32;
|
||||
(f64, f64, f64) -> f64;
|
||||
(f32, i32) -> f32;
|
||||
(f32, i64) -> f32;
|
||||
(f32) -> i32;
|
||||
(f64) -> i32;
|
||||
(f64, i32) -> f64;
|
||||
(f64, i64) -> f64;
|
||||
}
|
||||
|
||||
impl CallTest for fn(f32, &mut f32) -> f32 {
|
||||
fn check(f: Self) {
|
||||
let mut tmp = 0.0;
|
||||
f(0.0, &mut tmp);
|
||||
}
|
||||
}
|
||||
impl CallTest for fn(f64, &mut f64) -> f64 {
|
||||
fn check(f: Self) {
|
||||
let mut tmp = 0.0;
|
||||
f(0.0, &mut tmp);
|
||||
}
|
||||
}
|
||||
impl CallTest for fn(f32, &mut i32) -> f32 {
|
||||
fn check(f: Self) {
|
||||
let mut tmp = 1;
|
||||
f(0.0, &mut tmp);
|
||||
}
|
||||
}
|
||||
impl CallTest for fn(f64, &mut i32) -> f64 {
|
||||
fn check(f: Self) {
|
||||
let mut tmp = 1;
|
||||
f(0.0, &mut tmp);
|
||||
}
|
||||
}
|
||||
impl CallTest for fn(f32, f32, &mut i32) -> f32 {
|
||||
fn check(f: Self) {
|
||||
let mut tmp = 1;
|
||||
f(0.0, 0.0, &mut tmp);
|
||||
}
|
||||
}
|
||||
impl CallTest for fn(f64, f64, &mut i32) -> f64 {
|
||||
fn check(f: Self) {
|
||||
let mut tmp = 1;
|
||||
f(0.0, 0.0, &mut tmp);
|
||||
}
|
||||
}
|
||||
impl CallTest for fn(f32, &mut f32, &mut f32) {
|
||||
fn check(f: Self) {
|
||||
let mut tmp1 = 1.0;
|
||||
let mut tmp2 = 1.0;
|
||||
f(0.0, &mut tmp1, &mut tmp2);
|
||||
}
|
||||
}
|
||||
impl CallTest for fn(f64, &mut f64, &mut f64) {
|
||||
fn check(f: Self) {
|
||||
let mut tmp1 = 1.0;
|
||||
let mut tmp2 = 1.0;
|
||||
f(0.0, &mut tmp1, &mut tmp2);
|
||||
}
|
||||
}
|
||||
impl CallTest for fn(*const c_char) -> f32 {
|
||||
fn check(f: Self) {
|
||||
f(c"1".as_ptr());
|
||||
}
|
||||
}
|
||||
impl CallTest for fn(*const c_char) -> f64 {
|
||||
fn check(f: Self) {
|
||||
f(c"1".as_ptr());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
functions! {
|
||||
musl_acos: acos(a: f64) -> f64;
|
||||
musl_acosf: acosf(a: f32) -> f32;
|
||||
musl_acosh: acosh(a: f64) -> f64;
|
||||
musl_acoshf: acoshf(a: f32) -> f32;
|
||||
musl_asin: asin(a: f64) -> f64;
|
||||
musl_asinf: asinf(a: f32) -> f32;
|
||||
musl_asinh: asinh(a: f64) -> f64;
|
||||
musl_asinhf: asinhf(a: f32) -> f32;
|
||||
musl_atan2: atan2(a: f64, b: f64) -> f64;
|
||||
musl_atan2f: atan2f(a: f32, b: f32) -> f32;
|
||||
musl_atan: atan(a: f64) -> f64;
|
||||
musl_atanf: atanf(a: f32) -> f32;
|
||||
musl_atanh: atanh(a: f64) -> f64;
|
||||
musl_atanhf: atanhf(a: f32) -> f32;
|
||||
musl_cbrt: cbrt(a: f64) -> f64;
|
||||
musl_cbrtf: cbrtf(a: f32) -> f32;
|
||||
musl_ceil: ceil(a: f64) -> f64;
|
||||
musl_ceilf: ceilf(a: f32) -> f32;
|
||||
musl_copysign: copysign(a: f64, b: f64) -> f64;
|
||||
musl_copysignf: copysignf(a: f32, b: f32) -> f32;
|
||||
musl_cos: cos(a: f64) -> f64;
|
||||
musl_cosf: cosf(a: f32) -> f32;
|
||||
musl_cosh: cosh(a: f64) -> f64;
|
||||
musl_coshf: coshf(a: f32) -> f32;
|
||||
musl_drem: drem(a: f64, b: f64) -> f64;
|
||||
musl_dremf: dremf(a: f32, b: f32) -> f32;
|
||||
musl_erf: erf(a: f64) -> f64;
|
||||
musl_erfc: erfc(a: f64) -> f64;
|
||||
musl_erfcf: erfcf(a: f32) -> f32;
|
||||
musl_erff: erff(a: f32) -> f32;
|
||||
musl_exp10: exp10(a: f64) -> f64;
|
||||
musl_exp10f: exp10f(a: f32) -> f32;
|
||||
musl_exp2: exp2(a: f64) -> f64;
|
||||
musl_exp2f: exp2f(a: f32) -> f32;
|
||||
musl_exp: exp(a: f64) -> f64;
|
||||
musl_expf: expf(a: f32) -> f32;
|
||||
musl_expm1: expm1(a: f64) -> f64;
|
||||
musl_expm1f: expm1f(a: f32) -> f32;
|
||||
musl_fabs: fabs(a: f64) -> f64;
|
||||
musl_fabsf: fabsf(a: f32) -> f32;
|
||||
musl_fdim: fdim(a: f64, b: f64) -> f64;
|
||||
musl_fdimf: fdimf(a: f32, b: f32) -> f32;
|
||||
musl_finite: finite(a: f64) -> c_int;
|
||||
musl_finitef: finitef(a: f32) -> c_int;
|
||||
musl_floor: floor(a: f64) -> f64;
|
||||
musl_floorf: floorf(a: f32) -> f32;
|
||||
musl_fma: fma(a: f64, b: f64, c: f64) -> f64;
|
||||
musl_fmaf: fmaf(a: f32, b: f32, c: f32) -> f32;
|
||||
musl_fmax: fmax(a: f64, b: f64) -> f64;
|
||||
musl_fmaxf: fmaxf(a: f32, b: f32) -> f32;
|
||||
musl_fmin: fmin(a: f64, b: f64) -> f64;
|
||||
musl_fminf: fminf(a: f32, b: f32) -> f32;
|
||||
musl_fmod: fmod(a: f64, b: f64) -> f64;
|
||||
musl_fmodf: fmodf(a: f32, b: f32) -> f32;
|
||||
musl_frexp: frexp(a: f64, b: &mut c_int) -> f64;
|
||||
musl_frexpf: frexpf(a: f32, b: &mut c_int) -> f32;
|
||||
musl_hypot: hypot(a: f64, b: f64) -> f64;
|
||||
musl_hypotf: hypotf(a: f32, b: f32) -> f32;
|
||||
musl_ilogb: ilogb(a: f64) -> c_int;
|
||||
musl_ilogbf: ilogbf(a: f32) -> c_int;
|
||||
musl_j0: j0(a: f64) -> f64;
|
||||
musl_j0f: j0f(a: f32) -> f32;
|
||||
musl_j1: j1(a: f64) -> f64;
|
||||
musl_j1f: j1f(a: f32) -> f32;
|
||||
musl_jn: jn(a: c_int, b: f64) -> f64;
|
||||
musl_jnf: jnf(a: c_int, b: f32) -> f32;
|
||||
musl_ldexp: ldexp(a: f64, b: c_int) -> f64;
|
||||
musl_ldexpf: ldexpf(a: f32, b: c_int) -> f32;
|
||||
musl_lgamma: lgamma(a: f64) -> f64;
|
||||
musl_lgamma_r: lgamma_r(a: f64, b: &mut c_int) -> f64;
|
||||
musl_lgammaf: lgammaf(a: f32) -> f32;
|
||||
musl_lgammaf_r: lgammaf_r(a: f32, b: &mut c_int) -> f32;
|
||||
musl_log10: log10(a: f64) -> f64;
|
||||
musl_log10f: log10f(a: f32) -> f32;
|
||||
musl_log1p: log1p(a: f64) -> f64;
|
||||
musl_log1pf: log1pf(a: f32) -> f32;
|
||||
musl_log2: log2(a: f64) -> f64;
|
||||
musl_log2f: log2f(a: f32) -> f32;
|
||||
musl_log: log(a: f64) -> f64;
|
||||
musl_logb: logb(a: f64) -> f64;
|
||||
musl_logbf: logbf(a: f32) -> f32;
|
||||
musl_logf: logf(a: f32) -> f32;
|
||||
musl_modf: modf(a: f64, b: &mut f64) -> f64;
|
||||
musl_modff: modff(a: f32, b: &mut f32) -> f32;
|
||||
musl_nan: nan(a: *const c_char) -> f64;
|
||||
musl_nanf: nanf(a: *const c_char) -> f32;
|
||||
musl_nearbyint: nearbyint(a: f64) -> f64;
|
||||
musl_nearbyintf: nearbyintf(a: f32) -> f32;
|
||||
musl_nextafter: nextafter(a: f64, b: f64) -> f64;
|
||||
musl_nextafterf: nextafterf(a: f32, b: f32) -> f32;
|
||||
musl_pow10: pow10(a: f64) -> f64;
|
||||
musl_pow10f: pow10f(a: f32) -> f32;
|
||||
musl_pow: pow(a: f64, b: f64) -> f64;
|
||||
musl_powf: powf(a: f32, b: f32) -> f32;
|
||||
musl_remainder: remainder(a: f64, b: f64) -> f64;
|
||||
musl_remainderf: remainderf(a: f32, b: f32) -> f32;
|
||||
musl_remquo: remquo(a: f64, b: f64, c: &mut c_int) -> f64;
|
||||
musl_remquof: remquof(a: f32, b: f32, c: &mut c_int) -> f32;
|
||||
musl_rint: rint(a: f64) -> f64;
|
||||
musl_rintf: rintf(a: f32) -> f32;
|
||||
musl_round: round(a: f64) -> f64;
|
||||
musl_roundf: roundf(a: f32) -> f32;
|
||||
musl_scalbln: scalbln(a: f64, b: c_long) -> f64;
|
||||
musl_scalblnf: scalblnf(a: f32, b: c_long) -> f32;
|
||||
musl_scalbn: scalbn(a: f64, b: c_int) -> f64;
|
||||
musl_scalbnf: scalbnf(a: f32, b: c_int) -> f32;
|
||||
musl_significand: significand(a: f64) -> f64;
|
||||
musl_significandf: significandf(a: f32) -> f32;
|
||||
musl_sin: sin(a: f64) -> f64;
|
||||
musl_sincos: sincos(a: f64, b: &mut f64, c: &mut f64) -> ();
|
||||
musl_sincosf: sincosf(a: f32, b: &mut f32, c: &mut f32) -> ();
|
||||
musl_sinf: sinf(a: f32) -> f32;
|
||||
musl_sinh: sinh(a: f64) -> f64;
|
||||
musl_sinhf: sinhf(a: f32) -> f32;
|
||||
musl_sqrt: sqrt(a: f64) -> f64;
|
||||
musl_sqrtf: sqrtf(a: f32) -> f32;
|
||||
musl_tan: tan(a: f64) -> f64;
|
||||
musl_tanf: tanf(a: f32) -> f32;
|
||||
musl_tanh: tanh(a: f64) -> f64;
|
||||
musl_tanhf: tanhf(a: f32) -> f32;
|
||||
musl_tgamma: tgamma(a: f64) -> f64;
|
||||
musl_tgammaf: tgammaf(a: f32) -> f32;
|
||||
musl_trunc: trunc(a: f64) -> f64;
|
||||
musl_truncf: truncf(a: f32) -> f32;
|
||||
musl_y0: y0(a: f64) -> f64;
|
||||
musl_y0f: y0f(a: f32) -> f32;
|
||||
musl_y1: y1(a: f64) -> f64;
|
||||
musl_y1f: y1f(a: f32) -> f32;
|
||||
musl_ynf: ynf(a: c_int, b: f32) -> f32;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue