diff options
| author | bors <bors@rust-lang.org> | 2024-09-12 06:11:50 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2024-09-12 06:11:50 +0000 |
| commit | 5fc0865d2ec0a71a7e369403463b47cb194bae38 (patch) | |
| tree | c16367f9b4c3a659aa924238daef9704756e4bcb /tests/ui/float | |
| parent | 59835ae7594246736ead0e1e50264e0ec6b35fc2 (diff) | |
| parent | 93ef7cd2dd40b4661bf918a33336558784248103 (diff) | |
Auto merge of #3879 - rust-lang:rustup-2024-09-12, r=RalfJung
Automatic Rustup
Diffstat (limited to 'tests/ui/float')
| -rw-r--r-- | tests/ui/float/classify-runtime-const.rs | 130 | ||||
| -rw-r--r-- | tests/ui/float/conv-bits-runtime-const.rs | 168 | ||||
| -rw-r--r-- | tests/ui/float/int-to-float-miscompile-issue-105626.rs | 17 |
3 files changed, 315 insertions, 0 deletions
diff --git a/tests/ui/float/classify-runtime-const.rs b/tests/ui/float/classify-runtime-const.rs new file mode 100644 index 00000000000..b19e67d5284 --- /dev/null +++ b/tests/ui/float/classify-runtime-const.rs @@ -0,0 +1,130 @@ +//@ run-pass +//@ revisions: opt noopt ctfe +//@[opt] compile-flags: -O +//@[noopt] compile-flags: -Zmir-opt-level=0 +// ignore-tidy-linelength + +// This tests the float classification functions, for regular runtime code and for const evaluation. + +#![feature(f16_const)] +#![feature(f128_const)] +#![feature(const_float_classify)] + +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 )* ) => { + 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() { + f32(); + f64(); + // FIXME(f16_f128): also test f16 and f128 +} diff --git a/tests/ui/float/conv-bits-runtime-const.rs b/tests/ui/float/conv-bits-runtime-const.rs new file mode 100644 index 00000000000..e85a889d2c2 --- /dev/null +++ b/tests/ui/float/conv-bits-runtime-const.rs @@ -0,0 +1,168 @@ +//@ compile-flags: -Zmir-opt-level=0 +//@ run-pass + +// This tests the float classification functions, for regular runtime code and for const evaluation. + +#![feature(const_float_classify)] +#![feature(f16)] +#![feature(f128)] +#![feature(f16_const)] +#![feature(f128_const)] +#![allow(unused_macro_rules)] + +use std::hint::black_box; + +macro_rules! both_assert { + ($a:expr) => { + { + const _: () = assert!($a); + // `black_box` prevents promotion, and MIR opts are disabled above, so this is truly + // going through LLVM. + assert!(black_box($a)); + } + }; + ($a:expr, $b:expr) => { + { + const _: () = assert!($a == $b); + assert_eq!(black_box($a), black_box($b)); + } + }; +} + +fn has_broken_floats() -> bool { + // i586 targets are broken due to <https://github.com/rust-lang/rust/issues/114479>. + cfg!(all(target_arch = "x86", not(target_feature = "sse2"))) +} + +#[cfg(target_arch = "x86_64")] +fn f16(){ + both_assert!((1f16).to_bits(), 0x3c00); + both_assert!(u16::from_be_bytes(1f16.to_be_bytes()), 0x3c00); + both_assert!((12.5f16).to_bits(), 0x4a40); + both_assert!(u16::from_le_bytes(12.5f16.to_le_bytes()), 0x4a40); + both_assert!((1337f16).to_bits(), 0x6539); + both_assert!(u16::from_ne_bytes(1337f16.to_ne_bytes()), 0x6539); + both_assert!((-14.25f16).to_bits(), 0xcb20); + both_assert!(f16::from_bits(0x3c00), 1.0); + both_assert!(f16::from_be_bytes(0x3c00u16.to_be_bytes()), 1.0); + both_assert!(f16::from_bits(0x4a40), 12.5); + both_assert!(f16::from_le_bytes(0x4a40u16.to_le_bytes()), 12.5); + both_assert!(f16::from_bits(0x5be0), 252.0); + both_assert!(f16::from_ne_bytes(0x5be0u16.to_ne_bytes()), 252.0); + both_assert!(f16::from_bits(0xcb20), -14.25); + + // Check that NaNs roundtrip their bits regardless of signalingness + // 0xA is 0b1010; 0x5 is 0b0101 -- so these two together clobbers all the mantissa bits + // NOTE: These names assume `f{BITS}::NAN` is a quiet NAN and IEEE754-2008's NaN rules apply! + const QUIET_NAN: u16 = f16::NAN.to_bits() ^ 0x0155; + const SIGNALING_NAN: u16 = f16::NAN.to_bits() ^ 0x02AA; + + both_assert!(f16::from_bits(QUIET_NAN).is_nan()); + both_assert!(f16::from_bits(SIGNALING_NAN).is_nan()); + both_assert!(f16::from_bits(QUIET_NAN).to_bits(), QUIET_NAN); + if !has_broken_floats() { + both_assert!(f16::from_bits(SIGNALING_NAN).to_bits(), SIGNALING_NAN); + } +} + +fn f32() { + both_assert!((1f32).to_bits(), 0x3f800000); + both_assert!(u32::from_be_bytes(1f32.to_be_bytes()), 0x3f800000); + both_assert!((12.5f32).to_bits(), 0x41480000); + both_assert!(u32::from_le_bytes(12.5f32.to_le_bytes()), 0x41480000); + both_assert!((1337f32).to_bits(), 0x44a72000); + both_assert!(u32::from_ne_bytes(1337f32.to_ne_bytes()), 0x44a72000); + both_assert!((-14.25f32).to_bits(), 0xc1640000); + both_assert!(f32::from_bits(0x3f800000), 1.0); + both_assert!(f32::from_be_bytes(0x3f800000u32.to_be_bytes()), 1.0); + both_assert!(f32::from_bits(0x41480000), 12.5); + both_assert!(f32::from_le_bytes(0x41480000u32.to_le_bytes()), 12.5); + both_assert!(f32::from_bits(0x44a72000), 1337.0); + both_assert!(f32::from_ne_bytes(0x44a72000u32.to_ne_bytes()), 1337.0); + both_assert!(f32::from_bits(0xc1640000), -14.25); + + // Check that NaNs roundtrip their bits regardless of signalingness + // 0xA is 0b1010; 0x5 is 0b0101 -- so these two together clobbers all the mantissa bits + // NOTE: These names assume `f{BITS}::NAN` is a quiet NAN and IEEE754-2008's NaN rules apply! + const QUIET_NAN: u32 = f32::NAN.to_bits() ^ 0x002A_AAAA; + const SIGNALING_NAN: u32 = f32::NAN.to_bits() ^ 0x0055_5555; + + both_assert!(f32::from_bits(QUIET_NAN).is_nan()); + both_assert!(f32::from_bits(SIGNALING_NAN).is_nan()); + both_assert!(f32::from_bits(QUIET_NAN).to_bits(), QUIET_NAN); + if !has_broken_floats() { + both_assert!(f32::from_bits(SIGNALING_NAN).to_bits(), SIGNALING_NAN); + } +} + +fn f64() { + both_assert!((1f64).to_bits(), 0x3ff0000000000000); + both_assert!(u64::from_be_bytes(1f64.to_be_bytes()), 0x3ff0000000000000); + both_assert!((12.5f64).to_bits(), 0x4029000000000000); + both_assert!(u64::from_le_bytes(12.5f64.to_le_bytes()), 0x4029000000000000); + both_assert!((1337f64).to_bits(), 0x4094e40000000000); + both_assert!(u64::from_ne_bytes(1337f64.to_ne_bytes()), 0x4094e40000000000); + both_assert!((-14.25f64).to_bits(), 0xc02c800000000000); + both_assert!(f64::from_bits(0x3ff0000000000000), 1.0); + both_assert!(f64::from_be_bytes(0x3ff0000000000000u64.to_be_bytes()), 1.0); + both_assert!(f64::from_bits(0x4029000000000000), 12.5); + both_assert!(f64::from_le_bytes(0x4029000000000000u64.to_le_bytes()), 12.5); + both_assert!(f64::from_bits(0x4094e40000000000), 1337.0); + both_assert!(f64::from_ne_bytes(0x4094e40000000000u64.to_ne_bytes()), 1337.0); + both_assert!(f64::from_bits(0xc02c800000000000), -14.25); + + // Check that NaNs roundtrip their bits regardless of signalingness + // 0xA is 0b1010; 0x5 is 0b0101 -- so these two together clobbers all the mantissa bits + // NOTE: These names assume `f{BITS}::NAN` is a quiet NAN and IEEE754-2008's NaN rules apply! + const QUIET_NAN: u64 = f64::NAN.to_bits() ^ 0x0005_5555_5555_5555; + const SIGNALING_NAN: u64 = f64::NAN.to_bits() ^ 0x000A_AAAA_AAAA_AAAA; + + both_assert!(f64::from_bits(QUIET_NAN).is_nan()); + both_assert!(f64::from_bits(SIGNALING_NAN).is_nan()); + both_assert!(f64::from_bits(QUIET_NAN).to_bits(), QUIET_NAN); + if !has_broken_floats() { + both_assert!(f64::from_bits(SIGNALING_NAN).to_bits(), SIGNALING_NAN); + } +} + +#[cfg(target_arch = "x86_64")] +fn f128() { + both_assert!((1f128).to_bits(), 0x3fff0000000000000000000000000000); + both_assert!(u128::from_be_bytes(1f128.to_be_bytes()), 0x3fff0000000000000000000000000000); + both_assert!((12.5f128).to_bits(), 0x40029000000000000000000000000000); + both_assert!(u128::from_le_bytes(12.5f128.to_le_bytes()), 0x40029000000000000000000000000000); + both_assert!((1337f128).to_bits(), 0x40094e40000000000000000000000000); + both_assert!(u128::from_ne_bytes(1337f128.to_ne_bytes()), 0x40094e40000000000000000000000000); + both_assert!((-14.25f128).to_bits(), 0xc002c800000000000000000000000000); + both_assert!(f128::from_bits(0x3fff0000000000000000000000000000), 1.0); + both_assert!(f128::from_be_bytes(0x3fff0000000000000000000000000000u128.to_be_bytes()), 1.0); + both_assert!(f128::from_bits(0x40029000000000000000000000000000), 12.5); + both_assert!(f128::from_le_bytes(0x40029000000000000000000000000000u128.to_le_bytes()), 12.5); + both_assert!(f128::from_bits(0x40094e40000000000000000000000000), 1337.0); + assert_eq!(f128::from_ne_bytes(0x40094e40000000000000000000000000u128.to_ne_bytes()), 1337.0); + both_assert!(f128::from_bits(0xc002c800000000000000000000000000), -14.25); + + // Check that NaNs roundtrip their bits regardless of signalingness + // 0xA is 0b1010; 0x5 is 0b0101 -- so these two together clobbers all the mantissa bits + // NOTE: These names assume `f{BITS}::NAN` is a quiet NAN and IEEE754-2008's NaN rules apply! + const QUIET_NAN: u128 = f128::NAN.to_bits() | 0x0000_AAAA_AAAA_AAAA_AAAA_AAAA_AAAA_AAAA; + const SIGNALING_NAN: u128 = f128::NAN.to_bits() ^ 0x0000_5555_5555_5555_5555_5555_5555_5555; + + both_assert!(f128::from_bits(QUIET_NAN).is_nan()); + both_assert!(f128::from_bits(SIGNALING_NAN).is_nan()); + both_assert!(f128::from_bits(QUIET_NAN).to_bits(), QUIET_NAN); + if !has_broken_floats() { + both_assert!(f128::from_bits(SIGNALING_NAN).to_bits(), SIGNALING_NAN); + } +} + +fn main() { + f32(); + f64(); + + #[cfg(target_arch = "x86_64")] + { + f16(); + f128(); + } +} diff --git a/tests/ui/float/int-to-float-miscompile-issue-105626.rs b/tests/ui/float/int-to-float-miscompile-issue-105626.rs new file mode 100644 index 00000000000..8d4a7c308e7 --- /dev/null +++ b/tests/ui/float/int-to-float-miscompile-issue-105626.rs @@ -0,0 +1,17 @@ +//@ run-pass +//@ only-x86 +//@ compile-flags: -Ctarget-feature=+sse2 + +use std::hint::black_box; + +fn main() { + let n: i64 = black_box(0x3fffffdfffffff); + let r = f32::from_bits(0x5a7fffff); + + assert_ne!((n as f64) as f32, n as f32); + + // FIXME: these assertions fail if only x87 is enabled + // see also https://github.com/rust-lang/rust/issues/114479 + assert_eq!(n as i64 as f32, r); + assert_eq!(n as u64 as f32, r); +} |
