]> granicus.if.org Git - llvm/commitdiff
[Support] Add some helpers to generate bitmasks.
authorZachary Turner <zturner@google.com>
Wed, 19 Apr 2017 15:45:31 +0000 (15:45 +0000)
committerZachary Turner <zturner@google.com>
Wed, 19 Apr 2017 15:45:31 +0000 (15:45 +0000)
Frequently you you want a bitmask consisting of a specified
number of 1s, either at the beginning or end of a word.

The naive way to do this is to write

template<typename T>
T leadingBitMask(unsigned N) {
  return (T(1) << N) - 1;
}

but using this function you cannot produce a word with every
bit set to 1 (i.e. leadingBitMask<uint8_t>(8)) because left
shift is undefined when N is greater than or equal to the
number of bits in the word.

This patch provides an efficient, branch-free implementation
that works for all values of N in [0, CHAR_BIT*sizeof(T)]

Differential Revision: https://reviews.llvm.org/D32212

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@300710 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/Support/MathExtras.h
unittests/Support/MathExtrasTest.cpp

index 19380b23d9d24768b8312a8fa56fb525c28ef41e..e389a7e3b95bd2f0c8f9dfe301bfc10dd1620a22 100644 (file)
@@ -198,6 +198,21 @@ template <typename T> T findFirstSet(T Val, ZeroBehavior ZB = ZB_Max) {
   return countTrailingZeros(Val, ZB_Undefined);
 }
 
+/// \brief Create a bitmask with the N right-most bits set to 1, and all other
+/// bits set to 0.  Only unsigned types are allowed.
+template <typename T> T maskTrailingOnes(unsigned N) {
+  static_assert(std::is_unsigned<T>::value, "Invalid type!");
+  const unsigned Bits = CHAR_BIT * sizeof(T);
+  assert(N <= Bits && "Invalid bit index");
+  return -T(N != 0) & (T(-1) >> (Bits - N));
+}
+
+/// \brief Create a bitmask with the N left-most bits set to 1, and all other
+/// bits set to 0.  Only unsigned types are allowed.
+template <typename T> T maskLeadingOnes(unsigned N) {
+  return ~maskTrailingOnes<T>(CHAR_BIT * sizeof(T) - N);
+}
+
 /// \brief Get the index of the last set bit starting from the least
 ///   significant bit.
 ///
index b2c3779788744d97ed71f810bdec170d9799fa58..de8272170833bb954120ddc330175f165e6344da 100644 (file)
@@ -66,6 +66,26 @@ TEST(MathExtras, countLeadingZeros) {
   }
 }
 
+TEST(MathExtras, onesMask) {
+  EXPECT_EQ(0U, maskLeadingOnes<uint8_t>(0));
+  EXPECT_EQ(0U, maskTrailingOnes<uint8_t>(0));
+  EXPECT_EQ(0U, maskLeadingOnes<uint16_t>(0));
+  EXPECT_EQ(0U, maskTrailingOnes<uint16_t>(0));
+  EXPECT_EQ(0U, maskLeadingOnes<uint32_t>(0));
+  EXPECT_EQ(0U, maskTrailingOnes<uint32_t>(0));
+  EXPECT_EQ(0U, maskLeadingOnes<uint64_t>(0));
+  EXPECT_EQ(0U, maskTrailingOnes<uint64_t>(0));
+
+  EXPECT_EQ(0x00000003U, maskTrailingOnes<uint32_t>(2U));
+  EXPECT_EQ(0xC0000000U, maskLeadingOnes<uint32_t>(2U));
+
+  EXPECT_EQ(0x000007FFU, maskTrailingOnes<uint32_t>(11U));
+  EXPECT_EQ(0xFFE00000U, maskLeadingOnes<uint32_t>(11U));
+
+  EXPECT_EQ(0xFFFFFFFFU, maskTrailingOnes<uint32_t>(32U));
+  EXPECT_EQ(0xFFFFFFFFU, maskLeadingOnes<uint32_t>(32U));
+}
+
 TEST(MathExtras, findFirstSet) {
   uint8_t Z8 = 0;
   uint16_t Z16 = 0;