Skip to content

Commit bf79280

Browse files
committed
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.
1 parent 672ba57 commit bf79280

File tree

6 files changed

+128
-122
lines changed

6 files changed

+128
-122
lines changed

crates/libm-macros/src/lib.rs

+30
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,9 @@ pub fn base_name_enum(attributes: pm::TokenStream, tokens: pm::TokenStream) -> p
116116
/// // a simplified match-like syntax.
117117
/// fn_extra: match MACRO_FN_NAME {
118118
/// hypot | hypotf => |x| x.hypot(),
119+
/// // `ALL_*` magic matchers also work to extract specific types
120+
/// ALL_F64 => |x| x,
121+
/// // The default pattern gets applied to everything that did not match
119122
/// _ => |x| x,
120123
/// },
121124
/// }
@@ -138,6 +141,27 @@ pub fn for_each_function(tokens: pm::TokenStream) -> pm::TokenStream {
138141
///
139142
/// Returns the list of function names that we should expand for.
140143
fn validate(input: &mut StructuredInput) -> syn::Result<Vec<&'static MathOpInfo>> {
144+
// Replace magic mappers with a list of relevant functions.
145+
if let Some(map) = &mut input.fn_extra {
146+
for (name, ty) in [
147+
("ALL_F16", FloatTy::F16),
148+
("ALL_F32", FloatTy::F32),
149+
("ALL_F64", FloatTy::F64),
150+
("ALL_F128", FloatTy::F128),
151+
] {
152+
let Some(k) = map.keys().find(|key| *key == name) else {
153+
continue;
154+
};
155+
156+
let key = k.clone();
157+
let val = map.remove(&key).unwrap();
158+
159+
for op in ALL_OPERATIONS.iter().filter(|op| op.float_ty == ty) {
160+
map.insert(Ident::new(op.name, key.span()), val.clone());
161+
}
162+
}
163+
}
164+
141165
// Collect lists of all functions that are provied as macro inputs in various fields (only,
142166
// skip, attributes).
143167
let attr_mentions = input
@@ -195,6 +219,12 @@ fn validate(input: &mut StructuredInput) -> syn::Result<Vec<&'static MathOpInfo>
195219
continue;
196220
}
197221

222+
// Omit f16 and f128 functions if requested
223+
if input.skip_f16_f128 && (func.float_ty == FloatTy::F16 || func.float_ty == FloatTy::F128)
224+
{
225+
continue;
226+
}
227+
198228
// Run everything else
199229
fn_list.push(func);
200230
}

crates/libm-macros/src/parse.rs

+15-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use syn::parse::{Parse, ParseStream, Parser};
66
use syn::punctuated::Punctuated;
77
use syn::spanned::Spanned;
88
use syn::token::{self, Comma};
9-
use syn::{Arm, Attribute, Expr, ExprMatch, Ident, Meta, Token, bracketed};
9+
use syn::{Arm, Attribute, Expr, ExprMatch, Ident, LitBool, Meta, Token, bracketed};
1010

