From 1069346b6dcfac68e3d059bdd79000406b04c95c Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 22 Dec 2024 11:22:02 +0000 Subject: [PATCH 1/4] Move the macro's input function list to a new module `shared` This will enable us to `include!` the file to access these types in `libm-test`, rather than somehow reproducing the types as part of the macro. Ideally `libm-test` would just `use` the types from `libm-macros` but proc macro crates cannot currently export anything else. This also adjusts naming to closer match the scheme described in `libm_test::op`. --- .../libm/crates/libm-macros/src/enums.rs | 7 +- .../libm/crates/libm-macros/src/lib.rs | 299 +++--------------- .../libm/crates/libm-macros/src/shared.rs | 277 ++++++++++++++++ 3 files changed, 320 insertions(+), 263 deletions(-) create mode 100644 library/compiler-builtins/libm/crates/libm-macros/src/shared.rs diff --git a/library/compiler-builtins/libm/crates/libm-macros/src/enums.rs b/library/compiler-builtins/libm/crates/libm-macros/src/enums.rs index 1f9fca2ef9e9..82dedc66ecd9 100644 --- a/library/compiler-builtins/libm/crates/libm-macros/src/enums.rs +++ b/library/compiler-builtins/libm/crates/libm-macros/src/enums.rs @@ -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( @@ -33,7 +33,7 @@ pub fn function_enum( let mut as_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()); @@ -85,8 +85,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(); diff --git a/library/compiler-builtins/libm/crates/libm-macros/src/lib.rs b/library/compiler-builtins/libm/crates/libm-macros/src/lib.rs index 1e7cd08b908e..916b539ed58c 100644 --- a/library/compiler-builtins/libm/crates/libm-macros/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-macros/src/lib.rs @@ -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, &[&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> = 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> { +fn validate(input: &mut StructuredInput) -> syn::Result> { // 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 syn::Result syn::Result syn::Result { +fn expand(input: StructuredInput, fn_list: &[&MathOpInfo]) -> syn::Result { 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::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); + } +} diff --git a/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs b/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs new file mode 100644 index 000000000000..100bcc7ad8cb --- /dev/null +++ b/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs @@ -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, &[&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> = 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 +}); From fc4b88aecd8c044d246e026d0c267a10350e9406 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 22 Dec 2024 11:41:43 +0000 Subject: [PATCH 2/4] Include `shared.rs` in `libm_test::op` These types from `libm-macros` provide a way to get information about an operation at runtime, rather than only being encoded in the type system. Include the file and reexport relevant types. --- .../compiler-builtins/libm/crates/libm-test/src/lib.rs | 2 +- library/compiler-builtins/libm/crates/libm-test/src/op.rs | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs index 622b2dec98ca..e3a690678416 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/lib.rs @@ -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}; diff --git a/library/compiler-builtins/libm/crates/libm-test/src/op.rs b/library/compiler-builtins/libm/crates/libm-test/src/op.rs index bcea31c22b6e..a2f21d3c1916 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/op.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/op.rs @@ -13,8 +13,16 @@ //! - "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)] From b9ecacf03b7d295f898368216d2c9750b1affe5f Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 29 Dec 2024 08:06:53 +0000 Subject: [PATCH 3/4] Add new trait implementations for `Identifier` and `BaseName` These allow for more convenient printing, as well as storage in map types. --- .../libm/crates/libm-test/src/op.rs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/op.rs b/library/compiler-builtins/libm/crates/libm-test/src/op.rs index a2f21d3c1916..e58c28903628 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/op.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/op.rs @@ -25,14 +25,26 @@ mod shared { /// 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 { From 6e97fef9c9b340b71e8f5051389ed24185003909 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 22 Dec 2024 11:26:22 +0000 Subject: [PATCH 4/4] Add `ALL`, `from_str` and `math_op` to `Identifier` Introduce new API to iterate the function list and associate items with their `MathOp`. --- .../libm/crates/libm-macros/src/enums.rs | 23 +++++++++++++++ .../libm/crates/libm-macros/tests/enum.rs | 29 +++++++++++++++---- 2 files changed, 47 insertions(+), 5 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-macros/src/enums.rs b/library/compiler-builtins/libm/crates/libm-macros/src/enums.rs index 82dedc66ecd9..864b625eab38 100644 --- a/library/compiler-builtins/libm/crates/libm-macros/src/enums.rs +++ b/library/compiler-builtins/libm/crates/libm-macros/src/enums.rs @@ -31,6 +31,7 @@ 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_OPERATIONS.iter() { @@ -40,6 +41,7 @@ pub fn function_enum( // 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 { + 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() + } } }; diff --git a/library/compiler-builtins/libm/crates/libm-macros/tests/enum.rs b/library/compiler-builtins/libm/crates/libm-macros/tests/enum.rs index 884b8d8d6518..93e209a0dcc9 100644 --- a/library/compiler-builtins/libm/crates/libm-macros/tests/enum.rs +++ b/library/compiler-builtins/libm/crates/libm-macros/tests/enum.rs @@ -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;