Skip to content

Commit 1ba1389

Browse files
committed
Refactor float test macros to have a fallback
Change float test macros to fall back to testing against `rustc_apfloat` when system implementations are not available, rather than just skipping tests. This allows for easier debugging where operations may not be supported.
1 parent 1aea775 commit 1ba1389

File tree

5 files changed

+127
-36
lines changed

5 files changed

+127
-36
lines changed

testcrate/src/lib.rs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,3 +263,55 @@ pub fn fuzz_float_2<F: Float, E: Fn(F, F)>(n: u32, f: E) {
263263
f(x, y)
264264
}
265265
}
266+
267+
/// Perform an operation using builtin types if available, falling back to apfloat if not.
268+
#[macro_export]
269+
macro_rules! apfloat_fallback {
270+
(
271+
$float_ty:ty,
272+
// Type name in `rustc_apfloat::ieee`. Not a full path, it automatically gets the prefix.
273+
$apfloat_ty:ident,
274+
// Cfg expression for when builtin system operations should be used
275+
$sys_available:meta,
276+
// The expression to run. This expression may use `FloatTy` for its signature.
277+
// Optionally, the final conversion back to a float can be suppressed using
278+
// `=> no_convert` (for e.g. operations that return a bool).
279+
$op:expr $(=> $convert:ident)?,
280+
// Arguments that get passed to `$op` after converting to a float
281+
$($arg:expr),+
282+
$(,)?
283+
) => {{
284+
#[cfg($sys_available)]
285+
let ret = {
286+
type FloatTy = $float_ty;
287+
$op( $($arg),+ )
288+
};
289+
290+
#[cfg(not($sys_available))]
291+
let ret = {
292+
use rustc_apfloat::Float;
293+
type FloatTy = rustc_apfloat::ieee::$apfloat_ty;
294+
295+
let op_res = $op( $(FloatTy::from_bits($arg.to_bits().into())),+ );
296+
297+
apfloat_fallback!(@convert $float_ty, op_res $(,$convert)?)
298+
};
299+
300+
ret
301+
}};
302+
303+
// Operations that do not need converting back to a float
304+
(@convert $float_ty:ty, $val:expr, no_convert) => {
305+
$val
306+
};
307+
308+
// Some apfloat operations return a `StatusAnd` that we need to extract the value from. This
309+
// is the default.
310+
(@convert $float_ty:ty, $val:expr) => {{
311+
// ignore the status, just get the value
312+
let unwrapped = $val.value;
313+
314+
<$float_ty>::from_bits(FloatTy::to_bits(unwrapped).try_into().unwrap())
315+
}};
316+
317+
}

testcrate/tests/addsub.rs

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#![allow(unused_macros)]
22

3+
use core::ops::{Add, Sub};
34
use testcrate::*;
45

56
macro_rules! sum {
@@ -71,28 +72,28 @@ fn addsub() {
7172
}
7273

7374
macro_rules! float_sum {
74-
($($f:ty, $fn_add:ident, $fn_sub:ident);*;) => {
75+
($($f:ty, $fn_add:ident, $fn_sub:ident, $apfloat_ty:ident, $sys_available:meta);*;) => {
7576
$(
7677
fuzz_float_2(N, |x: $f, y: $f| {
77-
let add0 = x + y;
78-
let sub0 = x - y;
78+
let add0 = apfloat_fallback!($f, $apfloat_ty, $sys_available, Add::add, x, y);
79+
let sub0 = apfloat_fallback!($f, $apfloat_ty, $sys_available, Sub::sub, x, y);
7980
let add1: $f = $fn_add(x, y);
8081
let sub1: $f = $fn_sub(x, y);
8182
if !Float::eq_repr(add0, add1) {
8283
panic!(
83-
"{}({}, {}): std: {}, builtins: {}",
84+
"{}({:?}, {:?}): std: {:?}, builtins: {:?}",
8485
stringify!($fn_add), x, y, add0, add1
8586
);
8687
}
8788
if !Float::eq_repr(sub0, sub1) {
8889
panic!(
89-
"{}({}, {}): std: {}, builtins: {}",
90+
"{}({:?}, {:?}): std: {:?}, builtins: {:?}",
9091
stringify!($fn_sub), x, y, sub0, sub1
9192
);
9293
}
9394
});
9495
)*
95-
};
96+
}
9697
}
9798

9899
#[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))]
@@ -105,8 +106,8 @@ fn float_addsub() {
105106
};
106107

107108
float_sum!(
108-
f32, __addsf3, __subsf3;
109-
f64, __adddf3, __subdf3;
109+
f32, __addsf3, __subsf3, Single, all();
110+
f64, __adddf3, __subdf3, Double, all();
110111
);
111112
}
112113

