diff --git a/libc/src/__support/FPUtil/CMakeLists.txt b/libc/src/__support/FPUtil/CMakeLists.txt index 3d6d712fc2058..1cb22536a1cf6 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 e72dae60844b8..04da5c031f88a 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 @@ -80,16 +81,6 @@ template <> struct FPBaseProperties { FPEncoding::X86_ExtendedPrecision; }; -// TODO: Move this utility elsewhere. -template static constexpr T mask_trailing_ones() { - static_assert(cpp::is_unsigned_v); - 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 @@ -122,15 +113,15 @@ struct FPProperties : public internal::FPBaseProperties { // Masks LIBC_INLINE_VAR static constexpr UIntType SIG_MASK = - internal::mask_trailing_ones() << SIG_MASK_SHIFT; + mask_trailing_ones() << SIG_MASK_SHIFT; LIBC_INLINE_VAR static constexpr UIntType EXP_MASK = - internal::mask_trailing_ones() << EXP_MASK_SHIFT; + mask_trailing_ones() << 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() << SIGN_MASK_SHIFT; + mask_trailing_ones() << SIGN_MASK_SHIFT; LIBC_INLINE_VAR static constexpr UIntType FP_MASK = - internal::mask_trailing_ones(); + mask_trailing_ones(); 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 { LIBC_INLINE_VAR static constexpr uint32_t MANTISSA_PRECISION = MANTISSA_WIDTH + 1; LIBC_INLINE_VAR static constexpr BitsType MANTISSA_MASK = - internal::mask_trailing_ones(); + mask_trailing_ones(); 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 860cdda8586d1..89bd0b72669ea 100644 --- a/libc/src/__support/math_extras.h +++ b/libc/src/__support/math_extras.h @@ -10,12 +10,36 @@ #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 // 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 +LIBC_INLINE constexpr T mask_trailing_ones() { + static_assert(cpp::is_unsigned_v); + 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 +LIBC_INLINE constexpr T mask_leading_ones() { + constexpr T mask(mask_trailing_ones()); + return T(~mask); // bitwise NOT performs integer promotion. +} + // Add with carry template 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 48c8fe95c689a..e55d995592cc1 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())); + EXPECT_EQ(uint8_t(0), (mask_trailing_ones())); + EXPECT_EQ(uint16_t(0), (mask_leading_ones())); + EXPECT_EQ(uint16_t(0), (mask_trailing_ones())); + EXPECT_EQ(uint32_t(0), (mask_leading_ones())); + EXPECT_EQ(uint32_t(0), (mask_trailing_ones())); + EXPECT_EQ(uint64_t(0), (mask_leading_ones())); + EXPECT_EQ(uint64_t(0), (mask_trailing_ones())); + + EXPECT_EQ(uint32_t(0x00000003), (mask_trailing_ones())); + EXPECT_EQ(uint32_t(0xC0000000), (mask_leading_ones())); + + EXPECT_EQ(uint32_t(0x000007FF), (mask_trailing_ones())); + EXPECT_EQ(uint32_t(0xFFE00000), (mask_leading_ones())); + + EXPECT_EQ(uint32_t(0xFFFFFFFF), (mask_trailing_ones())); + EXPECT_EQ(uint32_t(0xFFFFFFFF), (mask_leading_ones())); + EXPECT_EQ(uint64_t(0xFFFFFFFFFFFFFFFF), (mask_trailing_ones())); + EXPECT_EQ(uint64_t(0xFFFFFFFFFFFFFFFF), (mask_leading_ones())); + + EXPECT_EQ(uint64_t(0x0000FFFFFFFFFFFF), (mask_trailing_ones())); + EXPECT_EQ(uint64_t(0xFFFFFFFFFFFF0000), (mask_leading_ones())); } } // namespace LIBC_NAMESPACE diff --git a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel index 95d6f9d220c25..b9bdb8f7c6d3e 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", ], )