diff options
Diffstat (limited to 'library/compiler-builtins/crates')
4 files changed, 121 insertions, 41 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) } } | 
