libm/math/support/macros.rs
1/// `libm` cannot have dependencies, so this is vendored directly from the `cfg-if` crate
2/// (with some comments stripped for compactness).
3macro_rules! cfg_if {
4 // match if/else chains with a final `else`
5 ($(
6 if #[cfg($meta:meta)] { $($tokens:tt)* }
7 ) else * else {
8 $($tokens2:tt)*
9 }) => {
10 cfg_if! { @__items () ; $( ( ($meta) ($($tokens)*) ), )* ( () ($($tokens2)*) ), }
11 };
12
13 // match if/else chains lacking a final `else`
14 (
15 if #[cfg($i_met:meta)] { $($i_tokens:tt)* }
16 $( else if #[cfg($e_met:meta)] { $($e_tokens:tt)* } )*
17 ) => {
18 cfg_if! {
19 @__items
20 () ;
21 ( ($i_met) ($($i_tokens)*) ),
22 $( ( ($e_met) ($($e_tokens)*) ), )*
23 ( () () ),
24 }
25 };
26
27 // Internal and recursive macro to emit all the items
28 //
29 // Collects all the negated cfgs in a list at the beginning and after the
30 // semicolon is all the remaining items
31 (@__items ($($not:meta,)*) ; ) => {};
32 (@__items ($($not:meta,)*) ; ( ($($m:meta),*) ($($tokens:tt)*) ), $($rest:tt)*) => {
33 #[cfg(all($($m,)* not(any($($not),*))))] cfg_if! { @__identity $($tokens)* }
34 cfg_if! { @__items ($($not,)* $($m,)*) ; $($rest)* }
35 };
36
37 // Internal macro to make __apply work out right for different match types,
38 // because of how macros matching/expand stuff.
39 (@__identity $($tokens:tt)*) => { $($tokens)* };
40}
41
42/// Choose between using an arch-specific implementation and the function body. Returns directly
43/// if the arch implementation is used, otherwise continue with the rest of the function.
44///
45/// Specify a `use_arch` meta field if an architecture-specific implementation is provided.
46/// These live in the `math::arch::some_target_arch` module.
47///
48/// Specify a `use_arch_required` meta field if something architecture-specific must be used
49/// regardless of feature configuration (`force-soft-floats`).
50///
51/// The passed meta options do not need to account for the `arch` target feature.
52macro_rules! select_implementation {
53 (
54 name: $fn_name:ident,
55 // Configuration meta for when to use arch-specific implementation that requires hard
56 // float ops
57 $( use_arch: $use_arch:meta, )?
58 // Configuration meta for when to use the arch module regardless of whether softfloats
59 // have been requested.
60 $( use_arch_required: $use_arch_required:meta, )?
61 args: $($arg:ident),+ ,
62 ) => {
63 // FIXME: these use paths that are a pretty fragile (`super`). We should figure out
64 // something better w.r.t. how this is vendored into compiler-builtins.
65
66 // However, we do need a few things from `arch` that are used even with soft floats.
67 select_implementation! {
68 @cfg $($use_arch_required)?;
69 if true {
70 return super::arch::$fn_name( $($arg),+ );
71 }
72 }
73
74 // By default, never use arch-specific implementations if we have force-soft-floats
75 #[cfg(arch_enabled)]
76 select_implementation! {
77 @cfg $($use_arch)?;
78 // Wrap in `if true` to avoid unused warnings
79 if true {
80 return super::arch::$fn_name( $($arg),+ );
81 }
82 }
83 };
84
85 // Coalesce helper to construct an expression only if a config is provided
86 (@cfg ; $ex:expr) => { };
87 (@cfg $provided:meta; $ex:expr) => { #[cfg($provided)] $ex };
88}
89
90/// Construct a 16-bit float from hex float representation (C-style), guaranteed to
91/// evaluate at compile time.
92#[cfg(f16_enabled)]
93#[cfg_attr(feature = "unstable-public-internals", macro_export)]
94#[allow(unused_macros)]
95macro_rules! hf16 {
96 ($s:literal) => {{
97 const X: f16 = $crate::support::hf16($s);
98 X
99 }};
100}
101
102/// Construct a 32-bit float from hex float representation (C-style), guaranteed to
103/// evaluate at compile time.
104#[allow(unused_macros)]
105#[cfg_attr(feature = "unstable-public-internals", macro_export)]
106macro_rules! hf32 {
107 ($s:literal) => {{
108 const X: f32 = $crate::support::hf32($s);
109 X
110 }};
111}
112
113/// Construct a 64-bit float from hex float representation (C-style), guaranteed to
114/// evaluate at compile time.
115#[allow(unused_macros)]
116#[cfg_attr(feature = "unstable-public-internals", macro_export)]
117macro_rules! hf64 {
118 ($s:literal) => {{
119 const X: f64 = $crate::support::hf64($s);
120 X
121 }};
122}
123
124/// Construct a 128-bit float from hex float representation (C-style), guaranteed to
125/// evaluate at compile time.
126#[cfg(f128_enabled)]
127#[allow(unused_macros)]
128#[cfg_attr(feature = "unstable-public-internals", macro_export)]
129macro_rules! hf128 {
130 ($s:literal) => {{
131 const X: f128 = $crate::support::hf128($s);
132 X
133 }};
134}
135
136/// Assert `F::biteq` with better messages.
137#[cfg(test)]
138macro_rules! assert_biteq {
139 ($left:expr, $right:expr, $($tt:tt)*) => {{
140 use $crate::support::Int;
141 let l = $left;
142 let r = $right;
143 let bits = Int::leading_zeros(l.to_bits() - l.to_bits()); // hack to get the width from the value
144 assert!(
145 l.biteq(r),
146 "{}\nl: {l:?} ({lb:#0width$x})\nr: {r:?} ({rb:#0width$x})",
147 format_args!($($tt)*),
148 lb = l.to_bits(),
149 rb = r.to_bits(),
150 width = ((bits / 4) + 2) as usize,
151
152 );
153 }};
154 ($left:expr, $right:expr $(,)?) => {
155 assert_biteq!($left, $right, "")
156 };
157}