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