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

``