@@ -66,7 +66,9 @@ template <typename T> T maskTrailingOnes(unsigned N) {
66
66
static_assert (std::is_unsigned_v<T>, " Invalid type!" );
67
67
const unsigned Bits = CHAR_BIT * sizeof (T);
68
68
assert (N <= Bits && " Invalid bit index" );
69
- return N == 0 ? 0 : (T (-1 ) >> (Bits - N));
69
+ if (N == 0 )
70
+ return 0 ;
71
+ return T (-1 ) >> (Bits - N);
70
72
}
71
73
72
74
// / Create a bitmask with the N left-most bits set to 1, and all other
@@ -149,6 +151,8 @@ constexpr inline uint64_t Make_64(uint32_t High, uint32_t Low) {
149
151
150
152
// / Checks if an integer fits into the given bit width.
151
153
template <unsigned N> constexpr inline bool isInt (int64_t x) {
154
+ if constexpr (N == 0 )
155
+ return 0 == x;
152
156
if constexpr (N == 8 )
153
157
return static_cast <int8_t >(x) == x;
154
158
if constexpr (N == 16 )
@@ -164,15 +168,15 @@ template <unsigned N> constexpr inline bool isInt(int64_t x) {
164
168
// / Checks if a signed integer is an N bit number shifted left by S.
165
169
template <unsigned N, unsigned S>
166
170
constexpr inline bool isShiftedInt (int64_t x) {
167
- static_assert (
168
- N > 0 , " isShiftedInt<0> doesn't make sense (refers to a 0-bit number." );
171
+ static_assert (S < 64 , " isShiftedInt<N, S> with S >= 64 is too much." );
169
172
static_assert (N + S <= 64 , " isShiftedInt<N, S> with N + S > 64 is too wide." );
170
173
return isInt<N + S>(x) && (x % (UINT64_C (1 ) << S) == 0 );
171
174
}
172
175
173
176
// / Checks if an unsigned integer fits into the given bit width.
174
177
template <unsigned N> constexpr inline bool isUInt (uint64_t x) {
175
- static_assert (N > 0 , " isUInt<0> doesn't make sense" );
178
+ if constexpr (N == 0 )
179
+ return 0 == x;
176
180
if constexpr (N == 8 )
177
181
return static_cast <uint8_t >(x) == x;
178
182
if constexpr (N == 16 )
@@ -188,39 +192,46 @@ template <unsigned N> constexpr inline bool isUInt(uint64_t x) {
188
192
// / Checks if a unsigned integer is an N bit number shifted left by S.
189
193
template <unsigned N, unsigned S>
190
194
constexpr inline bool isShiftedUInt (uint64_t x) {
191
- static_assert (
192
- N > 0 , " isShiftedUInt<0> doesn't make sense (refers to a 0-bit number)" );
195
+ static_assert (S < 64 , " isShiftedUInt<N, S> with S >= 64 is too much." );
193
196
static_assert (N + S <= 64 ,
194
197
" isShiftedUInt<N, S> with N + S > 64 is too wide." );
195
- // Per the two static_asserts above, S must be strictly less than 64. So
196
- // 1 << S is not undefined behavior.
198
+ // S must be strictly less than 64. So 1 << S is not undefined behavior.
197
199
return isUInt<N + S>(x) && (x % (UINT64_C (1 ) << S) == 0 );
198
200
}
199
201
200
202
// / Gets the maximum value for a N-bit unsigned integer.
201
203
inline uint64_t maxUIntN (uint64_t N) {
202
- assert (N > 0 && N <= 64 && " integer width out of range" );
204
+ assert (N <= 64 && " integer width out of range" );
203
205
204
206
// uint64_t(1) << 64 is undefined behavior, so we can't do
205
207
// (uint64_t(1) << N) - 1
206
208
// without checking first that N != 64. But this works and doesn't have a
207
- // branch.
209
+ // branch for N != 0.
210
+ // Unfortunately, shifting a uint64_t right by 64 bit is undefined
211
+ // behavior, so the condition on N == 0 is necessary. Fortunately, most
212
+ // optimizers do not emit branches for this check.
213
+ if (N == 0 )
214
+ return 0 ;
208
215
return UINT64_MAX >> (64 - N);
209
216
}
210
217
211
218
// / Gets the minimum value for a N-bit signed integer.
212
219
inline int64_t minIntN (int64_t N) {
213
- assert (N > 0 && N <= 64 && " integer width out of range" );
220
+ assert (N <= 64 && " integer width out of range" );
214
221
222
+ if (N == 0 )
223
+ return 0 ;
215
224
return UINT64_C (1 ) + ~(UINT64_C (1 ) << (N - 1 ));
216
225
}
217
226
218
227
// / Gets the maximum value for a N-bit signed integer.
219
228
inline int64_t maxIntN (int64_t N) {
220
- assert (N > 0 && N <= 64 && " integer width out of range" );
229
+ assert (N <= 64 && " integer width out of range" );
221
230
222
231
// This relies on two's complement wraparound when N == 64, so we convert to
223
232
// int64_t only at the very end to avoid UB.
233
+ if (N == 0 )
234
+ return 0 ;
224
235
return (UINT64_C (1 ) << (N - 1 )) - 1 ;
225
236
}
226
237
@@ -432,34 +443,38 @@ inline uint64_t alignDown(uint64_t Value, uint64_t Align, uint64_t Skew = 0) {
432
443
}
433
444
434
445
// / Sign-extend the number in the bottom B bits of X to a 32-bit integer.
435
- // / Requires 0 < B <= 32.
446
+ // / Requires B <= 32.
436
447
template <unsigned B> constexpr inline int32_t SignExtend32 (uint32_t X) {
437
- static_assert (B > 0 , " Bit width can't be 0." );
438
448
static_assert (B <= 32 , " Bit width out of range." );
449
+ if constexpr (B == 0 )
450
+ return 0 ;
439
451
return int32_t (X << (32 - B)) >> (32 - B);
440
452
}
441
453
442
454
// / Sign-extend the number in the bottom B bits of X to a 32-bit integer.
443
- // / Requires 0 < B <= 32.
455
+ // / Requires B <= 32.
444
456
inline int32_t SignExtend32 (uint32_t X, unsigned B) {
445
- assert (B > 0 && " Bit width can't be 0." );
446
457
assert (B <= 32 && " Bit width out of range." );
458
+ if (B == 0 )
459
+ return 0 ;
447
460
return int32_t (X << (32 - B)) >> (32 - B);
448
461
}
449
462
450
463
// / Sign-extend the number in the bottom B bits of X to a 64-bit integer.
451
- // / Requires 0 < B <= 64.
464
+ // / Requires B <= 64.
452
465
template <unsigned B> constexpr inline int64_t SignExtend64 (uint64_t x) {
453
- static_assert (B > 0 , " Bit width can't be 0." );
454
466
static_assert (B <= 64 , " Bit width out of range." );
467
+ if constexpr (B == 0 )
468
+ return 0 ;
455
469
return int64_t (x << (64 - B)) >> (64 - B);
456
470
}
457
471
458
472
// / Sign-extend the number in the bottom B bits of X to a 64-bit integer.
459
- // / Requires 0 < B <= 64.
473
+ // / Requires B <= 64.
460
474
inline int64_t SignExtend64 (uint64_t X, unsigned B) {
461
- assert (B > 0 && " Bit width can't be 0." );
462
475
assert (B <= 64 && " Bit width out of range." );
476
+ if (B == 0 )
477
+ return 0 ;
463
478
return int64_t (X << (64 - B)) >> (64 - B);
464
479
}
465
480
@@ -564,7 +579,6 @@ SaturatingMultiplyAdd(T X, T Y, T A, bool *ResultOverflowed = nullptr) {
564
579
// / Use this rather than HUGE_VALF; the latter causes warnings on MSVC.
565
580
extern const float huge_valf;
566
581
567
-
568
582
// / Add two signed integers, computing the two's complement truncated result,
569
583
// / returning true if overflow occurred.
570
584
template <typename T>
@@ -644,6 +658,6 @@ std::enable_if_t<std::is_signed_v<T>, T> MulOverflow(T X, T Y, T &Result) {
644
658
return UX > (static_cast <U>(std::numeric_limits<T>::max ())) / UY;
645
659
}
646
660
647
- } // End llvm namespace
661
+ } // namespace llvm
648
662
649
663
#endif
0 commit comments