diff --git a/llvm/include/llvm/Support/MathExtras.h b/llvm/include/llvm/Support/MathExtras.h index 6de754f472635..f6b1fdb6aba9e 100644 --- a/llvm/include/llvm/Support/MathExtras.h +++ b/llvm/include/llvm/Support/MathExtras.h @@ -23,6 +23,22 @@ #include namespace llvm { +/// Some template parameter helpers to optimize for bitwidth, for functions that +/// take multiple arguments. + +// We can't verify signedness, since callers rely on implicit coercions to +// signed/unsigned. +template +using enableif_int = + std::enable_if_t && std::is_integral_v>; + +// Use std::common_type_t to widen only up to the widest argument. +template > +using common_uint = + std::common_type_t, std::make_unsigned_t>; +template > +using common_sint = + std::common_type_t, std::make_signed_t>; /// Mathematical constants. namespace numbers { @@ -346,7 +362,8 @@ inline unsigned Log2_64_Ceil(uint64_t Value) { /// A and B are either alignments or offsets. Return the minimum alignment that /// may be assumed after adding the two together. -constexpr uint64_t MinAlign(uint64_t A, uint64_t B) { +template > +constexpr T MinAlign(U A, V B) { // The largest power of 2 that divides both A and B. // // Replace "-Value" by "1+~Value" in the following commented code to avoid @@ -355,6 +372,11 @@ constexpr uint64_t MinAlign(uint64_t A, uint64_t B) { return (A | B) & (1 + ~(A | B)); } +/// Fallback when arguments aren't integral. +constexpr uint64_t MinAlign(uint64_t A, uint64_t B) { + return (A | B) & (1 + ~(A | B)); +} + /// Returns the next power of two (in 64-bits) that is strictly greater than A. /// Returns zero on overflow. constexpr uint64_t NextPowerOf2(uint64_t A) { @@ -375,60 +397,17 @@ inline uint64_t PowerOf2Ceil(uint64_t A) { return UINT64_C(1) << Log2_64_Ceil(A); } -/// Returns 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. -/// -/// Examples: -/// \code -/// alignTo(5, 8) = 8 -/// alignTo(17, 8) = 24 -/// alignTo(~0LL, 8) = 0 -/// alignTo(321, 255) = 510 -/// \endcode -/// -/// May overflow. -inline uint64_t alignTo(uint64_t Value, uint64_t Align) { - assert(Align != 0u && "Align can't be 0."); - return (Value + Align - 1) / Align * Align; -} - -inline uint64_t alignToPowerOf2(uint64_t Value, uint64_t Align) { - assert(Align != 0 && (Align & (Align - 1)) == 0 && - "Align must be a power of 2"); - // Replace unary minus to avoid compilation error on Windows: - // "unary minus operator applied to unsigned type, result still unsigned" - uint64_t negAlign = (~Align) + 1; - return (Value + Align - 1) & negAlign; -} - -/// If non-zero \p Skew is specified, the return value will be a minimal integer -/// that is greater than or equal to \p Size and equal to \p A * N + \p Skew for -/// some integer N. If \p Skew is larger than \p A, its value is adjusted to '\p -/// Skew mod \p A'. \p Align must be non-zero. -/// -/// Examples: -/// \code -/// alignTo(5, 8, 7) = 7 -/// alignTo(17, 8, 1) = 17 -/// alignTo(~0LL, 8, 3) = 3 -/// alignTo(321, 255, 42) = 552 -/// \endcode -inline uint64_t alignTo(uint64_t Value, uint64_t Align, uint64_t Skew) { - assert(Align != 0u && "Align can't be 0."); - Skew %= Align; - return alignTo(Value - Skew, Align) + Skew; -} - -/// Returns the next integer (mod 2**64) that is greater than or equal to -/// \p Value and is a multiple of \c Align. \c Align must be non-zero. -template constexpr uint64_t alignTo(uint64_t Value) { - static_assert(Align != 0u, "Align must be non-zero"); - return (Value + Align - 1) / Align * Align; -} - /// Returns the integer ceil(Numerator / Denominator). Unsigned version. /// Guaranteed to never overflow. -inline uint64_t divideCeil(uint64_t Numerator, uint64_t Denominator) { +template > +constexpr T divideCeil(U Numerator, V Denominator) { + assert(Denominator && "Division by zero"); + T Bias = (Numerator != 0); + return (Numerator - Bias) / Denominator + Bias; +} + +/// Fallback when arguments aren't integral. +constexpr uint64_t divideCeil(uint64_t Numerator, uint64_t Denominator) { assert(Denominator && "Division by zero"); uint64_t Bias = (Numerator != 0); return (Numerator - Bias) / Denominator + Bias; @@ -437,12 +416,13 @@ inline uint64_t divideCeil(uint64_t Numerator, uint64_t Denominator) { /// Returns the integer ceil(Numerator / Denominator). Signed version. /// Guaranteed to never overflow, unless Numerator is INT64_MIN and Denominator /// is -1. -inline int64_t divideCeilSigned(int64_t Numerator, int64_t Denominator) { +template > +constexpr T divideCeilSigned(U Numerator, V Denominator) { assert(Denominator && "Division by zero"); if (!Numerator) return 0; // C's integer division rounds towards 0. - int64_t Bias = (Denominator >= 0 ? 1 : -1); + T Bias = Denominator >= 0 ? 1 : -1; bool SameSign = (Numerator >= 0) == (Denominator >= 0); return SameSign ? (Numerator - Bias) / Denominator + 1 : Numerator / Denominator; @@ -451,12 +431,13 @@ inline int64_t divideCeilSigned(int64_t Numerator, int64_t Denominator) { /// Returns the integer floor(Numerator / Denominator). Signed version. /// Guaranteed to never overflow, unless Numerator is INT64_MIN and Denominator /// is -1. -inline int64_t divideFloorSigned(int64_t Numerator, int64_t Denominator) { +template > +constexpr T divideFloorSigned(U Numerator, V Denominator) { assert(Denominator && "Division by zero"); if (!Numerator) return 0; // C's integer division rounds towards 0. - int64_t Bias = Denominator >= 0 ? -1 : 1; + T Bias = Denominator >= 0 ? -1 : 1; bool SameSign = (Numerator >= 0) == (Denominator >= 0); return SameSign ? Numerator / Denominator : (Numerator - Bias) / Denominator - 1; @@ -464,23 +445,97 @@ inline int64_t divideFloorSigned(int64_t Numerator, int64_t Denominator) { /// Returns the remainder of the Euclidean division of LHS by RHS. Result is /// always non-negative. -inline int64_t mod(int64_t Numerator, int64_t Denominator) { +template > +constexpr T mod(U Numerator, V Denominator) { assert(Denominator >= 1 && "Mod by non-positive number"); - int64_t Mod = Numerator % Denominator; + T Mod = Numerator % Denominator; return Mod < 0 ? Mod + Denominator : Mod; } /// Returns (Numerator / Denominator) rounded by round-half-up. Guaranteed to /// never overflow. -inline uint64_t divideNearest(uint64_t Numerator, uint64_t Denominator) { +template > +constexpr T divideNearest(U Numerator, V Denominator) { assert(Denominator && "Division by zero"); - uint64_t Mod = Numerator % Denominator; - return (Numerator / Denominator) + (Mod > (Denominator - 1) / 2); + T Mod = Numerator % Denominator; + return (Numerator / Denominator) + + (Mod > (static_cast(Denominator) - 1) / 2); +} + +/// Returns the next integer (mod 2**nbits) that is greater than or equal to +/// \p Value and is a multiple of \p Align. \p Align must be non-zero. +/// +/// Examples: +/// \code +/// alignTo(5, 8) = 8 +/// alignTo(17, 8) = 24 +/// alignTo(~0LL, 8) = 0 +/// alignTo(321, 255) = 510 +/// \endcode +/// +/// Will overflow only if result is not representable in T. +template > +constexpr T alignTo(U Value, V Align) { + assert(Align != 0u && "Align can't be 0."); + T CeilDiv = divideCeil(Value, Align); + return CeilDiv * Align; +} + +/// Fallback when arguments aren't integral. +constexpr uint64_t alignTo(uint64_t Value, uint64_t Align) { + assert(Align != 0u && "Align can't be 0."); + uint64_t CeilDiv = divideCeil(Value, Align); + return CeilDiv * Align; +} + +constexpr uint64_t alignToPowerOf2(uint64_t Value, uint64_t Align) { + assert(Align != 0 && (Align & (Align - 1)) == 0 && + "Align must be a power of 2"); + // Replace unary minus to avoid compilation error on Windows: + // "unary minus operator applied to unsigned type, result still unsigned" + uint64_t NegAlign = (~Align) + 1; + return (Value + Align - 1) & NegAlign; +} + +/// If non-zero \p Skew is specified, the return value will be a minimal integer +/// that is greater than or equal to \p Size and equal to \p A * N + \p Skew for +/// some integer N. If \p Skew is larger than \p A, its value is adjusted to '\p +/// Skew mod \p A'. \p Align must be non-zero. +/// +/// Examples: +/// \code +/// alignTo(5, 8, 7) = 7 +/// alignTo(17, 8, 1) = 17 +/// alignTo(~0LL, 8, 3) = 3 +/// alignTo(321, 255, 42) = 552 +/// \endcode +/// +/// May overflow. +template , W>> +constexpr T alignTo(U Value, V Align, W Skew) { + assert(Align != 0u && "Align can't be 0."); + Skew %= Align; + return alignTo(Value - Skew, 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) { +/// Returns the next integer (mod 2**nbits) that is greater than or equal to +/// \p Value and is a multiple of \c Align. \c Align must be non-zero. +/// +/// Will overflow only if result is not representable in T. +template > +constexpr T alignTo(V Value) { + static_assert(Align != 0u, "Align must be non-zero"); + T CeilDiv = divideCeil(Value, Align); + return CeilDiv * Align; +} + +/// Returns the largest unsigned integer less than or equal to \p Value and is +/// \p Skew mod \p Align. \p Align must be non-zero. Guaranteed to never +/// overflow. +template , W>> +constexpr T alignDown(U Value, V Align, W Skew = 0) { assert(Align != 0u && "Align can't be 0."); Skew %= Align; return (Value - Skew) / Align * Align + Skew; @@ -524,8 +579,8 @@ inline int64_t SignExtend64(uint64_t X, unsigned B) { /// Subtract two unsigned integers, X and Y, of type T and return the absolute /// value of the result. -template -std::enable_if_t, T> AbsoluteDifference(T X, T Y) { +template > +constexpr T AbsoluteDifference(U X, V Y) { return X > Y ? (X - Y) : (Y - X); } diff --git a/llvm/unittests/Support/MathExtrasTest.cpp b/llvm/unittests/Support/MathExtrasTest.cpp index bd09bab9be004..a557b61db9752 100644 --- a/llvm/unittests/Support/MathExtrasTest.cpp +++ b/llvm/unittests/Support/MathExtrasTest.cpp @@ -189,8 +189,13 @@ TEST(MathExtras, AlignTo) { EXPECT_EQ(8u, alignTo(5, 8)); EXPECT_EQ(24u, alignTo(17, 8)); EXPECT_EQ(0u, alignTo(~0LL, 8)); - EXPECT_EQ(static_cast(std::numeric_limits::max()) + 1, - alignTo(std::numeric_limits::max(), 2)); + EXPECT_EQ(8u, alignTo(5ULL, 8ULL)); + + EXPECT_EQ(8u, alignTo<8>(5)); + EXPECT_EQ(24u, alignTo<8>(17)); + EXPECT_EQ(0u, alignTo<8>(~0LL)); + EXPECT_EQ(254u, + alignTo(127)>(static_cast(200))); EXPECT_EQ(7u, alignTo(5, 8, 7)); EXPECT_EQ(17u, alignTo(17, 8, 1)); @@ -198,12 +203,21 @@ TEST(MathExtras, AlignTo) { EXPECT_EQ(552u, alignTo(321, 255, 42)); EXPECT_EQ(std::numeric_limits::max(), alignTo(std::numeric_limits::max(), 2, 1)); + + // Overflow. + EXPECT_EQ(0u, alignTo(static_cast(200), static_cast(128))); + EXPECT_EQ(0u, alignTo(128)>(static_cast(200))); + EXPECT_EQ(0u, alignTo(static_cast(200), static_cast(128), + static_cast(0))); + EXPECT_EQ(0u, alignTo(std::numeric_limits::max(), 2)); } TEST(MathExtras, AlignToPowerOf2) { + EXPECT_EQ(0u, alignToPowerOf2(0u, 8)); EXPECT_EQ(8u, alignToPowerOf2(5, 8)); EXPECT_EQ(24u, alignToPowerOf2(17, 8)); EXPECT_EQ(0u, alignToPowerOf2(~0LL, 8)); + EXPECT_EQ(240u, alignToPowerOf2(240, 16)); EXPECT_EQ(static_cast(std::numeric_limits::max()) + 1, alignToPowerOf2(std::numeric_limits::max(), 2)); }