simplify float::classify logic · qinheping/verify-rust-std@abe63f6 (original) (raw)
`@@ -652,42 +652,18 @@ impl f32 {
`
652
652
`#[stable(feature = "rust1", since = "1.0.0")]
`
653
653
`#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
`
654
654
`pub const fn classify(self) -> FpCategory {
`
655
``
`-
// A previous implementation tried to only use bitmask-based checks,
`
656
``
`-
// using f32::to_bits to transmute the float to its bit repr and match on that.
`
657
``
`-
// If we only cared about being "technically" correct, that's an entirely legit
`
658
``
`-
// implementation.
`
659
``
`-
//
`
660
``
`-
// Unfortunately, there is hardware out there that does not correctly implement the IEEE
`
661
``
`-
// float semantics Rust relies on: x87 uses a too-large mantissa and exponent, and some
`
662
``
`-
// hardware flushes subnormals to zero. These are platforms bugs, and Rust will misbehave on
`
663
``
`-
// such hardware, but we can at least try to make things seem as sane as possible by being
`
664
``
`-
// careful here.
`
665
``
`-
// see also https://github.com/rust-lang/rust/issues/114479
`
666
``
`-
if self.is_infinite() {
`
667
``
`-
// A value may compare unequal to infinity, despite having a "full" exponent mask.
`
668
``
`-
FpCategory::Infinite
`
669
``
`-
} else if self.is_nan() {
`
670
``
`-
// And it may not be NaN, as it can simply be an "overextended" finite value.
`
671
``
`-
FpCategory::Nan
`
672
``
`-
} else {
`
673
``
`-
// However, std can't simply compare to zero to check for zero, either,
`
674
``
`-
// as correctness requires avoiding equality tests that may be Subnormal == -0.0
`
675
``
`-
// because it may be wrong under "denormals are zero" and "flush to zero" modes.
`
676
``
`-
// Most of std's targets don't use those, but they are used for thumbv7neon.
`
677
``
`-
// So, this does use bitpattern matching for the rest. On x87, due to the incorrect
`
678
``
`-
// float codegen on this hardware, this doesn't actually return a right answer for NaN
`
679
``
`-
// because it cannot correctly discern between a floating point NaN, and some normal
`
680
``
`-
// floating point numbers truncated from an x87 FPU -- but we took care of NaN above, so
`
681
``
`-
// we are fine.
`
682
``
`-
// FIXME(jubilee): This probably could at least answer things correctly for Infinity,
`
683
``
`-
// like the f64 version does, but I need to run more checks on how things go on x86.
`
684
``
`-
// I fear losing mantissa data that would have answered that differently.
`
685
``
`-
let b = self.to_bits();
`
686
``
`-
match (b & Self::MAN_MASK, b & Self::EXP_MASK) {
`
687
``
`-
(0, 0) => FpCategory::Zero,
`
688
``
`-
(_, 0) => FpCategory::Subnormal,
`
689
``
`-
_ => FpCategory::Normal,
`
690
``
`-
}
`
``
655
`+
// We used to have complicated logic here that avoids the simple bit-based tests to work
`
``
656
`+
// around buggy codegen for x87 targets (see
`
``
657
`+
// https://github.com/rust-lang/rust/issues/114479). However, some LLVM versions later, none
`
``
658
`+
// of our tests is able to find any difference between the complicated and the naive
`
``
659
`+
// version, so now we are back to the naive version.
`
``
660
`+
let b = self.to_bits();
`
``
661
`+
match (b & Self::MAN_MASK, b & Self::EXP_MASK) {
`
``
662
`+
(0, Self::EXP_MASK) => FpCategory::Infinite,
`
``
663
`+
(_, Self::EXP_MASK) => FpCategory::Nan,
`
``
664
`+
(0, 0) => FpCategory::Zero,
`
``
665
`+
(_, 0) => FpCategory::Subnormal,
`
``
666
`+
_ => FpCategory::Normal,
`
691
667
`}
`
692
668
`}
`
693
669
``