Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions crates/libm-macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
/// },
/// }
Expand All @@ -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
Expand Down Expand Up @@ -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);
}
Expand Down
16 changes: 15 additions & 1 deletion crates/libm-macros/src/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down Expand Up @@ -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
Expand All @@ -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();
Expand All @@ -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())?),
Expand Down Expand Up @@ -122,6 +130,7 @@ impl StructuredInput {
callback: expect_ident(cb_expr)?,
emit_types,
skip,
skip_f16_f128,
only,
only_span,
attributes,
Expand Down Expand Up @@ -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) {
Expand Down
72 changes: 72 additions & 0 deletions crates/libm-macros/tests/basic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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}");
}
}
44 changes: 4 additions & 40 deletions crates/util/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}
Expand Down
45 changes: 4 additions & 41 deletions libm-test/benches/random.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
43 changes: 3 additions & 40 deletions libm-test/tests/compare_built_musl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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
],
}
Loading