Mark some f16
and f128
functions unstably const · model-checking/verify-rust-std@14c24b1 (original) (raw)
`@@ -12,6 +12,8 @@
`
12
12
`#![unstable(feature = "f16", issue = "116909")]
`
13
13
``
14
14
`use crate::convert::FloatToInt;
`
``
15
`+
#[cfg(not(test))]
`
``
16
`+
use crate::intrinsics;
`
15
17
`use crate::mem;
`
16
18
`use crate::num::FpCategory;
`
17
19
``
`@@ -788,12 +790,52 @@ impl f16 {
`
788
790
```` /// ```
`789`
`791`
`#[inline]
`
`790`
`792`
`#[unstable(feature = "f16", issue = "116909")]
`
``
`793`
`+
#[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
`
`791`
`794`
`#[must_use = "this returns the result of the operation, without modifying the original"]
`
`792`
``
`-
pub fn to_bits(self) -> u16 {
`
`793`
``
`` -
// SAFETY: `u16` is a plain old datatype so we can always... uh...
``
`794`
``
`-
// ...look, just pretend you forgot what you just read.
`
`795`
``
`-
// Stability concerns.
`
`796`
``
`-
unsafe { mem::transmute(self) }
`
``
`795`
`+
pub const fn to_bits(self) -> u16 {
`
``
`796`
`` +
// SAFETY: `u16` is a plain old datatype so we can always transmute to it.
``
``
`797`
`+
// ...sorta.
`
``
`798`
`+
//
`
``
`799`
`+
// It turns out that at runtime, it is possible for a floating point number
`
``
`800`
`+
// to be subject to a floating point mode that alters nonzero subnormal numbers
`
``
`801`
`+
// to zero on reads and writes, aka "denormals are zero" and "flush to zero".
`
``
`802`
`+
//
`
``
`803`
`+
// And, of course evaluating to a NaN value is fairly nondeterministic.
`
``
`804`
`+
// More precisely: when NaN should be returned is knowable, but which NaN?
`
``
`805`
`+
// So far that's defined by a combination of LLVM and the CPU, not Rust.
`
``
`806`
`+
// This function, however, allows observing the bitstring of a NaN,
`
``
`807`
`+
// thus introspection on CTFE.
`
``
`808`
`+
//
`
``
`809`
`+
// In order to preserve, at least for the moment, const-to-runtime equivalence,
`
``
`810`
`+
// we reject any of these possible situations from happening.
`
``
`811`
`+
#[inline]
`
``
`812`
`+
#[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
`
``
`813`
`+
const fn ct_f16_to_u16(ct: f16) -> u16 {
`
``
`814`
`` +
// FIXME(f16_f128): we should use `.classify()` like `f32` and `f64`, but we don't yet
``
``
`815`
`+
// want to rely on that on all platforms because it is nondeterministic (e.g. x86 has
`
``
`816`
`+
// convention discrepancies calling intrinsics). So just classify the bits instead.
`
``
`817`
`+`
``
`818`
`+
// SAFETY: this is a POD transmutation
`
``
`819`
`+
let bits = unsafe { mem::transmute::<f16, u16>(ct) };
`
``
`820`
`+
match f16::classify_bits(bits) {
`
``
`821`
`+
FpCategory::Nan => {
`
``
`822`
`+
panic!("const-eval error: cannot use f16::to_bits on a NaN")
`
``
`823`
`+
}
`
``
`824`
`+
FpCategory::Subnormal => {
`
``
`825`
`+
panic!("const-eval error: cannot use f16::to_bits on a subnormal number")
`
``
`826`
`+
}
`
``
`827`
`+
FpCategory::Infinite | FpCategory::Normal | FpCategory::Zero => bits,
`
``
`828`
`+
}
`
``
`829`
`+
}
`
``
`830`
`+`
``
`831`
`+
#[inline(always)] // See https://github.com/rust-lang/compiler-builtins/issues/491
`
``
`832`
`+
fn rt_f16_to_u16(x: f16) -> u16 {
`
``
`833`
`` +
// SAFETY: `u16` is a plain old datatype so we can always... uh...
``
``
`834`
`+
// ...look, just pretend you forgot what you just read.
`
``
`835`
`+
// Stability concerns.
`
``
`836`
`+
unsafe { mem::transmute(x) }
`
``
`837`
`+
}
`
``
`838`
`+
intrinsics::const_eval_select((self,), ct_f16_to_u16, rt_f16_to_u16)
`
`797`
`839`
`}
`
`798`
`840`
``
`799`
`841`
`` /// Raw transmutation from `u16`.
``
`@@ -837,11 +879,52 @@ impl f16 {
`
`837`
`879`
`#[inline]
`
`838`
`880`
`#[must_use]
`
`839`
`881`
`#[unstable(feature = "f16", issue = "116909")]
`
`840`
``
`-
pub fn from_bits(v: u16) -> Self {
`
`841`
``
`` -
// SAFETY: `u16` is a plain old datatype so we can always... uh...
``
`842`
``
`-
// ...look, just pretend you forgot what you just read.
`
`843`
``
`-
// Stability concerns.
`
`844`
``
`-
unsafe { mem::transmute(v) }
`
``
`882`
`+
#[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
`
``
`883`
`+
pub const fn from_bits(v: u16) -> Self {
`
``
`884`
`+
// It turns out the safety issues with sNaN were overblown! Hooray!
`
``
`885`
`` +
// SAFETY: `u16` is a plain old datatype so we can always transmute from it
``
``
`886`
`+
// ...sorta.
`
``
`887`
`+
//
`
``
`888`
`+
// It turns out that at runtime, it is possible for a floating point number
`
``
`889`
`+
// to be subject to floating point modes that alter nonzero subnormal numbers
`
``
`890`
`+
// to zero on reads and writes, aka "denormals are zero" and "flush to zero".
`
``
`891`
`+
// This is not a problem usually, but at least one tier2 platform for Rust
`
``
`892`
`+
// actually exhibits this behavior by default: thumbv7neon
`
``
`893`
`+
// aka "the Neon FPU in AArch32 state"
`
``
`894`
`+
//
`
``
`895`
`+
// And, of course evaluating to a NaN value is fairly nondeterministic.
`
``
`896`
`+
// More precisely: when NaN should be returned is knowable, but which NaN?
`
``
`897`
`+
// So far that's defined by a combination of LLVM and the CPU, not Rust.
`
``
`898`
`+
// This function, however, allows observing the bitstring of a NaN,
`
``
`899`
`+
// thus introspection on CTFE.
`
``
`900`
`+
//
`
``
`901`
`+
// In order to preserve, at least for the moment, const-to-runtime equivalence,
`
``
`902`
`+
// reject any of these possible situations from happening.
`
``
`903`
`+
#[inline]
`
``
`904`
`+
#[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
`
``
`905`
`+
const fn ct_u16_to_f16(ct: u16) -> f16 {
`
``
`906`
`+
match f16::classify_bits(ct) {
`
``
`907`
`+
FpCategory::Subnormal => {
`
``
`908`
`+
panic!("const-eval error: cannot use f16::from_bits on a subnormal number")
`
``
`909`
`+
}
`
``
`910`
`+
FpCategory::Nan => {
`
``
`911`
`+
panic!("const-eval error: cannot use f16::from_bits on NaN")
`
``
`912`
`+
}
`
``
`913`
`+
FpCategory::Infinite | FpCategory::Normal | FpCategory::Zero => {
`
``
`914`
`+
// SAFETY: It's not a frumious number
`
``
`915`
`+
unsafe { mem::transmute::<u16, f16>(ct) }
`
``
`916`
`+
}
`
``
`917`
`+
}
`
``
`918`
`+
}
`
``
`919`
`+`
``
`920`
`+
#[inline(always)] // See https://github.com/rust-lang/compiler-builtins/issues/491
`
``
`921`
`+
fn rt_u16_to_f16(x: u16) -> f16 {
`
``
`922`
`` +
// SAFETY: `u16` is a plain old datatype so we can always... uh...
``
``
`923`
`+
// ...look, just pretend you forgot what you just read.
`
``
`924`
`+
// Stability concerns.
`
``
`925`
`+
unsafe { mem::transmute(x) }
`
``
`926`
`+
}
`
``
`927`
`+
intrinsics::const_eval_select((v,), ct_u16_to_f16, rt_u16_to_f16)
`
`845`
`928`
`}
`
`846`
`929`
``
`847`
`930`
`/// Return the memory representation of this floating point number as a byte array in
`
`@@ -860,8 +943,9 @@ impl f16 {
`
`860`
`943`
```` /// ```
861
944
`#[inline]
`
862
945
`#[unstable(feature = "f16", issue = "116909")]
`
``
946
`+
#[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
`
863
947
`#[must_use = "this returns the result of the operation, without modifying the original"]
`
864
``
`-
pub fn to_be_bytes(self) -> [u8; 2] {
`
``
948
`+
pub const fn to_be_bytes(self) -> [u8; 2] {
`
865
949
`self.to_bits().to_be_bytes()
`
866
950
`}
`
867
951
``
`@@ -881,8 +965,9 @@ impl f16 {
`
881
965
```` /// ```
`882`
`966`
`#[inline]
`
`883`
`967`
`#[unstable(feature = "f16", issue = "116909")]
`
``
`968`
`+
#[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
`
`884`
`969`
`#[must_use = "this returns the result of the operation, without modifying the original"]
`
`885`
``
`-
pub fn to_le_bytes(self) -> [u8; 2] {
`
``
`970`
`+
pub const fn to_le_bytes(self) -> [u8; 2] {
`
`886`
`971`
`self.to_bits().to_le_bytes()
`
`887`
`972`
`}
`
`888`
`973`
``
`@@ -915,8 +1000,9 @@ impl f16 {
`
`915`
`1000`
```` /// ```
916
1001
`#[inline]
`
917
1002
`#[unstable(feature = "f16", issue = "116909")]
`
``
1003
`+
#[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
`
918
1004
`#[must_use = "this returns the result of the operation, without modifying the original"]
`
919
``
`-
pub fn to_ne_bytes(self) -> [u8; 2] {
`
``
1005
`+
pub const fn to_ne_bytes(self) -> [u8; 2] {
`
920
1006
`self.to_bits().to_ne_bytes()
`
921
1007
`}
`
922
1008
``
`@@ -938,7 +1024,8 @@ impl f16 {
`
938
1024
`#[inline]
`
939
1025
`#[must_use]
`
940
1026
`#[unstable(feature = "f16", issue = "116909")]
`
941
``
`-
pub fn from_be_bytes(bytes: [u8; 2]) -> Self {
`
``
1027
`+
#[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
`
``
1028
`+
pub const fn from_be_bytes(bytes: [u8; 2]) -> Self {
`
942
1029
`Self::from_bits(u16::from_be_bytes(bytes))
`
943
1030
`}
`
944
1031
``
`@@ -960,7 +1047,8 @@ impl f16 {
`
960
1047
`#[inline]
`
961
1048
`#[must_use]
`
962
1049
`#[unstable(feature = "f16", issue = "116909")]
`
963
``
`-
pub fn from_le_bytes(bytes: [u8; 2]) -> Self {
`
``
1050
`+
#[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
`
``
1051
`+
pub const fn from_le_bytes(bytes: [u8; 2]) -> Self {
`
964
1052
`Self::from_bits(u16::from_le_bytes(bytes))
`
965
1053
`}
`
966
1054
``
`@@ -993,7 +1081,8 @@ impl f16 {
`
993
1081
`#[inline]
`
994
1082
`#[must_use]
`
995
1083
`#[unstable(feature = "f16", issue = "116909")]
`
996
``
`-
pub fn from_ne_bytes(bytes: [u8; 2]) -> Self {
`
``
1084
`+
#[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
`
``
1085
`+
pub const fn from_ne_bytes(bytes: [u8; 2]) -> Self {
`
997
1086
`Self::from_bits(u16::from_ne_bytes(bytes))
`
998
1087
`}
`
999
1088
``