8686#include < limits> // numeric_limits
8787#include < type_traits>
8888
89+ #include " llvm/Support/MathExtras.h"
90+
8991namespace llvm {
9092
9193namespace 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.
15697template <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