Skip to content

Commit 9809848

Browse files
committed
add support for i0 in MathExtras.h
1 parent 417a068 commit 9809848

File tree

3 files changed

+38
-24
lines changed

3 files changed

+38
-24
lines changed

llvm/include/llvm/Support/MathExtras.h

Lines changed: 27 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,8 @@ constexpr inline uint64_t Make_64(uint32_t High, uint32_t Low) {
149149

150150
/// Checks if an integer fits into the given bit width.
151151
template <unsigned N> constexpr inline bool isInt(int64_t x) {
152+
if constexpr (N == 0)
153+
return 0 == x;
152154
if constexpr (N == 8)
153155
return static_cast<int8_t>(x) == x;
154156
if constexpr (N == 16)
@@ -164,15 +166,15 @@ template <unsigned N> constexpr inline bool isInt(int64_t x) {
164166
/// Checks if a signed integer is an N bit number shifted left by S.
165167
template <unsigned N, unsigned S>
166168
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.");
169+
static_assert(S < 64, "isShiftedInt<N, S> with S >= 64 is too much.");
169170
static_assert(N + S <= 64, "isShiftedInt<N, S> with N + S > 64 is too wide.");
170171
return isInt<N + S>(x) && (x % (UINT64_C(1) << S) == 0);
171172
}
172173

173174
/// Checks if an unsigned integer fits into the given bit width.
174175
template <unsigned N> constexpr inline bool isUInt(uint64_t x) {
175-
static_assert(N > 0, "isUInt<0> doesn't make sense");
176+
if constexpr (N == 0)
177+
return 0 == x;
176178
if constexpr (N == 8)
177179
return static_cast<uint8_t>(x) == x;
178180
if constexpr (N == 16)
@@ -188,8 +190,7 @@ template <unsigned N> constexpr inline bool isUInt(uint64_t x) {
188190
/// Checks if a unsigned integer is an N bit number shifted left by S.
189191
template <unsigned N, unsigned S>
190192
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)");
193+
static_assert(S < 64, "isShiftedUInt<N, S> with S >= 64 is too much.");
193194
static_assert(N + S <= 64,
194195
"isShiftedUInt<N, S> with N + S > 64 is too wide.");
195196
// Per the two static_asserts above, S must be strictly less than 64. So
@@ -199,29 +200,32 @@ constexpr inline bool isShiftedUInt(uint64_t x) {
199200

200201
/// Gets the maximum value for a N-bit unsigned integer.
201202
inline uint64_t maxUIntN(uint64_t N) {
202-
assert(N > 0 && N <= 64 && "integer width out of range");
203+
assert(N <= 64 && "integer width out of range");
203204

204205
// uint64_t(1) << 64 is undefined behavior, so we can't do
205206
// (uint64_t(1) << N) - 1
206207
// without checking first that N != 64. But this works and doesn't have a
207-
// branch.
208-
return UINT64_MAX >> (64 - N);
208+
// branch for N != 0.
209+
// Unfortunately, shifting a uint64_t right by 64 bit is undefined
210+
// behavior, so the condition on N == 0 is necessary. Fortunately, most
211+
// optimizers do not emit branches for this check.
212+
return N == 0 ? 0 : UINT64_MAX >> (64 - N);
209213
}
210214

211215
/// Gets the minimum value for a N-bit signed integer.
212216
inline int64_t minIntN(int64_t N) {
213-
assert(N > 0 && N <= 64 && "integer width out of range");
217+
assert(N <= 64 && "integer width out of range");
214218

215-
return UINT64_C(1) + ~(UINT64_C(1) << (N - 1));
219+
return N == 0 ? 0 : UINT64_C(1) + ~(UINT64_C(1) << (N - 1));
216220
}
217221

218222
/// Gets the maximum value for a N-bit signed integer.
219223
inline int64_t maxIntN(int64_t N) {
220-
assert(N > 0 && N <= 64 && "integer width out of range");
224+
assert(N <= 64 && "integer width out of range");
221225

222226
// This relies on two's complement wraparound when N == 64, so we convert to
223227
// int64_t only at the very end to avoid UB.
224-
return (UINT64_C(1) << (N - 1)) - 1;
228+
return N == 0 ? 0 : (UINT64_C(1) << (N - 1)) - 1;
225229
}
226230

227231
/// Checks if an unsigned integer fits into the given (dynamic) bit width.
@@ -432,35 +436,35 @@ inline uint64_t alignDown(uint64_t Value, uint64_t Align, uint64_t Skew = 0) {
432436
}
433437

434438
/// Sign-extend the number in the bottom B bits of X to a 32-bit integer.
435-
/// Requires 0 < B <= 32.
439+
/// Requires B <= 32.
436440
template <unsigned B> constexpr inline int32_t SignExtend32(uint32_t X) {
437-
static_assert(B > 0, "Bit width can't be 0.");
438441
static_assert(B <= 32, "Bit width out of range.");
442+
if constexpr (B == 0)
443+
return 0;
439444
return int32_t(X << (32 - B)) >> (32 - B);
440445
}
441446

442447
/// Sign-extend the number in the bottom B bits of X to a 32-bit integer.
443-
/// Requires 0 < B <= 32.
448+
/// Requires B <= 32.
444449
inline int32_t SignExtend32(uint32_t X, unsigned B) {
445-
assert(B > 0 && "Bit width can't be 0.");
446450
assert(B <= 32 && "Bit width out of range.");
447-
return int32_t(X << (32 - B)) >> (32 - B);
451+
return B == 0 ? 0 : int32_t(X << (32 - B)) >> (32 - B);
448452
}
449453

450454
/// Sign-extend the number in the bottom B bits of X to a 64-bit integer.
451-
/// Requires 0 < B <= 64.
455+
/// Requires B <= 64.
452456
template <unsigned B> constexpr inline int64_t SignExtend64(uint64_t x) {
453-
static_assert(B > 0, "Bit width can't be 0.");
454457
static_assert(B <= 64, "Bit width out of range.");
458+
if constexpr (B == 0)
459+
return 0;
455460
return int64_t(x << (64 - B)) >> (64 - B);
456461
}
457462

458463
/// Sign-extend the number in the bottom B bits of X to a 64-bit integer.
459-
/// Requires 0 < B <= 64.
464+
/// Requires B <= 64.
460465
inline int64_t SignExtend64(uint64_t X, unsigned B) {
461-
assert(B > 0 && "Bit width can't be 0.");
462466
assert(B <= 64 && "Bit width out of range.");
463-
return int64_t(X << (64 - B)) >> (64 - B);
467+
return B == 0 ? 0 : int64_t(X << (64 - B)) >> (64 - B);
464468
}
465469

466470
/// Subtract two unsigned integers, X and Y, of type T and return the absolute
@@ -564,7 +568,6 @@ SaturatingMultiplyAdd(T X, T Y, T A, bool *ResultOverflowed = nullptr) {
564568
/// Use this rather than HUGE_VALF; the latter causes warnings on MSVC.
565569
extern const float huge_valf;
566570

567-
568571
/// Add two signed integers, computing the two's complement truncated result,
569572
/// returning true if overflow occurred.
570573
template <typename T>
@@ -644,6 +647,6 @@ std::enable_if_t<std::is_signed_v<T>, T> MulOverflow(T X, T Y, T &Result) {
644647
return UX > (static_cast<U>(std::numeric_limits<T>::max())) / UY;
645648
}
646649

647-
} // End llvm namespace
650+
} // namespace llvm
648651

649652
#endif

llvm/unittests/ADT/APIntTest.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2797,6 +2797,9 @@ TEST(APIntTest, sext) {
27972797
EXPECT_EQ(63U, i32_neg1.countl_one());
27982798
EXPECT_EQ(0U, i32_neg1.countr_zero());
27992799
EXPECT_EQ(63U, i32_neg1.popcount());
2800+
2801+
EXPECT_EQ(APInt(32u, 0), APInt(0u, 0).sext(32));
2802+
EXPECT_EQ(APInt(64u, 0), APInt(0u, 0).sext(64));
28002803
}
28012804

28022805
TEST(APIntTest, trunc) {

llvm/unittests/Support/MathExtrasTest.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,27 +41,34 @@ TEST(MathExtras, onesMask) {
4141
TEST(MathExtras, isIntN) {
4242
EXPECT_TRUE(isIntN(16, 32767));
4343
EXPECT_FALSE(isIntN(16, 32768));
44+
EXPECT_TRUE(isUIntN(0, 0));
45+
EXPECT_FALSE(isUIntN(0, 1));
46+
EXPECT_FALSE(isUIntN(0, -1));
4447
}
4548

4649
TEST(MathExtras, isUIntN) {
4750
EXPECT_TRUE(isUIntN(16, 65535));
4851
EXPECT_FALSE(isUIntN(16, 65536));
4952
EXPECT_TRUE(isUIntN(1, 0));
5053
EXPECT_TRUE(isUIntN(6, 63));
54+
EXPECT_TRUE(isUIntN(0, 0));
55+
EXPECT_FALSE(isUIntN(0, 1));
5156
}
5257

5358
TEST(MathExtras, maxIntN) {
5459
EXPECT_EQ(32767, maxIntN(16));
5560
EXPECT_EQ(2147483647, maxIntN(32));
5661
EXPECT_EQ(std::numeric_limits<int32_t>::max(), maxIntN(32));
5762
EXPECT_EQ(std::numeric_limits<int64_t>::max(), maxIntN(64));
63+
EXPECT_EQ(0, maxIntN(0));
5864
}
5965

6066
TEST(MathExtras, minIntN) {
6167
EXPECT_EQ(-32768LL, minIntN(16));
6268
EXPECT_EQ(-64LL, minIntN(7));
6369
EXPECT_EQ(std::numeric_limits<int32_t>::min(), minIntN(32));
6470
EXPECT_EQ(std::numeric_limits<int64_t>::min(), minIntN(64));
71+
EXPECT_EQ(0, minIntN(0));
6572
}
6673

6774
TEST(MathExtras, maxUIntN) {
@@ -70,6 +77,7 @@ TEST(MathExtras, maxUIntN) {
7077
EXPECT_EQ(0xffffffffffffffffULL, maxUIntN(64));
7178
EXPECT_EQ(1ULL, maxUIntN(1));
7279
EXPECT_EQ(0x0fULL, maxUIntN(4));
80+
EXPECT_EQ(0, maxUIntN(0));
7381
}
7482

7583
TEST(MathExtras, reverseBits) {

0 commit comments

Comments
 (0)