about summary refs log tree commit diff
diff options
context:
space:
mode:
authorTrevor Gross <tmgross@umich.edu>2025-04-23 07:47:48 +0000
committerTrevor Gross <t.gross35@gmail.com>2025-04-23 15:04:51 -0400
commit99202af0758bbeb9909acf848de3cd968a41148f (patch)
tree859351306dc714d9dbe28de7f3194c15cb51d74f
parent1dd39e27f06d0028bc62452283cf00a2d932d981 (diff)
downloadrust-99202af0758bbeb9909acf848de3cd968a41148f.tar.gz
rust-99202af0758bbeb9909acf848de3cd968a41148f.zip
libm-macros: Allow a way to bulk match f16 and f128 functions
These are never available in musl, so introduce easier ways to skip them
rather than needing to exclude f16/f128 functions in three different
places.
-rw-r--r--library/compiler-builtins/crates/libm-macros/src/lib.rs30
-rw-r--r--library/compiler-builtins/crates/libm-macros/src/parse.rs16
-rw-r--r--library/compiler-builtins/crates/libm-macros/tests/basic.rs72
-rw-r--r--library/compiler-builtins/crates/util/src/main.rs44
-rw-r--r--library/compiler-builtins/libm-test/benches/random.rs45
-rw-r--r--library/compiler-builtins/libm-test/tests/compare_built_musl.rs43
6 files changed, 128 insertions, 122 deletions
diff --git a/library/compiler-builtins/crates/libm-macros/src/lib.rs b/library/compiler-builtins/crates/libm-macros/src/lib.rs
index 144676c1253..e8afe3aad55 100644
--- a/library/compiler-builtins/crates/libm-macros/src/lib.rs
+++ b/library/compiler-builtins/crates/libm-macros/src/lib.rs
@@ -116,6 +116,9 @@ pub fn base_name_enum(attributes: pm::TokenStream, tokens: pm::TokenStream) -> p
 ///     // a simplified match-like syntax.
 ///     fn_extra: match MACRO_FN_NAME {
 ///         hypot | hypotf => |x| x.hypot(),
+///         // `ALL_*` magic matchers also work to extract specific types
+///         ALL_F64 => |x| x,
+///         // The default pattern gets applied to everything that did not match
 ///         _ => |x| x,
 ///     },
 /// }
@@ -138,6 +141,27 @@ pub fn for_each_function(tokens: pm::TokenStream) -> pm::TokenStream {
 ///
 /// Returns the list of function names that we should expand for.
 fn validate(input: &mut StructuredInput) -> syn::Result<Vec<&'static MathOpInfo>> {
+    // Replace magic mappers with a list of relevant functions.
+    if let Some(map) = &mut input.fn_extra {
+        for (name, ty) in [
+            ("ALL_F16", FloatTy::F16),
+            ("ALL_F32", FloatTy::F32),
+            ("ALL_F64", FloatTy::F64),
+            ("ALL_F128", FloatTy::F128),
+        ] {
+            let Some(k) = map.keys().find(|key| *key == name) else {
+                continue;
+            };
+
+            let key = k.clone();
+            let val = map.remove(&key).unwrap();
+
+            for op in ALL_OPERATIONS.iter().filter(|op| op.float_ty == ty) {
+                map.insert(Ident::new(op.name, key.span()), val.clone());
+            }
+        }
+    }
+
     // Collect lists of all functions that are provied as macro inputs in various fields (only,
     // skip, attributes).
     let attr_mentions = input
@@ -195,6 +219,12 @@ fn validate(input: &mut StructuredInput) -> syn::Result<Vec<&'static MathOpInfo>
             continue;
         }
 
+        // Omit f16 and f128 functions if requested
+        if input.skip_f16_f128 && (func.float_ty == FloatTy::F16 || func.float_ty == FloatTy::F128)
+        {
+            continue;
+        }
+
         // Run everything else
         fn_list.push(func);
     }