@@ -120,7 +121,7 @@ fn float_addsub_arm() {
120121
};
121122

122123
float_sum!(
123-
f32, __addsf3vfp, __subsf3vfp;
124-
f64, __adddf3vfp, __subdf3vfp;
124+
f32, __addsf3vfp, __subsf3vfp, Single, all();
125+
f64, __adddf3vfp, __subdf3vfp, Double, all();
125126
);
126127
}

testcrate/tests/cmp.rs

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,48 @@
11
#![allow(unused_macros)]
2+
#![allow(unreachable_code)]
23

34
#[cfg(not(target_arch = "powerpc64"))]
45
use testcrate::*;
56

67
macro_rules! cmp {
7-
($x:ident, $y:ident, $($unordered_val:expr, $fn:ident);*;) => {
8+
(
9+
$f:ty, $x:ident, $y:ident, $apfloat_ty:ident, $sys_available:meta,
10+
$($unordered_val:expr, $fn:ident);*;
11+
) => {
812
$(
9-
let cmp0 = if $x.is_nan() || $y.is_nan() {
13+
let cmp0 = if apfloat_fallback!(
14+
$f, $apfloat_ty, $sys_available,
15+
|x: FloatTy| x.is_nan() => no_convert,
16+
$x
17+
) || apfloat_fallback!(
18+
$f, $apfloat_ty, $sys_available,
19+
|y: FloatTy| y.is_nan() => no_convert,
20+
$y
21+
)
22+
{
1023
$unordered_val
11-
} else if $x < $y {
24+
} else if apfloat_fallback!(
25+
$f, $apfloat_ty, $sys_available,
26+
|x, y| x < y => no_convert,
27+
$x, $y
28+
) {
1229
-1
13-
} else if $x == $y {
30+
} else if apfloat_fallback!(
31+
$f, $apfloat_ty, $sys_available,
32+
|x, y| x == y => no_convert,
33+
$x, $y
34+
) {
1435
0
1536
} else {
1637
1
1738
};
39+
1840
let cmp1 = $fn($x, $y);
1941
if cmp0 != cmp1 {
20-
panic!("{}({}, {}): std: {}, builtins: {}", stringify!($fn_builtins), $x, $y, cmp0, cmp1);
42+
panic!(
43+
"{}({:?}, {:?}): std: {:?}, builtins: {:?}",
44+
stringify!($fn), $x, $y, cmp0, cmp1
45+
);
2146
}
2247
)*
2348
};
@@ -34,7 +59,7 @@ fn float_comparisons() {
3459

3560
fuzz_float_2(N, |x: f32, y: f32| {
3661
assert_eq!(__unordsf2(x, y) != 0, x.is_nan() || y.is_nan());
37-
cmp!(x, y,
62+
cmp!(f32, x, y, Single, all(),
3863
1, __ltsf2;
3964
1, __lesf2;
4065
1, __eqsf2;
@@ -45,7 +70,7 @@ fn float_comparisons() {
4570
});
4671
fuzz_float_2(N, |x: f64, y: f64| {
4772
assert_eq!(__unorddf2(x, y) != 0, x.is_nan() || y.is_nan());
48-
cmp!(x, y,
73+
cmp!(f64, x, y, Double, all(),
4974
1, __ltdf2;
5075
1, __ledf2;
5176
1, __eqdf2;

testcrate/tests/div_rem.rs

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
use compiler_builtins::int::sdiv::{__divmoddi4, __divmodsi4, __divmodti4};
44
use compiler_builtins::int::udiv::{__udivmoddi4, __udivmodsi4, __udivmodti4, u128_divide_sparc};
5+
56
use testcrate::*;
67

78
// Division algorithms have by far the nastiest and largest number of edge cases, and experience shows
@@ -104,16 +105,20 @@ fn divide_sparc() {
104105
}
105106

106107
macro_rules! float {
107-
($($i:ty, $fn:ident);*;) => {
108+
($($f:ty, $fn:ident, $apfloat_ty:ident, $sys_available:meta);*;) => {
108109
$(
109-
fuzz_float_2(N, |x: $i, y: $i| {
110-
let quo0 = x / y;
111-
let quo1: $i = $fn(x, y);
110+
fuzz_float_2(N, |x: $f, y: $f| {
111+
let quo0: $f = apfloat_fallback!($f, $apfloat_ty, $sys_available, Div::div, x, y);
112+
let quo1: $f = $fn(x, y);
112113
#[cfg(not(target_arch = "arm"))]
113114
if !Float::eq_repr(quo0, quo1) {
114115
panic!(
115-
"{}({}, {}): std: {}, builtins: {}",
116-
stringify!($fn), x, y, quo0, quo1
116+
"{}({:?}, {:?}): std: {:?}, builtins: {:?}",
117+
stringify!($fn),
118+
x,
119+
y,
120+
quo0,
121+
quo1
117122
);
118123
}
119124

@@ -122,8 +127,12 @@ macro_rules! float {
122127
if !(Float::is_subnormal(quo0) || Float::is_subnormal(quo1)) {
123128
if !Float::eq_repr(quo0, quo1) {
124129
panic!(
125-
"{}({}, {}): std: {}, builtins: {}",
126-
stringify!($fn), x, y, quo0, quo1
130+
"{}({:?}, {:?}): std: {:?}, builtins: {:?}",
131+
stringify!($fn),
132+
x,
133+
y,
134+
quo0,
135+
quo1
127136
);
128137
}
129138
}
@@ -139,10 +148,11 @@ fn float_div() {
139148
div::{__divdf3, __divsf3},
140149
Float,
141150
};
151+
use core::ops::Div;
142152

143153
float!(
144-
f32, __divsf3;
145-
f64, __divdf3;
154+
f32, __divsf3, Single, all();
155+
f64, __divdf3, Double, all();
146156
);
147157
}
148158

@@ -153,9 +163,10 @@ fn float_div_arm() {
153163
div::{__divdf3vfp, __divsf3vfp},
154164
Float,
155165
};
166+
use core::ops::Div;
156167

157168
float!(
158-
f32, __divsf3vfp;
159-
f64, __divdf3vfp;
169+
f32, __divsf3vfp, Single, all();
170+
f64, __divdf3vfp, Double, all();
160171
);
161172
}

testcrate/tests/mul.rs

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -82,16 +82,16 @@ fn overflowing_mul() {
8282
}
8383

8484
macro_rules! float_mul {
85-
($($f:ty, $fn:ident);*;) => {
85+
($($f:ty, $fn:ident, $apfloat_ty:ident, $sys_available:meta);*;) => {
8686
$(
8787
fuzz_float_2(N, |x: $f, y: $f| {
88-
let mul0 = x * y;
88+
let mul0 = apfloat_fallback!($f, $apfloat_ty, $sys_available, Mul::mul, x, y);
8989
let mul1: $f = $fn(x, y);
9090
// multiplication of subnormals is not currently handled
9191
if !(Float::is_subnormal(mul0) || Float::is_subnormal(mul1)) {
9292
if !Float::eq_repr(mul0, mul1) {
9393
panic!(
94-
"{}({}, {}): std: {}, builtins: {}",
94+
"{}({:?}, {:?}): std: {:?}, builtins: {:?}",
9595
stringify!($fn), x, y, mul0, mul1
9696
);
9797
}
@@ -108,10 +108,11 @@ fn float_mul() {
108108
mul::{__muldf3, __mulsf3},
109109
Float,
110110
};
111+
use core::ops::Mul;
111112

112113
float_mul!(
113-
f32, __mulsf3;
114-
f64, __muldf3;
114+
f32, __mulsf3, Single, all();
115+
f64, __muldf3, Double, all();
115116
);
116117
}
117118

@@ -122,9 +123,10 @@ fn float_mul_arm() {
122123
mul::{__muldf3vfp, __mulsf3vfp},
123124
Float,
124125
};
126+
use core::ops::Mul;
125127

126128
float_mul!(
127-
f32, __mulsf3vfp;
128-
f64, __muldf3vfp;
129+
f32, __mulsf3vfp, Single, all();
130+
f64, __muldf3vfp, Double, all();
129131
);
130132
}

0 commit comments

Comments
 (0)