Skip to content

Commit dd85e67

Browse files
authored
[libc] Add mask functions to math_extras (#75169)
1 parent dfb7d56 commit dd85e67

File tree

5 files changed

+56
-18
lines changed

5 files changed

+56
-18
lines changed

libc/src/__support/FPUtil/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ add_header_library(
3030
DEPENDS
3131
libc.src.__support.macros.properties.float
3232
libc.src.__support.uint128
33+
libc.src.__support.math_extras
3334
)
3435

3536
add_header_library(

libc/src/__support/FPUtil/FloatProperties.h

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "src/__support/UInt128.h"
1313
#include "src/__support/macros/attributes.h" // LIBC_INLINE, LIBC_INLINE_VAR
1414
#include "src/__support/macros/properties/float.h" // LIBC_COMPILER_HAS_FLOAT128
15+
#include "src/__support/math_extras.h" // mask_trailing_ones
1516

1617
#include <stdint.h>
1718

@@ -80,16 +81,6 @@ template <> struct FPBaseProperties<FPType::X86_Binary80> {
8081
FPEncoding::X86_ExtendedPrecision;
8182
};
8283

83-
// TODO: Move this utility elsewhere.
84-
template <typename T, size_t count> static constexpr T mask_trailing_ones() {
85-
static_assert(cpp::is_unsigned_v<T>);
86-
constexpr unsigned t_bits = CHAR_BIT * sizeof(T);
87-
static_assert(count <= t_bits && "Invalid bit index");
88-
// It's important not to initialize T with -1, since T may be BigInt which
89-
// will take -1 as a uint64_t and only initialize the low 64 bits.
90-
return count == 0 ? 0 : ((~T(0)) >> (t_bits - count));
91-
}
92-
9384
} // namespace internal
9485

9586
template <FPType fp_type>
@@ -122,15 +113,15 @@ struct FPProperties : public internal::FPBaseProperties<fp_type> {
122113

123114
// Masks
124115
LIBC_INLINE_VAR static constexpr UIntType SIG_MASK =
125-
internal::mask_trailing_ones<UIntType, SIG_BITS>() << SIG_MASK_SHIFT;
116+
mask_trailing_ones<UIntType, SIG_BITS>() << SIG_MASK_SHIFT;
126117
LIBC_INLINE_VAR static constexpr UIntType EXP_MASK =
127-
internal::mask_trailing_ones<UIntType, EXP_BITS>() << EXP_MASK_SHIFT;
118+
mask_trailing_ones<UIntType, EXP_BITS>() << EXP_MASK_SHIFT;
128119
// Trailing underscore on SIGN_MASK_ is temporary - it will be removed
129120
// once we can replace the public part below with the private one.
130121
LIBC_INLINE_VAR static constexpr UIntType SIGN_MASK_ =
131-
internal::mask_trailing_ones<UIntType, SIGN_BITS>() << SIGN_MASK_SHIFT;
122+
mask_trailing_ones<UIntType, SIGN_BITS>() << SIGN_MASK_SHIFT;
132123
LIBC_INLINE_VAR static constexpr UIntType FP_MASK =
133-
internal::mask_trailing_ones<UIntType, TOTAL_BITS>();
124+
mask_trailing_ones<UIntType, TOTAL_BITS>();
134125
static_assert((SIG_MASK & EXP_MASK & SIGN_MASK_) == 0, "masks disjoint");
135126
static_assert((SIG_MASK | EXP_MASK | SIGN_MASK_) == FP_MASK, "masks cover");
136127

@@ -162,7 +153,7 @@ struct FPProperties : public internal::FPBaseProperties<fp_type> {
162153
LIBC_INLINE_VAR static constexpr uint32_t MANTISSA_PRECISION =
163154
MANTISSA_WIDTH + 1;
164155
LIBC_INLINE_VAR static constexpr BitsType MANTISSA_MASK =
165-
internal::mask_trailing_ones<UIntType, MANTISSA_WIDTH>();
156+
mask_trailing_ones<UIntType, MANTISSA_WIDTH>();
166157
LIBC_INLINE_VAR static constexpr uint32_t EXPONENT_WIDTH = EXP_BITS;
167158
LIBC_INLINE_VAR static constexpr int32_t EXPONENT_BIAS = EXP_BIAS;
168159
LIBC_INLINE_VAR static constexpr BitsType SIGN_MASK = SIGN_MASK_;

libc/src/__support/math_extras.h

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,36 @@
1010
#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_EXTRAS_H
1111
#define LLVM_LIBC_SRC___SUPPORT_MATH_EXTRAS_H
1212

13-
#include "src/__support/CPP/type_traits.h"
13+
#include "src/__support/CPP/type_traits.h" // is_unsigned_v
1414
#include "src/__support/macros/attributes.h" // LIBC_INLINE
1515
#include "src/__support/macros/config.h" // LIBC_HAS_BUILTIN
1616

17+
#include <limits.h> // CHAR_BIT
18+
1719
namespace LIBC_NAMESPACE {
1820

21+
// Create a bitmask with the count right-most bits set to 1, and all other bits
22+
// set to 0. Only unsigned types are allowed.
23+
template <typename T, size_t count>
24+
LIBC_INLINE constexpr T mask_trailing_ones() {
25+
static_assert(cpp::is_unsigned_v<T>);
26+
constexpr unsigned t_bits = CHAR_BIT * sizeof(T);
27+
static_assert(count <= t_bits && "Invalid bit index");
28+
// It's important not to initialize T with -1, since T may be BigInt which
29+
// will take -1 as a uint64_t and only initialize the low 64 bits.
30+
constexpr T all_zeroes(0);
31+
constexpr T all_ones(~all_zeroes); // bitwise NOT performs integer promotion.
32+
return count == 0 ? 0 : (all_ones >> (t_bits - count));
33+
}
34+
35+
// Create a bitmask with the count left-most bits set to 1, and all other bits
36+
// set to 0. Only unsigned types are allowed.
37+
template <typename T, size_t count>
38+
LIBC_INLINE constexpr T mask_leading_ones() {
39+
constexpr T mask(mask_trailing_ones<T, CHAR_BIT * sizeof(T) - count>());
40+
return T(~mask); // bitwise NOT performs integer promotion.
41+
}
42+
1943
// Add with carry
2044
template <typename T> struct SumCarry {
2145
T sum;

libc/test/src/__support/math_extras_test.cpp

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,29 @@
1111

1212
namespace LIBC_NAMESPACE {
1313

14-
TEST(LlvmLibcBlockMathExtrasTest, TODO) {
15-
// TODO Implement me.
14+
TEST(LlvmLibcBlockMathExtrasTest, mask_trailing_ones) {
15+
EXPECT_EQ(uint8_t(0), (mask_leading_ones<uint8_t, 0>()));
16+
EXPECT_EQ(uint8_t(0), (mask_trailing_ones<uint8_t, 0>()));
17+
EXPECT_EQ(uint16_t(0), (mask_leading_ones<uint16_t, 0>()));
18+
EXPECT_EQ(uint16_t(0), (mask_trailing_ones<uint16_t, 0>()));
19+
EXPECT_EQ(uint32_t(0), (mask_leading_ones<uint32_t, 0>()));
20+
EXPECT_EQ(uint32_t(0), (mask_trailing_ones<uint32_t, 0>()));
21+
EXPECT_EQ(uint64_t(0), (mask_leading_ones<uint64_t, 0>()));
22+
EXPECT_EQ(uint64_t(0), (mask_trailing_ones<uint64_t, 0>()));
23+
24+
EXPECT_EQ(uint32_t(0x00000003), (mask_trailing_ones<uint32_t, 2>()));
25+
EXPECT_EQ(uint32_t(0xC0000000), (mask_leading_ones<uint32_t, 2>()));
26+
27+
EXPECT_EQ(uint32_t(0x000007FF), (mask_trailing_ones<uint32_t, 11>()));
28+
EXPECT_EQ(uint32_t(0xFFE00000), (mask_leading_ones<uint32_t, 11>()));
29+
30+
EXPECT_EQ(uint32_t(0xFFFFFFFF), (mask_trailing_ones<uint32_t, 32>()));
31+
EXPECT_EQ(uint32_t(0xFFFFFFFF), (mask_leading_ones<uint32_t, 32>()));
32+
EXPECT_EQ(uint64_t(0xFFFFFFFFFFFFFFFF), (mask_trailing_ones<uint64_t, 64>()));
33+
EXPECT_EQ(uint64_t(0xFFFFFFFFFFFFFFFF), (mask_leading_ones<uint64_t, 64>()));
34+
35+
EXPECT_EQ(uint64_t(0x0000FFFFFFFFFFFF), (mask_trailing_ones<uint64_t, 48>()));
36+
EXPECT_EQ(uint64_t(0xFFFFFFFFFFFF0000), (mask_leading_ones<uint64_t, 48>()));
1637
}
1738

1839
} // namespace LIBC_NAMESPACE

utils/bazel/llvm-project-overlay/libc/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -664,6 +664,7 @@ libc_support_library(
664664
deps = [
665665
":__support_macros_attributes",
666666
":__support_macros_properties_float",
667+
":__support_math_extras",
667668
":__support_uint128",
668669
],
669670
)

0 commit comments

Comments
 (0)