Auto merge of #127020 - tgross35:f16-f128-classify, r=workingjubilee · model-checking/verify-rust-std@ac443f2 (original) (raw)

`@@ -12,7 +12,10 @@

`

12

12

`#![unstable(feature = "f128", issue = "116909")]

`

13

13

``

14

14

`use crate::convert::FloatToInt;

`

``

15

`+

#[cfg(not(test))]

`

``

16

`+

use crate::intrinsics;

`

15

17

`use crate::mem;

`

``

18

`+

use crate::num::FpCategory;

`

16

19

``

17

20

`/// Basic mathematical constants.

`

18

21

`#[unstable(feature = "f128", issue = "116909")]

`

`@@ -251,6 +254,12 @@ impl f128 {

`

251

254

`#[cfg(not(bootstrap))]

`

252

255

`pub(crate) const SIGN_MASK: u128 = 0x8000_0000_0000_0000_0000_0000_0000_0000;

`

253

256

``

``

257

`+

/// Exponent mask

`

``

258

`+

pub(crate) const EXP_MASK: u128 = 0x7fff_0000_0000_0000_0000_0000_0000_0000;

`

``

259

+

``

260

`+

/// Mantissa mask

`

``

261

`+

pub(crate) const MAN_MASK: u128 = 0x0000_ffff_ffff_ffff_ffff_ffff_ffff_ffff;

`

``

262

+

254

263

`/// Minimum representable positive value (min subnormal)

`

255

264

`#[cfg(not(bootstrap))]

`

256

265

`const TINY_BITS: u128 = 0x1;

`

`@@ -354,6 +363,119 @@ impl f128 {

`

354

363

`self.abs_private() < Self::INFINITY

`

355

364

`}

`

356

365

``

``

366

`` +

/// Returns true if the number is [subnormal].

``

``

367

`+

///

`

``

368


/// ```

``

369

`+

/// #![feature(f128)]

`

``

370

`` +

/// # // FIXME(f16_f128): remove when eqtf2 is available

``

``

371

`+

/// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] {

`

``

372

`+

///

`

``

373

`+

/// let min = f128::MIN_POSITIVE; // 3.362103143e-4932f128

`

``

374

`+

/// let max = f128::MAX;

`

``

375

`+

/// let lower_than_min = 1.0e-4960_f128;

`

``

376

`+

/// let zero = 0.0_f128;

`

``

377

`+

///

`

``

378

`+

/// assert!(!min.is_subnormal());

`

``

379

`+

/// assert!(!max.is_subnormal());

`

``

380

`+

///

`

``

381

`+

/// assert!(!zero.is_subnormal());

`

``

382

`+

/// assert!(!f128::NAN.is_subnormal());

`

``

383

`+

/// assert!(!f128::INFINITY.is_subnormal());

`

``

384

`` +

/// // Values between 0 and min are Subnormal.

``

``

385

`+

/// assert!(lower_than_min.is_subnormal());

`

``

386

`+

/// # }

`

``

387


/// ```

``

388

`+

///

`

``

389

`+

/// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number

`

``

390

`+

#[inline]

`

``

391

`+

#[must_use]

`

``

392

`+

#[cfg(not(bootstrap))]

`

``

393

`+

#[unstable(feature = "f128", issue = "116909")]

`

``

394

`+

#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]

`

``

395

`+

pub const fn is_subnormal(self) -> bool {

`

``

396

`+

matches!(self.classify(), FpCategory::Subnormal)

`

``

397

`+

}

`

``

398

+

``

399

`` +

/// Returns true if the number is neither zero, infinite, [subnormal], or NaN.

``

``

400

`+

///

`

``

401


/// ```

``

402

`+

/// #![feature(f128)]

`

``

403

`` +

/// # // FIXME(f16_f128): remove when eqtf2 is available

``

``

404

`+

/// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] {

`

``

405

`+

///

`

``

406

`+

/// let min = f128::MIN_POSITIVE; // 3.362103143e-4932f128

`

``

407

