From 1dd39e27f06d0028bc62452283cf00a2d932d981 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 23 Apr 2025 06:46:31 +0000 Subject: [PATCH] libm-macros: Start tracking which functions are public It would be nice to reuse some of the macro structure for internal functions, like `rem_pio2`. To facilitate this, add a `public` field and make it available in the macro's API. --- .../crates/libm-macros/src/lib.rs | 6 +- .../crates/libm-macros/src/shared.rs | 383 ++++++++++-------- .../crates/libm-macros/tests/basic.rs | 2 + library/compiler-builtins/libm-test/src/op.rs | 10 +- 4 files changed, 226 insertions(+), 175 deletions(-) diff --git a/library/compiler-builtins/crates/libm-macros/src/lib.rs b/library/compiler-builtins/crates/libm-macros/src/lib.rs index 3cdd364e8300..144676c12536 100644 --- a/library/compiler-builtins/crates/libm-macros/src/lib.rs +++ b/library/compiler-builtins/crates/libm-macros/src/lib.rs @@ -12,7 +12,7 @@ use syn::visit_mut::VisitMut; use syn::{Ident, ItemEnum}; const KNOWN_TYPES: &[&str] = &[ - "FTy", "CFn", "CArgs", "CRet", "RustFn", "RustArgs", "RustRet", + "FTy", "CFn", "CArgs", "CRet", "RustFn", "RustArgs", "RustRet", "public", ]; /// Populate an enum with a variant representing function. Names are in upper camel case. @@ -80,6 +80,8 @@ pub fn base_name_enum(attributes: pm::TokenStream, tokens: pm::TokenStream) -> p /// RustArgs: $RustArgs:ty, /// // The Rust version's return type (e.g. `(f32, f32)`) /// RustRet: $RustRet:ty, +/// // True if this is part of `libm`'s public API +/// public: $public:expr, /// // Attributes for the current function, if any /// attrs: [$($attr:meta),*], /// // Extra tokens passed directly (if any) @@ -329,6 +331,7 @@ fn expand(input: StructuredInput, fn_list: &[&MathOpInfo]) -> syn::Result syn::Result quote! { RustFn: fn( #(#rust_args),* ,) -> ( #(#rust_ret),* ), }, "RustArgs" => quote! { RustArgs: ( #(#rust_args),* ,), }, "RustRet" => quote! { RustRet: ( #(#rust_ret),* ), }, + "public" => quote! { public: #public, }, _ => unreachable!("checked in validation"), }; ty_fields.push(field); diff --git a/library/compiler-builtins/crates/libm-macros/src/shared.rs b/library/compiler-builtins/crates/libm-macros/src/shared.rs index 750ed1afb057..1cefe4e8c7ed 100644 --- a/library/compiler-builtins/crates/libm-macros/src/shared.rs +++ b/library/compiler-builtins/crates/libm-macros/src/shared.rs @@ -3,16 +3,26 @@ use std::fmt; use std::sync::LazyLock; -const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] = &[ - ( +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` - FloatTy::F16, - Signature { + float_ty: FloatTy::F16, + rust_sig: Signature { args: &[Ty::F16], returns: &[Ty::F16], }, - None, - &[ + c_sig: None, + fn_list: &[ "ceilf16", "fabsf16", "floorf16", @@ -22,16 +32,17 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] "sqrtf16", "truncf16", ], - ), - ( + public: true, + }, + NestedOp { // `fn(f32) -> f32` - FloatTy::F32, - Signature { + float_ty: FloatTy::F32, + rust_sig: Signature { args: &[Ty::F32], returns: &[Ty::F32], }, - None, - &[ + c_sig: None, + fn_list: &[ "acosf", "acoshf", "asinf", @@ -70,16 +81,17 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] "y0f", "y1f", ], - ), - ( + public: true, + }, + NestedOp { // `(f64) -> f64` - FloatTy::F64, - Signature { + float_ty: FloatTy::F64, + rust_sig: Signature { args: &[Ty::F64], returns: &[Ty::F64], }, - None, - &[ + c_sig: None, + fn_list: &[ "acos", "acosh", "asin", @@ -118,16 +130,17 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] "y0", "y1", ], - ), - ( + public: true, + }, + NestedOp { // `fn(f128) -> f128` - FloatTy::F128, - Signature { + float_ty: FloatTy::F128, + rust_sig: Signature { args: &[Ty::F128], returns: &[Ty::F128], }, - None, - &[ + c_sig: None, + fn_list: &[ "ceilf128", "fabsf128", "floorf128", @@ -137,16 +150,17 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] "sqrtf128", "truncf128", ], - ), - ( + public: true, + }, + NestedOp { // `(f16, f16) -> f16` - FloatTy::F16, - Signature { + float_ty: FloatTy::F16, + rust_sig: Signature { args: &[Ty::F16, Ty::F16], returns: &[Ty::F16], }, - None, - &[ + c_sig: None, + fn_list: &[ "copysignf16", "fdimf16", "fmaxf16", @@ -157,16 +171,17 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] "fminimumf16", "fmodf16", ], - ), - ( + public: true, + }, + NestedOp { // `(f32, f32) -> f32` - FloatTy::F32, - Signature { + float_ty: FloatTy::F32, + rust_sig: Signature { args: &[Ty::F32, Ty::F32], returns: &[Ty::F32], }, - None, - &[ + c_sig: None, + fn_list: &[ "atan2f", "copysignf", "fdimf", @@ -182,16 +197,17 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] "powf", "remainderf", ], - ), - ( + public: true, + }, + NestedOp { // `(f64, f64) -> f64` - FloatTy::F64, - Signature { + float_ty: FloatTy::F64, + rust_sig: Signature { args: &[Ty::F64, Ty::F64], returns: &[Ty::F64], }, - None, - &[ + c_sig: None, + fn_list: &[ "atan2", "copysign", "fdim", @@ -207,16 +223,17 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] "pow", "remainder", ], - ), - ( + public: true, + }, + NestedOp { // `(f128, f128) -> f128` - FloatTy::F128, - Signature { + float_ty: FloatTy::F128, + rust_sig: Signature { args: &[Ty::F128, Ty::F128], returns: &[Ty::F128], }, - None, - &[ + c_sig: None, + fn_list: &[ "copysignf128", "fdimf128", "fmaxf128", @@ -227,221 +244,241 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] "fminimumf128", "fmodf128", ], - ), - ( + public: true, + }, + NestedOp { // `(f32, f32, f32) -> f32` - FloatTy::F32, - Signature { + float_ty: FloatTy::F32, + rust_sig: Signature { args: &[Ty::F32, Ty::F32, Ty::F32], returns: &[Ty::F32], }, - None, - &["fmaf"], - ), - ( + c_sig: None, + fn_list: &["fmaf"], + public: true, + }, + NestedOp { // `(f64, f64, f64) -> f64` - FloatTy::F64, - Signature { + float_ty: FloatTy::F64, + rust_sig: Signature { args: &[Ty::F64, Ty::F64, Ty::F64], returns: &[Ty::F64], }, - None, - &["fma"], - ), - ( + c_sig: None, + fn_list: &["fma"], + public: true, + }, + NestedOp { // `(f128, f128, f128) -> f128` - FloatTy::F128, - Signature { + float_ty: FloatTy::F128, + rust_sig: Signature { args: &[Ty::F128, Ty::F128, Ty::F128], returns: &[Ty::F128], }, - None, - &["fmaf128"], - ), - ( + c_sig: None, + fn_list: &["fmaf128"], + public: true, + }, + NestedOp { // `(f32) -> i32` - FloatTy::F32, - Signature { + float_ty: FloatTy::F32, + rust_sig: Signature { args: &[Ty::F32], returns: &[Ty::I32], }, - None, - &["ilogbf"], - ), - ( + c_sig: None, + fn_list: &["ilogbf"], + public: true, + }, + NestedOp { // `(f64) -> i32` - FloatTy::F64, - Signature { + float_ty: FloatTy::F64, + rust_sig: Signature { args: &[Ty::F64], returns: &[Ty::I32], }, - None, - &["ilogb"], - ), - ( + c_sig: None, + fn_list: &["ilogb"], + public: true, + }, + NestedOp { // `(i32, f32) -> f32` - FloatTy::F32, - Signature { + float_ty: FloatTy::F32, + rust_sig: Signature { args: &[Ty::I32, Ty::F32], returns: &[Ty::F32], }, - None, - &["jnf", "ynf"], - ), - ( + c_sig: None, + fn_list: &["jnf", "ynf"], + public: true, + }, + NestedOp { // `(i32, f64) -> f64` - FloatTy::F64, - Signature { + float_ty: FloatTy::F64, + rust_sig: Signature { args: &[Ty::I32, Ty::F64], returns: &[Ty::F64], }, - None, - &["jn", "yn"], - ), - ( + c_sig: None, + fn_list: &["jn", "yn"], + public: true, + }, + NestedOp { // `(f16, i32) -> f16` - FloatTy::F16, - Signature { + float_ty: FloatTy::F16, + rust_sig: Signature { args: &[Ty::F16, Ty::I32], returns: &[Ty::F16], }, - None, - &["ldexpf16", "scalbnf16"], - ), - ( + c_sig: None, + fn_list: &["ldexpf16", "scalbnf16"], + public: true, + }, + NestedOp { // `(f32, i32) -> f32` - FloatTy::F32, - Signature { + float_ty: FloatTy::F32, + rust_sig: Signature { args: &[Ty::F32, Ty::I32], returns: &[Ty::F32], }, - None, - &["ldexpf", "scalbnf"], - ), - ( + c_sig: None, + fn_list: &["ldexpf", "scalbnf"], + public: true, + }, + NestedOp { // `(f64, i64) -> f64` - FloatTy::F64, - Signature { + float_ty: FloatTy::F64, + rust_sig: Signature { args: &[Ty::F64, Ty::I32], returns: &[Ty::F64], }, - None, - &["ldexp", "scalbn"], - ), - ( + c_sig: None, + fn_list: &["ldexp", "scalbn"], + public: true, + }, + NestedOp { // `(f128, i32) -> f128` - FloatTy::F128, - Signature { + float_ty: FloatTy::F128, + rust_sig: Signature { args: &[Ty::F128, Ty::I32], returns: &[Ty::F128], }, - None, - &["ldexpf128", "scalbnf128"], - ), - ( + c_sig: None, + fn_list: &["ldexpf128", "scalbnf128"], + public: true, + }, + NestedOp { // `(f32, &mut f32) -> f32` as `(f32) -> (f32, f32)` - FloatTy::F32, - Signature { + float_ty: FloatTy::F32, + rust_sig: Signature { args: &[Ty::F32], returns: &[Ty::F32, Ty::F32], }, - Some(Signature { + c_sig: Some(Signature { args: &[Ty::F32, Ty::MutF32], returns: &[Ty::F32], }), - &["modff"], - ), - ( + fn_list: &["modff"], + public: true, + }, + NestedOp { // `(f64, &mut f64) -> f64` as `(f64) -> (f64, f64)` - FloatTy::F64, - Signature { + float_ty: FloatTy::F64, + rust_sig: Signature { args: &[Ty::F64], returns: &[Ty::F64, Ty::F64], }, - Some(Signature { + c_sig: Some(Signature { args: &[Ty::F64, Ty::MutF64], returns: &[Ty::F64], }), - &["modf"], - ), - ( + fn_list: &["modf"], + public: true, + }, + NestedOp { // `(f32, &mut c_int) -> f32` as `(f32) -> (f32, i32)` - FloatTy::F32, - Signature { + float_ty: FloatTy::F32, + rust_sig: Signature { args: &[Ty::F32], returns: &[Ty::F32, Ty::I32], }, - Some(Signature { + c_sig: Some(Signature { args: &[Ty::F32, Ty::MutCInt], returns: &[Ty::F32], }), - &["frexpf", "lgammaf_r"], - ), - ( + fn_list: &["frexpf", "lgammaf_r"], + public: true, + }, + NestedOp { // `(f64, &mut c_int) -> f64` as `(f64) -> (f64, i32)` - FloatTy::F64, - Signature { + float_ty: FloatTy::F64, + rust_sig: Signature { args: &[Ty::F64], returns: &[Ty::F64, Ty::I32], }, - Some(Signature { + c_sig: Some(Signature { args: &[Ty::F64, Ty::MutCInt], returns: &[Ty::F64], }), - &["frexp", "lgamma_r"], - ), - ( + fn_list: &["frexp", "lgamma_r"], + public: true, + }, + NestedOp { // `(f32, f32, &mut c_int) -> f32` as `(f32, f32) -> (f32, i32)` - FloatTy::F32, - Signature { + float_ty: FloatTy::F32, + rust_sig: Signature { args: &[Ty::F32, Ty::F32], returns: &[Ty::F32, Ty::I32], }, - Some(Signature { + c_sig: Some(Signature { args: &[Ty::F32, Ty::F32, Ty::MutCInt], returns: &[Ty::F32], }), - &["remquof"], - ), - ( + fn_list: &["remquof"], + public: true, + }, + NestedOp { // `(f64, f64, &mut c_int) -> f64` as `(f64, f64) -> (f64, i32)` - FloatTy::F64, - Signature { + float_ty: FloatTy::F64, + rust_sig: Signature { args: &[Ty::F64, Ty::F64], returns: &[Ty::F64, Ty::I32], }, - Some(Signature { + c_sig: Some(Signature { args: &[Ty::F64, Ty::F64, Ty::MutCInt], returns: &[Ty::F64], }), - &["remquo"], - ), - ( + fn_list: &["remquo"], + public: true, + }, + NestedOp { // `(f32, &mut f32, &mut f32)` as `(f32) -> (f32, f32)` - FloatTy::F32, - Signature { + float_ty: FloatTy::F32, + rust_sig: Signature { args: &[Ty::F32], returns: &[Ty::F32, Ty::F32], }, - Some(Signature { + c_sig: Some(Signature { args: &[Ty::F32, Ty::MutF32, Ty::MutF32], returns: &[], }), - &["sincosf"], - ), - ( + fn_list: &["sincosf"], + public: true, + }, + NestedOp { // `(f64, &mut f64, &mut f64)` as `(f64) -> (f64, f64)` - FloatTy::F64, - Signature { + float_ty: FloatTy::F64, + rust_sig: Signature { args: &[Ty::F64], returns: &[Ty::F64, Ty::F64], }, - Some(Signature { + c_sig: Some(Signature { args: &[Ty::F64, Ty::MutF64, Ty::MutF64], returns: &[], }), - &["sincos"], - ), + fn_list: &["sincos"], + public: true, + }, ]; /// A type used in a function signature. @@ -520,27 +557,31 @@ pub struct MathOpInfo { 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 (base_fty, rust_sig, c_sig, names) in ALL_OPERATIONS_NESTED { - for name in *names { + for op in ALL_OPERATIONS_NESTED { + let fn_names = op.fn_list; + for name in fn_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()), + 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 !names.is_sorted() { - let mut sorted = (*names).to_owned(); + if !fn_names.is_sorted() { + let mut sorted = (*fn_names).to_owned(); sorted.sort_unstable(); - panic!("names list is not sorted: {names:?}\nExpected: {sorted:?}"); + panic!("names list is not sorted: {fn_names:?}\nExpected: {sorted:?}"); } } diff --git a/library/compiler-builtins/crates/libm-macros/tests/basic.rs b/library/compiler-builtins/crates/libm-macros/tests/basic.rs index 5314e84bbb0a..260350ef254e 100644 --- a/library/compiler-builtins/crates/libm-macros/tests/basic.rs +++ b/library/compiler-builtins/crates/libm-macros/tests/basic.rs @@ -13,6 +13,7 @@ macro_rules! basic { RustFn: $RustFn:ty, RustArgs: $RustArgs:ty, RustRet: $RustRet:ty, + public: $public:expr, attrs: [$($attr:meta),*], extra: [$($extra_tt:tt)*], fn_extra: $fn_extra:expr, @@ -25,6 +26,7 @@ macro_rules! basic { type RustFnTy = $RustFn; type RustArgsTy = $RustArgs; type RustRetTy = $RustRet; + const PUBLIC: bool = $public; const A: &[&str] = &[$($extra_tt)*]; fn foo(a: f32) -> f32 { $fn_extra(a) diff --git a/library/compiler-builtins/libm-test/src/op.rs b/library/compiler-builtins/libm-test/src/op.rs index bd17aad7d035..afd445ff9c5a 100644 --- a/library/compiler-builtins/libm-test/src/op.rs +++ b/library/compiler-builtins/libm-test/src/op.rs @@ -90,6 +90,9 @@ pub trait MathOp { /// The function in `libm` which can be called. const ROUTINE: Self::RustFn; + + /// Whether or not the function is part of libm public API. + const PUBLIC: bool; } /// Access the associated `FTy` type from an op (helper to avoid ambiguous associated types). @@ -107,7 +110,7 @@ pub type OpRustArgs = ::RustArgs; /// Access the associated `RustRet` type from an op (helper to avoid ambiguous associated types). pub type OpRustRet = ::RustRet; -macro_rules! do_thing { +macro_rules! create_op_modules { // Matcher for unary functions ( fn_name: $fn_name:ident, @@ -118,8 +121,8 @@ macro_rules! do_thing { RustFn: $RustFn:ty, RustArgs: $RustArgs:ty, RustRet: $RustRet:ty, + public: $public:expr, attrs: [$($attr:meta),*], - ) => { paste::paste! { $(#[$attr])* @@ -138,6 +141,7 @@ macro_rules! do_thing { const IDENTIFIER: Identifier = Identifier::[< $fn_name:camel >]; const ROUTINE: Self::RustFn = libm::$fn_name; + const PUBLIC: bool = $public; } } @@ -146,6 +150,6 @@ macro_rules! do_thing { } libm_macros::for_each_function! { - callback: do_thing, + callback: create_op_modules, emit_types: all, }