1 | /// `libm` cannot have dependencies, so this is vendored directly from the `cfg-if` crate |
2 | /// (with some comments stripped for compactness). |
3 | macro_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. |
52 | macro_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)] |
95 | macro_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)] |
106 | macro_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)] |
117 | macro_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)] |
129 | macro_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)] |
138 | macro_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 | } |
158 | |