1111
/// The input to our macro; just a list of `field: value` items.
1212
#[derive(Debug)]
@@ -50,6 +50,8 @@ pub struct StructuredInput {
5050
pub emit_types: Vec<Ident>,
5151
/// Skip these functions
5252
pub skip: Vec<Ident>,
53+
/// If true, omit f16 and f128 functions that aren't present in other libraries.
54+
pub skip_f16_f128: bool,
5355
/// Invoke only for these functions
5456
pub only: Option<Vec<Ident>>,
5557
/// Attributes that get applied to specific functions
@@ -70,6 +72,7 @@ impl StructuredInput {
7072
let cb_expr = expect_field(&mut map, "callback")?;
7173
let emit_types_expr = expect_field(&mut map, "emit_types").ok();
7274
let skip_expr = expect_field(&mut map, "skip").ok();
75+
let skip_f16_f128 = expect_field(&mut map, "skip_f16_f128").ok();
7376
let only_expr = expect_field(&mut map, "only").ok();
7477
let attr_expr = expect_field(&mut map, "attributes").ok();
7578
let extra = expect_field(&mut map, "extra").ok();
@@ -93,6 +96,11 @@ impl StructuredInput {
9396
None => Vec::new(),
9497
};
9598

99+
let skip_f16_f128 = match skip_f16_f128 {
100+
Some(expr) => expect_litbool(expr)?.value,
101+
None => false,
102+
};
103+
96104
let only_span = only_expr.as_ref().map(|expr| expr.span());
97105
let only = match only_expr {
98106
Some(expr) => Some(Parser::parse2(parse_ident_array, expr.into_token_stream())?),
@@ -122,6 +130,7 @@ impl StructuredInput {
122130
callback: expect_ident(cb_expr)?,
123131
emit_types,
124132
skip,
133+
skip_f16_f128,
125134
only,
126135
only_span,
127136
attributes,
@@ -220,6 +229,11 @@ fn expect_ident(expr: Expr) -> syn::Result<Ident> {
220229
syn::parse2(expr.into_token_stream())
221230
}
222231

232+
/// Coerce an expression into a simple keyword.
233+
fn expect_litbool(expr: Expr) -> syn::Result<LitBool> {
234+
syn::parse2(expr.into_token_stream())
235+
}
236+
223237
/// Parse either a single identifier (`foo`) or an array of identifiers (`[foo, bar, baz]`).
224238
fn parse_ident_or_array(input: ParseStream) -> syn::Result<Vec<Ident>> {
225239
if !input.peek(token::Bracket) {

crates/libm-macros/tests/basic.rs

+72
Original file line numberDiff line numberDiff line change
@@ -103,3 +103,75 @@ mod test_emit_types {
103103
emit_types: [RustFn, RustArgs],
104104
}
105105
}
106+
107+
#[test]
108+
fn test_skip_f16_f128() {
109+
macro_rules! skip_f16_f128 {
110+
(
111+
fn_name: $fn_name:ident,
112+
attrs: [$($attr:meta),*],
113+
extra: $vec:ident,
114+
) => {
115+
$vec.push(stringify!($fn_name));
116+
};
117+
}
118+
119+
let mut v = Vec::new();
120+
// Test with no extra, no skip, and no attributes
121+
libm_macros::for_each_function! {
122+
callback: skip_f16_f128,
123+
skip_f16_f128: true,
124+
extra: v,
125+
}
126+
127+
for name in v {
128+
assert!(!name.contains("f16"), "{name}");
129+
assert!(!name.contains("f128"), "{name}");
130+
}
131+
}
132+
133+
#[test]
134+
fn test_fn_extra_expansion() {
135+
macro_rules! fn_extra_expansion {
136+
(
137+
fn_name: $fn_name:ident,
138+
attrs: [$($attr:meta),*],
139+
fn_extra: $vec:expr,
140+
) => {
141+
$vec.push(stringify!($fn_name));
142+
};
143+
}
144+
145+
let mut vf16 = Vec::new();
146+
let mut vf32 = Vec::new();
147+
let mut vf64 = Vec::new();
148+
let mut vf128 = Vec::new();
149+
150+
// Test with no extra, no skip, and no attributes
151+
libm_macros::for_each_function! {
152+
callback: fn_extra_expansion,
153+
fn_extra: match MACRO_FN_NAME {
154+
ALL_F16 => vf16,
155+
ALL_F32 => vf32,
156+
ALL_F64 => vf64,
157+
ALL_F128 => vf128,
158+
}
159+
}
160+
161+
// Skip functions with a suffix after the type spec
162+
vf16.retain(|name| !name.ends_with("_r"));
163+
vf32.retain(|name| !name.ends_with("_r"));
164+
vf64.retain(|name| !name.ends_with("_r"));
165+
vf128.retain(|name| !name.ends_with("_r"));
166+
167+
for name in vf16 {
168+
assert!(name.ends_with("f16"), "{name}");
169+
}
170+
for name in vf32 {
171+
assert!(name.ends_with("f"), "{name}");
172+
}
173+
let _ = vf64;
174+
for name in vf128 {
175+
assert!(name.ends_with("f128"), "{name}");
176+
}
177+
}

crates/util/src/main.rs

+4-40
Original file line numberDiff line numberDiff line change
@@ -86,55 +86,19 @@ fn do_eval(basis: &str, op: &str, inputs: &[&str]) {
8686
emit_types: [CFn, RustFn, RustArgs],
8787
extra: (basis, op, inputs),
8888
fn_extra: match MACRO_FN_NAME {
89-
ceilf128
90-
| ceilf16
91-
| copysignf128
92-
| copysignf16
93-
| fabsf128
94-
| fabsf16
95-
| fdimf128
96-
| fdimf16
97-
| floorf128
98-
| floorf16
99-
| fmaf128
100-
| fmaxf128
101-
| fmaxf16
102-
| fmaximum
89+
// Not provided by musl
90+
fmaximum
10391
| fmaximum_num
10492
| fmaximum_numf
105-
| fmaximum_numf128
106-
| fmaximum_numf16
10793
| fmaximumf
108-
| fmaximumf128
109-
| fmaximumf16
110-
| fminf128
111-
| fminf16
11294
| fminimum
11395
| fminimum_num
11496
| fminimum_numf
115-
| fminimum_numf128
116-
| fminimum_numf16
11797
| fminimumf
118-
| fminimumf128
119-
| fminimumf16
120-
| fmodf128
121-
| fmodf16
122-
| ldexpf128
123-
| ldexpf16
124-
| rintf128
125-
| rintf16
12698
| roundeven
12799
| roundevenf
128-
| roundevenf128
129-
| roundevenf16
130-
| roundf128
131-
| roundf16
132-
| scalbnf128
133-
| scalbnf16
134-
| sqrtf128
135-
| sqrtf16
136-
| truncf128
137-
| truncf16 => None,
100+
| ALL_F16
101+
| ALL_F128 => None,
138102
_ => Some(musl_math_sys::MACRO_FN_NAME)
139103
}
140104
}

libm-test/benches/random.rs

+4-41
Original file line numberDiff line numberDiff line change
@@ -125,56 +125,19 @@ libm_macros::for_each_function! {
125125
// FIXME(correctness): exp functions have the wrong result on i586
126126
exp10 | exp10f | exp2 | exp2f => (true, Some(musl_math_sys::MACRO_FN_NAME)),
127127

128-
// Musl does not provide `f16` and `f128` functions
129-
ceilf128
130-
| ceilf16
131-
| copysignf128
132-
| copysignf16
133-
| fabsf128
134-
| fabsf16
135-
| fdimf128
136-
| fdimf16
137-
| floorf128
138-
| floorf16
139-
| fmaf128
140-
| fmaxf128
141-
| fmaxf16
142-
| fmaximum
128+
// Musl does not provide `f16` and `f128` functions, as well as a handful of others
129+
fmaximum
143130
| fmaximum_num
144131
| fmaximum_numf
145-
| fmaximum_numf128
146-
| fmaximum_numf16
147132
| fmaximumf
148-
| fmaximumf128
149-
| fmaximumf16
150-
| fminf128
151-
| fminf16
152133
| fminimum
153134
| fminimum_num
154135
| fminimum_numf
155-
| fminimum_numf128
156-
| fminimum_numf16
157136
| fminimumf
158-
| fminimumf128
159-
| fminimumf16
160-
| fmodf128
161-
| fmodf16
162-
| ldexpf128
163-
| ldexpf16
164-
| rintf128
165-
| rintf16
166137
| roundeven
167138
| roundevenf
168-
| roundevenf128
169-
| roundevenf16
170-
| roundf128
171-
| roundf16
172-
| scalbnf128
173-
| scalbnf16
174-
| sqrtf128
175-
| sqrtf16
176-
| truncf128
177-
| truncf16 => (false, None),
139+
| ALL_F16
140+
| ALL_F128 => (false, None),
178141

179142
// By default we never skip (false) and always have a musl function available
180143
_ => (false, Some(musl_math_sys::MACRO_FN_NAME))

libm-test/tests/compare_built_musl.rs

+3-40
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ macro_rules! musl_tests {
7676
libm_macros::for_each_function! {
7777
callback: musl_tests,
7878
attributes: [],
79+
// Not provided by musl
80+
skip_f16_f128: true,
7981
skip: [
8082
// TODO integer inputs
8183
jn,
@@ -89,55 +91,16 @@ libm_macros::for_each_function! {
8991

9092
// Not provided by musl
9193
// verify-sorted-start
92-
ceilf128,
93-
ceilf16,
94-
copysignf128,
95-
copysignf16,
96-
fabsf128,
97-
fabsf16,
98-
fdimf128,
99-
fdimf16,
100-
floorf128,
101-
floorf16,
102-
fmaf128,
103-
fmaxf128,
104-
fmaxf16,
10594
fmaximum,
10695
fmaximum_num,
10796
fmaximum_numf,
108-
fmaximum_numf128,
109-
fmaximum_numf16,
11097
fmaximumf,
111-
fmaximumf128,
112-
fmaximumf16,
113-
fminf128,
114-
fminf16,
11598
fminimum,
11699
fminimum_num,
117100
fminimum_numf,
118-
fminimum_numf128,
119-
fminimum_numf16,
120101
fminimumf,
121-
fminimumf128,
122-
fminimumf16,
123-
fmodf128,
124-
fmodf16,
125-
ldexpf128,
126-
ldexpf16,
127-
rintf128,
128-
rintf16,
129102
roundeven,
130103
roundevenf,
131-
roundevenf128,
132-
roundevenf16,
133-
roundf128,
134-
roundf16,
135-
scalbnf128,
136-
scalbnf16,
137-
sqrtf128,
138-
sqrtf16,
139-
truncf128,
140-
truncf16,
141-
// verify-sorted-end
104+
// // verify-sorted-end
142105
],
143106
}

0 commit comments

Comments
 (0)