Skip to content

Commit d010809

Browse files
committed
Backport another LLVM commit to rustc_apfloat
Backports LLVM commit: [APFloat] convert SNaN to QNaN in convert() and raise Invalid signal llvm/llvm-project@149f5b5 SNaN to QNaN conversion also matches what my Intel x86_64 hardware does.
1 parent 7f5008c commit d010809

File tree

2 files changed

+27
-27
lines changed

2 files changed

+27
-27
lines changed

compiler/rustc_apfloat/src/ieee.rs

+10-17
Original file line numberDiff line numberDiff line change
@@ -1511,23 +1511,16 @@ impl<S: Semantics, T: Semantics> FloatConvert<IeeeFloat<T>> for IeeeFloat<S> {
15111511
sig::set_bit(&mut r.sig, T::PRECISION - 1);
15121512
}
15131513

1514-
// If we are truncating NaN, it is possible that we shifted out all of the
1515-
// set bits in a signalling NaN payload. But NaN must remain NaN, so some
1516-
// bit in the significand must be set (otherwise it is Inf).
1517-
// This can only happen with sNaN. Set the 1st bit after the quiet bit,
1518-
// so that we still have an sNaN.
1519-
if r.sig[0] == 0 {
1520-
assert!(shift < 0, "Should not lose NaN payload on extend");
1521-
assert!(T::PRECISION >= 3, "Unexpectedly narrow significand");
1522-
assert!(*loses_info, "Missing payload should have set lost info");
1523-
sig::set_bit(&mut r.sig, T::PRECISION - 3);
1524-
}
1525-
1526-
// gcc forces the Quiet bit on, which means (float)(double)(float_sNan)
1527-
// does not give you back the same bits. This is dubious, and we
1528-
// don't currently do it. You're really supposed to get
1529-
// an invalid operation signal at runtime, but nobody does that.
1530-
status = Status::OK;
1514+
// Convert of sNaN creates qNaN and raises an exception (invalid op).
1515+
// This also guarantees that a sNaN does not become Inf on a truncation
1516+
// that loses all payload bits.
1517+
if self.is_signaling() {
1518+
// Quiet signaling NaN.
1519+
sig::set_bit(&mut r.sig, T::QNAN_BIT);
1520+
status = Status::INVALID_OP;
1521+
} else {
1522+
status = Status::OK;
1523+
}
15311524
} else {
15321525
*loses_info = false;
15331526
status = Status::OK;

compiler/rustc_apfloat/tests/ieee.rs

+17-10
Original file line numberDiff line numberDiff line change
@@ -570,9 +570,11 @@ fn fma() {
570570
fn issue_69532() {
571571
let f = Double::from_bits(0x7FF0_0000_0000_0001u64 as u128);
572572
let mut loses_info = false;
573-
let r: Single = f.convert(&mut loses_info).value;
573+
let sta = f.convert(&mut loses_info);
574+
let r: Single = sta.value;
574575
assert!(loses_info);
575576
assert!(r.is_nan());
577+
assert_eq!(sta.status, Status::INVALID_OP);
576578
}
577579

578580
#[test]
@@ -1501,27 +1503,32 @@ fn convert() {
15011503
assert_eq!(4294967295.0, test.to_f64());
15021504
assert!(!loses_info);
15031505

1504-
let test = Single::snan(None);
1505-
let x87_snan = X87DoubleExtended::snan(None);
1506-
let test: X87DoubleExtended = test.convert(&mut loses_info).value;
1507-
assert!(test.bitwise_eq(x87_snan));
1508-
assert!(!loses_info);
1509-
15101506
let test = Single::qnan(None);
15111507
let x87_qnan = X87DoubleExtended::qnan(None);
15121508
let test: X87DoubleExtended = test.convert(&mut loses_info).value;
15131509
assert!(test.bitwise_eq(x87_qnan));
15141510
assert!(!loses_info);
15151511

1516-
let test = X87DoubleExtended::snan(None);
1517-
let test: X87DoubleExtended = test.convert(&mut loses_info).value;
1518-
assert!(test.bitwise_eq(x87_snan));
1512+
let test = Single::snan(None);
1513+
let sta = test.convert(&mut loses_info);
1514+
let test: X87DoubleExtended = sta.value;
1515+
assert!(test.is_nan());
1516+
assert!(!test.is_signaling());
15191517
assert!(!loses_info);
1518+
assert_eq!(sta.status, Status::INVALID_OP);
15201519

15211520
let test = X87DoubleExtended::qnan(None);
15221521
let test: X87DoubleExtended = test.convert(&mut loses_info).value;
15231522
assert!(test.bitwise_eq(x87_qnan));
15241523
assert!(!loses_info);
1524+
1525+
let test = X87DoubleExtended::snan(None);
1526+
let sta = test.convert(&mut loses_info);
1527+
let test: X87DoubleExtended = sta.value;
1528+
assert!(test.is_nan());
1529+
assert!(!test.is_signaling());
1530+
assert!(!loses_info);
1531+
assert_eq!(sta.status, Status::INVALID_OP);
15251532
}
15261533

15271534
#[test]

0 commit comments

Comments
 (0)