Skip to content

Commit

Permalink
[libc] Add mask functions to math_extras (#75169)
Browse files Browse the repository at this point in the history
  • Loading branch information
gchatelet committed Dec 12, 2023
1 parent dfb7d56 commit dd85e67
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 18 deletions.
1 change: 1 addition & 0 deletions libc/src/__support/FPUtil/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
21 changes: 6 additions & 15 deletions libc/src/__support/FPUtil/FloatProperties.h
Original file line number Diff line number Diff line change
Expand Up @@ -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>

Expand Down Expand Up @@ -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>
Expand Down Expand Up @@ -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");

Expand Down Expand Up @@ -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_;
Expand Down
26 changes: 25 additions & 1 deletion libc/src/__support/math_extras.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 <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.
}

// Add with carry
template <typename T> struct SumCarry {
T sum;
Expand Down
25 changes: 23 additions & 2 deletions libc/test/src/__support/math_extras_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
1 change: 1 addition & 0 deletions utils/bazel/llvm-project-overlay/libc/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -664,6 +664,7 @@ libc_support_library(
deps = [
":__support_macros_attributes",
":__support_macros_properties_float",
":__support_math_extras",
":__support_uint128",
],
)
Expand Down

0 comments on commit dd85e67

Please sign in to comment.