Skip to content

Commit e29b7ca

Browse files
[ADT] Simplify Bitfields.h (NFC)
BitPatterns and Compressor collectively provide three main features: - check the value range - truncate the value before going into the bitfield - sign-extend the signed bitfield This patch retains the range check as separate function checkValue while inlining the rest into their respective callers, update() and extract().
1 parent 3f46a5c commit e29b7ca

File tree

1 file changed

+23
-66
lines changed

1 file changed

+23
-66
lines changed

llvm/include/llvm/ADT/Bitfields.h

Lines changed: 23 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -86,89 +86,44 @@
8686
#include <limits> // numeric_limits
8787
#include <type_traits>
8888

89+
#include "llvm/Support/MathExtras.h"
90+
8991
namespace llvm {
9092

9193
namespace bitfields_details {
9294

93-
/// A struct defining useful bit patterns for n-bits integer types.
94-
template <typename T, unsigned Bits> struct BitPatterns {
95-
/// Bit patterns are forged using the equivalent `Unsigned` type because of
96-
/// undefined operations over signed types (e.g. Bitwise shift operators).
97-
/// Moreover same size casting from unsigned to signed is well defined but not
98-
/// the other way around.
99-
using Unsigned = std::make_unsigned_t<T>;
100-
static_assert(sizeof(Unsigned) == sizeof(T), "Types must have same size");
101-
102-
static constexpr unsigned TypeBits = sizeof(Unsigned) * CHAR_BIT;
103-
static_assert(TypeBits >= Bits, "n-bit must fit in T");
104-
105-
/// e.g. with TypeBits == 8 and Bits == 6.
106-
static constexpr Unsigned AllZeros = Unsigned(0); // 00000000
107-
static constexpr Unsigned AllOnes = ~Unsigned(0); // 11111111
108-
static constexpr Unsigned Umin = AllZeros; // 00000000
109-
static constexpr Unsigned Umax = AllOnes >> (TypeBits - Bits); // 00111111
110-
static constexpr Unsigned SignBitMask = Unsigned(1) << (Bits - 1); // 00100000
111-
static constexpr Unsigned Smax = Umax >> 1U; // 00011111
112-
static constexpr Unsigned Smin = ~Smax; // 11100000
113-
static constexpr Unsigned SignExtend = Unsigned(Smin << 1U); // 11000000
114-
};
115-
116-
/// `Compressor` is used to manipulate the bits of a (possibly signed) integer
117-
/// type so it can be packed and unpacked into a `bits` sized integer,
118-
/// `Compressor` is specialized on signed-ness so no runtime cost is incurred.
119-
/// The `pack` method also checks that the passed in `UserValue` is valid.
120-
template <typename T, unsigned Bits, bool = std::is_unsigned<T>::value>
121-
struct Compressor {
122-
static_assert(std::is_unsigned<T>::value, "T must be unsigned");
123-
using BP = BitPatterns<T, Bits>;
124-
125-
static T pack(T UserValue, T UserMaxValue) {
126-
assert(UserValue <= UserMaxValue && "value is too big");
127-
assert(UserValue <= BP::Umax && "value is too big");
128-
return UserValue;
129-
}
130-
131-
static T unpack(T StorageValue) { return StorageValue; }
132-
};
133-
134-
template <typename T, unsigned Bits> struct Compressor<T, Bits, false> {
135-
static_assert(std::is_signed<T>::value, "T must be signed");
136-
using BP = BitPatterns<T, Bits>;
137-
138-
static T pack(T UserValue, T UserMaxValue) {
139-
assert(UserValue <= UserMaxValue && "value is too big");
140-
assert(UserValue <= T(BP::Smax) && "value is too big");
141-
assert(UserValue >= T(BP::Smin) && "value is too small");
142-
if (UserValue < 0)
143-
UserValue &= ~BP::SignExtend;
144-
return UserValue;
145-
}
146-
147-
static T unpack(T StorageValue) {
148-
if (StorageValue >= T(BP::SignBitMask))
149-
StorageValue |= BP::SignExtend;
150-
return StorageValue;
151-
}
152-
};
153-
15495
/// Impl is where Bifield description and Storage are put together to interact
15596
/// with values.
15697
template <typename Bitfield, typename StorageType> struct Impl {
15798
static_assert(std::is_unsigned<StorageType>::value,
15899
"Storage must be unsigned");
159100
using IntegerType = typename Bitfield::IntegerType;
160-
using C = Compressor<IntegerType, Bitfield::Bits>;
161-
using BP = BitPatterns<StorageType, Bitfield::Bits>;
162101

163102
static constexpr size_t StorageBits = sizeof(StorageType) * CHAR_BIT;
164103
static_assert(Bitfield::FirstBit <= StorageBits, "Data must fit in mask");
165104
static_assert(Bitfield::LastBit <= StorageBits, "Data must fit in mask");
166-
static constexpr StorageType Mask = BP::Umax << Bitfield::Shift;
105+
static constexpr StorageType LowMask =
106+
maskTrailingOnes<StorageType>(Bitfield::Bits);
107+
static constexpr StorageType Mask = LowMask << Bitfield::Shift;
108+
109+
/// Validates that `UserValue` fits within the bitfield's range.
110+
static void checkValue(IntegerType UserValue, IntegerType UserMaxValue) {
111+
assert(UserValue <= UserMaxValue && "value is too big");
112+
if constexpr (std::is_unsigned_v<IntegerType>) {
113+
assert(isUInt<Bitfield::Bits>(UserValue) && "value is too big");
114+
} else {
115+
static_assert(std::is_signed_v<IntegerType>,
116+
"IntegerType must be signed");
117+
assert(UserValue <= maxIntN(Bitfield::Bits) && "value is too big");
118+
assert(UserValue >= minIntN(Bitfield::Bits) && "value is too small");
119+
}
120+
}
167121

168122
/// Checks `UserValue` is within bounds and packs it between `FirstBit` and
169123
/// `LastBit` of `Packed` leaving the rest unchanged.
170124
static void update(StorageType &Packed, IntegerType UserValue) {
171-
const StorageType StorageValue = C::pack(UserValue, Bitfield::UserMaxValue);
125+
checkValue(UserValue, Bitfield::UserMaxValue);
126+
const StorageType StorageValue = UserValue & LowMask;
172127
Packed &= ~Mask;
173128
Packed |= StorageValue << Bitfield::Shift;
174129
}
@@ -177,7 +132,9 @@ template <typename Bitfield, typename StorageType> struct Impl {
177132
/// an`IntegerType`.
178133
static IntegerType extract(StorageType Packed) {
179134
const StorageType StorageValue = (Packed & Mask) >> Bitfield::Shift;
180-
return C::unpack(StorageValue);
135+
if constexpr (std::is_signed_v<IntegerType>)
136+
return SignExtend64<Bitfield::Bits>(StorageValue);
137+
return StorageValue;
181138
}
182139

183140
/// Interprets bits between `FirstBit` and `LastBit` of `Packed` as

0 commit comments

Comments
 (0)