[libc-commits] [libc] [llvm] [libc] Add `next_toward_inf` fo `FPBits` (PR #80654)
Guillaume Chatelet via libc-commits
libc-commits at lists.llvm.org
Mon Feb 5 02:43:19 PST 2024
https://github.com/gchatelet updated https://github.com/llvm/llvm-project/pull/80654
>From 734466d9e83cb1ef92ee5da6e45646cd1b6cd8d9 Mon Sep 17 00:00:00 2001
From: Guillaume Chatelet <gchatelet at google.com>
Date: Mon, 5 Feb 2024 09:47:12 +0000
Subject: [PATCH 1/3] [libc] Add `next_toward_inf` fo `FPBits`
It is needed to provide correct rounding when building FPRep from greater precision representations.
---
libc/src/__support/FPUtil/FPBits.h | 34 +++++++++++++++++++
.../test/src/__support/FPUtil/fpbits_test.cpp | 22 ++++++++++++
2 files changed, 56 insertions(+)
diff --git a/libc/src/__support/FPUtil/FPBits.h b/libc/src/__support/FPUtil/FPBits.h
index 7bfdfc1691a2d..271fc7c2c968d 100644
--- a/libc/src/__support/FPUtil/FPBits.h
+++ b/libc/src/__support/FPUtil/FPBits.h
@@ -266,6 +266,16 @@ template <FPType fp_type> struct FPStorage : public FPLayout<fp_type> {
LIBC_INLINE constexpr operator Exponent() const {
return Exponent(UP::value - EXP_BIAS);
}
+
+ LIBC_INLINE constexpr BiasedExponent &operator++() {
+ ++UP::value;
+ return *this;
+ }
+
+ LIBC_INLINE constexpr BiasedExponent &operator--() {
+ --UP::value;
+ return *this;
+ }
};
// An opaque type to store a floating point significand.
@@ -435,6 +445,13 @@ struct FPRepSem : public FPStorage<fp_type> {
LIBC_INLINE constexpr bool is_normal() const {
return is_finite() && !is_subnormal();
}
+
+ // Modifiers
+ LIBC_INLINE constexpr void next_toward_inf() {
+ if (is_finite())
+ ++UP::bits;
+ }
+
// Returns the mantissa with the implicit bit set iff the current
// value is a valid normal number.
LIBC_INLINE constexpr StorageType get_explicit_mantissa() const {
@@ -551,6 +568,22 @@ struct FPRepSem<FPType::X86_Binary80, RetT>
return false;
return get_implicit_bit();
}
+
+ // Modifiers
+ LIBC_INLINE constexpr void next_toward_inf() {
+ if (is_finite()) {
+ if (exp_sig_bits() == max_normal().uintval()) {
+ bits = inf(sign()).uintval();
+ } else if (exp_sig_bits() == max_subnormal().uintval()) {
+ bits = min_normal(sign()).uintval();
+ } else if (sig_bits() == SIG_MASK) {
+ bits = encode(sign(), ++biased_exponent(), Significand::ZERO());
+ } else {
+ ++bits;
+ }
+ }
+ }
+
LIBC_INLINE constexpr StorageType get_explicit_mantissa() const {
return sig_bits();
}
@@ -633,6 +666,7 @@ struct FPRepImpl : public FPRepSem<fp_type, RetT> {
using UP::max_subnormal;
using UP::min_normal;
using UP::min_subnormal;
+ using UP::next_toward_inf;
using UP::one;
using UP::quiet_nan;
using UP::signaling_nan;
diff --git a/libc/test/src/__support/FPUtil/fpbits_test.cpp b/libc/test/src/__support/FPUtil/fpbits_test.cpp
index 65823511e82f5..c0dedc08780cf 100644
--- a/libc/test/src/__support/FPUtil/fpbits_test.cpp
+++ b/libc/test/src/__support/FPUtil/fpbits_test.cpp
@@ -306,6 +306,28 @@ TYPED_TEST(LlvmLibcFPBitsTest, Properties, FPTypes) {
}
}
+#define ASSERT_SAME_REP(A, B) ASSERT_EQ(A.uintval(), B.uintval());
+
+TYPED_TEST(LlvmLibcFPBitsTest, NextTowardInf, FPTypes) {
+ struct {
+ FP before, after;
+ } TEST_CASES[] = {
+ {FP::ZERO, FP::MIN_SUBNORMAL}, //
+ {FP::MAX_SUBNORMAL, FP::MIN_NORMAL}, //
+ {FP::MAX_NORMAL, FP::INF}, //
+ {FP::INF, FP::INF}, //
+ {FP::QUIET_NAN, FP::QUIET_NAN}, //
+ {FP::SIGNALING_NAN, FP::SIGNALING_NAN}, //
+ };
+ for (Sign sign : all_signs) {
+ for (auto tc : TEST_CASES) {
+ T val = make<T>(sign, tc.before);
+ val.next_toward_inf();
+ ASSERT_SAME_REP(val, make<T>(sign, tc.after));
+ }
+ }
+}
+
TEST(LlvmLibcFPBitsTest, FloatType) {
using FloatBits = FPBits<float>;
>From 6a32ff54d9c25ba79651bf33a6adbbcac44fef77 Mon Sep 17 00:00:00 2001
From: Guillaume Chatelet <gchatelet at google.com>
Date: Mon, 5 Feb 2024 10:12:37 +0000
Subject: [PATCH 2/3] Add assert / fix formatting
---
libc/src/__support/FPUtil/CMakeLists.txt | 1 +
libc/src/__support/FPUtil/FPBits.h | 5 ++++-
utils/bazel/llvm-project-overlay/libc/BUILD.bazel | 1 +
3 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/libc/src/__support/FPUtil/CMakeLists.txt b/libc/src/__support/FPUtil/CMakeLists.txt
index 50cc904f0cfad..47c102a47426c 100644
--- a/libc/src/__support/FPUtil/CMakeLists.txt
+++ b/libc/src/__support/FPUtil/CMakeLists.txt
@@ -31,6 +31,7 @@ add_header_library(
libc.src.__support.common
libc.src.__support.CPP.bit
libc.src.__support.CPP.type_traits
+ libc.src.__support.libc_assert
libc.src.__support.macros.attributes
libc.src.__support.macros.properties.float
libc.src.__support.math_extras
diff --git a/libc/src/__support/FPUtil/FPBits.h b/libc/src/__support/FPUtil/FPBits.h
index 271fc7c2c968d..e33c8402b6296 100644
--- a/libc/src/__support/FPUtil/FPBits.h
+++ b/libc/src/__support/FPUtil/FPBits.h
@@ -13,6 +13,7 @@
#include "src/__support/CPP/type_traits.h"
#include "src/__support/UInt128.h"
#include "src/__support/common.h"
+#include "src/__support/libc_assert.h" // LIBC_ASSERT
#include "src/__support/macros/attributes.h" // LIBC_INLINE, LIBC_INLINE_VAR
#include "src/__support/macros/properties/float.h" // LIBC_COMPILER_HAS_FLOAT128
#include "src/__support/math_extras.h" // mask_trailing_ones
@@ -268,11 +269,13 @@ template <FPType fp_type> struct FPStorage : public FPLayout<fp_type> {
}
LIBC_INLINE constexpr BiasedExponent &operator++() {
+ LIBC_ASSERT(*this != BiasedExponent(Exponent::INF()));
++UP::value;
return *this;
}
LIBC_INLINE constexpr BiasedExponent &operator--() {
+ LIBC_ASSERT(*this != BiasedExponent(Exponent::SUBNORMAL()));
--UP::value;
return *this;
}
@@ -568,7 +571,7 @@ struct FPRepSem<FPType::X86_Binary80, RetT>
return false;
return get_implicit_bit();
}
-
+
// Modifiers
LIBC_INLINE constexpr void next_toward_inf() {
if (is_finite()) {
diff --git a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
index f1fe823354ed7..adce590bcf2ae 100644
--- a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
+++ b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
@@ -666,6 +666,7 @@ libc_support_library(
":__support_common",
":__support_cpp_bit",
":__support_cpp_type_traits",
+ ":__support_libc_assert",
":__support_macros_attributes",
":__support_macros_properties_float",
":__support_math_extras",
>From c98c64e503e49da16d5df888475cda6f065403be Mon Sep 17 00:00:00 2001
From: Guillaume Chatelet <gchatelet at google.com>
Date: Mon, 5 Feb 2024 10:42:59 +0000
Subject: [PATCH 3/3] Make `next_toward_inf` return a value
---
libc/src/__support/FPUtil/FPBits.h | 23 +++++++++----------
.../test/src/__support/FPUtil/fpbits_test.cpp | 3 +--
2 files changed, 12 insertions(+), 14 deletions(-)
diff --git a/libc/src/__support/FPUtil/FPBits.h b/libc/src/__support/FPUtil/FPBits.h
index e33c8402b6296..6665c90845683 100644
--- a/libc/src/__support/FPUtil/FPBits.h
+++ b/libc/src/__support/FPUtil/FPBits.h
@@ -383,6 +383,7 @@ struct FPRepSem : public FPStorage<fp_type> {
protected:
using typename UP::Exponent;
using typename UP::Significand;
+ using UP::bits;
using UP::encode;
using UP::exp_bits;
using UP::exp_sig_bits;
@@ -448,11 +449,10 @@ struct FPRepSem : public FPStorage<fp_type> {
LIBC_INLINE constexpr bool is_normal() const {
return is_finite() && !is_subnormal();
}
-
- // Modifiers
- LIBC_INLINE constexpr void next_toward_inf() {
+ LIBC_INLINE constexpr RetT next_toward_inf() const {
if (is_finite())
- ++UP::bits;
+ return RetT(bits + StorageType(1));
+ return RetT(bits);
}
// Returns the mantissa with the implicit bit set iff the current
@@ -571,20 +571,19 @@ struct FPRepSem<FPType::X86_Binary80, RetT>
return false;
return get_implicit_bit();
}
-
- // Modifiers
- LIBC_INLINE constexpr void next_toward_inf() {
+ LIBC_INLINE constexpr RetT next_toward_inf() const {
if (is_finite()) {
if (exp_sig_bits() == max_normal().uintval()) {
- bits = inf(sign()).uintval();
+ return inf(sign());
} else if (exp_sig_bits() == max_subnormal().uintval()) {
- bits = min_normal(sign()).uintval();
+ return min_normal(sign());
} else if (sig_bits() == SIG_MASK) {
- bits = encode(sign(), ++biased_exponent(), Significand::ZERO());
+ return RetT(encode(sign(), ++biased_exponent(), Significand::ZERO()));
} else {
- ++bits;
+ return RetT(bits + StorageType(1));
}
}
+ return RetT(bits);
}
LIBC_INLINE constexpr StorageType get_explicit_mantissa() const {
@@ -669,7 +668,6 @@ struct FPRepImpl : public FPRepSem<fp_type, RetT> {
using UP::max_subnormal;
using UP::min_normal;
using UP::min_subnormal;
- using UP::next_toward_inf;
using UP::one;
using UP::quiet_nan;
using UP::signaling_nan;
@@ -690,6 +688,7 @@ struct FPRepImpl : public FPRepSem<fp_type, RetT> {
using UP::is_signaling_nan;
using UP::is_subnormal;
using UP::is_zero;
+ using UP::next_toward_inf;
using UP::sign;
LIBC_INLINE constexpr bool is_inf_or_nan() const { return !is_finite(); }
LIBC_INLINE constexpr bool is_neg() const { return sign().is_neg(); }
diff --git a/libc/test/src/__support/FPUtil/fpbits_test.cpp b/libc/test/src/__support/FPUtil/fpbits_test.cpp
index c0dedc08780cf..4504a4f0cfcc7 100644
--- a/libc/test/src/__support/FPUtil/fpbits_test.cpp
+++ b/libc/test/src/__support/FPUtil/fpbits_test.cpp
@@ -322,8 +322,7 @@ TYPED_TEST(LlvmLibcFPBitsTest, NextTowardInf, FPTypes) {
for (Sign sign : all_signs) {
for (auto tc : TEST_CASES) {
T val = make<T>(sign, tc.before);
- val.next_toward_inf();
- ASSERT_SAME_REP(val, make<T>(sign, tc.after));
+ ASSERT_SAME_REP(val.next_toward_inf(), make<T>(sign, tc.after));
}
}
}
More information about the libc-commits
mailing list