Skip to content

Commit

Permalink
Advance the port to llvm/llvm-project@6dabc38
Browse files Browse the repository at this point in the history
(last APFloat-related LLVM commit from 2020).
  • Loading branch information
eddyb committed Jul 18, 2023
1 parent 00087e4 commit 5992c2f
Show file tree
Hide file tree
Showing 5 changed files with 45 additions and 20 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
members = ["fuzz"]

[workspace.package]
version = "0.0.5+llvm-a2588948febc"
version = "0.0.6+llvm-6dabc38cce73"
edition = "2021"
license = "Apache-2.0 WITH LLVM-exception"

Expand Down
2 changes: 1 addition & 1 deletion fuzz/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ echo | clang++ -x c++ - -std=c++17 \
$clang_codegen_flags \
-I "$llvm"/include \
-I "$OUT_DIR"/fake-config \
-DNDEBUG -DHAVE_UNISTD_H \
-DNDEBUG -DHAVE_UNISTD_H -DLLVM_ON_UNIX \
--include="$llvm"/lib/Support/{APInt,APFloat,SmallVector,ErrorHandling}.cpp \
--include="$OUT_DIR"/cxx_apf_fuzz.cpp \
-c -emit-llvm -o "$OUT_DIR"/cxx_apf_fuzz.bc
Expand Down
16 changes: 5 additions & 11 deletions src/ieee.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,13 +100,10 @@ pub trait Semantics: Sized {
};

if r.exp == Self::MIN_EXP - 1 && r.sig == [0] {
// Exponent, significand meaningless.
r.category = Category::Zero;
} else if r.exp == Self::MAX_EXP + 1 && r.sig == [0] {
// Exponent, significand meaningless.
r.category = Category::Infinity;
} else if r.exp == Self::MAX_EXP + 1 && r.sig != [0] {
// Sign, exponent, significand meaningless.
r.category = Category::NaN;
} else {
r.category = Category::Normal;
Expand Down Expand Up @@ -220,16 +217,14 @@ impl Semantics for X87DoubleExtendedS {
let integer_bit = r.sig[0] >> (Self::PRECISION - 1);

if r.exp == Self::MIN_EXP - 1 && r.sig == [0] {
// Exponent, significand meaningless.
r.category = Category::Zero;
} else if r.exp == Self::MAX_EXP + 1 && r.sig == [1 << (Self::PRECISION - 1)] {
// Exponent, significand meaningless.
r.category = Category::Infinity;
} else if r.exp == Self::MAX_EXP + 1 && r.sig != [1 << (Self::PRECISION - 1)]
|| r.exp != Self::MAX_EXP + 1 && r.exp != Self::MIN_EXP - 1 && integer_bit == 0
{
// Sign, exponent, significand meaningless.
r.category = Category::NaN;
r.exp = Self::MAX_EXP + 1;
} else {
r.category = Category::Normal;
if r.exp == Self::MIN_EXP - 1 {
Expand Down Expand Up @@ -1739,11 +1734,10 @@ impl<S: Semantics, T: Semantics> FloatConvert<IeeeFloat<T>> for IeeeFloat<S> {
sig::set_bit(&mut r.sig, T::PRECISION - 1);
}

// 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
// an invalid operation signal at runtime, but nobody does that.
status = Status::OK;
// Convert of sNaN creates qNaN and raises an exception (invalid op).
// This also guarantees that a sNaN does not become Inf on a truncation
// that loses all payload bits.
r = unpack!(status=, IeeeDefaultExceptionHandling::result_from_nan(r));
} else {
*loses_info = false;
status = Status::OK;
Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Port of LLVM's APFloat software floating-point implementation from the
//! following C++ sources (please update commit hash when backporting):
//! https://github.com/llvm/llvm-project/commit/a2588948febccfed5ba074fc32dcb093484fa5c8
//! https://github.com/llvm/llvm-project/commit/6dabc38cce73549ed747c537f81f6f4dd79eba39
//! * `llvm/include/llvm/ADT/APFloat.h` -> `Float` and `FloatConvert` traits
//! * `llvm/lib/Support/APFloat.cpp` -> `ieee` and `ppc` modules
//! * `llvm/unittests/ADT/APFloatTest.cpp` -> `tests` directory
Expand Down
43 changes: 37 additions & 6 deletions tests/ieee.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1743,6 +1743,8 @@ fn copy_sign() {
#[test]
fn convert() {
let mut loses_info = false;
let mut status;

let test = "1.0".parse::<Double>().unwrap();
let test: Single = test.convert(&mut loses_info).value;
assert_eq!(1.0, test.to_f32());
Expand All @@ -1768,26 +1770,45 @@ fn convert() {
assert!(!loses_info);

let test = Single::snan(None);
let x87_snan = X87DoubleExtended::snan(None);
let test: X87DoubleExtended = test.convert(&mut loses_info).value;
assert!(test.bitwise_eq(x87_snan));
let test: X87DoubleExtended = unpack!(status=, test.convert(&mut loses_info));
// Conversion quiets the SNAN, so now 2 bits of the 64-bit significand should be set.
assert!(test.bitwise_eq(X87DoubleExtended::qnan(Some(0x6000000000000000))));
assert!(!loses_info);
assert_eq!(status, Status::INVALID_OP);

let test = Single::qnan(None);
let x87_qnan = X87DoubleExtended::qnan(None);
let test: X87DoubleExtended = test.convert(&mut loses_info).value;
assert!(test.bitwise_eq(x87_qnan));
assert!(!loses_info);

let test = X87DoubleExtended::snan(None);
// NOTE(eddyb) these were mistakenly noops upstream, here they're already
// fixed (by instead converting from `Double` to `X87DoubleExtended`),
// see also upstream issue https://github.com/llvm/llvm-project/issues/63842.
let test = Double::snan(None);
let test: X87DoubleExtended = test.convert(&mut loses_info).value;
assert!(test.bitwise_eq(x87_snan));
// Conversion quiets the SNAN, so now 2 bits of the 64-bit significand should be set.
assert!(test.bitwise_eq(X87DoubleExtended::qnan(Some(0x6000000000000000))));
assert!(!loses_info);

let test = X87DoubleExtended::qnan(None);
let test = Double::qnan(None);
let test: X87DoubleExtended = test.convert(&mut loses_info).value;
assert!(test.bitwise_eq(x87_qnan));
assert!(!loses_info);

// The payload is lost in truncation, but we retain NaN by setting the quiet bit.
let test = Double::snan(Some(1));
let test: Single = unpack!(status=, test.convert(&mut loses_info));
assert_eq!(0x7fc00000, test.to_bits());
assert!(loses_info);
assert_eq!(status, Status::INVALID_OP);

// The payload is lost in truncation. QNaN remains QNaN.
let test = Double::qnan(Some(1));
let test: Single = unpack!(status=, test.convert(&mut loses_info));
assert_eq!(0x7fc00000, test.to_bits());
assert!(loses_info);
assert_eq!(status, Status::OK);
}

#[test]
Expand Down Expand Up @@ -3978,3 +3999,13 @@ fn remainder() {
assert_eq!(status, Status::OK);
}
}

#[test]
fn x87_largest() {
assert!(X87DoubleExtended::largest().is_largest());
}

#[test]
fn x87_next() {
assert_eq!("-1.0".parse::<X87DoubleExtended>().unwrap().next_up().value.ilogb(), -1);
}

0 comments on commit 5992c2f

Please sign in to comment.