Skip to content

Commit ffdf4b0

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 4a38773 commit ffdf4b0

File tree

5 files changed

+126
-36
lines changed

5 files changed

+126
-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,22 +1,47 @@
11
#![allow(unused_macros)]
2+
#![allow(unreachable_code)]
23

34
use testcrate::*;
45

56
macro_rules! cmp {
6-
($x:ident, $y:ident, $($unordered_val:expr, $fn:ident);*;) => {
7+
(
8+
$f:ty, $x:ident, $y:ident, $apfloat_ty:ident, $sys_available:meta,
9+
$($unordered_val:expr, $fn:ident);*;
10+
) => {
711
$(
8-
let cmp0 = if $x.is_nan() || $y.is_nan() {
12+
let cmp0 = if apfloat_fallback!(
13+
$f, $apfloat_ty, $sys_available,
14+
|x: FloatTy| x.is_nan() => no_convert,
15+
$x
16+
) || apfloat_fallback!(
17+
$f, $apfloat_ty, $sys_available,
18+
|y: FloatTy| y.is_nan() => no_convert,
19+
$y
20+
)
21+
{
922
$unordered_val
10-
} else if $x < $y {
23+
} else if apfloat_fallback!(
24+
$f, $apfloat_ty, $sys_available,
25+
|x, y| x < y => no_convert,
26+
$x, $y
27+
) {
1128
-1
12-
} else if $x == $y {
29+
} else if apfloat_fallback!(
30+
$f, $apfloat_ty, $sys_available,
31+
|x, y| x == y => no_convert,
32+
$x, $y
33+
) {
1334
0
1435
} else {
1536
1
1637
};
38+
1739
let cmp1 = $fn($x, $y);
1840
if cmp0 != cmp1 {
19-
panic!("{}({}, {}): std: {}, builtins: {}", stringify!($fn_builtins), $x, $y, cmp0, cmp1);
41+
panic!(
42+
"{}({:?}, {:?}): std: {:?}, builtins: {:?}",
43+
stringify!($fn), $x, $y, cmp0, cmp1
44+
);
2045
}
2146
)*
2247
};
@@ -33,7 +58,7 @@ fn float_comparisons() {
3358

3459
fuzz_float_2(N, |x: f32, y: f32| {
3560
assert_eq!(__unordsf2(x, y) != 0, x.is_nan() || y.is_nan());
36-
cmp!(x, y,
61+
cmp!(f32, x, y, Single, all(),
3762
1, __ltsf2;
3863
1, __lesf2;
3964
1, __eqsf2;
@@ -44,7 +69,7 @@ fn float_comparisons() {
4469
});
4570
fuzz_float_2(N, |x: f64, y: f64| {
4671
assert_eq!(__unorddf2(x, y) != 0, x.is_nan() || y.is_nan());
47-
cmp!(x, y,
72+
cmp!(f64, x, y, Double, all(),
4873
1, __ltdf2;
4974
1, __ledf2;
5075
1, __eqdf2;

testcrate/tests/div_rem.rs

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

3+
use core::ops::Div;
4+
35
use compiler_builtins::int::sdiv::{__divmoddi4, __divmodsi4, __divmodti4};
46
use compiler_builtins::int::udiv::{__udivmoddi4, __udivmodsi4, __udivmodti4, u128_divide_sparc};
7+
58
use testcrate::*;
69

710
// Division algorithms have by far the nastiest and largest number of edge cases, and experience shows
@@ -104,16 +107,20 @@ fn divide_sparc() {
104107
}
105108

106109
macro_rules! float {
107-
($($i:ty, $fn:ident);*;) => {
110+
($($f:ty, $fn:ident, $apfloat_ty:ident, $sys_available:meta);*;) => {
108111
$(
109-
fuzz_float_2(N, |x: $i, y: $i| {
110-
let quo0 = x / y;
111-
let quo1: $i = $fn(x, y);
112+
fuzz_float_2(N, |x: $f, y: $f| {
113+
let quo0: $f = apfloat_fallback!($f, $apfloat_ty, $sys_available, Div::div, x, y);
114+
let quo1: $f = $fn(x, y);
112115
#[cfg(not(target_arch = "arm"))]
113116
if !Float::eq_repr(quo0, quo1) {
114117
panic!(
115-
"{}({}, {}): std: {}, builtins: {}",
116-
stringify!($fn), x, y, quo0, quo1
118+
"{}({:?}, {:?}): std: {:?}, builtins: {:?}",
119+
stringify!($fn),
120+
x,
121+
y,
122+
quo0,
123+
quo1
117124
);
118125
}
119126

@@ -122,8 +129,12 @@ macro_rules! float {
122129
if !(Float::is_subnormal(quo0) || Float::is_subnormal(quo1)) {
123130
if !Float::eq_repr(quo0, quo1) {
124131
panic!(
125-
"{}({}, {}): std: {}, builtins: {}",
126-
stringify!($fn), x, y, quo0, quo1
132+
"{}({:?}, {:?}): std: {:?}, builtins: {:?}",
133+
stringify!($fn),
134+
x,
135+
y,
136+
quo0,
137+
quo1
127138
);
128139
}
129140
}
@@ -141,8 +152,8 @@ fn float_div() {
141152
};
142153

143154
float!(
144-
f32, __divsf3;
145-
f64, __divdf3;
155+
f32, __divsf3, Single, all();
156+
f64, __divdf3, Double, all();
146157
);
147158
}
148159

@@ -155,7 +166,7 @@ fn float_div_arm() {
155166
};
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: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#![allow(unused_macros)]
22

3+
use core::ops::Mul;
34
use testcrate::*;
45

56
macro_rules! mul {
@@ -82,16 +83,16 @@ fn overflowing_mul() {
8283
}
8384

8485
macro_rules! float_mul {
85-
($($f:ty, $fn:ident);*;) => {
86+
($($f:ty, $fn:ident, $apfloat_ty:ident, $sys_available:meta);*;) => {
8687
$(
8788
fuzz_float_2(N, |x: $f, y: $f| {
88-
let mul0 = x * y;
89+
let mul0 = apfloat_fallback!($f, $apfloat_ty, $sys_available, Mul::mul, x, y);
8990
let mul1: $f = $fn(x, y);
9091
// multiplication of subnormals is not currently handled
9192
if !(Float::is_subnormal(mul0) || Float::is_subnormal(mul1)) {
9293
if !Float::eq_repr(mul0, mul1) {
9394
panic!(
94-
"{}({}, {}): std: {}, builtins: {}",
95+
"{}({:?}, {:?}): std: {:?}, builtins: {:?}",
9596
stringify!($fn), x, y, mul0, mul1
9697
);
9798
}
@@ -110,8 +111,8 @@ fn float_mul() {
110111
};
111112

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

@@ -124,7 +125,7 @@ fn float_mul_arm() {
124125
};
125126

126127
float_mul!(
127-
f32, __mulsf3vfp;
128-
f64, __muldf3vfp;
128+
f32, __mulsf3vfp, Single, all();
129+
f64, __muldf3vfp, Double, all();
129130
);
130131
}

0 commit comments

Comments
 (0)