`+

/// let max = f128::MAX;

`

``

408

`+

/// let lower_than_min = 1.0e-4960_f128;

`

``

409

`+

/// let zero = 0.0_f128;

`

``

410

`+

///

`

``

411

`+

/// assert!(min.is_normal());

`

``

412

`+

/// assert!(max.is_normal());

`

``

413

`+

///

`

``

414

`+

/// assert!(!zero.is_normal());

`

``

415

`+

/// assert!(!f128::NAN.is_normal());

`

``

416

`+

/// assert!(!f128::INFINITY.is_normal());

`

``

417

`` +

/// // Values between 0 and min are Subnormal.

``

``

418

`+

/// assert!(!lower_than_min.is_normal());

`

``

419

`+

/// # }

`

``

420


/// ```

``

421

`+

///

`

``

422

`+

/// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number

`

``

423

`+

#[inline]

`

``

424

`+

#[must_use]

`

``

425

`+

#[cfg(not(bootstrap))]

`

``

426

`+

#[unstable(feature = "f128", issue = "116909")]

`

``

427

`+

#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]

`

``

428

`+

pub const fn is_normal(self) -> bool {

`

``

429

`+

matches!(self.classify(), FpCategory::Normal)

`

``

430

`+

}

`

``

431

+

``

432

`+

/// Returns the floating point category of the number. If only one property

`

``

433

`+

/// is going to be tested, it is generally faster to use the specific

`

``

434

`+

/// predicate instead.

`

``

435

`+

///

`

``

436


/// ```

``

437

`+

/// #![feature(f128)]

`

``

438

`` +

/// # // FIXME(f16_f128): remove when eqtf2 is available

``

``

439

`+

/// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] {

`

``

440

`+

///

`

``

441

`+

/// use std::num::FpCategory;

`

``

442

`+

///

`

``

443

`+

/// let num = 12.4_f128;

`

``

444

`+

/// let inf = f128::INFINITY;

`

``

445

`+

///

`

``

446

`+

/// assert_eq!(num.classify(), FpCategory::Normal);

`

``

447

`+

/// assert_eq!(inf.classify(), FpCategory::Infinite);

`

``

448

`+

/// # }

`

``

449


/// ```

``

450

`+

#[inline]

`

``

451

`+

#[cfg(not(bootstrap))]

`

``

452

`+

#[unstable(feature = "f128", issue = "116909")]

`

``

453

`+

#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]

`

``

454

`+

pub const fn classify(self) -> FpCategory {

`

``

455

`+

// Other float types cannot use a bitwise classify because they may suffer a variety

`

``

456

`` +

// of errors if the backend chooses to cast to different float types (x87). f128 cannot

``

``

457

`+

// fit into any other float types so this is not a concern, and we rely on bit patterns.

`

``

458

+

``

459

`` +

// SAFETY: POD bitcast, same as in to_bits.

``

``

460

`+

let bits = unsafe { mem::transmute::<f128, u128>(self) };

`

``

461

`+

Self::classify_bits(bits)

`

``

462

`+

}

`

``

463

+

``

464

`+

/// This operates on bits, and only bits, so it can ignore concerns about weird FPUs.

`

``

465

`+

/// FIXME(jubilee): In a just world, this would be the entire impl for classify,

`

``

466

`+

/// plus a transmute. We do not live in a just world, but we can make it more so.

`

``

467

`+

#[inline]

`

``

468

`+

#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]

`

``

469

`+

const fn classify_bits(b: u128) -> FpCategory {

`

``

470

`+

match (b & Self::MAN_MASK, b & Self::EXP_MASK) {

`

``

471

`+

(0, Self::EXP_MASK) => FpCategory::Infinite,

`

``

472

`+

(_, Self::EXP_MASK) => FpCategory::Nan,

`

``

473

`+

(0, 0) => FpCategory::Zero,

`

``

474

`+

(_, 0) => FpCategory::Subnormal,

`

``

475

`+

_ => FpCategory::Normal,

`

``

476

`+

}

`

``

477

