[libc] [llvm] [libc] Add mask functions to math_extras (PR #75169)

Guillaume Chatelet via llvm-commits llvm-commits at lists.llvm.org
Tue Dec 12 04:14:18 PST 2023


https://github.com/gchatelet updated https://github.com/llvm/llvm-project/pull/75169

>From ae32181a0d867fe9da83dea3ca7339883ab22f8a Mon Sep 17 00:00:00 2001
From: Guillaume Chatelet <gchatelet at google.com>
Date: Tue, 12 Dec 2023 11:58:56 +0000
Subject: [PATCH 1/2] [libc] Add mask functions to math_extras

---
 libc/src/__support/FPUtil/CMakeLists.txt      |  1 +
 libc/src/__support/FPUtil/FloatProperties.h   | 21 +++-------
 libc/src/__support/math_extras.h              | 40 ++++++++++++++++++-
 libc/test/src/__support/math_extras_test.cpp  | 25 +++++++++++-
 .../llvm-project-overlay/libc/BUILD.bazel     |  1 +
 5 files changed, 70 insertions(+), 18 deletions(-)

diff --git a/libc/src/__support/FPUtil/CMakeLists.txt b/libc/src/__support/FPUtil/CMakeLists.txt
index 3d6d712fc20584..1cb22536a1cf6e 100644
--- a/libc/src/__support/FPUtil/CMakeLists.txt
+++ b/libc/src/__support/FPUtil/CMakeLists.txt
@@ -30,6 +30,7 @@ add_header_library(
   DEPENDS
     libc.src.__support.macros.properties.float
     libc.src.__support.uint128
+    libc.src.__support.math_extras
 )
 
 add_header_library(
diff --git a/libc/src/__support/FPUtil/FloatProperties.h b/libc/src/__support/FPUtil/FloatProperties.h
index e72dae60844b80..04da5c031f88a5 100644
--- a/libc/src/__support/FPUtil/FloatProperties.h
+++ b/libc/src/__support/FPUtil/FloatProperties.h
@@ -12,6 +12,7 @@
 #include "src/__support/UInt128.h"
 #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
 
 #include <stdint.h>
 
@@ -80,16 +81,6 @@ template <> struct FPBaseProperties<FPType::X86_Binary80> {
       FPEncoding::X86_ExtendedPrecision;
 };
 
-// TODO: Move this utility elsewhere.
-template <typename T, size_t count> static constexpr T mask_trailing_ones() {
-  static_assert(cpp::is_unsigned_v<T>);
-  constexpr unsigned t_bits = CHAR_BIT * sizeof(T);
-  static_assert(count <= t_bits && "Invalid bit index");
-  // It's important not to initialize T with -1, since T may be BigInt which
-  // will take -1 as a uint64_t and only initialize the low 64 bits.
-  return count == 0 ? 0 : ((~T(0)) >> (t_bits - count));
-}
-
 } // namespace internal
 
 template <FPType fp_type>
@@ -122,15 +113,15 @@ struct FPProperties : public internal::FPBaseProperties<fp_type> {
 
   // Masks
   LIBC_INLINE_VAR static constexpr UIntType SIG_MASK =
-      internal::mask_trailing_ones<UIntType, SIG_BITS>() << SIG_MASK_SHIFT;
+      mask_trailing_ones<UIntType, SIG_BITS>() << SIG_MASK_SHIFT;
   LIBC_INLINE_VAR static constexpr UIntType EXP_MASK =
-      internal::mask_trailing_ones<UIntType, EXP_BITS>() << EXP_MASK_SHIFT;
+      mask_trailing_ones<UIntType, EXP_BITS>() << EXP_MASK_SHIFT;
   // Trailing underscore on SIGN_MASK_ is temporary - it will be removed
   // once we can replace the public part below with the private one.
   LIBC_INLINE_VAR static constexpr UIntType SIGN_MASK_ =
-      internal::mask_trailing_ones<UIntType, SIGN_BITS>() << SIGN_MASK_SHIFT;
+      mask_trailing_ones<UIntType, SIGN_BITS>() << SIGN_MASK_SHIFT;
   LIBC_INLINE_VAR static constexpr UIntType FP_MASK =
-      internal::mask_trailing_ones<UIntType, TOTAL_BITS>();
+      mask_trailing_ones<UIntType, TOTAL_BITS>();
   static_assert((SIG_MASK & EXP_MASK & SIGN_MASK_) == 0, "masks disjoint");
   static_assert((SIG_MASK | EXP_MASK | SIGN_MASK_) == FP_MASK, "masks cover");
 
@@ -162,7 +153,7 @@ struct FPProperties : public internal::FPBaseProperties<fp_type> {
   LIBC_INLINE_VAR static constexpr uint32_t MANTISSA_PRECISION =
       MANTISSA_WIDTH + 1;
   LIBC_INLINE_VAR static constexpr BitsType MANTISSA_MASK =
-      internal::mask_trailing_ones<UIntType, MANTISSA_WIDTH>();
+      mask_trailing_ones<UIntType, MANTISSA_WIDTH>();
   LIBC_INLINE_VAR static constexpr uint32_t EXPONENT_WIDTH = EXP_BITS;
   LIBC_INLINE_VAR static constexpr int32_t EXPONENT_BIAS = EXP_BIAS;
   LIBC_INLINE_VAR static constexpr BitsType SIGN_MASK = SIGN_MASK_;
diff --git a/libc/src/__support/math_extras.h b/libc/src/__support/math_extras.h
index 860cdda8586d1e..571a3409e28bd5 100644
--- a/libc/src/__support/math_extras.h
+++ b/libc/src/__support/math_extras.h
@@ -10,12 +10,50 @@
 #ifndef LLVM_LIBC_SRC___SUPPORT_MATH_EXTRAS_H
 #define LLVM_LIBC_SRC___SUPPORT_MATH_EXTRAS_H
 
-#include "src/__support/CPP/type_traits.h"
+#include "src/__support/CPP/type_traits.h"   // is_unsigned_v
 #include "src/__support/macros/attributes.h" // LIBC_INLINE
 #include "src/__support/macros/config.h"     // LIBC_HAS_BUILTIN
 
+#include <limits.h> // CHAR_BIT
+
 namespace LIBC_NAMESPACE {
 
+// Create a bitmask with the count right-most bits set to 1, and all other bits
+// set to 0.  Only unsigned types are allowed.
+template <typename T, size_t count>
+LIBC_INLINE constexpr T mask_trailing_ones() {
+  static_assert(cpp::is_unsigned_v<T>);
+  constexpr unsigned t_bits = CHAR_BIT * sizeof(T);
+  static_assert(count <= t_bits && "Invalid bit index");
+  // It's important not to initialize T with -1, since T may be BigInt which
+  // will take -1 as a uint64_t and only initialize the low 64 bits.
+  constexpr T all_zeroes(0);
+  constexpr T all_ones(~all_zeroes); // bitwise NOT performs integer promotion.
+  return count == 0 ? 0 : (all_ones >> (t_bits - count));
+}
+
+// Create a bitmask with the count left-most bits set to 1, and all other bits
+// set to 0.  Only unsigned types are allowed.
+template <typename T, size_t count>
+LIBC_INLINE constexpr T mask_leading_ones() {
+  constexpr T mask(mask_trailing_ones<T, CHAR_BIT * sizeof(T) - count>());
+  return T(~mask); // bitwise NOT performs integer promotion.
+}
+
+// Create a bitmask with the count right-most bits set to 0, and all other bits
+// set to 1.  Only unsigned types are allowed.
+template <typename T, size_t count>
+LIBC_INLINE constexpr T mask_trailing_zeros() {
+  return mask_leading_ones<T, CHAR_BIT * sizeof(T) - count>();
+}
+
+// Create a bitmask with the count left-most bits set to 0, and all other bits
+// set to 1.  Only unsigned types are allowed.
+template <typename T, size_t count>
+LIBC_INLINE constexpr T mask_leading_zeros() {
+  return mask_trailing_ones<T, CHAR_BIT * sizeof(T) - count>();
+}
+
 // Add with carry
 template <typename T> struct SumCarry {
   T sum;
diff --git a/libc/test/src/__support/math_extras_test.cpp b/libc/test/src/__support/math_extras_test.cpp
index 48c8fe95c689a1..e55d995592cc1c 100644
--- a/libc/test/src/__support/math_extras_test.cpp
+++ b/libc/test/src/__support/math_extras_test.cpp
@@ -11,8 +11,29 @@
 
 namespace LIBC_NAMESPACE {
 
-TEST(LlvmLibcBlockMathExtrasTest, TODO) {
-  // TODO Implement me.
+TEST(LlvmLibcBlockMathExtrasTest, mask_trailing_ones) {
+  EXPECT_EQ(uint8_t(0), (mask_leading_ones<uint8_t, 0>()));
+  EXPECT_EQ(uint8_t(0), (mask_trailing_ones<uint8_t, 0>()));
+  EXPECT_EQ(uint16_t(0), (mask_leading_ones<uint16_t, 0>()));
+  EXPECT_EQ(uint16_t(0), (mask_trailing_ones<uint16_t, 0>()));
+  EXPECT_EQ(uint32_t(0), (mask_leading_ones<uint32_t, 0>()));
+  EXPECT_EQ(uint32_t(0), (mask_trailing_ones<uint32_t, 0>()));
+  EXPECT_EQ(uint64_t(0), (mask_leading_ones<uint64_t, 0>()));
+  EXPECT_EQ(uint64_t(0), (mask_trailing_ones<uint64_t, 0>()));
+
+  EXPECT_EQ(uint32_t(0x00000003), (mask_trailing_ones<uint32_t, 2>()));
+  EXPECT_EQ(uint32_t(0xC0000000), (mask_leading_ones<uint32_t, 2>()));
+
+  EXPECT_EQ(uint32_t(0x000007FF), (mask_trailing_ones<uint32_t, 11>()));
+  EXPECT_EQ(uint32_t(0xFFE00000), (mask_leading_ones<uint32_t, 11>()));
+
+  EXPECT_EQ(uint32_t(0xFFFFFFFF), (mask_trailing_ones<uint32_t, 32>()));
+  EXPECT_EQ(uint32_t(0xFFFFFFFF), (mask_leading_ones<uint32_t, 32>()));
+  EXPECT_EQ(uint64_t(0xFFFFFFFFFFFFFFFF), (mask_trailing_ones<uint64_t, 64>()));
+  EXPECT_EQ(uint64_t(0xFFFFFFFFFFFFFFFF), (mask_leading_ones<uint64_t, 64>()));
+
+  EXPECT_EQ(uint64_t(0x0000FFFFFFFFFFFF), (mask_trailing_ones<uint64_t, 48>()));
+  EXPECT_EQ(uint64_t(0xFFFFFFFFFFFF0000), (mask_leading_ones<uint64_t, 48>()));
 }
 
 } // namespace LIBC_NAMESPACE
diff --git a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
index 95d6f9d220c25e..b9bdb8f7c6d3eb 100644
--- a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
+++ b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
@@ -664,6 +664,7 @@ libc_support_library(
     deps = [
         ":__support_macros_attributes",
         ":__support_macros_properties_float",
+        ":__support_math_extras",
         ":__support_uint128",
     ],
 )

>From 1ff61675097192058c9c25b2c5097805a53ec29a Mon Sep 17 00:00:00 2001
From: Guillaume Chatelet <gchatelet at google.com>
Date: Tue, 12 Dec 2023 12:14:00 +0000
Subject: [PATCH 2/2] rebase and remove unused functions

---
 libc/src/__support/math_extras.h | 14 --------------
 1 file changed, 14 deletions(-)

diff --git a/libc/src/__support/math_extras.h b/libc/src/__support/math_extras.h
index 571a3409e28bd5..89bd0b72669ea2 100644
--- a/libc/src/__support/math_extras.h
+++ b/libc/src/__support/math_extras.h
@@ -40,20 +40,6 @@ LIBC_INLINE constexpr T mask_leading_ones() {
   return T(~mask); // bitwise NOT performs integer promotion.
 }
 
-// Create a bitmask with the count right-most bits set to 0, and all other bits
-// set to 1.  Only unsigned types are allowed.
-template <typename T, size_t count>
-LIBC_INLINE constexpr T mask_trailing_zeros() {
-  return mask_leading_ones<T, CHAR_BIT * sizeof(T) - count>();
-}
-
-// Create a bitmask with the count left-most bits set to 0, and all other bits
-// set to 1.  Only unsigned types are allowed.
-template <typename T, size_t count>
-LIBC_INLINE constexpr T mask_leading_zeros() {
-  return mask_trailing_ones<T, CHAR_BIT * sizeof(T) - count>();
-}
-
 // Add with carry
 template <typename T> struct SumCarry {
   T sum;



More information about the llvm-commits mailing list