Skip to content

Commit 45c2345

Browse files
committed
Advance the port to llvm/llvm-project@69f6098
(last APFloat-related LLVM commit from 2018). This commit is also notable as the last APFloat-related commit before the LLVM relicensing in early 2019 (llvm/llvm-project@2946cd7).
1 parent 697bf3c commit 45c2345

File tree

5 files changed

+118
-29
lines changed

5 files changed

+118
-29
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
members = ["fuzz"]
33

44
[workspace.package]
5-
version = "0.0.1+llvm-768d6dd08783"
5+
version = "0.0.2+llvm-69f6098e8931"
66
edition = "2021"
77
license = "Apache-2.0 WITH LLVM-exception"
88

src/ieee.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -199,9 +199,9 @@ impl Semantics for X87DoubleExtendedS {
199199
/// does not support these bit patterns:
200200
/// exponent = all 1's, integer bit 0, significand 0 ("pseudoinfinity")
201201
/// exponent = all 1's, integer bit 0, significand nonzero ("pseudoNaN")
202-
/// exponent = 0, integer bit 1 ("pseudodenormal")
203202
/// exponent!=0 nor all 1's, integer bit 0 ("unnormal")
204-
/// At the moment, the first two are treated as NaNs, the second two as Normal.
203+
/// exponent = 0, integer bit 1 ("pseudodenormal")
204+
/// At the moment, the first three are treated as NaNs, the last one as Normal.
205205
fn from_bits(bits: u128) -> IeeeFloat<Self> {
206206
let sign = bits & (1 << (Self::BITS - 1));
207207
let exponent = (bits & !sign) >> Self::PRECISION;
@@ -214,13 +214,17 @@ impl Semantics for X87DoubleExtendedS {
214214
marker: PhantomData,
215215
};
216216

217+
let integer_bit = r.sig[0] >> (Self::PRECISION - 1);
218+
217219
if r.exp == Self::MIN_EXP - 1 && r.sig == [0] {
218220
// Exponent, significand meaningless.
219221
r.category = Category::Zero;
220222
} else if r.exp == Self::MAX_EXP + 1 && r.sig == [1 << (Self::PRECISION - 1)] {
221223
// Exponent, significand meaningless.
222224
r.category = Category::Infinity;
223-
} else if r.exp == Self::MAX_EXP + 1 && r.sig != [1 << (Self::PRECISION - 1)] {
225+
} else if r.exp == Self::MAX_EXP + 1 && r.sig != [1 << (Self::PRECISION - 1)]
226+
|| r.exp != Self::MAX_EXP + 1 && r.exp != Self::MIN_EXP - 1 && integer_bit == 0
227+
{
224228
// Sign, exponent, significand meaningless.
225229
r.category = Category::NaN;
226230
} else {

src/lib.rs

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! Port of LLVM's APFloat software floating-point implementation from the
22
//! following C++ sources (please update commit hash when backporting):
3-
//! https://github.com/llvm/llvm-project/commit/768d6dd08783440606da83dac490889329619898
3+
//! https://github.com/llvm/llvm-project/commit/69f6098e89312b934ed87e4cd3603401a9b436b4
44
//! * `llvm/include/llvm/ADT/APFloat.h` -> `Float` and `FloatConvert` traits
55
//! * `llvm/lib/Support/APFloat.cpp` -> `ieee` and `ppc` modules
66
//! * `llvm/unittests/ADT/APFloatTest.cpp` -> `tests` directory
@@ -456,6 +456,46 @@ pub trait Float:
456456
}
457457
}
458458

459+
/// Implements IEEE 754-2018 minimum semantics. Returns the smaller of 2
460+
/// arguments, propagating NaNs and treating -0 as less than +0.
461+
fn minimum(self, other: Self) -> Self {
462+
if self.is_nan() {
463+
self
464+
} else if other.is_nan() {
465+
other
466+
} else if self.is_zero() && other.is_zero() && self.is_negative() != other.is_negative() {
467+
if self.is_negative() {
468+
self
469+
} else {
470+
other
471+
}
472+
} else if other.partial_cmp(&self) == Some(Ordering::Less) {
473+
other
474+
} else {
475+
self
476+
}
477+
}
478+
479+
/// Implements IEEE 754-2018 maximum semantics. Returns the larger of 2
480+
/// arguments, propagating NaNs and treating -0 as less than +0.
481+
fn maximum(self, other: Self) -> Self {
482+
if self.is_nan() {
483+
self
484+
} else if other.is_nan() {
485+
other
486+
} else if self.is_zero() && other.is_zero() && self.is_negative() != other.is_negative() {
487+
if self.is_negative() {
488+
other
489+
} else {
490+
self
491+
}
492+
} else if self.partial_cmp(&other) == Some(Ordering::Less) {
493+
other
494+
} else {
495+
self
496+
}
497+
}
498+
459499
/// IEEE-754R isSignMinus: Returns true if and only if the current value is
460500
/// negative.
461501
///

tests/downstream.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -391,10 +391,7 @@ fn fuzz_fma_with_expected_outputs() {
391391
// found many examples in all ops, as the root issue was the handling of the
392392
// bit-level encoding itself, but negation was the easiest op to test here).
393393
pub const FUZZ_X87_F80_NEG_CASES_WITH_EXPECTED_OUTPUTS: &[(u128, u128)] = &[
394-
(
395-
0x01010101010100000000, /* 3.05337213397376214408E-4857 */
396-
0x81010101010100000000, /* -3.05337213397376214408E-4857 */
397-
),
394+
(0x01010101010100000000 /* NaN */, 0xffff0101010100000000 /* NaN */),
398395
(
399396
0x0000ff7f2300ff000000, /* 6.71098449692300485303E-4932 */
400397
0x8001ff7f2300ff000000, /* -6.71098449692300485303E-4932 */

tests/ieee.rs

Lines changed: 68 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -590,6 +590,38 @@ fn max_num() {
590590
assert_eq!(1.0, nan.max(f1).to_f64());
591591
}
592592

593+
#[test]
594+
fn minimum() {
595+
let f1 = Double::from_f64(1.0);
596+
let f2 = Double::from_f64(2.0);
597+
let zp = Double::from_f64(0.0);
598+
let zn = Double::from_f64(-0.0);
599+
let nan = Double::NAN;
600+
601+
assert_eq!(1.0, f1.minimum(f2).to_f64());
602+
assert_eq!(1.0, f2.minimum(f1).to_f64());
603+
assert_eq!(-0.0, zp.minimum(zn).to_f64());
604+
assert_eq!(-0.0, zn.minimum(zp).to_f64());
605+
assert!(f1.minimum(nan).to_f64().is_nan());
606+
assert!(nan.minimum(f1).to_f64().is_nan());
607+
}
608+
609+
#[test]
610+
fn maximum() {
611+
let f1 = Double::from_f64(1.0);
612+
let f2 = Double::from_f64(2.0);
613+
let zp = Double::from_f64(0.0);
614+
let zn = Double::from_f64(-0.0);
615+
let nan = Double::NAN;
616+
617+
assert_eq!(2.0, f1.maximum(f2).to_f64());
618+
assert_eq!(2.0, f2.maximum(f1).to_f64());
619+
assert_eq!(0.0, zp.maximum(zn).to_f64());
620+
assert_eq!(0.0, zn.maximum(zp).to_f64());
621+
assert!(f1.maximum(nan).to_f64().is_nan());
622+
assert!(nan.maximum(f1).to_f64().is_nan());
623+
}
624+
593625
#[test]
594626
fn denormal() {
595627
// Test single precision
@@ -1003,6 +1035,7 @@ fn to_string() {
10031035
assert_eq!("873.18340000000001", to_string(873.1834, 0, 1));
10041036
assert_eq!("8.73183400000000010e+02", to_string(873.1834, 0, 0));
10051037
assert_eq!("1.79769313486231570e+308", to_string(1.7976931348623157E+308, 0, 0));
1038+
assert_eq!("NaN", X87DoubleExtended::from_bits(1 << 64).to_string());
10061039
}
10071040

10081041
#[test]
@@ -1072,11 +1105,11 @@ fn to_integer() {
10721105

10731106
#[test]
10741107
fn nan() {
1075-
fn nanbits<T: Float>(signaling: bool, negative: bool, fill: u128) -> u128 {
1108+
fn nanbits_from_u128<T: Float>(signaling: bool, negative: bool, payload: u128) -> u128 {
10761109
let x = if signaling {
1077-
T::snan(Some(fill))
1110+
T::snan(Some(payload))
10781111
} else {
1079-
T::qnan(Some(fill))
1112+
T::qnan(Some(payload))
10801113
};
10811114
if negative {
10821115
(-x).to_bits()
@@ -1085,23 +1118,38 @@ fn nan() {
10851118
}
10861119
}
10871120

1088-
assert_eq!(0x7fc00000, nanbits::<Single>(false, false, 0));
1089-
assert_eq!(0xffc00000, nanbits::<Single>(false, true, 0));
1090-
assert_eq!(0x7fc0ae72, nanbits::<Single>(false, false, 0xae72));
1091-
assert_eq!(0x7fffae72, nanbits::<Single>(false, false, 0xffffae72));
1092-
assert_eq!(0x7fa00000, nanbits::<Single>(true, false, 0));
1093-
assert_eq!(0xffa00000, nanbits::<Single>(true, true, 0));
1094-
assert_eq!(0x7f80ae72, nanbits::<Single>(true, false, 0xae72));
1095-
assert_eq!(0x7fbfae72, nanbits::<Single>(true, false, 0xffffae72));
1096-
1097-
assert_eq!(0x7ff8000000000000, nanbits::<Double>(false, false, 0));
1098-
assert_eq!(0xfff8000000000000, nanbits::<Double>(false, true, 0));
1099-
assert_eq!(0x7ff800000000ae72, nanbits::<Double>(false, false, 0xae72));
1100-
assert_eq!(0x7fffffffffffae72, nanbits::<Double>(false, false, 0xffffffffffffae72));
1101-
assert_eq!(0x7ff4000000000000, nanbits::<Double>(true, false, 0));
1102-
assert_eq!(0xfff4000000000000, nanbits::<Double>(true, true, 0));
1103-
assert_eq!(0x7ff000000000ae72, nanbits::<Double>(true, false, 0xae72));
1104-
assert_eq!(0x7ff7ffffffffae72, nanbits::<Double>(true, false, 0xffffffffffffae72));
1121+
let tests_single = [
1122+
// expected SNaN Neg payload
1123+
(0x7fc00000, false, false, 0x00000000),
1124+
(0xffc00000, false, true, 0x00000000),
1125+
(0x7fc0ae72, false, false, 0x0000ae72),
1126+
(0x7fffae72, false, false, 0xffffae72),
1127+
(0x7fdaae72, false, false, 0x00daae72),
1128+
(0x7fa00000, true, false, 0x00000000),
1129+
(0xffa00000, true, true, 0x00000000),
1130+
(0x7f80ae72, true, false, 0x0000ae72),
1131+
(0x7fbfae72, true, false, 0xffffae72),
1132+
(0x7f9aae72, true, false, 0x001aae72),
1133+
];
1134+
let tests_double = [
1135+
// expected SNaN Neg payload
1136+
(0x7ff8000000000000, false, false, 0x0000000000000000),
1137+
(0xfff8000000000000, false, true, 0x0000000000000000),
1138+
(0x7ff800000000ae72, false, false, 0x000000000000ae72),
1139+
(0x7fffffffffffae72, false, false, 0xffffffffffffae72),
1140+
(0x7ffdaaaaaaaaae72, false, false, 0x000daaaaaaaaae72),
1141+
(0x7ff4000000000000, true, false, 0x0000000000000000),
1142+
(0xfff4000000000000, true, true, 0x0000000000000000),
1143+
(0x7ff000000000ae72, true, false, 0x000000000000ae72),
1144+
(0x7ff7ffffffffae72, true, false, 0xffffffffffffae72),
1145+
(0x7ff1aaaaaaaaae72, true, false, 0x0001aaaaaaaaae72),
1146+
];
1147+
for (expected, signaling, negative, payload) in tests_single {
1148+
assert_eq!(expected, nanbits_from_u128::<Single>(signaling, negative, payload));
1149+
}
1150+
for (expected, signaling, negative, payload) in tests_double {
1151+
assert_eq!(expected, nanbits_from_u128::<Double>(signaling, negative, payload));
1152+
}
11051153
}
11061154

11071155
#[test]

0 commit comments

Comments
 (0)