`+

}

`

``

478

+

357

479

`` /// Returns true if self has a positive sign, including +0.0, NaNs with

``

358

480

`/// positive sign bit and positive infinity. Note that IEEE 754 doesn't assign any

`

359

481

`/// meaning to the sign bit in case of a NaN, and as Rust doesn't guarantee that

`

`@@ -638,12 +760,52 @@ impl f128 {

`

638

760

```` /// ```


`639`

`761`

`#[inline]

`

`640`

`762`

`#[unstable(feature = "f128", issue = "116909")]

`

``

`763`

`+

#[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]

`

`641`

`764`

`#[must_use = "this returns the result of the operation, without modifying the original"]

`

`642`

``

`-

pub fn to_bits(self) -> u128 {

`

`643`

``

`` -

// SAFETY: `u128` is a plain old datatype so we can always... uh...

``

`644`

``

`-

// ...look, just pretend you forgot what you just read.

`

`645`

``

`-

// Stability concerns.

`

`646`

``

`-

unsafe { mem::transmute(self) }

`

``

`765`

`+

pub const fn to_bits(self) -> u128 {

`

``

`766`

`` +

// SAFETY: `u128` is a plain old datatype so we can always transmute to it.

``

``

`767`

`+

// ...sorta.

`

``

`768`

`+

//

`

``

`769`

`+

// It turns out that at runtime, it is possible for a floating point number

`

``

`770`

`+

// to be subject to a floating point mode that alters nonzero subnormal numbers

`

``

`771`

`+

// to zero on reads and writes, aka "denormals are zero" and "flush to zero".

`

``

`772`

`+

//

`

``

`773`

`+

// And, of course evaluating to a NaN value is fairly nondeterministic.

`

``

`774`

`+

// More precisely: when NaN should be returned is knowable, but which NaN?

`

``

`775`

`+

// So far that's defined by a combination of LLVM and the CPU, not Rust.

`

``

`776`

`+

// This function, however, allows observing the bitstring of a NaN,

`

``

`777`

`+

// thus introspection on CTFE.

`

``

`778`

`+

//

`

``

`779`

`+

// In order to preserve, at least for the moment, const-to-runtime equivalence,

`

``

`780`

`+

// we reject any of these possible situations from happening.

`

``

`781`

`+

#[inline]

`

``

`782`

`+

#[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]

`

``

`783`

`+

const fn ct_f128_to_u128(ct: f128) -> u128 {

`

``

`784`

`` +

// FIXME(f16_f128): we should use `.classify()` like `f32` and `f64`, but that

``

``

`785`

`` +

// is not available on all platforms (needs `netf2` and `unordtf2`). So classify

``

``

`786`

`+

// the bits instead.

`

``

`787`

`+`

``

`788`

`+

// SAFETY: this is a POD transmutation

`

``

`789`

`+

let bits = unsafe { mem::transmute::<f128, u128>(ct) };

`

``

`790`

`+

match f128::classify_bits(bits) {

`

``

`791`

`+

FpCategory::Nan => {

`

``

`792`

`+

panic!("const-eval error: cannot use f128::to_bits on a NaN")

`

``

`793`

`+

}

`

``

`794`

`+

FpCategory::Subnormal => {

`

``

`795`

`+

panic!("const-eval error: cannot use f128::to_bits on a subnormal number")

`

``

`796`

`+

}

`

``

`797`

`+

FpCategory::Infinite | FpCategory::Normal | FpCategory::Zero => bits,

`

``

`798`

`+

}

`

``

`799`

`+

}

`

``

`800`

`+`

``

`801`

`+

#[inline(always)] // See https://github.com/rust-lang/compiler-builtins/issues/491

`

``

`802`

`+

fn rt_f128_to_u128(x: f128) -> u128 {

`

``

`803`

`` +

// SAFETY: `u128` is a plain old datatype so we can always... uh...

``

``

`804`

`+

// ...look, just pretend you forgot what you just read.

`

``

`805`

`+

// Stability concerns.

`

