[llvm] Make more math&bit functions constexpr, NFC (PR #145856)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Jun 26 05:13:57 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-adt
Author: Haojian Wu (hokein)
<details>
<summary>Changes</summary>
---
Full diff: https://github.com/llvm/llvm-project/pull/145856.diff
2 Files Affected:
- (modified) llvm/include/llvm/ADT/bit.h (+8-8)
- (modified) llvm/include/llvm/Support/MathExtras.h (+25-22)
``````````diff
diff --git a/llvm/include/llvm/ADT/bit.h b/llvm/include/llvm/ADT/bit.h
index d6e33c3e6133a..207653f2f8478 100644
--- a/llvm/include/llvm/ADT/bit.h
+++ b/llvm/include/llvm/ADT/bit.h
@@ -154,7 +154,7 @@ template <typename T, typename = std::enable_if_t<std::is_unsigned_v<T>>>
/// Only unsigned integral types are allowed.
///
/// Returns std::numeric_limits<T>::digits on an input of 0.
-template <typename T> [[nodiscard]] int countr_zero(T Val) {
+template <typename T> [[nodiscard]] constexpr int countr_zero(T Val) {
static_assert(std::is_unsigned_v<T>,
"Only unsigned integral types are allowed.");
if (!Val)
@@ -200,7 +200,7 @@ template <typename T> [[nodiscard]] int countr_zero(T Val) {
/// Only unsigned integral types are allowed.
///
/// Returns std::numeric_limits<T>::digits on an input of 0.
-template <typename T> [[nodiscard]] int countl_zero(T Val) {
+template <typename T> [[nodiscard]] constexpr int countl_zero(T Val) {
static_assert(std::is_unsigned_v<T>,
"Only unsigned integral types are allowed.");
if (!Val)
@@ -244,7 +244,7 @@ template <typename T> [[nodiscard]] int countl_zero(T Val) {
/// Only unsigned integral types are allowed.
///
/// Returns std::numeric_limits<T>::digits on an input of all ones.
-template <typename T> [[nodiscard]] int countl_one(T Value) {
+template <typename T> [[nodiscard]] constexpr int countl_one(T Value) {
static_assert(std::is_unsigned_v<T>,
"Only unsigned integral types are allowed.");
return llvm::countl_zero<T>(~Value);
@@ -257,7 +257,7 @@ template <typename T> [[nodiscard]] int countl_one(T Value) {
/// Only unsigned integral types are allowed.
///
/// Returns std::numeric_limits<T>::digits on an input of all ones.
-template <typename T> [[nodiscard]] int countr_one(T Value) {
+template <typename T> [[nodiscard]] constexpr int countr_one(T Value) {
static_assert(std::is_unsigned_v<T>,
"Only unsigned integral types are allowed.");
return llvm::countr_zero<T>(~Value);
@@ -267,7 +267,7 @@ template <typename T> [[nodiscard]] int countr_one(T Value) {
/// Returns 0 otherwise.
///
/// Ex. bit_width(5) == 3.
-template <typename T> [[nodiscard]] int bit_width(T Value) {
+template <typename T> [[nodiscard]] constexpr int bit_width(T Value) {
static_assert(std::is_unsigned_v<T>,
"Only unsigned integral types are allowed.");
return std::numeric_limits<T>::digits - llvm::countl_zero(Value);
@@ -277,7 +277,7 @@ template <typename T> [[nodiscard]] int bit_width(T Value) {
/// nonzero. Returns 0 otherwise.
///
/// Ex. bit_floor(5) == 4.
-template <typename T> [[nodiscard]] T bit_floor(T Value) {
+template <typename T> [[nodiscard]] constexpr T bit_floor(T Value) {
static_assert(std::is_unsigned_v<T>,
"Only unsigned integral types are allowed.");
if (!Value)
@@ -292,7 +292,7 @@ template <typename T> [[nodiscard]] T bit_floor(T Value) {
///
/// The return value is undefined if the input is larger than the largest power
/// of two representable in T.
-template <typename T> [[nodiscard]] T bit_ceil(T Value) {
+template <typename T> [[nodiscard]] constexpr T bit_ceil(T Value) {
static_assert(std::is_unsigned_v<T>,
"Only unsigned integral types are allowed.");
if (Value < 2)
@@ -304,7 +304,7 @@ template <typename T> [[nodiscard]] T bit_ceil(T Value) {
/// Ex. popcount(0xF000F000) = 8
/// Returns 0 if the word is zero.
template <typename T, typename = std::enable_if_t<std::is_unsigned_v<T>>>
-[[nodiscard]] inline int popcount(T Value) noexcept {
+[[nodiscard]] inline constexpr int popcount(T Value) noexcept {
if constexpr (sizeof(T) <= 4) {
#if defined(__GNUC__)
return (int)__builtin_popcount(Value);
diff --git a/llvm/include/llvm/Support/MathExtras.h b/llvm/include/llvm/Support/MathExtras.h
index 7bbf1b3aab761..2cf0511231976 100644
--- a/llvm/include/llvm/Support/MathExtras.h
+++ b/llvm/include/llvm/Support/MathExtras.h
@@ -303,8 +303,8 @@ constexpr bool isPowerOf2_64(uint64_t Value) {
/// If true, \p MaskIdx will specify the index of the lowest set bit and \p
/// MaskLen is updated to specify the length of the mask, else neither are
/// updated.
-inline bool isShiftedMask_32(uint32_t Value, unsigned &MaskIdx,
- unsigned &MaskLen) {
+inline constexpr bool isShiftedMask_32(uint32_t Value, unsigned &MaskIdx,
+ unsigned &MaskLen) {
if (!isShiftedMask_32(Value))
return false;
MaskIdx = llvm::countr_zero(Value);
@@ -316,8 +316,8 @@ inline bool isShiftedMask_32(uint32_t Value, unsigned &MaskIdx,
/// remainder zero (64 bit version.) If true, \p MaskIdx will specify the index
/// of the lowest set bit and \p MaskLen is updated to specify the length of the
/// mask, else neither are updated.
-inline bool isShiftedMask_64(uint64_t Value, unsigned &MaskIdx,
- unsigned &MaskLen) {
+inline constexpr bool isShiftedMask_64(uint64_t Value, unsigned &MaskIdx,
+ unsigned &MaskLen) {
if (!isShiftedMask_64(Value))
return false;
MaskIdx = llvm::countr_zero(Value);
@@ -337,26 +337,26 @@ template <> constexpr size_t CTLog2<1>() { return 0; }
/// Return the floor log base 2 of the specified value, -1 if the value is zero.
/// (32 bit edition.)
/// Ex. Log2_32(32) == 5, Log2_32(1) == 0, Log2_32(0) == -1, Log2_32(6) == 2
-inline unsigned Log2_32(uint32_t Value) {
+inline constexpr unsigned Log2_32(uint32_t Value) {
return 31 - llvm::countl_zero(Value);
}
/// Return the floor log base 2 of the specified value, -1 if the value is zero.
/// (64 bit edition.)
-inline unsigned Log2_64(uint64_t Value) {
+inline constexpr unsigned Log2_64(uint64_t Value) {
return 63 - llvm::countl_zero(Value);
}
/// Return the ceil log base 2 of the specified value, 32 if the value is zero.
/// (32 bit edition).
/// Ex. Log2_32_Ceil(32) == 5, Log2_32_Ceil(1) == 0, Log2_32_Ceil(6) == 3
-inline unsigned Log2_32_Ceil(uint32_t Value) {
+inline constexpr unsigned Log2_32_Ceil(uint32_t Value) {
return 32 - llvm::countl_zero(Value - 1);
}
/// Return the ceil log base 2 of the specified value, 64 if the value is zero.
/// (64 bit edition.)
-inline unsigned Log2_64_Ceil(uint64_t Value) {
+inline constexpr unsigned Log2_64_Ceil(uint64_t Value) {
return 64 - llvm::countl_zero(Value - 1);
}
@@ -391,7 +391,7 @@ constexpr uint64_t NextPowerOf2(uint64_t A) {
/// Returns the power of two which is greater than or equal to the given value.
/// Essentially, it is a ceil operation across the domain of powers of two.
-inline uint64_t PowerOf2Ceil(uint64_t A) {
+inline constexpr uint64_t PowerOf2Ceil(uint64_t A) {
if (!A || A > UINT64_MAX / 2)
return 0;
return UINT64_C(1) << Log2_64_Ceil(A);
@@ -569,7 +569,7 @@ template <unsigned B> constexpr int32_t SignExtend32(uint32_t X) {
/// Sign-extend the number in the bottom B bits of X to a 32-bit integer.
/// Requires B <= 32.
-inline int32_t SignExtend32(uint32_t X, unsigned B) {
+inline constexpr int32_t SignExtend32(uint32_t X, unsigned B) {
assert(B <= 32 && "Bit width out of range.");
if (B == 0)
return 0;
@@ -587,7 +587,7 @@ template <unsigned B> constexpr int64_t SignExtend64(uint64_t x) {
/// Sign-extend the number in the bottom B bits of X to a 64-bit integer.
/// Requires B <= 64.
-inline int64_t SignExtend64(uint64_t X, unsigned B) {
+inline constexpr int64_t SignExtend64(uint64_t X, unsigned B) {
assert(B <= 64 && "Bit width out of range.");
if (B == 0)
return 0;
@@ -614,9 +614,9 @@ constexpr T AbsoluteDifference(U X, V Y) {
/// maximum representable value of T on overflow. ResultOverflowed indicates if
/// the result is larger than the maximum representable value of type T.
template <typename T>
-std::enable_if_t<std::is_unsigned_v<T>, T>
+constexpr std::enable_if_t<std::is_unsigned_v<T>, T>
SaturatingAdd(T X, T Y, bool *ResultOverflowed = nullptr) {
- bool Dummy;
+ bool Dummy = 0;
bool &Overflowed = ResultOverflowed ? *ResultOverflowed : Dummy;
// Hacker's Delight, p. 29
T Z = X + Y;
@@ -630,8 +630,8 @@ SaturatingAdd(T X, T Y, bool *ResultOverflowed = nullptr) {
/// Add multiple unsigned integers of type T. Clamp the result to the
/// maximum representable value of T on overflow.
template <class T, class... Ts>
-std::enable_if_t<std::is_unsigned_v<T>, T> SaturatingAdd(T X, T Y, T Z,
- Ts... Args) {
+constexpr std::enable_if_t<std::is_unsigned_v<T>, T>
+SaturatingAdd(T X, T Y, T Z, Ts... Args) {
bool Overflowed = false;
T XY = SaturatingAdd(X, Y, &Overflowed);
if (Overflowed)
@@ -643,9 +643,9 @@ std::enable_if_t<std::is_unsigned_v<T>, T> SaturatingAdd(T X, T Y, T Z,
/// maximum representable value of T on overflow. ResultOverflowed indicates if
/// the result is larger than the maximum representable value of type T.
template <typename T>
-std::enable_if_t<std::is_unsigned_v<T>, T>
+constexpr std::enable_if_t<std::is_unsigned_v<T>, T>
SaturatingMultiply(T X, T Y, bool *ResultOverflowed = nullptr) {
- bool Dummy;
+ bool Dummy = 0;
bool &Overflowed = ResultOverflowed ? *ResultOverflowed : Dummy;
// Hacker's Delight, p. 30 has a different algorithm, but we don't use that
@@ -689,9 +689,9 @@ SaturatingMultiply(T X, T Y, bool *ResultOverflowed = nullptr) {
/// overflow. ResultOverflowed indicates if the result is larger than the
/// maximum representable value of type T.
template <typename T>
-std::enable_if_t<std::is_unsigned_v<T>, T>
+constexpr std::enable_if_t<std::is_unsigned_v<T>, T>
SaturatingMultiplyAdd(T X, T Y, T A, bool *ResultOverflowed = nullptr) {
- bool Dummy;
+ bool Dummy = 0;
bool &Overflowed = ResultOverflowed ? *ResultOverflowed : Dummy;
T Product = SaturatingMultiply(X, Y, &Overflowed);
@@ -707,7 +707,8 @@ LLVM_ABI extern const float huge_valf;
/// Add two signed integers, computing the two's complement truncated result,
/// returning true if overflow occurred.
template <typename T>
-std::enable_if_t<std::is_signed_v<T>, T> AddOverflow(T X, T Y, T &Result) {
+constexpr std::enable_if_t<std::is_signed_v<T>, T> AddOverflow(T X, T Y,
+ T &Result) {
#if __has_builtin(__builtin_add_overflow)
return __builtin_add_overflow(X, Y, &Result);
#else
@@ -733,7 +734,8 @@ std::enable_if_t<std::is_signed_v<T>, T> AddOverflow(T X, T Y, T &Result) {
/// Subtract two signed integers, computing the two's complement truncated
/// result, returning true if an overflow occurred.
template <typename T>
-std::enable_if_t<std::is_signed_v<T>, T> SubOverflow(T X, T Y, T &Result) {
+constexpr std::enable_if_t<std::is_signed_v<T>, T> SubOverflow(T X, T Y,
+ T &Result) {
#if __has_builtin(__builtin_sub_overflow)
return __builtin_sub_overflow(X, Y, &Result);
#else
@@ -759,7 +761,8 @@ std::enable_if_t<std::is_signed_v<T>, T> SubOverflow(T X, T Y, T &Result) {
/// Multiply two signed integers, computing the two's complement truncated
/// result, returning true if an overflow occurred.
template <typename T>
-std::enable_if_t<std::is_signed_v<T>, T> MulOverflow(T X, T Y, T &Result) {
+constexpr std::enable_if_t<std::is_signed_v<T>, T> MulOverflow(T X, T Y,
+ T &Result) {
#if __has_builtin(__builtin_mul_overflow)
return __builtin_mul_overflow(X, Y, &Result);
#else
``````````
</details>
https://github.com/llvm/llvm-project/pull/145856
More information about the llvm-commits
mailing list