| //@ run-pass | |
| //@ revisions: opt noopt ctfe | |
| //@[opt] compile-flags: -O | |
| //@[noopt] compile-flags: -Zmir-opt-level=0 | |
| //@ min-llvm-version: 22 | |
| //@ compile-flags: --check-cfg=cfg(target_has_reliable_f16) | |
| // ignore-tidy-file-linelength | |
| #![feature(cfg_target_has_reliable_f16_f128)] | |
| #![cfg_attr(target_has_reliable_f16, feature(f16))] | |
| // This tests the float classification functions, for regular runtime code and for const evaluation. | |
| 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 )* ) => { | |
| #[cfg(target_has_reliable_f16)] | |
| fn f16() { | |
| #[allow(unused)] | |
| type $tyname = f16; | |
| suite_inner!(f16 => $($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() { | |
| #[cfg(target_has_reliable_f16)] | |
| f16(); | |
| f32(); | |
| f64(); | |
| // FIXME(f128): also test f128 | |
| } |