``

`806`

`+

unsafe { mem::transmute(x) }

`

``

`807`

`+

}

`

``

`808`

`+

intrinsics::const_eval_select((self,), ct_f128_to_u128, rt_f128_to_u128)

`

`647`

`809`

`}

`

`648`

`810`

``

`649`

`811`

`` /// Raw transmutation from `u128`.

``

`@@ -688,11 +850,52 @@ impl f128 {

`

`688`

`850`

`#[inline]

`

`689`

`851`

`#[must_use]

`

`690`

`852`

`#[unstable(feature = "f128", issue = "116909")]

`

`691`

``

`-

pub fn from_bits(v: u128) -> Self {

`

`692`

``

`` -

// SAFETY: `u128 is a plain old datatype so we can always... uh...

``

`693`

``

`-

// ...look, just pretend you forgot what you just read.

`

`694`

``

`-

// Stability concerns.

`

`695`

``

`-

unsafe { mem::transmute(v) }

`

``

`853`

`+

#[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]

`

``

`854`

`+

pub const fn from_bits(v: u128) -> Self {

`

``

`855`

`+

// It turns out the safety issues with sNaN were overblown! Hooray!

`

``

`856`

`` +

// SAFETY: `u128` is a plain old datatype so we can always transmute from it

``

``

`857`

`+

// ...sorta.

`

``

`858`

`+

//

`

``

`859`

`+

// It turns out that at runtime, it is possible for a floating point number

`

``

`860`

`+

// to be subject to floating point modes that alter nonzero subnormal numbers

`

``

`861`

`+

// to zero on reads and writes, aka "denormals are zero" and "flush to zero".

`

``

`862`

`+

// This is not a problem usually, but at least one tier2 platform for Rust

`

``

`863`

`+

// actually exhibits this behavior by default: thumbv7neon

`

``

`864`

`+

// aka "the Neon FPU in AArch32 state"

`

``

`865`

`+

//

`

``

`866`

`+

// And, of course evaluating to a NaN value is fairly nondeterministic.

`

``

`867`

`+

// More precisely: when NaN should be returned is knowable, but which NaN?

`

``

`868`

`+

// So far that's defined by a combination of LLVM and the CPU, not Rust.

`

``

`869`

`+

// This function, however, allows observing the bitstring of a NaN,

`

``

`870`

`+

// thus introspection on CTFE.

`

``

`871`

`+

//

`

``

`872`

`+

// In order to preserve, at least for the moment, const-to-runtime equivalence,

`

``

`873`

`+

// reject any of these possible situations from happening.

`

``

`874`

`+

#[inline]

`

``

`875`

`+

#[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]

`

``

`876`

`+

const fn ct_u128_to_f128(ct: u128) -> f128 {

`

``

`877`

`+

match f128::classify_bits(ct) {

`

``

`878`

`+

FpCategory::Subnormal => {

`

``

`879`

`+

panic!("const-eval error: cannot use f128::from_bits on a subnormal number")

`

``

`880`

`+

}

`

``

`881`

`+

FpCategory::Nan => {

`

``

`882`

`+

panic!("const-eval error: cannot use f128::from_bits on NaN")

`

``

`883`

`+

}

`

``

`884`

`+

FpCategory::Infinite | FpCategory::Normal | FpCategory::Zero => {

`

``

`885`

`+

// SAFETY: It's not a frumious number

`

``

`886`

`+

unsafe { mem::transmute::<u128, f128>(ct) }

`

``

`887`

`+

}

`

``

`888`

`+

}

`

``

`889`

`+

}

`

``

`890`

`+`

``

`891`

`+

#[inline(always)] // See https://github.com/rust-lang/compiler-builtins/issues/491

`

``

`892`

`+

fn rt_u128_to_f128(x: u128) -> f128 {

`

``

`893`

`` +

// SAFETY: `u128` is a plain old datatype so we can always... uh...

``

``

`894`

`+

// ...look, just pretend you forgot what you just read.

`

``

`895`

`+

// Stability concerns.

`

