/* List of all functions that is shared between `libm-macros` and `libm-test`. */ use std::fmt; use std::sync::LazyLock; struct NestedOp { float_ty: FloatTy, rust_sig: Signature, c_sig: Option, fn_list: &'static [&'static str], public: bool, } /// We need a flat list to work with most of the time, but define things as a more convenient /// nested list. const ALL_OPERATIONS_NESTED: &[NestedOp] = &[ NestedOp { // `fn(f16) -> f16` float_ty: FloatTy::F16, rust_sig: Signature { args: &[Ty::F16], returns: &[Ty::F16], }, c_sig: None, fn_list: &[ "ceilf16", "fabsf16", "floorf16", "rintf16", "roundevenf16", "roundf16", "sqrtf16", "truncf16", ], public: true, }, NestedOp { // `fn(f32) -> f32` float_ty: FloatTy::F32, rust_sig: Signature { args: &[Ty::F32], returns: &[Ty::F32], }, c_sig: None, fn_list: &[ "acosf", "acoshf", "asinf", "asinhf", "atanf", "atanhf", "cbrtf", "ceilf", "cosf", "coshf", "erfcf", "erff", "exp10f", "exp2f", "expf", "expm1f", "fabsf", "floorf", "j0f", "j1f", "lgammaf", "log10f", "log1pf", "log2f", "logf", "rintf", "roundevenf", "roundf", "sinf", "sinhf", "sqrtf", "tanf", "tanhf", "tgammaf", "truncf", "y0f", "y1f", ], public: true, }, NestedOp { // `(f64) -> f64` float_ty: FloatTy::F64, rust_sig: Signature { args: &[Ty::F64], returns: &[Ty::F64], }, c_sig: None, fn_list: &[ "acos", "acosh", "asin", "asinh", "atan", "atanh", "cbrt", "ceil", "cos", "cosh", "erf", "erfc", "exp", "exp10", "exp2", "expm1", "fabs", "floor", "j0", "j1", "lgamma", "log", "log10", "log1p", "log2", "rint", "round", "roundeven", "sin", "sinh", "sqrt", "tan", "tanh", "tgamma", "trunc", "y0", "y1", ], public: true, }, NestedOp { // `fn(f128) -> f128` float_ty: FloatTy::F128, rust_sig: Signature { args: &[Ty::F128], returns: &[Ty::F128], }, c_sig: None, fn_list: &[ "ceilf128", "fabsf128", "floorf128", "rintf128", "roundevenf128", "roundf128", "sqrtf128", "truncf128", ], public: true, }, NestedOp { // `(f16, f16) -> f16` float_ty: FloatTy::F16, rust_sig: Signature { args: &[Ty::F16, Ty::F16], returns: &[Ty::F16], }, c_sig: None, fn_list: &[ "copysignf16", "fdimf16", "fmaxf16", "fmaximum_numf16", "fmaximumf16", "fminf16", "fminimum_numf16", "fminimumf16", "fmodf16", ], public: true, }, NestedOp { // `(f32, f32) -> f32` float_ty: FloatTy::F32, rust_sig: Signature { args: &[Ty::F32, Ty::F32], returns: &[Ty::F32], }, c_sig: None, fn_list: &[ "atan2f", "copysignf", "fdimf", "fmaxf", "fmaximum_numf", "fmaximumf", "fminf", "fminimum_numf", "fminimumf", "fmodf", "hypotf", "nextafterf", "powf", "remainderf", ], public: true, }, NestedOp { // `(f64, f64) -> f64` float_ty: FloatTy::F64, rust_sig: Signature { args: &[Ty::F64, Ty::F64], returns: &[Ty::F64], }, c_sig: None, fn_list: &[ "atan2", "copysign", "fdim", "fmax", "fmaximum", "fmaximum_num", "fmin", "fminimum", "fminimum_num", "fmod", "hypot", "nextafter", "pow", "remainder", ], public: true, }, NestedOp { // `(f128, f128) -> f128` float_ty: FloatTy::F128, rust_sig: Signature { args: &[Ty::F128, Ty::F128], returns: &[Ty::F128], }, c_sig: None, fn_list: &[ "copysignf128", "fdimf128", "fmaxf128", "fmaximum_numf128", "fmaximumf128", "fminf128", "fminimum_numf128", "fminimumf128", "fmodf128", ], public: true, }, NestedOp { // `(f32, f32, f32) -> f32` float_ty: FloatTy::F32, rust_sig: Signature { args: &[Ty::F32, Ty::F32, Ty::F32], returns: &[Ty::F32], }, c_sig: None, fn_list: &["fmaf"], public: true, }, NestedOp { // `(f64, f64, f64) -> f64` float_ty: FloatTy::F64, rust_sig: Signature { args: &[Ty::F64, Ty::F64, Ty::F64], returns: &[Ty::F64], }, c_sig: None, fn_list: &["fma"], public: true, }, NestedOp { // `(f128, f128, f128) -> f128` float_ty: FloatTy::F128, rust_sig: Signature { args: &[Ty::F128, Ty::F128, Ty::F128], returns: &[Ty::F128], }, c_sig: None, fn_list: &["fmaf128"], public: true, }, NestedOp { // `(f32) -> i32` float_ty: FloatTy::F32, rust_sig: Signature { args: &[Ty::F32], returns: &[Ty::I32], }, c_sig: None, fn_list: &["ilogbf"], public: true, }, NestedOp { // `(f64) -> i32` float_ty: FloatTy::F64, rust_sig: Signature { args: &[Ty::F64], returns: &[Ty::I32], }, c_sig: None, fn_list: &["ilogb"], public: true, }, NestedOp { // `(i32, f32) -> f32` float_ty: FloatTy::F32, rust_sig: Signature { args: &[Ty::I32, Ty::F32], returns: &[Ty::F32], }, c_sig: None, fn_list: &["jnf", "ynf"], public: true, }, NestedOp { // `(i32, f64) -> f64` float_ty: FloatTy::F64, rust_sig: Signature { args: &[Ty::I32, Ty::F64], returns: &[Ty::F64], }, c_sig: None, fn_list: &["jn", "yn"], public: true, }, NestedOp { // `(f16, i32) -> f16` float_ty: FloatTy::F16, rust_sig: Signature { args: &[Ty::F16, Ty::I32], returns: &[Ty::F16], }, c_sig: None, fn_list: &["ldexpf16", "scalbnf16"], public: true, }, NestedOp { // `(f32, i32) -> f32` float_ty: FloatTy::F32, rust_sig: Signature { args: &[Ty::F32, Ty::I32], returns: &[Ty::F32], }, c_sig: None, fn_list: &["ldexpf", "scalbnf"], public: true, }, NestedOp { // `(f64, i64) -> f64` float_ty: FloatTy::F64, rust_sig: Signature { args: &[Ty::F64, Ty::I32], returns: &[Ty::F64], }, c_sig: None, fn_list: &["ldexp", "scalbn"], public: true, }, NestedOp { // `(f128, i32) -> f128` float_ty: FloatTy::F128, rust_sig: Signature { args: &[Ty::F128, Ty::I32], returns: &[Ty::F128], }, c_sig: None, fn_list: &["ldexpf128", "scalbnf128"], public: true, }, NestedOp { // `(f32, &mut f32) -> f32` as `(f32) -> (f32, f32)` float_ty: FloatTy::F32, rust_sig: Signature { args: &[Ty::F32], returns: &[Ty::F32, Ty::F32], }, c_sig: Some(Signature { args: &[Ty::F32, Ty::MutF32], returns: &[Ty::F32], }), fn_list: &["modff"], public: true, }, NestedOp { // `(f64, &mut f64) -> f64` as `(f64) -> (f64, f64)` float_ty: FloatTy::F64, rust_sig: Signature { args: &[Ty::F64], returns: &[Ty::F64, Ty::F64], }, c_sig: Some(Signature { args: &[Ty::F64, Ty::MutF64], returns: &[Ty::F64], }), fn_list: &["modf"], public: true, }, NestedOp { // `(f32, &mut c_int) -> f32` as `(f32) -> (f32, i32)` float_ty: FloatTy::F32, rust_sig: Signature { args: &[Ty::F32], returns: &[Ty::F32, Ty::I32], }, c_sig: Some(Signature { args: &[Ty::F32, Ty::MutCInt], returns: &[Ty::F32], }), fn_list: &["frexpf", "lgammaf_r"], public: true, }, NestedOp { // `(f64, &mut c_int) -> f64` as `(f64) -> (f64, i32)` float_ty: FloatTy::F64, rust_sig: Signature { args: &[Ty::F64], returns: &[Ty::F64, Ty::I32], }, c_sig: Some(Signature { args: &[Ty::F64, Ty::MutCInt], returns: &[Ty::F64], }), fn_list: &["frexp", "lgamma_r"], public: true, }, NestedOp { // `(f32, f32, &mut c_int) -> f32` as `(f32, f32) -> (f32, i32)` float_ty: FloatTy::F32, rust_sig: Signature { args: &[Ty::F32, Ty::F32], returns: &[Ty::F32, Ty::I32], }, c_sig: Some(Signature { args: &[Ty::F32, Ty::F32, Ty::MutCInt], returns: &[Ty::F32], }), fn_list: &["remquof"], public: true, }, NestedOp { // `(f64, f64, &mut c_int) -> f64` as `(f64, f64) -> (f64, i32)` float_ty: FloatTy::F64, rust_sig: Signature { args: &[Ty::F64, Ty::F64], returns: &[Ty::F64, Ty::I32], }, c_sig: Some(Signature { args: &[Ty::F64, Ty::F64, Ty::MutCInt], returns: &[Ty::F64], }), fn_list: &["remquo"], public: true, }, NestedOp { // `(f32, &mut f32, &mut f32)` as `(f32) -> (f32, f32)` float_ty: FloatTy::F32, rust_sig: Signature { args: &[Ty::F32], returns: &[Ty::F32, Ty::F32], }, c_sig: Some(Signature { args: &[Ty::F32, Ty::MutF32, Ty::MutF32], returns: &[], }), fn_list: &["sincosf"], public: true, }, NestedOp { // `(f64, &mut f64, &mut f64)` as `(f64) -> (f64, f64)` float_ty: FloatTy::F64, rust_sig: Signature { args: &[Ty::F64], returns: &[Ty::F64, Ty::F64], }, c_sig: Some(Signature { args: &[Ty::F64, Ty::MutF64, Ty::MutF64], returns: &[], }), fn_list: &["sincos"], public: true, }, ]; /// A type used in a function signature. #[allow(dead_code)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub enum Ty { F16, F32, F64, F128, I32, CInt, MutF16, MutF32, MutF64, MutF128, MutI32, MutCInt, } /// A subset of [`Ty`] representing only floats. #[allow(dead_code)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub enum FloatTy { F16, F32, F64, F128, } impl fmt::Display for Ty { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let s = match self { Ty::F16 => "f16", Ty::F32 => "f32", Ty::F64 => "f64", Ty::F128 => "f128", Ty::I32 => "i32", Ty::CInt => "::core::ffi::c_int", Ty::MutF16 => "&mut f16", Ty::MutF32 => "&mut f32", Ty::MutF64 => "&mut f64", Ty::MutF128 => "&mut f128", Ty::MutI32 => "&mut i32", Ty::MutCInt => "&mut ::core::ffi::c_int", }; f.write_str(s) } } impl fmt::Display for FloatTy { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let s = match self { FloatTy::F16 => "f16", FloatTy::F32 => "f32", FloatTy::F64 => "f64", FloatTy::F128 => "f128", }; f.write_str(s) } } /// Representation of e.g. `(f32, f32) -> f32` #[derive(Debug, Clone)] pub struct Signature { pub args: &'static [Ty], pub returns: &'static [Ty], } /// Combined information about a function implementation. #[derive(Debug, Clone)] pub struct MathOpInfo { pub name: &'static str, pub float_ty: FloatTy, /// Function signature for C implementations pub c_sig: Signature, /// Function signature for Rust implementations pub rust_sig: Signature, /// True if part of libm's public API pub public: bool, } /// A flat representation of `ALL_FUNCTIONS`. pub static ALL_OPERATIONS: LazyLock> = LazyLock::new(|| { let mut ret = Vec::new(); for op in ALL_OPERATIONS_NESTED { let fn_names = op.fn_list; for name in fn_names { let api = MathOpInfo { name, float_ty: op.float_ty, rust_sig: op.rust_sig.clone(), c_sig: op.c_sig.clone().unwrap_or_else(|| op.rust_sig.clone()), public: op.public, }; ret.push(api); } if !fn_names.is_sorted() { let mut sorted = (*fn_names).to_owned(); sorted.sort_unstable(); panic!("names list is not sorted: {fn_names:?}\nExpected: {sorted:?}"); } } ret.sort_by_key(|item| item.name); ret });