diff --git a/library/compiler-builtins/crates/libm-macros/src/parse.rs b/library/compiler-builtins/crates/libm-macros/src/parse.rs
index d60d1247a9e..4876f3ef726 100644
--- a/library/compiler-builtins/crates/libm-macros/src/parse.rs
+++ b/library/compiler-builtins/crates/libm-macros/src/parse.rs
@@ -6,7 +6,7 @@ use syn::parse::{Parse, ParseStream, Parser};
 use syn::punctuated::Punctuated;
 use syn::spanned::Spanned;
 use syn::token::{self, Comma};
-use syn::{Arm, Attribute, Expr, ExprMatch, Ident, Meta, Token, bracketed};
+use syn::{Arm, Attribute, Expr, ExprMatch, Ident, LitBool, Meta, Token, bracketed};
 
 /// The input to our macro; just a list of `field: value` items.
 #[derive(Debug)]
@@ -50,6 +50,8 @@ pub struct StructuredInput {
     pub emit_types: Vec<Ident>,
     /// Skip these functions
     pub skip: Vec<Ident>,
+    /// If true, omit f16 and f128 functions that aren't present in other libraries.
+    pub skip_f16_f128: bool,
     /// Invoke only for these functions
     pub only: Option<Vec<Ident>>,
     /// Attributes that get applied to specific functions
@@ -70,6 +72,7 @@ impl StructuredInput {
         let cb_expr = expect_field(&mut map, "callback")?;
         let emit_types_expr = expect_field(&mut map, "emit_types").ok();
         let skip_expr = expect_field(&mut map, "skip").ok();
+        let skip_f16_f128 = expect_field(&mut map, "skip_f16_f128").ok();
         let only_expr = expect_field(&mut map, "only").ok();
         let attr_expr = expect_field(&mut map, "attributes").ok();
         let extra = expect_field(&mut map, "extra").ok();
@@ -93,6 +96,11 @@ impl StructuredInput {
             None => Vec::new(),
         };
 
+        let skip_f16_f128 = match skip_f16_f128 {
+            Some(expr) => expect_litbool(expr)?.value,
+            None => false,
+        };
+
         let only_span = only_expr.as_ref().map(|expr| expr.span());
         let only = match only_expr {
             Some(expr) => Some(Parser::parse2(parse_ident_array, expr.into_token_stream())?),
@@ -122,6 +130,7 @@ impl StructuredInput {
             callback: expect_ident(cb_expr)?,
             emit_types,
             skip,
+            skip_f16_f128,
             only,
             only_span,
             attributes,
@@ -220,6 +229,11 @@ fn expect_ident(expr: Expr) -> syn::Result<Ident> {
     syn::parse2(expr.into_token_stream())
 }
 
+/// Coerce an expression into a simple keyword.
+fn expect_litbool(expr: Expr) -> syn::Result<LitBool> {
+    syn::parse2(expr.into_token_stream())
+}
+
 /// Parse either a single identifier (`foo`) or an array of identifiers (`[foo, bar, baz]`).
 fn parse_ident_or_array(input: ParseStream) -> syn::Result<Vec<Ident>> {
     if !input.peek(token::Bracket) {
diff --git a/library/compiler-builtins/crates/libm-macros/tests/basic.rs b/library/compiler-builtins/crates/libm-macros/tests/basic.rs
index 260350ef254..b4276262229 100644
--- a/library/compiler-builtins/crates/libm-macros/tests/basic.rs
+++ b/library/compiler-builtins/crates/libm-macros/tests/basic.rs
@@ -103,3 +103,75 @@ mod test_emit_types {
         emit_types: [RustFn, RustArgs],
     }
 }
+
+#[test]
+fn test_skip_f16_f128() {
+    macro_rules! skip_f16_f128 {
+        (
+        fn_name: $fn_name:ident,
+        attrs: [$($attr:meta),*],
+        extra: $vec:ident,
+    ) => {
+            $vec.push(stringify!($fn_name));
+        };
+    }
+
+    let mut v = Vec::new();
+    // Test with no extra, no skip, and no attributes
+    libm_macros::for_each_function! {
+        callback: skip_f16_f128,
+        skip_f16_f128: true,
+        extra: v,
+    }
+
+    for name in v {
+        assert!(!name.contains("f16"), "{name}");
+        assert!(!name.contains("f128"), "{name}");
+    }
+}
+
+#[test]
+fn test_fn_extra_expansion() {
+    macro_rules! fn_extra_expansion {
+        (
+            fn_name: $fn_name:ident,
+            attrs: [$($attr:meta),*],
+            fn_extra: $vec:expr,
+        ) => {
+            $vec.push(stringify!($fn_name));
+        };
+    }
+
+    let mut vf16 = Vec::new();
+    let mut vf32 = Vec::new();
+    let mut vf64 = Vec::new();
+    let mut vf128 = Vec::new();
+
+    // Test with no extra, no skip, and no attributes
+    libm_macros::for_each_function! {
+        callback: fn_extra_expansion,
+        fn_extra: match MACRO_FN_NAME {
+            ALL_F16 => vf16,
+            ALL_F32 => vf32,
+            ALL_F64 => vf64,
+            ALL_F128 => vf128,
+        }
+    }
+
+    // Skip functions with a suffix after the type spec
+    vf16.retain(|name| !name.ends_with("_r"));
+    vf32.retain(|name| !name.ends_with("_r"));
+    vf64.retain(|name| !name.ends_with("_r"));
+    vf128.retain(|name| !name.ends_with("_r"));
+
+    for name in vf16 {
+        assert!(name.ends_with("f16"), "{name}");
+    }
+    for name in vf32 {
+        assert!(name.ends_with("f"), "{name}");
+    }
+    let _ = vf64;
+    for name in vf128 {
+        assert!(name.ends_with("f128"), "{name}");
+    }
+}
diff --git a/library/compiler-builtins/crates/util/src/main.rs b/library/compiler-builtins/crates/util/src/main.rs
index e7057869996..5972181531b 100644
--- a/library/compiler-builtins/crates/util/src/main.rs
+++ b/library/compiler-builtins/crates/util/src/main.rs
@@ -86,55 +86,19 @@ fn do_eval(basis: &str, op: &str, inputs: &[&str]) {
         emit_types: [CFn, RustFn, RustArgs],
         extra: (basis, op, inputs),
         fn_extra: match MACRO_FN_NAME {
-            ceilf128
-            | ceilf16
-            | copysignf128
-            | copysignf16
-            | fabsf128
-            | fabsf16
-            | fdimf128
-            | fdimf16
-            | floorf128
-            | floorf16
-            | fmaf128
-            | fmaxf128
-            | fmaxf16
-            | fmaximum
+            // Not provided by musl
+            fmaximum
             | fmaximum_num
             | fmaximum_numf
-            | fmaximum_numf128
-            | fmaximum_numf16
             | fmaximumf
-            | fmaximumf128
-            | fmaximumf16
-            | fminf128
-            | fminf16
             | fminimum
             | fminimum_num
             | fminimum_numf
-            | fminimum_numf128
-            | fminimum_numf16
             | fminimumf
-            | fminimumf128
-            | fminimumf16
-            | fmodf128
-            | fmodf16
-            | ldexpf128
-            | ldexpf16
-            | rintf128
-            | rintf16
             | roundeven
             | roundevenf
-            | roundevenf128
-            | roundevenf16
-            | roundf128
-            | roundf16
-            | scalbnf128
-            | scalbnf16
-            | sqrtf128
-            | sqrtf16
-            | truncf128
-            | truncf16  => None,
+            | ALL_F16
+            | ALL_F128 => None,
             _ => Some(musl_math_sys::MACRO_FN_NAME)
         }
     }
diff --git a/library/compiler-builtins/libm-test/benches/random.rs b/library/compiler-builtins/libm-test/benches/random.rs
index 81f58e3a658..1b17f049eca 100644
--- a/library/compiler-builtins/libm-test/benches/random.rs
+++ b/library/compiler-builtins/libm-test/benches/random.rs
@@ -125,56 +125,19 @@ libm_macros::for_each_function! {
         // FIXME(correctness): exp functions have the wrong result on i586
         exp10 | exp10f | exp2 | exp2f => (true, Some(musl_math_sys::MACRO_FN_NAME)),
 
-        // Musl does not provide `f16` and `f128` functions
-        ceilf128
-        | ceilf16
-        | copysignf128
-        | copysignf16
-        | fabsf128
-        | fabsf16
-        | fdimf128
-        | fdimf16
-        | floorf128
-        | floorf16
-        | fmaf128
-        | fmaxf128
-        | fmaxf16
-        | fmaximum
+        // Musl does not provide `f16` and `f128` functions, as well as a handful of others
+        fmaximum
         | fmaximum_num
         | fmaximum_numf
-        | fmaximum_numf128
-        | fmaximum_numf16
         | fmaximumf
-        | fmaximumf128
-        | fmaximumf16
-        | fminf128
-        | fminf16
         | fminimum
         | fminimum_num
         | fminimum_numf
-        | fminimum_numf128
-        | fminimum_numf16
         | fminimumf
-        | fminimumf128
-        | fminimumf16
-        | fmodf128
-        | fmodf16
-        | ldexpf128
-        | ldexpf16
-        | rintf128
-        | rintf16
         | roundeven
         | roundevenf
-        | roundevenf128
-        | roundevenf16
-        | roundf128
-        | roundf16
-        | scalbnf128
-        | scalbnf16
-        | sqrtf128
-        | sqrtf16
-        | truncf128
-        | truncf16 => (false, None),
+        | ALL_F16
+        | ALL_F128 => (false, None),
 
         // By default we never skip (false) and always have a musl function available
         _ => (false, Some(musl_math_sys::MACRO_FN_NAME))
diff --git a/library/compiler-builtins/libm-test/tests/compare_built_musl.rs b/library/compiler-builtins/libm-test/tests/compare_built_musl.rs
index cbb4bd49b9c..6ccbb6f4c51 100644
--- a/library/compiler-builtins/libm-test/tests/compare_built_musl.rs
+++ b/library/compiler-builtins/libm-test/tests/compare_built_musl.rs
@@ -76,6 +76,8 @@ macro_rules! musl_tests {
 libm_macros::for_each_function! {
     callback: musl_tests,
     attributes: [],
+    // Not provided by musl
+    skip_f16_f128: true,
     skip: [
         // TODO integer inputs
         jn,
@@ -89,55 +91,16 @@ libm_macros::for_each_function! {
 
         // Not provided by musl
         // verify-sorted-start
-        ceilf128,
-        ceilf16,
-        copysignf128,
-        copysignf16,
-        fabsf128,
-        fabsf16,
-        fdimf128,
-        fdimf16,
-        floorf128,
-        floorf16,
-        fmaf128,
-        fmaxf128,
-        fmaxf16,
         fmaximum,
         fmaximum_num,
         fmaximum_numf,
-        fmaximum_numf128,
-        fmaximum_numf16,
         fmaximumf,
-        fmaximumf128,
-        fmaximumf16,
-        fminf128,
-        fminf16,
         fminimum,
         fminimum_num,
         fminimum_numf,
-        fminimum_numf128,
-        fminimum_numf16,
         fminimumf,
-        fminimumf128,
-        fminimumf16,
-        fmodf128,
-        fmodf16,
-        ldexpf128,
-        ldexpf16,
-        rintf128,
-        rintf16,
         roundeven,
         roundevenf,
-        roundevenf128,
-        roundevenf16,
-        roundf128,
-        roundf16,
-        scalbnf128,
-        scalbnf16,
-        sqrtf128,
-        sqrtf16,
-        truncf128,
-        truncf16,
-        // verify-sorted-end
+        // // verify-sorted-end
     ],
 }