Merge pull request rust-lang/libm#377 from tgross35/shared-function-list
Share a list of all functions between `libm-macros` and `libm-test`
This commit is contained in:
commit
e3a58da4f8
6 changed files with 390 additions and 271 deletions
|
|
@ -5,7 +5,7 @@ use quote::quote;
|
|||
use syn::spanned::Spanned;
|
||||
use syn::{Fields, ItemEnum, Variant};
|
||||
|
||||
use crate::{ALL_FUNCTIONS_FLAT, base_name};
|
||||
use crate::{ALL_OPERATIONS, base_name};
|
||||
|
||||
/// Implement `#[function_enum]`, see documentation in `lib.rs`.
|
||||
pub fn function_enum(
|
||||
|
|
@ -31,15 +31,17 @@ pub fn function_enum(
|
|||
|
||||
let enum_name = &item.ident;
|
||||
let mut as_str_arms = Vec::new();
|
||||
let mut from_str_arms = Vec::new();
|
||||
let mut base_arms = Vec::new();
|
||||
|
||||
for func in ALL_FUNCTIONS_FLAT.iter() {
|
||||
for func in ALL_OPERATIONS.iter() {
|
||||
let fn_name = func.name;
|
||||
let ident = Ident::new(&fn_name.to_upper_camel_case(), Span::call_site());
|
||||
let bname_ident = Ident::new(&base_name(fn_name).to_upper_camel_case(), Span::call_site());
|
||||
|
||||
// Match arm for `fn as_str(self)` matcher
|
||||
as_str_arms.push(quote! { Self::#ident => #fn_name });
|
||||
from_str_arms.push(quote! { #fn_name => Self::#ident });
|
||||
|
||||
// Match arm for `fn base_name(self)` matcher
|
||||
base_arms.push(quote! { Self::#ident => #base_enum::#bname_ident });
|
||||
|
|
@ -50,11 +52,18 @@ pub fn function_enum(
|
|||
item.variants.push(variant);
|
||||
}
|
||||
|
||||
let variants = item.variants.iter();
|
||||
|
||||
let res = quote! {
|
||||
// Instantiate the enum
|
||||
#item
|
||||
|
||||
impl #enum_name {
|
||||
/// All variants of this enum.
|
||||
pub const ALL: &[Self] = &[
|
||||
#( Self::#variants, )*
|
||||
];
|
||||
|
||||
/// The stringified version of this function name.
|
||||
pub const fn as_str(self) -> &'static str {
|
||||
match self {
|
||||
|
|
@ -62,12 +71,26 @@ pub fn function_enum(
|
|||
}
|
||||
}
|
||||
|
||||
/// If `s` is the name of a function, return it.
|
||||
pub fn from_str(s: &str) -> Option<Self> {
|
||||
let ret = match s {
|
||||
#( #from_str_arms , )*
|
||||
_ => return None,
|
||||
};
|
||||
Some(ret)
|
||||
}
|
||||
|
||||
/// The base name enum for this function.
|
||||
pub const fn base_name(self) -> #base_enum {
|
||||
match self {
|
||||
#( #base_arms, )*
|
||||
}
|
||||
}
|
||||
|
||||
/// Return information about this operation.
|
||||
pub fn math_op(self) -> &'static crate::op::MathOpInfo {
|
||||
crate::op::ALL_OPERATIONS.iter().find(|op| op.name == self.as_str()).unwrap()
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -85,8 +108,7 @@ pub fn base_name_enum(
|
|||
return Err(syn::Error::new(sp.span(), "no attributes expected"));
|
||||
}
|
||||
|
||||
let mut base_names: Vec<_> =
|
||||
ALL_FUNCTIONS_FLAT.iter().map(|func| base_name(func.name)).collect();
|
||||
let mut base_names: Vec<_> = ALL_OPERATIONS.iter().map(|func| base_name(func.name)).collect();
|
||||
base_names.sort_unstable();
|
||||
base_names.dedup();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,270 +1,18 @@
|
|||
mod enums;
|
||||
mod parse;
|
||||
|
||||
use std::sync::LazyLock;
|
||||
mod shared;
|
||||
|
||||
use parse::{Invocation, StructuredInput};
|
||||
use proc_macro as pm;
|
||||
use proc_macro2::{self as pm2, Span};
|
||||
use quote::{ToTokens, quote};
|
||||
pub(crate) use shared::{ALL_OPERATIONS, FloatTy, MathOpInfo, Ty};
|
||||
use syn::spanned::Spanned;
|
||||
use syn::visit_mut::VisitMut;
|
||||
use syn::{Ident, ItemEnum};
|
||||
|
||||
const ALL_FUNCTIONS: &[(Ty, Signature, Option<Signature>, &[&str])] = &[
|
||||
(
|
||||
// `fn(f32) -> f32`
|
||||
Ty::F32,
|
||||
Signature { args: &[Ty::F32], returns: &[Ty::F32] },
|
||||
None,
|
||||
&[
|
||||
"acosf", "acoshf", "asinf", "asinhf", "atanf", "atanhf", "cbrtf", "ceilf", "cosf",
|
||||
"coshf", "erff", "exp10f", "exp2f", "expf", "expm1f", "fabsf", "floorf", "j0f", "j1f",
|
||||
"lgammaf", "log10f", "log1pf", "log2f", "logf", "rintf", "roundf", "sinf", "sinhf",
|
||||
"sqrtf", "tanf", "tanhf", "tgammaf", "truncf",
|
||||
],
|
||||
),
|
||||
(
|
||||
// `(f64) -> f64`
|
||||
Ty::F64,
|
||||
Signature { args: &[Ty::F64], returns: &[Ty::F64] },
|
||||
None,
|
||||
&[
|
||||
"acos", "acosh", "asin", "asinh", "atan", "atanh", "cbrt", "ceil", "cos", "cosh",
|
||||
"erf", "exp10", "exp2", "exp", "expm1", "fabs", "floor", "j0", "j1", "lgamma", "log10",
|
||||
"log1p", "log2", "log", "rint", "round", "sin", "sinh", "sqrt", "tan", "tanh",
|
||||
"tgamma", "trunc",
|
||||
],
|
||||
),
|
||||
(
|
||||
// `(f32, f32) -> f32`
|
||||
Ty::F32,
|
||||
Signature { args: &[Ty::F32, Ty::F32], returns: &[Ty::F32] },
|
||||
None,
|
||||
&[
|
||||
"atan2f",
|
||||
"copysignf",
|
||||
"fdimf",
|
||||
"fmaxf",
|
||||
"fminf",
|
||||
"fmodf",
|
||||
"hypotf",
|
||||
"nextafterf",
|
||||
"powf",
|
||||
"remainderf",
|
||||
],
|
||||
),
|
||||
(
|
||||
// `(f64, f64) -> f64`
|
||||
Ty::F64,
|
||||
Signature { args: &[Ty::F64, Ty::F64], returns: &[Ty::F64] },
|
||||
None,
|
||||
&[
|
||||
"atan2",
|
||||
"copysign",
|
||||
"fdim",
|
||||
"fmax",
|
||||
"fmin",
|
||||
"fmod",
|
||||
"hypot",
|
||||
"nextafter",
|
||||
"pow",
|
||||
"remainder",
|
||||
],
|
||||
),
|
||||
(
|
||||
// `(f32, f32, f32) -> f32`
|
||||
Ty::F32,
|
||||
Signature { args: &[Ty::F32, Ty::F32, Ty::F32], returns: &[Ty::F32] },
|
||||
None,
|
||||
&["fmaf"],
|
||||
),
|
||||
(
|
||||
// `(f64, f64, f64) -> f64`
|
||||
Ty::F64,
|
||||
Signature { args: &[Ty::F64, Ty::F64, Ty::F64], returns: &[Ty::F64] },
|
||||
None,
|
||||
&["fma"],
|
||||
),
|
||||
(
|
||||
// `(f32) -> i32`
|
||||
Ty::F32,
|
||||
Signature { args: &[Ty::F32], returns: &[Ty::I32] },
|
||||
None,
|
||||
&["ilogbf"],
|
||||
),
|
||||
(
|
||||
// `(f64) -> i32`
|
||||
Ty::F64,
|
||||
Signature { args: &[Ty::F64], returns: &[Ty::I32] },
|
||||
None,
|
||||
&["ilogb"],
|
||||
),
|
||||
(
|
||||
// `(i32, f32) -> f32`
|
||||
Ty::F32,
|
||||
Signature { args: &[Ty::I32, Ty::F32], returns: &[Ty::F32] },
|
||||
None,
|
||||
&["jnf"],
|
||||
),
|
||||
(
|
||||
// `(i32, f64) -> f64`
|
||||
Ty::F64,
|
||||
Signature { args: &[Ty::I32, Ty::F64], returns: &[Ty::F64] },
|
||||
None,
|
||||
&["jn"],
|
||||
),
|
||||
(
|
||||
// `(f32, i32) -> f32`
|
||||
Ty::F32,
|
||||
Signature { args: &[Ty::F32, Ty::I32], returns: &[Ty::F32] },
|
||||
None,
|
||||
&["scalbnf", "ldexpf"],
|
||||
),
|
||||
(
|
||||
// `(f64, i64) -> f64`
|
||||
Ty::F64,
|
||||
Signature { args: &[Ty::F64, Ty::I32], returns: &[Ty::F64] },
|
||||
None,
|
||||
&["scalbn", "ldexp"],
|
||||
),
|
||||
(
|
||||
// `(f32, &mut f32) -> f32` as `(f32) -> (f32, f32)`
|
||||
Ty::F32,
|
||||
Signature { args: &[Ty::F32], returns: &[Ty::F32, Ty::F32] },
|
||||
Some(Signature { args: &[Ty::F32, Ty::MutF32], returns: &[Ty::F32] }),
|
||||
&["modff"],
|
||||
),
|
||||
(
|
||||
// `(f64, &mut f64) -> f64` as `(f64) -> (f64, f64)`
|
||||
Ty::F64,
|
||||
Signature { args: &[Ty::F64], returns: &[Ty::F64, Ty::F64] },
|
||||
Some(Signature { args: &[Ty::F64, Ty::MutF64], returns: &[Ty::F64] }),
|
||||
&["modf"],
|
||||
),
|
||||
(
|
||||
// `(f32, &mut c_int) -> f32` as `(f32) -> (f32, i32)`
|
||||
Ty::F32,
|
||||
Signature { args: &[Ty::F32], returns: &[Ty::F32, Ty::I32] },
|
||||
Some(Signature { args: &[Ty::F32, Ty::MutCInt], returns: &[Ty::F32] }),
|
||||
&["frexpf", "lgammaf_r"],
|
||||
),
|
||||
(
|
||||
// `(f64, &mut c_int) -> f64` as `(f64) -> (f64, i32)`
|
||||
Ty::F64,
|
||||
Signature { args: &[Ty::F64], returns: &[Ty::F64, Ty::I32] },
|
||||
Some(Signature { args: &[Ty::F64, Ty::MutCInt], returns: &[Ty::F64] }),
|
||||
&["frexp", "lgamma_r"],
|
||||
),
|
||||
(
|
||||
// `(f32, f32, &mut c_int) -> f32` as `(f32, f32) -> (f32, i32)`
|
||||
Ty::F32,
|
||||
Signature { args: &[Ty::F32, Ty::F32], returns: &[Ty::F32, Ty::I32] },
|
||||
Some(Signature { args: &[Ty::F32, Ty::F32, Ty::MutCInt], returns: &[Ty::F32] }),
|
||||
&["remquof"],
|
||||
),
|
||||
(
|
||||
// `(f64, f64, &mut c_int) -> f64` as `(f64, f64) -> (f64, i32)`
|
||||
Ty::F64,
|
||||
Signature { args: &[Ty::F64, Ty::F64], returns: &[Ty::F64, Ty::I32] },
|
||||
Some(Signature { args: &[Ty::F64, Ty::F64, Ty::MutCInt], returns: &[Ty::F64] }),
|
||||
&["remquo"],
|
||||
),
|
||||
(
|
||||
// `(f32, &mut f32, &mut f32)` as `(f32) -> (f32, f32)`
|
||||
Ty::F32,
|
||||
Signature { args: &[Ty::F32], returns: &[Ty::F32, Ty::F32] },
|
||||
Some(Signature { args: &[Ty::F32, Ty::MutF32, Ty::MutF32], returns: &[] }),
|
||||
&["sincosf"],
|
||||
),
|
||||
(
|
||||
// `(f64, &mut f64, &mut f64)` as `(f64) -> (f64, f64)`
|
||||
Ty::F64,
|
||||
Signature { args: &[Ty::F64], returns: &[Ty::F64, Ty::F64] },
|
||||
Some(Signature { args: &[Ty::F64, Ty::MutF64, Ty::MutF64], returns: &[] }),
|
||||
&["sincos"],
|
||||
),
|
||||
];
|
||||
|
||||
const KNOWN_TYPES: &[&str] = &["FTy", "CFn", "CArgs", "CRet", "RustFn", "RustArgs", "RustRet"];
|
||||
|
||||
/// A type used in a function signature.
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
enum Ty {
|
||||
F16,
|
||||
F32,
|
||||
F64,
|
||||
F128,
|
||||
I32,
|
||||
CInt,
|
||||
MutF16,
|
||||
MutF32,
|
||||
MutF64,
|
||||
MutF128,
|
||||
MutI32,
|
||||
MutCInt,
|
||||
}
|
||||
|
||||
impl ToTokens for Ty {
|
||||
fn to_tokens(&self, tokens: &mut pm2::TokenStream) {
|
||||
let ts = match self {
|
||||
Ty::F16 => quote! { f16 },
|
||||
Ty::F32 => quote! { f32 },
|
||||
Ty::F64 => quote! { f64 },
|
||||
Ty::F128 => quote! { f128 },
|
||||
Ty::I32 => quote! { i32 },
|
||||
Ty::CInt => quote! { ::core::ffi::c_int },
|
||||
Ty::MutF16 => quote! { &'a mut f16 },
|
||||
Ty::MutF32 => quote! { &'a mut f32 },
|
||||
Ty::MutF64 => quote! { &'a mut f64 },
|
||||
Ty::MutF128 => quote! { &'a mut f128 },
|
||||
Ty::MutI32 => quote! { &'a mut i32 },
|
||||
Ty::MutCInt => quote! { &'a mut core::ffi::c_int },
|
||||
};
|
||||
|
||||
tokens.extend(ts);
|
||||
}
|
||||
}
|
||||
|
||||
/// Representation of e.g. `(f32, f32) -> f32`
|
||||
#[derive(Debug, Clone)]
|
||||
struct Signature {
|
||||
args: &'static [Ty],
|
||||
returns: &'static [Ty],
|
||||
}
|
||||
|
||||
/// Combined information about a function implementation.
|
||||
#[derive(Debug, Clone)]
|
||||
struct FunctionInfo {
|
||||
name: &'static str,
|
||||
base_fty: Ty,
|
||||
/// Function signature for C implementations
|
||||
c_sig: Signature,
|
||||
/// Function signature for Rust implementations
|
||||
rust_sig: Signature,
|
||||
}
|
||||
|
||||
/// A flat representation of `ALL_FUNCTIONS`.
|
||||
static ALL_FUNCTIONS_FLAT: LazyLock<Vec<FunctionInfo>> = LazyLock::new(|| {
|
||||
let mut ret = Vec::new();
|
||||
|
||||
for (base_fty, rust_sig, c_sig, names) in ALL_FUNCTIONS {
|
||||
for name in *names {
|
||||
let api = FunctionInfo {
|
||||
name,
|
||||
base_fty: *base_fty,
|
||||
rust_sig: rust_sig.clone(),
|
||||
c_sig: c_sig.clone().unwrap_or_else(|| rust_sig.clone()),
|
||||
};
|
||||
ret.push(api);
|
||||
}
|
||||
}
|
||||
|
||||
ret.sort_by_key(|item| item.name);
|
||||
ret
|
||||
});
|
||||
|
||||
/// Populate an enum with a variant representing function. Names are in upper camel case.
|
||||
///
|
||||
/// Applied to an empty enum. Expects one attribute `#[function_enum(BaseName)]` that provides
|
||||
|
|
@ -382,7 +130,7 @@ pub fn for_each_function(tokens: pm::TokenStream) -> pm::TokenStream {
|
|||
/// Check for any input that is structurally correct but has other problems.
|
||||
///
|
||||
/// Returns the list of function names that we should expand for.
|
||||
fn validate(input: &mut StructuredInput) -> syn::Result<Vec<&'static FunctionInfo>> {
|
||||
fn validate(input: &mut StructuredInput) -> syn::Result<Vec<&'static MathOpInfo>> {
|
||||
// Collect lists of all functions that are provied as macro inputs in various fields (only,
|
||||
// skip, attributes).
|
||||
let attr_mentions = input
|
||||
|
|
@ -398,7 +146,7 @@ fn validate(input: &mut StructuredInput) -> syn::Result<Vec<&'static FunctionInf
|
|||
|
||||
// Make sure that every function mentioned is a real function
|
||||
for mentioned in all_mentioned_fns {
|
||||
if !ALL_FUNCTIONS_FLAT.iter().any(|func| mentioned == func.name) {
|
||||
if !ALL_OPERATIONS.iter().any(|func| mentioned == func.name) {
|
||||
let e = syn::Error::new(
|
||||
mentioned.span(),
|
||||
format!("unrecognized function name `{mentioned}`"),
|
||||
|
|
@ -417,7 +165,7 @@ fn validate(input: &mut StructuredInput) -> syn::Result<Vec<&'static FunctionInf
|
|||
|
||||
// Construct a list of what we intend to expand
|
||||
let mut fn_list = Vec::new();
|
||||
for func in ALL_FUNCTIONS_FLAT.iter() {
|
||||
for func in ALL_OPERATIONS.iter() {
|
||||
let fn_name = func.name;
|
||||
// If we have an `only` list and it does _not_ contain this function name, skip it
|
||||
if input.only.as_ref().is_some_and(|only| !only.iter().any(|o| o == fn_name)) {
|
||||
|
|
@ -498,7 +246,7 @@ fn validate(input: &mut StructuredInput) -> syn::Result<Vec<&'static FunctionInf
|
|||
}
|
||||
|
||||
/// Expand our structured macro input into invocations of the callback macro.
|
||||
fn expand(input: StructuredInput, fn_list: &[&FunctionInfo]) -> syn::Result<pm2::TokenStream> {
|
||||
fn expand(input: StructuredInput, fn_list: &[&MathOpInfo]) -> syn::Result<pm2::TokenStream> {
|
||||
let mut out = pm2::TokenStream::new();
|
||||
let default_ident = Ident::new("_", Span::call_site());
|
||||
let callback = input.callback;
|
||||
|
|
@ -545,7 +293,7 @@ fn expand(input: StructuredInput, fn_list: &[&FunctionInfo]) -> syn::Result<pm2:
|
|||
None => pm2::TokenStream::new(),
|
||||
};
|
||||
|
||||
let base_fty = func.base_fty;
|
||||
let base_fty = func.float_ty;
|
||||
let c_args = &func.c_sig.args;
|
||||
let c_ret = &func.c_sig.returns;
|
||||
let rust_args = &func.rust_sig.args;
|
||||
|
|
@ -648,3 +396,36 @@ fn base_name(name: &str) -> &str {
|
|||
.unwrap_or(name),
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTokens for Ty {
|
||||
fn to_tokens(&self, tokens: &mut pm2::TokenStream) {
|
||||
let ts = match self {
|
||||
Ty::F16 => quote! { f16 },
|
||||
Ty::F32 => quote! { f32 },
|
||||
Ty::F64 => quote! { f64 },
|
||||
Ty::F128 => quote! { f128 },
|
||||
Ty::I32 => quote! { i32 },
|
||||
Ty::CInt => quote! { ::core::ffi::c_int },
|
||||
Ty::MutF16 => quote! { &'a mut f16 },
|
||||
Ty::MutF32 => quote! { &'a mut f32 },
|
||||
Ty::MutF64 => quote! { &'a mut f64 },
|
||||
Ty::MutF128 => quote! { &'a mut f128 },
|
||||
Ty::MutI32 => quote! { &'a mut i32 },
|
||||
Ty::MutCInt => quote! { &'a mut core::ffi::c_int },
|
||||
};
|
||||
|
||||
tokens.extend(ts);
|
||||
}
|
||||
}
|
||||
impl ToTokens for FloatTy {
|
||||
fn to_tokens(&self, tokens: &mut pm2::TokenStream) {
|
||||
let ts = match self {
|
||||
FloatTy::F16 => quote! { f16 },
|
||||
FloatTy::F32 => quote! { f32 },
|
||||
FloatTy::F64 => quote! { f64 },
|
||||
FloatTy::F128 => quote! { f128 },
|
||||
};
|
||||
|
||||
tokens.extend(ts);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
277
library/compiler-builtins/libm/crates/libm-macros/src/shared.rs
Normal file
277
library/compiler-builtins/libm/crates/libm-macros/src/shared.rs
Normal file
|
|
@ -0,0 +1,277 @@
|
|||
/* List of all functions that is shared between `libm-macros` and `libm-test`. */
|
||||
|
||||
use std::fmt;
|
||||
use std::sync::LazyLock;
|
||||
|
||||
const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option<Signature>, &[&str])] = &[
|
||||
(
|
||||
// `fn(f32) -> f32`
|
||||
FloatTy::F32,
|
||||
Signature { args: &[Ty::F32], returns: &[Ty::F32] },
|
||||
None,
|
||||
&[
|
||||
"acosf", "acoshf", "asinf", "asinhf", "atanf", "atanhf", "cbrtf", "ceilf", "cosf",
|
||||
"coshf", "erff", "exp10f", "exp2f", "expf", "expm1f", "fabsf", "floorf", "j0f", "j1f",
|
||||
"lgammaf", "log10f", "log1pf", "log2f", "logf", "rintf", "roundf", "sinf", "sinhf",
|
||||
"sqrtf", "tanf", "tanhf", "tgammaf", "truncf",
|
||||
],
|
||||
),
|
||||
(
|
||||
// `(f64) -> f64`
|
||||
FloatTy::F64,
|
||||
Signature { args: &[Ty::F64], returns: &[Ty::F64] },
|
||||
None,
|
||||
&[
|
||||
"acos", "acosh", "asin", "asinh", "atan", "atanh", "cbrt", "ceil", "cos", "cosh",
|
||||
"erf", "exp10", "exp2", "exp", "expm1", "fabs", "floor", "j0", "j1", "lgamma", "log10",
|
||||
"log1p", "log2", "log", "rint", "round", "sin", "sinh", "sqrt", "tan", "tanh",
|
||||
"tgamma", "trunc",
|
||||
],
|
||||
),
|
||||
(
|
||||
// `(f32, f32) -> f32`
|
||||
FloatTy::F32,
|
||||
Signature { args: &[Ty::F32, Ty::F32], returns: &[Ty::F32] },
|
||||
None,
|
||||
&[
|
||||
"atan2f",
|
||||
"copysignf",
|
||||
"fdimf",
|
||||
"fmaxf",
|
||||
"fminf",
|
||||
"fmodf",
|
||||
"hypotf",
|
||||
"nextafterf",
|
||||
"powf",
|
||||
"remainderf",
|
||||
],
|
||||
),
|
||||
(
|
||||
// `(f64, f64) -> f64`
|
||||
FloatTy::F64,
|
||||
Signature { args: &[Ty::F64, Ty::F64], returns: &[Ty::F64] },
|
||||
None,
|
||||
&[
|
||||
"atan2",
|
||||
"copysign",
|
||||
"fdim",
|
||||
"fmax",
|
||||
"fmin",
|
||||
"fmod",
|
||||
"hypot",
|
||||
"nextafter",
|
||||
"pow",
|
||||
"remainder",
|
||||
],
|
||||
),
|
||||
(
|
||||
// `(f32, f32, f32) -> f32`
|
||||
FloatTy::F32,
|
||||
Signature { args: &[Ty::F32, Ty::F32, Ty::F32], returns: &[Ty::F32] },
|
||||
None,
|
||||
&["fmaf"],
|
||||
),
|
||||
(
|
||||
// `(f64, f64, f64) -> f64`
|
||||
FloatTy::F64,
|
||||
Signature { args: &[Ty::F64, Ty::F64, Ty::F64], returns: &[Ty::F64] },
|
||||
None,
|
||||
&["fma"],
|
||||
),
|
||||
(
|
||||
// `(f32) -> i32`
|
||||
FloatTy::F32,
|
||||
Signature { args: &[Ty::F32], returns: &[Ty::I32] },
|
||||
None,
|
||||
&["ilogbf"],
|
||||
),
|
||||
(
|
||||
// `(f64) -> i32`
|
||||
FloatTy::F64,
|
||||
Signature { args: &[Ty::F64], returns: &[Ty::I32] },
|
||||
None,
|
||||
&["ilogb"],
|
||||
),
|
||||
(
|
||||
// `(i32, f32) -> f32`
|
||||
FloatTy::F32,
|
||||
Signature { args: &[Ty::I32, Ty::F32], returns: &[Ty::F32] },
|
||||
None,
|
||||
&["jnf"],
|
||||
),
|
||||
(
|
||||
// `(i32, f64) -> f64`
|
||||
FloatTy::F64,
|
||||
Signature { args: &[Ty::I32, Ty::F64], returns: &[Ty::F64] },
|
||||
None,
|
||||
&["jn"],
|
||||
),
|
||||
(
|
||||
// `(f32, i32) -> f32`
|
||||
FloatTy::F32,
|
||||
Signature { args: &[Ty::F32, Ty::I32], returns: &[Ty::F32] },
|
||||
None,
|
||||
&["scalbnf", "ldexpf"],
|
||||
),
|
||||
(
|
||||
// `(f64, i64) -> f64`
|
||||
FloatTy::F64,
|
||||
Signature { args: &[Ty::F64, Ty::I32], returns: &[Ty::F64] },
|
||||
None,
|
||||
&["scalbn", "ldexp"],
|
||||
),
|
||||
(
|
||||
// `(f32, &mut f32) -> f32` as `(f32) -> (f32, f32)`
|
||||
FloatTy::F32,
|
||||
Signature { args: &[Ty::F32], returns: &[Ty::F32, Ty::F32] },
|
||||
Some(Signature { args: &[Ty::F32, Ty::MutF32], returns: &[Ty::F32] }),
|
||||
&["modff"],
|
||||
),
|
||||
(
|
||||
// `(f64, &mut f64) -> f64` as `(f64) -> (f64, f64)`
|
||||
FloatTy::F64,
|
||||
Signature { args: &[Ty::F64], returns: &[Ty::F64, Ty::F64] },
|
||||
Some(Signature { args: &[Ty::F64, Ty::MutF64], returns: &[Ty::F64] }),
|
||||
&["modf"],
|
||||
),
|
||||
(
|
||||
// `(f32, &mut c_int) -> f32` as `(f32) -> (f32, i32)`
|
||||
FloatTy::F32,
|
||||
Signature { args: &[Ty::F32], returns: &[Ty::F32, Ty::I32] },
|
||||
Some(Signature { args: &[Ty::F32, Ty::MutCInt], returns: &[Ty::F32] }),
|
||||
&["frexpf", "lgammaf_r"],
|
||||
),
|
||||
(
|
||||
// `(f64, &mut c_int) -> f64` as `(f64) -> (f64, i32)`
|
||||
FloatTy::F64,
|
||||
Signature { args: &[Ty::F64], returns: &[Ty::F64, Ty::I32] },
|
||||
Some(Signature { args: &[Ty::F64, Ty::MutCInt], returns: &[Ty::F64] }),
|
||||
&["frexp", "lgamma_r"],
|
||||
),
|
||||
(
|
||||
// `(f32, f32, &mut c_int) -> f32` as `(f32, f32) -> (f32, i32)`
|
||||
FloatTy::F32,
|
||||
Signature { args: &[Ty::F32, Ty::F32], returns: &[Ty::F32, Ty::I32] },
|
||||
Some(Signature { args: &[Ty::F32, Ty::F32, Ty::MutCInt], returns: &[Ty::F32] }),
|
||||
&["remquof"],
|
||||
),
|
||||
(
|
||||
// `(f64, f64, &mut c_int) -> f64` as `(f64, f64) -> (f64, i32)`
|
||||
FloatTy::F64,
|
||||
Signature { args: &[Ty::F64, Ty::F64], returns: &[Ty::F64, Ty::I32] },
|
||||
Some(Signature { args: &[Ty::F64, Ty::F64, Ty::MutCInt], returns: &[Ty::F64] }),
|
||||
&["remquo"],
|
||||
),
|
||||
(
|
||||
// `(f32, &mut f32, &mut f32)` as `(f32) -> (f32, f32)`
|
||||
FloatTy::F32,
|
||||
Signature { args: &[Ty::F32], returns: &[Ty::F32, Ty::F32] },
|
||||
Some(Signature { args: &[Ty::F32, Ty::MutF32, Ty::MutF32], returns: &[] }),
|
||||
&["sincosf"],
|
||||
),
|
||||
(
|
||||
// `(f64, &mut f64, &mut f64)` as `(f64) -> (f64, f64)`
|
||||
FloatTy::F64,
|
||||
Signature { args: &[Ty::F64], returns: &[Ty::F64, Ty::F64] },
|
||||
Some(Signature { args: &[Ty::F64, Ty::MutF64, Ty::MutF64], returns: &[] }),
|
||||
&["sincos"],
|
||||
),
|
||||
];
|
||||
|
||||
/// 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,
|
||||
}
|
||||
|
||||
/// A flat representation of `ALL_FUNCTIONS`.
|
||||
pub static ALL_OPERATIONS: LazyLock<Vec<MathOpInfo>> = LazyLock::new(|| {
|
||||
let mut ret = Vec::new();
|
||||
|
||||
for (base_fty, rust_sig, c_sig, names) in ALL_OPERATIONS_NESTED {
|
||||
for name in *names {
|
||||
let api = MathOpInfo {
|
||||
name,
|
||||
float_ty: *base_fty,
|
||||
rust_sig: rust_sig.clone(),
|
||||
c_sig: c_sig.clone().unwrap_or_else(|| rust_sig.clone()),
|
||||
};
|
||||
ret.push(api);
|
||||
}
|
||||
}
|
||||
|
||||
ret.sort_by_key(|item| item.name);
|
||||
ret
|
||||
});
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
#[libm_macros::function_enum(BaseName)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
pub enum Function {}
|
||||
pub enum Identifier {}
|
||||
|
||||
#[libm_macros::base_name_enum]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
|
|
@ -8,12 +8,31 @@ pub enum BaseName {}
|
|||
|
||||
#[test]
|
||||
fn as_str() {
|
||||
assert_eq!(Function::Sin.as_str(), "sin");
|
||||
assert_eq!(Function::Sinf.as_str(), "sinf");
|
||||
assert_eq!(Identifier::Sin.as_str(), "sin");
|
||||
assert_eq!(Identifier::Sinf.as_str(), "sinf");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_str() {
|
||||
assert_eq!(Identifier::from_str("sin").unwrap(), Identifier::Sin);
|
||||
assert_eq!(Identifier::from_str("sinf").unwrap(), Identifier::Sinf);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn basename() {
|
||||
assert_eq!(Function::Sin.base_name(), BaseName::Sin);
|
||||
assert_eq!(Function::Sinf.base_name(), BaseName::Sin);
|
||||
assert_eq!(Identifier::Sin.base_name(), BaseName::Sin);
|
||||
assert_eq!(Identifier::Sinf.base_name(), BaseName::Sin);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn math_op() {
|
||||
assert_eq!(Identifier::Sin.math_op().float_ty, FloatTy::F64);
|
||||
assert_eq!(Identifier::Sinf.math_op().float_ty, FloatTy::F32);
|
||||
}
|
||||
|
||||
// Replicate the structure that we have in `libm-test`
|
||||
mod op {
|
||||
include!("../../libm-macros/src/shared.rs");
|
||||
}
|
||||
|
||||
use op::FloatTy;
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ mod test_traits;
|
|||
pub use f8_impl::f8;
|
||||
pub use libm::support::{Float, Int, IntTy, MinInt};
|
||||
pub use num::{FloatExt, logspace};
|
||||
pub use op::{BaseName, Identifier, MathOp, OpCFn, OpFTy, OpRustFn, OpRustRet};
|
||||
pub use op::{BaseName, FloatTy, Identifier, MathOp, OpCFn, OpFTy, OpRustFn, OpRustRet, Ty};
|
||||
pub use precision::{MaybeOverride, SpecialCase, default_ulp};
|
||||
pub use test_traits::{CheckBasis, CheckCtx, CheckOutput, GenerateInput, Hex, TupleCall};
|
||||
|
||||
|
|
|
|||
|
|
@ -13,18 +13,38 @@
|
|||
//! - "Operation" / "Op": Something that relates a routine to a function or is otherwise higher
|
||||
//! level. `Op` is also used as the name for generic parameters since it is terse.
|
||||
|
||||
use std::fmt;
|
||||
|
||||
pub use shared::{ALL_OPERATIONS, FloatTy, MathOpInfo, Ty};
|
||||
|
||||
use crate::{CheckOutput, Float, TupleCall};
|
||||
|
||||
mod shared {
|
||||
include!("../../libm-macros/src/shared.rs");
|
||||
}
|
||||
|
||||
/// An enum representing each possible symbol name (`sin`, `sinf`, `sinl`, etc).
|
||||
#[libm_macros::function_enum(BaseName)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub enum Identifier {}
|
||||
|
||||
impl fmt::Display for Identifier {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_str(self.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
/// The name without any type specifier, e.g. `sin` and `sinf` both become `sin`.
|
||||
#[libm_macros::base_name_enum]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub enum BaseName {}
|
||||
|
||||
impl fmt::Display for BaseName {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_str(self.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
/// Attributes ascribed to a `libm` routine including signature, type information,
|
||||
/// and naming.
|
||||
pub trait MathOp {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue