[libc] [llvm] [libc] Add `next_toward_inf` fo `FPBits` (PR #80654)

Guillaume Chatelet via llvm-commits llvm-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 llvm-commits mailing list