Skip to content

Backport LLVM apfloat commit to rustc_apfloat #77368

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Oct 4, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions compiler/rustc_apfloat/src/ieee.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1511,6 +1511,18 @@ impl<S: Semantics, T: Semantics> FloatConvert<IeeeFloat<T>> for IeeeFloat<S> {
sig::set_bit(&mut r.sig, T::PRECISION - 1);
}

// If we are truncating NaN, it is possible that we shifted out all of the
// set bits in a signalling NaN payload. But NaN must remain NaN, so some
// bit in the significand must be set (otherwise it is Inf).
// This can only happen with sNaN. Set the 1st bit after the quiet bit,
// so that we still have an sNaN.
if r.sig[0] == 0 {
assert!(shift < 0, "Should not lose NaN payload on extend");
assert!(T::PRECISION >= 3, "Unexpectedly narrow significand");
assert!(*loses_info, "Missing payload should have set lost info");
sig::set_bit(&mut r.sig, T::PRECISION - 3);
}

// gcc forces the Quiet bit on, which means (float)(double)(float_sNan)
// does not give you back the same bits. This is dubious, and we
// don't currently do it. You're really supposed to get
Expand Down
9 changes: 9 additions & 0 deletions compiler/rustc_apfloat/tests/ieee.rs
Original file line number Diff line number Diff line change
Expand Up @@ -566,6 +566,15 @@ fn fma() {
}
}

#[test]
fn issue_69532() {
let f = Double::from_bits(0x7FF0_0000_0000_0001u64 as u128);
let mut loses_info = false;
let r: Single = f.convert(&mut loses_info).value;
assert!(loses_info);
assert!(r.is_nan());
}

#[test]
fn min_num() {
let f1 = Double::from_f64(1.0);
Expand Down
24 changes: 24 additions & 0 deletions src/test/ui/issues/issue-69532.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// run-pass
#![feature(const_fn_transmute)]

const fn make_nans() -> (f64, f64, f32, f32) {
let nan1: f64 = unsafe { std::mem::transmute(0x7FF0_0001_0000_0001u64) };
let nan2: f64 = unsafe { std::mem::transmute(0x7FF0_0000_0000_0001u64) };

let nan1_32 = nan1 as f32;
let nan2_32 = nan2 as f32;

(nan1, nan2, nan1_32, nan2_32)
}

static NANS: (f64, f64, f32, f32) = make_nans();

fn main() {
let (nan1, nan2, nan1_32, nan2_32) = NANS;

assert!(nan1.is_nan());
assert!(nan2.is_nan());

assert!(nan1_32.is_nan());
assert!(nan2_32.is_nan());
}