``

`896`

`+

unsafe { mem::transmute(x) }

`

``

`897`

`+

}

`

``

`898`

`+

intrinsics::const_eval_select((v,), ct_u128_to_f128, rt_u128_to_f128)

`

`696`

`899`

`}

`

`697`

`900`

``

`698`

`901`

`/// Return the memory representation of this floating point number as a byte array in

`

`@@ -715,8 +918,9 @@ impl f128 {

`

`715`

`918`

```` /// ```

716

919

`#[inline]

`

717

920

`#[unstable(feature = "f128", issue = "116909")]

`

``

921

`+

#[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]

`

718

922

`#[must_use = "this returns the result of the operation, without modifying the original"]

`

719

``

`-

pub fn to_be_bytes(self) -> [u8; 16] {

`

``

923

`+

pub const fn to_be_bytes(self) -> [u8; 16] {

`

720

924

`self.to_bits().to_be_bytes()

`

721

925

`}

`

722

926

``

`@@ -740,8 +944,9 @@ impl f128 {

`

740

944

```` /// ```


`741`

`945`

`#[inline]

`

`742`

`946`

`#[unstable(feature = "f128", issue = "116909")]

`

``

`947`

`+

#[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]

`

`743`

`948`

`#[must_use = "this returns the result of the operation, without modifying the original"]

`

`744`

``

`-

pub fn to_le_bytes(self) -> [u8; 16] {

`

``

`949`

`+

pub const fn to_le_bytes(self) -> [u8; 16] {

`

`745`

`950`

`self.to_bits().to_le_bytes()

`

`746`

`951`

`}

`

`747`

`952`

``

`@@ -776,8 +981,9 @@ impl f128 {

`

`776`

`981`

```` /// ```

777

982

`#[inline]

`

778

983

`#[unstable(feature = "f128", issue = "116909")]

`

``

984

`+

#[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]

`

779

985

`#[must_use = "this returns the result of the operation, without modifying the original"]

`

780

``

`-

pub fn to_ne_bytes(self) -> [u8; 16] {

`

``

986

`+

pub const fn to_ne_bytes(self) -> [u8; 16] {

`

781

987

`self.to_bits().to_ne_bytes()

`

782

988

`}

`

783

989

``

`@@ -803,7 +1009,8 @@ impl f128 {

`

803

1009

`#[inline]

`

804

1010

`#[must_use]

`

805

1011

`#[unstable(feature = "f128", issue = "116909")]

`

806

``

`-

pub fn from_be_bytes(bytes: [u8; 16]) -> Self {

`

``

1012

`+

#[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]

`

``

1013

`+

pub const fn from_be_bytes(bytes: [u8; 16]) -> Self {

`

807

1014

`Self::from_bits(u128::from_be_bytes(bytes))

`

808

1015

`}

`

809

1016

``

`@@ -829,7 +1036,8 @@ impl f128 {

`

829

1036

`#[inline]

`

830

1037

`#[must_use]

`

831

1038

`#[unstable(feature = "f128", issue = "116909")]

`

832

``

`-

pub fn from_le_bytes(bytes: [u8; 16]) -> Self {

`

``

1039

`+

#[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]

`

``

1040

`+

pub const fn from_le_bytes(bytes: [u8; 16]) -> Self {

`

833

1041

`Self::from_bits(u128::from_le_bytes(bytes))

`

834

1042

`}

`

835

1043

``

`@@ -865,7 +1073,8 @@ impl f128 {

`

865

1073

`#[inline]

`

866

1074

`#[must_use]

`

867

1075

`#[unstable(feature = "f128", issue = "116909")]

`

868

``

`-

pub fn from_ne_bytes(bytes: [u8; 16]) -> Self {

`

``

1076

`+

#[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]

`

``

1077

`+

pub const fn from_ne_bytes(bytes: [u8; 16]) -> Self {

`

869

1078

`Self::from_bits(u128::from_ne_bytes(bytes))

`

870

1079

`}

`

871

1080

``