131 lines
4.7 KiB
Rust
131 lines
4.7 KiB
Rust
//@ run-pass
|
|
//@ revisions: opt noopt ctfe
|
|
//@[opt] compile-flags: -O
|
|
//@[noopt] compile-flags: -Zmir-opt-level=0
|
|
// ignore-tidy-linelength
|
|
|
|
// This tests the float classification functions, for regular runtime code and for const evaluation.
|
|
|
|
#![feature(f16_const)]
|
|
#![feature(f128_const)]
|
|
#![feature(const_float_classify)]
|
|
|
|
use std::num::FpCategory::*;
|
|
|
|
#[cfg(not(ctfe))]
|
|
use std::hint::black_box;
|
|
#[cfg(ctfe)]
|
|
#[allow(unused)]
|
|
const fn black_box<T>(x: T) -> T { x }
|
|
|
|
#[cfg(not(ctfe))]
|
|
macro_rules! assert_test {
|
|
($a:expr, NonDet) => {
|
|
{
|
|
// Compute `a`, but do not compare with anything as the result is non-deterministic.
|
|
let _val = $a;
|
|
}
|
|
};
|
|
($a:expr, $b:ident) => {
|
|
{
|
|
// Let-bind to avoid promotion.
|
|
// No black_box here! That can mask x87 failures.
|
|
let a = $a;
|
|
let b = $b;
|
|
assert_eq!(a, b, "{} produces wrong result", stringify!($a));
|
|
}
|
|
};
|
|
}
|
|
#[cfg(ctfe)]
|
|
macro_rules! assert_test {
|
|
($a:expr, NonDet) => {
|
|
{
|
|
// Compute `a`, but do not compare with anything as the result is non-deterministic.
|
|
const _: () = { let _val = $a; };
|
|
}
|
|
};
|
|
($a:expr, $b:ident) => {
|
|
{
|
|
const _: () = assert!(matches!($a, $b));
|
|
}
|
|
};
|
|
}
|
|
|
|
macro_rules! suite {
|
|
( $tyname:ident => $( $tt:tt )* ) => {
|
|
fn f32() {
|
|
#[allow(unused)]
|
|
type $tyname = f32;
|
|
suite_inner!(f32 => $($tt)*);
|
|
}
|
|
|
|
fn f64() {
|
|
#[allow(unused)]
|
|
type $tyname = f64;
|
|
suite_inner!(f64 => $($tt)*);
|
|
}
|
|
}
|
|
}
|
|
|
|
macro_rules! suite_inner {
|
|
(
|
|
$ty:ident => [$( $fn:ident ),*]:
|
|
$(@cfg: $attr:meta)?
|
|
$val:expr => [$($out:ident),*],
|
|
|
|
$( $tail:tt )*
|
|
) => {
|
|
$(#[cfg($attr)])?
|
|
{
|
|
// No black_box here! That can mask x87 failures.
|
|
$( assert_test!($ty::$fn($val), $out); )*
|
|
}
|
|
suite_inner!($ty => [$($fn),*]: $($tail)*)
|
|
};
|
|
|
|
( $ty:ident => [$( $fn:ident ),*]:) => {};
|
|
}
|
|
|
|
// The result of the `is_sign` methods are not checked for correctness, since we do not
|
|
// guarantee anything about the signedness of NaNs. See
|
|
// https://rust-lang.github.io/rfcs/3514-float-semantics.html.
|
|
|
|
suite! { T => // type alias for the type we are testing
|
|
[ classify, is_nan, is_infinite, is_finite, is_normal, is_sign_positive, is_sign_negative]:
|
|
black_box(0.0) / black_box(0.0) =>
|
|
[ Nan, true, false, false, false, NonDet, NonDet],
|
|
black_box(0.0) / black_box(-0.0) =>
|
|
[ Nan, true, false, false, false, NonDet, NonDet],
|
|
black_box(0.0) * black_box(T::INFINITY) =>
|
|
[ Nan, true, false, false, false, NonDet, NonDet],
|
|
black_box(0.0) * black_box(T::NEG_INFINITY) =>
|
|
[ Nan, true, false, false, false, NonDet, NonDet],
|
|
1.0 => [ Normal, false, false, true, true, true, false],
|
|
-1.0 => [ Normal, false, false, true, true, false, true],
|
|
0.0 => [ Zero, false, false, true, false, true, false],
|
|
-0.0 => [ Zero, false, false, true, false, false, true],
|
|
1.0 / black_box(0.0) =>
|
|
[ Infinite, false, true, false, false, true, false],
|
|
-1.0 / black_box(0.0) =>
|
|
[ Infinite, false, true, false, false, false, true],
|
|
2.0 * black_box(T::MAX) =>
|
|
[ Infinite, false, true, false, false, true, false],
|
|
-2.0 * black_box(T::MAX) =>
|
|
[ Infinite, false, true, false, false, false, true],
|
|
1.0 / black_box(T::MAX) =>
|
|
[Subnormal, false, false, true, false, true, false],
|
|
-1.0 / black_box(T::MAX) =>
|
|
[Subnormal, false, false, true, false, false, true],
|
|
// This specific expression causes trouble on x87 due to
|
|
// <https://github.com/rust-lang/rust/issues/114479>.
|
|
@cfg: not(all(target_arch = "x86", not(target_feature = "sse2")))
|
|
{ let x = black_box(T::MAX); x * x } =>
|
|
[ Infinite, false, true, false, false, true, false],
|
|
}
|
|
|
|
fn main() {
|
|
f32();
|
|
f64();
|
|
// FIXME(f16_f128): also test f16 and f128
|
|
}
|