summaryrefslogtreecommitdiff
path: root/include/llvm/Support/MathExtras.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/llvm/Support/MathExtras.h')
-rw-r--r--include/llvm/Support/MathExtras.h140
1 files changed, 99 insertions, 41 deletions
diff --git a/include/llvm/Support/MathExtras.h b/include/llvm/Support/MathExtras.h
index 408ae3c339a22..5c816ac9df922 100644
--- a/include/llvm/Support/MathExtras.h
+++ b/include/llvm/Support/MathExtras.h
@@ -16,9 +16,11 @@
#include "llvm/Support/Compiler.h"
#include "llvm/Support/SwapByteOrder.h"
+#include <algorithm>
#include <cassert>
#include <cstring>
#include <type_traits>
+#include <limits>
#ifdef _MSC_VER
#include <intrin.h>
@@ -281,14 +283,19 @@ inline bool isInt<32>(int64_t x) {
/// left by S.
template<unsigned N, unsigned S>
inline bool isShiftedInt(int64_t x) {
- return isInt<N+S>(x) && (x % (1<<S) == 0);
+ static_assert(
+ N > 0, "isShiftedInt<0> doesn't make sense (refers to a 0-bit number.");
+ static_assert(N + S <= 64, "isShiftedInt<N, S> with N + S > 64 is too wide.");
+ return isInt<N + S>(x) && (x % (UINT64_C(1) << S) == 0);
}
/// isUInt - Checks if an unsigned integer fits into the given bit width.
template<unsigned N>
inline bool isUInt(uint64_t x) {
+ static_assert(N > 0, "isUInt<0> doesn't make sense.");
return N >= 64 || x < (UINT64_C(1)<<(N));
}
+
// Template specializations to get better code for common cases.
template<>
inline bool isUInt<8>(uint64_t x) {
@@ -303,23 +310,55 @@ inline bool isUInt<32>(uint64_t x) {
return static_cast<uint32_t>(x) == x;
}
-/// isShiftedUInt<N,S> - Checks if a unsigned integer is an N bit number shifted
-/// left by S.
+/// Checks if a unsigned integer is an N bit number shifted left by S.
template<unsigned N, unsigned S>
inline bool isShiftedUInt(uint64_t x) {
- return isUInt<N+S>(x) && (x % (1<<S) == 0);
+ static_assert(
+ N > 0, "isShiftedUInt<0> doesn't make sense (refers to a 0-bit number)");
+ static_assert(N + S <= 64,
+ "isShiftedUInt<N, S> with N + S > 64 is too wide.");
+ // Per the two static_asserts above, S must be strictly less than 64. So
+ // 1 << S is not undefined behavior.
+ return isUInt<N + S>(x) && (x % (UINT64_C(1) << S) == 0);
+}
+
+/// Gets the maximum value for a N-bit unsigned integer.
+inline uint64_t maxUIntN(uint64_t N) {
+ assert(N > 0 && N <= 64 && "integer width out of range");
+
+ // uint64_t(1) << 64 is undefined behavior, so we can't do
+ // (uint64_t(1) << N) - 1
+ // without checking first that N != 64. But this works and doesn't have a
+ // branch.
+ return UINT64_MAX >> (64 - N);
+}
+
+/// Gets the minimum value for a N-bit signed integer.
+inline int64_t minIntN(int64_t N) {
+ assert(N > 0 && N <= 64 && "integer width out of range");
+
+ return -(UINT64_C(1)<<(N-1));
+}
+
+/// Gets the maximum value for a N-bit signed integer.
+inline int64_t maxIntN(int64_t N) {
+ assert(N > 0 && N <= 64 && "integer width out of range");
+
+ // This relies on two's complement wraparound when N == 64, so we convert to
+ // int64_t only at the very end to avoid UB.
+ return (UINT64_C(1) << (N - 1)) - 1;
}
/// isUIntN - Checks if an unsigned integer fits into the given (dynamic)
/// bit width.
inline bool isUIntN(unsigned N, uint64_t x) {
- return N >= 64 || x < (UINT64_C(1)<<(N));
+ return N >= 64 || x <= maxUIntN(N);
}
/// isIntN - Checks if an signed integer fits into the given (dynamic)
/// bit width.
inline bool isIntN(unsigned N, int64_t x) {
- return N >= 64 || (-(INT64_C(1)<<(N-1)) <= x && x < (INT64_C(1)<<(N-1)));
+ return N >= 64 || (minIntN(N) <= x && x <= maxIntN(N));
}
/// isMask_32 - This function returns true if the argument is a non-empty
@@ -606,57 +645,78 @@ inline uint64_t PowerOf2Floor(uint64_t A) {
///
/// Examples:
/// \code
-/// RoundUpToAlignment(5, 8) = 8
-/// RoundUpToAlignment(17, 8) = 24
-/// RoundUpToAlignment(~0LL, 8) = 0
-/// RoundUpToAlignment(321, 255) = 510
+/// alignTo(5, 8) = 8
+/// alignTo(17, 8) = 24
+/// alignTo(~0LL, 8) = 0
+/// alignTo(321, 255) = 510
///
-/// RoundUpToAlignment(5, 8, 7) = 7
-/// RoundUpToAlignment(17, 8, 1) = 17
-/// RoundUpToAlignment(~0LL, 8, 3) = 3
-/// RoundUpToAlignment(321, 255, 42) = 552
+/// alignTo(5, 8, 7) = 7
+/// alignTo(17, 8, 1) = 17
+/// alignTo(~0LL, 8, 3) = 3
+/// alignTo(321, 255, 42) = 552
/// \endcode
-inline uint64_t RoundUpToAlignment(uint64_t Value, uint64_t Align,
- uint64_t Skew = 0) {
+inline uint64_t alignTo(uint64_t Value, uint64_t Align, uint64_t Skew = 0) {
Skew %= Align;
return (Value + Align - 1 - Skew) / Align * Align + Skew;
}
+/// Returns the largest uint64_t less than or equal to \p Value and is
+/// \p Skew mod \p Align. \p Align must be non-zero
+inline uint64_t alignDown(uint64_t Value, uint64_t Align, uint64_t Skew = 0) {
+ Skew %= Align;
+ return (Value - Skew) / Align * Align + Skew;
+}
+
/// Returns the offset to the next integer (mod 2**64) that is greater than
/// or equal to \p Value and is a multiple of \p Align. \p Align must be
/// non-zero.
inline uint64_t OffsetToAlignment(uint64_t Value, uint64_t Align) {
- return RoundUpToAlignment(Value, Align) - Value;
+ return alignTo(Value, Align) - Value;
}
-/// SignExtend32 - Sign extend B-bit number x to 32-bit int.
-/// Usage int32_t r = SignExtend32<5>(x);
-template <unsigned B> inline int32_t SignExtend32(uint32_t x) {
- return int32_t(x << (32 - B)) >> (32 - B);
+/// Sign-extend the number in the bottom B bits of X to a 32-bit integer.
+/// Requires 0 < B <= 32.
+template <unsigned B> inline int32_t SignExtend32(uint32_t X) {
+ static_assert(B > 0, "Bit width can't be 0.");
+ static_assert(B <= 32, "Bit width out of range.");
+ return int32_t(X << (32 - B)) >> (32 - B);
}
-/// \brief Sign extend number in the bottom B bits of X to a 32-bit int.
-/// Requires 0 < B <= 32.
+/// Sign-extend the number in the bottom B bits of X to a 32-bit integer.
+/// Requires 0 < B < 32.
inline int32_t SignExtend32(uint32_t X, unsigned B) {
+ assert(B > 0 && "Bit width can't be 0.");
+ assert(B <= 32 && "Bit width out of range.");
return int32_t(X << (32 - B)) >> (32 - B);
}
-/// SignExtend64 - Sign extend B-bit number x to 64-bit int.
-/// Usage int64_t r = SignExtend64<5>(x);
+/// Sign-extend the number in the bottom B bits of X to a 64-bit integer.
+/// Requires 0 < B < 64.
template <unsigned B> inline int64_t SignExtend64(uint64_t x) {
+ static_assert(B > 0, "Bit width can't be 0.");
+ static_assert(B <= 64, "Bit width out of range.");
return int64_t(x << (64 - B)) >> (64 - B);
}
-/// \brief Sign extend number in the bottom B bits of X to a 64-bit int.
-/// Requires 0 < B <= 64.
+/// Sign-extend the number in the bottom B bits of X to a 64-bit integer.
+/// Requires 0 < B < 64.
inline int64_t SignExtend64(uint64_t X, unsigned B) {
+ assert(B > 0 && "Bit width can't be 0.");
+ assert(B <= 64 && "Bit width out of range.");
return int64_t(X << (64 - B)) >> (64 - B);
}
-/// \brief Add two unsigned integers, X and Y, of type T.
-/// Clamp the result to the maximum representable value of T on overflow.
-/// ResultOverflowed indicates if the result is larger than the maximum
-/// representable value of type T.
+/// Subtract two unsigned integers, X and Y, of type T and return the absolute
+/// value of the result.
+template <typename T>
+typename std::enable_if<std::is_unsigned<T>::value, T>::type
+AbsoluteDifference(T X, T Y) {
+ return std::max(X, Y) - std::min(X, Y);
+}
+
+/// Add two unsigned integers, X and Y, of type T. Clamp the result to the
+/// 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>
typename std::enable_if<std::is_unsigned<T>::value, T>::type
SaturatingAdd(T X, T Y, bool *ResultOverflowed = nullptr) {
@@ -671,10 +731,9 @@ SaturatingAdd(T X, T Y, bool *ResultOverflowed = nullptr) {
return Z;
}
-/// \brief Multiply two unsigned integers, X and Y, of type T.
-/// Clamp the result to the maximum representable value of T on overflow.
-/// ResultOverflowed indicates if the result is larger than the maximum
-/// representable value of type T.
+/// Multiply two unsigned integers, X and Y, of type T. Clamp the result to the
+/// 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>
typename std::enable_if<std::is_unsigned<T>::value, T>::type
SaturatingMultiply(T X, T Y, bool *ResultOverflowed = nullptr) {
@@ -717,12 +776,10 @@ SaturatingMultiply(T X, T Y, bool *ResultOverflowed = nullptr) {
return Z;
}
-/// \brief Multiply two unsigned integers, X and Y, and add the unsigned
-/// integer, A to the product. Clamp the result to the maximum representable
-/// value of T on overflow. ResultOverflowed indicates if the result is larger
-/// than the maximum representable value of type T.
-/// Note that this is purely a convenience function as there is no distinction
-/// where overflow occurred in a 'fused' multiply-add for unsigned numbers.
+/// Multiply two unsigned integers, X and Y, and add the unsigned integer, A to
+/// the product. Clamp the result to the 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>
typename std::enable_if<std::is_unsigned<T>::value, T>::type
SaturatingMultiplyAdd(T X, T Y, T A, bool *ResultOverflowed = nullptr) {
@@ -736,6 +793,7 @@ SaturatingMultiplyAdd(T X, T Y, T A, bool *ResultOverflowed = nullptr) {
return SaturatingAdd(A, Product, &Overflowed);
}
+/// Use this rather than HUGE_VALF; the latter causes warnings on MSVC.
extern const float huge_valf;
} // End llvm namespace