Skip to content

Commit 339c8f3

Browse files
committed
Advance the port to llvm/llvm-project@f45d5e7
(last APFloat-related LLVM commit from 2021).
1 parent b3a5da8 commit 339c8f3

File tree

3 files changed

+245
-3
lines changed

3 files changed

+245
-3
lines changed

fuzz/build.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ fn main() -> std::io::Result<ExitCode> {
4343
// FIXME(eddyb) ensure this is kept in sync.
4444
(
4545
"llvm_project_git_hash",
46-
"6dabc38cce73549ed747c537f81f6f4dd79eba39",
46+
"f45d5e71d3e1ef9d565815850681719418a99d19",
4747
),
4848
("cxx_apf_fuzz_exports", &cxx_exported_symbols.join(",")),
4949
(

src/lib.rs

Lines changed: 1 addition & 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/6dabc38cce73549ed747c537f81f6f4dd79eba39
3+
//! https://github.com/llvm/llvm-project/commit/f45d5e71d3e1ef9d565815850681719418a99d19
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

tests/ieee.rs

Lines changed: 243 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
extern crate rustc_apfloat;
33

44
use core::cmp::Ordering;
5-
use rustc_apfloat::ieee::{Double, Half, Quad, Single, X87DoubleExtended};
5+
use rustc_apfloat::ieee::{BFloat, Double, Half, Quad, Single, X87DoubleExtended};
66
use rustc_apfloat::{Category, ExpInt, IEK_INF, IEK_NAN, IEK_ZERO};
77
use rustc_apfloat::{Float, FloatConvert, Round, Status};
88

@@ -36,6 +36,35 @@ impl DoubleExt for Double {
3636
}
3737
}
3838

39+
// NOTE(eddyb) these match the C++ `convertToFloat`/`convertToDouble` methods,
40+
// after their generalization to allow an optional lossless conversion to their
41+
// expected semantics (from e.g. `IEEEhalf`/`BFloat`, for `convertToSingle`).
42+
// FIXME(eddyb) should the methods have e.g. `_lossless_via_convert` in their names?
43+
fn assert_lossless_conversion<S: FloatConvert<T>, T: Float>(src: S) -> T {
44+
let mut loses_info = false;
45+
let status;
46+
let r = unpack!(status=, src.convert(&mut loses_info));
47+
assert!(!status.intersects(Status::INEXACT) && !loses_info, "Unexpected imprecision");
48+
r
49+
}
50+
51+
trait ToF32LosslessViaConvertToSingle: FloatConvert<Single> {
52+
fn to_f32(self) -> f32 {
53+
assert_lossless_conversion(self).to_f32()
54+
}
55+
}
56+
impl ToF32LosslessViaConvertToSingle for Half {}
57+
impl ToF32LosslessViaConvertToSingle for BFloat {}
58+
59+
trait ToF64LosslessViaConvertToDouble: FloatConvert<Double> {
60+
fn to_f64(self) -> f64 {
61+
assert_lossless_conversion(self).to_f64()
62+
}
63+
}
64+
impl ToF64LosslessViaConvertToDouble for Single {}
65+
// HACK(eddyb) take advantage of the transitivity of "are conversions lossless".
66+
impl<T: ToF32LosslessViaConvertToSingle + FloatConvert<Double>> ToF64LosslessViaConvertToDouble for T {}
67+
3968
#[test]
4069
fn is_signaling() {
4170
// We test qNaN, -qNaN, +sNaN, -sNaN with and without payloads.
@@ -4009,3 +4038,216 @@ fn x87_largest() {
40094038
fn x87_next() {
40104039
assert_eq!("-1.0".parse::<X87DoubleExtended>().unwrap().next_up().value.ilogb(), -1);
40114040
}
4041+
4042+
// HACK(eddyb) C`{FLT,DBL}_TRUE_MIN` / C++ `std::numeric_limits<T>::denorm_min`
4043+
// equivalents, for the two tests below, as Rust seems to lack anything like them,
4044+
// but their bit-patterns are thankfuly trivial, with the main caveat that they
4045+
// can't be `const` (subnormals and NaNs are banned from CTFE `{to,from}_bits`).
4046+
fn f64_smallest_subnormal() -> f64 {
4047+
f64::from_bits(1)
4048+
}
4049+
fn f32_smallest_subnormal() -> f32 {
4050+
f32::from_bits(1)
4051+
}
4052+
4053+
#[test]
4054+
fn to_f64() {
4055+
let d_pos_zero = Double::from_f64(0.0);
4056+
assert!(Double::from_f64(d_pos_zero.to_f64()).is_pos_zero());
4057+
let d_neg_zero = Double::from_f64(-0.0);
4058+
assert!(Double::from_f64(d_neg_zero.to_f64()).is_neg_zero());
4059+
4060+
let d_one = Double::from_f64(1.0);
4061+
assert_eq!(1.0, d_one.to_f64());
4062+
let d_pos_largest = Double::largest();
4063+
assert_eq!(f64::MAX, d_pos_largest.to_f64());
4064+
let d_neg_largest = -Double::largest();
4065+
assert_eq!(-f64::MAX, d_neg_largest.to_f64());
4066+
let d_pos_smallest = Double::smallest_normalized();
4067+
assert_eq!(f64::MIN_POSITIVE, d_pos_smallest.to_f64());
4068+
let d_neg_smallest = -Double::smallest_normalized();
4069+
assert_eq!(-f64::MIN_POSITIVE, d_neg_smallest.to_f64());
4070+
4071+
let d_smallest_denorm = Double::SMALLEST;
4072+
assert_eq!(f64_smallest_subnormal(), d_smallest_denorm.to_f64());
4073+
let d_largest_denorm = "0x0.FFFFFFFFFFFFFp-1022".parse::<Double>().unwrap();
4074+
assert_eq!(/*0x0.FFFFFFFFFFFFFp-1022*/ 2.225073858507201e-308, d_largest_denorm.to_f64());
4075+
4076+
let d_pos_inf = Double::INFINITY;
4077+
assert_eq!(f64::INFINITY, d_pos_inf.to_f64());
4078+
let d_neg_inf = -Double::INFINITY;
4079+
assert_eq!(-f64::INFINITY, d_neg_inf.to_f64());
4080+
let d_qnan = Double::qnan(None);
4081+
assert!(d_qnan.to_f64().is_nan());
4082+
4083+
let f_pos_zero = Single::from_f32(0.0);
4084+
assert!(Double::from_f64(f_pos_zero.to_f64()).is_pos_zero());
4085+
let f_neg_zero = Single::from_f32(-0.0);
4086+
assert!(Double::from_f64(f_neg_zero.to_f64()).is_neg_zero());
4087+
4088+
let f_one = Single::from_f32(1.0);
4089+
assert_eq!(1.0, f_one.to_f64());
4090+
let f_pos_largest = Single::largest();
4091+
assert_eq!(f32::MAX as f64, f_pos_largest.to_f64());
4092+
let f_neg_largest = -Single::largest();
4093+
assert_eq!(-f32::MAX as f64, f_neg_largest.to_f64());
4094+
let f_pos_smallest = Single::smallest_normalized();
4095+
assert_eq!(f32::MIN_POSITIVE as f64, f_pos_smallest.to_f64());
4096+
let f_neg_smallest = -Single::smallest_normalized();
4097+
assert_eq!(-f32::MIN_POSITIVE as f64, f_neg_smallest.to_f64());
4098+
4099+
let f_smallest_denorm = Single::SMALLEST;
4100+
assert_eq!(f32_smallest_subnormal() as f64, f_smallest_denorm.to_f64());
4101+
let f_largest_denorm = "0x0.FFFFFEp-126".parse::<Double>().unwrap();
4102+
assert_eq!(/*0x0.FFFFFEp-126*/ 1.1754942106924411e-38, f_largest_denorm.to_f64());
4103+
4104+
let f_pos_inf = Single::INFINITY;
4105+
assert_eq!(f64::INFINITY, f_pos_inf.to_f64());
4106+
let f_neg_inf = -Single::INFINITY;
4107+
assert_eq!(-f64::INFINITY, f_neg_inf.to_f64());
4108+
let f_qnan = Single::qnan(None);
4109+
assert!(f_qnan.to_f64().is_nan());
4110+
4111+
let h_pos_zero = Half::ZERO;
4112+
assert!(Double::from_f64(h_pos_zero.to_f64()).is_pos_zero());
4113+
let h_neg_zero = -Half::ZERO;
4114+
assert!(Double::from_f64(h_neg_zero.to_f64()).is_neg_zero());
4115+
4116+
let h_one = "1.0".parse::<Half>().unwrap();
4117+
assert_eq!(1.0, h_one.to_f64());
4118+
let h_pos_largest = Half::largest();
4119+
assert_eq!(65504.0, h_pos_largest.to_f64());
4120+
let h_neg_largest = -Half::largest();
4121+
assert_eq!(-65504.0, h_neg_largest.to_f64());
4122+
let h_pos_smallest = Half::smallest_normalized();
4123+
assert_eq!(/*0x1.p-14*/ 6.103515625e-05, h_pos_smallest.to_f64());
4124+
let h_neg_smallest = -Half::smallest_normalized();
4125+
assert_eq!(/*-0x1.p-14*/ -6.103515625e-05, h_neg_smallest.to_f64());
4126+
4127+
let h_smallest_denorm = Half::SMALLEST;
4128+
assert_eq!(/*0x1.p-24*/ 5.960464477539063e-08, h_smallest_denorm.to_f64());
4129+
let h_largest_denorm = "0x1.FFCp-14".parse::<Half>().unwrap();
4130+
assert_eq!(/*0x1.FFCp-14*/ 0.00012201070785522461, h_largest_denorm.to_f64());
4131+
4132+
let h_pos_inf = Half::INFINITY;
4133+
assert_eq!(f64::INFINITY, h_pos_inf.to_f64());
4134+
let h_neg_inf = -Half::INFINITY;
4135+
assert_eq!(-f64::INFINITY, h_neg_inf.to_f64());
4136+
let h_qnan = Half::qnan(None);
4137+
assert!(h_qnan.to_f64().is_nan());
4138+
4139+
let b_pos_zero = Half::ZERO;
4140+
assert!(Double::from_f64(b_pos_zero.to_f64()).is_pos_zero());
4141+
let b_neg_zero = -Half::ZERO;
4142+
assert!(Double::from_f64(b_neg_zero.to_f64()).is_neg_zero());
4143+
4144+
let b_one = "1.0".parse::<BFloat>().unwrap();
4145+
assert_eq!(1.0, b_one.to_f64());
4146+
let b_pos_largest = BFloat::largest();
4147+
assert_eq!(/*0x1.FEp127*/ 3.3895313892515355e+38, b_pos_largest.to_f64());
4148+
let b_neg_largest = -BFloat::largest();
4149+
assert_eq!(/*-0x1.FEp127*/ -3.3895313892515355e+38, b_neg_largest.to_f64());
4150+
let b_pos_smallest = BFloat::smallest_normalized();
4151+
assert_eq!(/*0x1.p-126*/ 1.1754943508222875e-38, b_pos_smallest.to_f64());
4152+
let b_neg_smallest = -BFloat::smallest_normalized();
4153+
assert_eq!(/*-0x1.p-126*/ -1.1754943508222875e-38, b_neg_smallest.to_f64());
4154+
4155+
let b_smallest_denorm = BFloat::SMALLEST;
4156+
assert_eq!(/*0x1.p-133*/ 9.183549615799121e-41, b_smallest_denorm.to_f64());
4157+
let b_largest_denorm = "0x1.FCp-127".parse::<BFloat>().unwrap();
4158+
assert_eq!(/*0x1.FCp-127*/ 1.1663108012064884e-38, b_largest_denorm.to_f64());
4159+
4160+
let b_pos_inf = BFloat::INFINITY;
4161+
assert_eq!(f64::INFINITY, b_pos_inf.to_f64());
4162+
let b_neg_inf = -BFloat::INFINITY;
4163+
assert_eq!(-f64::INFINITY, b_neg_inf.to_f64());
4164+
let b_qnan = BFloat::qnan(None);
4165+
assert!(b_qnan.to_f64().is_nan());
4166+
}
4167+
4168+
#[test]
4169+
fn to_f32() {
4170+
let f_pos_zero = Single::from_f32(0.0);
4171+
assert!(Single::from_f32(f_pos_zero.to_f32()).is_pos_zero());
4172+
let f_neg_zero = Single::from_f32(-0.0);
4173+
assert!(Single::from_f32(f_neg_zero.to_f32()).is_neg_zero());
4174+
4175+
let f_one = Single::from_f32(1.0);
4176+
assert_eq!(1.0, f_one.to_f32());
4177+
let f_pos_largest = Single::largest();
4178+
assert_eq!(f32::MAX, f_pos_largest.to_f32());
4179+
let f_neg_largest = -Single::largest();
4180+
assert_eq!(-f32::MAX, f_neg_largest.to_f32());
4181+
let f_pos_smallest = Single::smallest_normalized();
4182+
assert_eq!(f32::MIN_POSITIVE, f_pos_smallest.to_f32());
4183+
let f_neg_smallest = -Single::smallest_normalized();
4184+
assert_eq!(-f32::MIN_POSITIVE, f_neg_smallest.to_f32());
4185+
4186+
let f_smallest_denorm = Single::SMALLEST;
4187+
assert_eq!(f32_smallest_subnormal(), f_smallest_denorm.to_f32());
4188+
let f_largest_denorm = "0x1.FFFFFEp-126".parse::<Single>().unwrap();
4189+
assert_eq!(/*0x1.FFFFFEp-126*/ 2.3509885615147286e-38, f_largest_denorm.to_f32());
4190+
4191+
let f_pos_inf = Single::INFINITY;
4192+
assert_eq!(f32::INFINITY, f_pos_inf.to_f32());
4193+
let f_neg_inf = -Single::INFINITY;
4194+
assert_eq!(-f32::INFINITY, f_neg_inf.to_f32());
4195+
let f_qnan = Single::qnan(None);
4196+
assert!(f_qnan.to_f32().is_nan());
4197+
4198+
let h_pos_zero = Half::ZERO;
4199+
assert!(Single::from_f32(h_pos_zero.to_f32()).is_pos_zero());
4200+
let h_neg_zero = -Half::ZERO;
4201+
assert!(Single::from_f32(h_neg_zero.to_f32()).is_neg_zero());
4202+
4203+
let h_one = "1.0".parse::<Half>().unwrap();
4204+
assert_eq!(1.0, h_one.to_f32());
4205+
let h_pos_largest = Half::largest();
4206+
assert_eq!(/*0x1.FFCp15*/ 65504.0, h_pos_largest.to_f32());
4207+
let h_neg_largest = -Half::largest();
4208+
assert_eq!(/*-0x1.FFCp15*/ -65504.0, h_neg_largest.to_f32());
4209+
let h_pos_smallest = Half::smallest_normalized();
4210+
assert_eq!(/*0x1.p-14*/ 6.103515625e-05, h_pos_smallest.to_f32());
4211+
let h_neg_smallest = -Half::smallest_normalized();
4212+
assert_eq!(/*-0x1.p-14*/ -6.103515625e-05, h_neg_smallest.to_f32());
4213+
4214+
let h_smallest_denorm = Half::SMALLEST;
4215+
assert_eq!(/*0x1.p-24*/ 5.960464477539063e-08, h_smallest_denorm.to_f32());
4216+
let h_largest_denorm = "0x1.FFCp-14".parse::<Half>().unwrap();
4217+
assert_eq!(/*0x1.FFCp-14*/ 0.00012201070785522461, h_largest_denorm.to_f32());
4218+
4219+
let h_pos_inf = Half::INFINITY;
4220+
assert_eq!(f32::INFINITY, h_pos_inf.to_f32());
4221+
let h_neg_inf = -Half::INFINITY;
4222+
assert_eq!(-f32::INFINITY, h_neg_inf.to_f32());
4223+
let h_qnan = Half::qnan(None);
4224+
assert!(h_qnan.to_f32().is_nan());
4225+
4226+
let b_pos_zero = BFloat::ZERO;
4227+
assert!(Single::from_f32(b_pos_zero.to_f32()).is_pos_zero());
4228+
let b_neg_zero = -BFloat::ZERO;
4229+
assert!(Single::from_f32(b_neg_zero.to_f32()).is_neg_zero());
4230+
4231+
let b_one = "1.0".parse::<BFloat>().unwrap();
4232+
assert_eq!(1.0, b_one.to_f32());
4233+
let b_pos_largest = BFloat::largest();
4234+
assert_eq!(/*0x1.FEp127*/ 3.3895313892515355e+38, b_pos_largest.to_f32());
4235+
let b_neg_largest = -BFloat::largest();
4236+
assert_eq!(/*-0x1.FEp127*/ -3.3895313892515355e+38, b_neg_largest.to_f32());
4237+
let b_pos_smallest = BFloat::smallest_normalized();
4238+
assert_eq!(/*0x1.p-126*/ 1.1754943508222875e-38, b_pos_smallest.to_f32());
4239+
let b_neg_smallest = -BFloat::smallest_normalized();
4240+
assert_eq!(/*-0x1.p-126*/ -1.1754943508222875e-38, b_neg_smallest.to_f32());
4241+
4242+
let b_smallest_denorm = BFloat::SMALLEST;
4243+
assert_eq!(/*0x1.p-133*/ 9.183549615799121e-41, b_smallest_denorm.to_f32());
4244+
let b_largest_denorm = "0x1.FCp-127".parse::<BFloat>().unwrap();
4245+
assert_eq!(/*0x1.FCp-127*/ 1.1663108012064884e-38, b_largest_denorm.to_f32());
4246+
4247+
let b_pos_inf = BFloat::INFINITY;
4248+
assert_eq!(f32::INFINITY, b_pos_inf.to_f32());
4249+
let b_neg_inf = -BFloat::INFINITY;
4250+
assert_eq!(-f32::INFINITY, b_neg_inf.to_f32());
4251+
let b_qnan = BFloat::qnan(None);
4252+
assert!(b_qnan.to_f32().is_nan());
4253+
}

0 commit comments

Comments
 (0)