[llvm] MathExtras: avoid unnecessarily widening types (PR #95426)

Ramkumar Ramachandra via llvm-commits llvm-commits at lists.llvm.org
Mon Jun 24 04:54:46 PDT 2024


https://github.com/artagnon updated https://github.com/llvm/llvm-project/pull/95426

>From 52f24adbdfebe7798f83467b9889c72e0cd649fe Mon Sep 17 00:00:00 2001
From: Ramkumar Ramachandra <ramkumar.ramachandra at codasip.com>
Date: Wed, 12 Jun 2024 12:58:03 +0100
Subject: [PATCH 1/3] MathExtras: avoid unnecessarily widening types

Several multi-argument functions unnecessarily widen types beyond the
argument types. Template'ize the functions, and use std::common_type_t
to avoid this, hence optimizing the functions. A requirement of this
patch is to change the overflow behavior of alignTo, to only overflow
when the result is not representable in the return type.
---
 llvm/include/llvm/Support/MathExtras.h    | 112 ++++++++++++++++------
 llvm/unittests/Support/MathExtrasTest.cpp |  20 +++-
 2 files changed, 103 insertions(+), 29 deletions(-)

diff --git a/llvm/include/llvm/Support/MathExtras.h b/llvm/include/llvm/Support/MathExtras.h
index 5bcefe4b6c361..5611dc00058ea 100644
--- a/llvm/include/llvm/Support/MathExtras.h
+++ b/llvm/include/llvm/Support/MathExtras.h
@@ -23,6 +23,22 @@
 #include <type_traits>
 
 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 <typename T, typename U>
+using enableif_int =
+    std::enable_if_t<std::is_integral_v<T> && std::is_integral_v<U>>;
+
+// Use std::common_type_t to widen only up to the widest argument.
+template <typename T, typename U, typename = enableif_int<T, U>>
+using common_uint =
+    std::common_type_t<std::make_unsigned_t<T>, std::make_unsigned_t<U>>;
+template <typename T, typename U, typename = enableif_int<T, U>>
+using common_sint =
+    std::common_type_t<std::make_signed_t<T>, std::make_signed_t<U>>;
 
 /// 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 inline uint64_t MinAlign(uint64_t A, uint64_t B) {
+template <typename U, typename V, typename T = common_uint<U, V>>
+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 inline uint64_t MinAlign(uint64_t A, uint64_t B) {
   return (A | B) & (1 + ~(A | B));
 }
 
+/// Fallback when arguments aren't integral.
+constexpr inline 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 inline uint64_t NextPowerOf2(uint64_t A) {
@@ -375,7 +397,7 @@ 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
+/// 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:
@@ -386,19 +408,30 @@ inline uint64_t PowerOf2Ceil(uint64_t A) {
 ///   alignTo(321, 255) = 510
 /// \endcode
 ///
-/// May overflow.
-inline uint64_t alignTo(uint64_t Value, uint64_t Align) {
+/// Will overflow only if result is not representable in T.
+template <typename U, typename V, typename T = common_uint<U, V>>
+constexpr T alignTo(U Value, V Align) {
+  assert(Align != 0u && "Align can't be 0.");
+  T Bias = (Value != 0);
+  T CeilDiv = (Value - Bias) / Align + Bias;
+  return CeilDiv * Align;
+}
+
+/// Fallback when arguments aren't integral.
+constexpr inline uint64_t alignTo(uint64_t Value, uint64_t Align) {
   assert(Align != 0u && "Align can't be 0.");
-  return (Value + Align - 1) / Align * Align;
+  uint64_t Bias = (Value != 0);
+  uint64_t CeilDiv = (Value - Bias) / Align + Bias;
+  return CeilDiv * Align;
 }
 
-inline uint64_t alignToPowerOf2(uint64_t Value, uint64_t Align) {
+constexpr 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;
+  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
@@ -413,22 +446,39 @@ inline uint64_t alignToPowerOf2(uint64_t Value, uint64_t Align) {
 ///   alignTo(~0LL, 8, 3) = 3
 ///   alignTo(321, 255, 42) = 552
 /// \endcode
-inline uint64_t alignTo(uint64_t Value, uint64_t Align, uint64_t Skew) {
+///
+/// Will overflow only if result is not representable in T.
+template <typename U, typename V, typename W,
+          typename T = common_uint<common_uint<U, V>, 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 next integer (mod 2**64) that is greater than or equal to
+/// 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.
-template <uint64_t Align> constexpr inline uint64_t alignTo(uint64_t Value) {
+///
+/// Will overflow only if result is not representable in T.
+template <auto Align, typename V, typename T = common_uint<decltype(Align), V>>
+constexpr T alignTo(V Value) {
   static_assert(Align != 0u, "Align must be non-zero");
-  return (Value + Align - 1) / Align * Align;
+  T Bias = (Value != 0);
+  T CeilDiv = (Value - Bias) / Align + Bias;
+  return CeilDiv * Align;
 }
 
 /// Returns the integer ceil(Numerator / Denominator). Unsigned version.
 /// Guaranteed to never overflow.
-inline uint64_t divideCeil(uint64_t Numerator, uint64_t Denominator) {
+template <typename U, typename V, typename T = common_uint<U, V>>
+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 inline uint64_t divideCeil(uint64_t Numerator, uint64_t Denominator) {
   assert(Denominator && "Division by zero");
   uint64_t Bias = (Numerator != 0);
   return (Numerator - Bias) / Denominator + Bias;
@@ -436,12 +486,13 @@ inline uint64_t divideCeil(uint64_t Numerator, uint64_t Denominator) {
 
 /// Returns the integer ceil(Numerator / Denominator). Signed version.
 /// Guaranteed to never overflow.
-inline int64_t divideCeilSigned(int64_t Numerator, int64_t Denominator) {
+template <typename U, typename V, typename T = common_sint<U, V>>
+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;
@@ -449,12 +500,13 @@ inline int64_t divideCeilSigned(int64_t Numerator, int64_t Denominator) {
 
 /// Returns the integer floor(Numerator / Denominator). Signed version.
 /// Guaranteed to never overflow.
-inline int64_t divideFloorSigned(int64_t Numerator, int64_t Denominator) {
+template <typename U, typename V, typename T = common_sint<U, V>>
+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;
@@ -462,23 +514,29 @@ 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 <typename U, typename V, typename T = common_sint<U, V>>
+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 <typename U, typename V, typename T = common_uint<U, V>>
+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<T>(Denominator) - 1) / 2);
 }
 
-/// 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 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 <typename U, typename V, typename W = uint8_t,
+          typename T = common_uint<common_uint<U, V>, 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;
@@ -522,8 +580,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 <typename T>
-std::enable_if_t<std::is_unsigned_v<T>, T> AbsoluteDifference(T X, T Y) {
+template <typename U, typename V, typename T = common_uint<U, V>>
+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..724942fa8e624 100644
--- a/llvm/unittests/Support/MathExtrasTest.cpp
+++ b/llvm/unittests/Support/MathExtrasTest.cpp
@@ -189,8 +189,15 @@ 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<uint64_t>(std::numeric_limits<uint32_t>::max()) + 1,
-            alignTo(std::numeric_limits<uint32_t>::max(), 2));
+  EXPECT_EQ(8u, alignTo(5ULL, 8ULL));
+  EXPECT_EQ(254u,
+            alignTo(static_cast<uint8_t>(200), static_cast<uint8_t>(127)));
+
+  EXPECT_EQ(8u, alignTo<8>(5));
+  EXPECT_EQ(24u, alignTo<8>(17));
+  EXPECT_EQ(0u, alignTo<8>(~0LL));
+  EXPECT_EQ(254u,
+            alignTo<static_cast<uint8_t>(127)>(static_cast<uint8_t>(200)));
 
   EXPECT_EQ(7u, alignTo(5, 8, 7));
   EXPECT_EQ(17u, alignTo(17, 8, 1));
@@ -198,12 +205,21 @@ TEST(MathExtras, AlignTo) {
   EXPECT_EQ(552u, alignTo(321, 255, 42));
   EXPECT_EQ(std::numeric_limits<uint32_t>::max(),
             alignTo(std::numeric_limits<uint32_t>::max(), 2, 1));
+
+  // Overflow.
+  EXPECT_EQ(0u, alignTo(static_cast<uint8_t>(200), static_cast<uint8_t>(128)));
+  EXPECT_EQ(0u, alignTo<static_cast<uint8_t>(128)>(static_cast<uint8_t>(200)));
+  EXPECT_EQ(0u, alignTo(static_cast<uint8_t>(200), static_cast<uint8_t>(128),
+                        static_cast<uint8_t>(0)));
+  EXPECT_EQ(0u, alignTo(std::numeric_limits<uint32_t>::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<uint64_t>(std::numeric_limits<uint32_t>::max()) + 1,
             alignToPowerOf2(std::numeric_limits<uint32_t>::max(), 2));
 }

>From 6189502b54022f16228e26f0bb1b796ca6ad41ed Mon Sep 17 00:00:00 2001
From: Ramkumar Ramachandra <ramkumar.ramachandra at codasip.com>
Date: Mon, 24 Jun 2024 10:41:26 +0100
Subject: [PATCH 2/3] MathExtras: s/constexpr inline/constexpr/

---
 llvm/include/llvm/Support/MathExtras.h | 44 +++++++++++++-------------
 1 file changed, 22 insertions(+), 22 deletions(-)

diff --git a/llvm/include/llvm/Support/MathExtras.h b/llvm/include/llvm/Support/MathExtras.h
index 5611dc00058ea..ba6d697d88e95 100644
--- a/llvm/include/llvm/Support/MathExtras.h
+++ b/llvm/include/llvm/Support/MathExtras.h
@@ -151,22 +151,22 @@ template <typename T> T reverseBits(T Val) {
 // ambiguity.
 
 /// Return the high 32 bits of a 64 bit value.
-constexpr inline uint32_t Hi_32(uint64_t Value) {
+constexpr uint32_t Hi_32(uint64_t Value) {
   return static_cast<uint32_t>(Value >> 32);
 }
 
 /// Return the low 32 bits of a 64 bit value.
-constexpr inline uint32_t Lo_32(uint64_t Value) {
+constexpr uint32_t Lo_32(uint64_t Value) {
   return static_cast<uint32_t>(Value);
 }
 
 /// Make a 64-bit integer from a high / low pair of 32-bit integers.
-constexpr inline uint64_t Make_64(uint32_t High, uint32_t Low) {
+constexpr uint64_t Make_64(uint32_t High, uint32_t Low) {
   return ((uint64_t)High << 32) | (uint64_t)Low;
 }
 
 /// Checks if an integer fits into the given bit width.
-template <unsigned N> constexpr inline bool isInt(int64_t x) {
+template <unsigned N> constexpr bool isInt(int64_t x) {
   if constexpr (N == 0)
     return 0 == x;
   if constexpr (N == 8)
@@ -183,14 +183,14 @@ template <unsigned N> constexpr inline bool isInt(int64_t x) {
 
 /// Checks if a signed integer is an N bit number shifted left by S.
 template <unsigned N, unsigned S>
-constexpr inline bool isShiftedInt(int64_t x) {
+constexpr bool isShiftedInt(int64_t x) {
   static_assert(S < 64, "isShiftedInt<N, S> with S >= 64 is too much.");
   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);
 }
 
 /// Checks if an unsigned integer fits into the given bit width.
-template <unsigned N> constexpr inline bool isUInt(uint64_t x) {
+template <unsigned N> constexpr bool isUInt(uint64_t x) {
   if constexpr (N == 0)
     return 0 == x;
   if constexpr (N == 8)
@@ -207,7 +207,7 @@ template <unsigned N> constexpr inline bool isUInt(uint64_t x) {
 
 /// Checks if a unsigned integer is an N bit number shifted left by S.
 template <unsigned N, unsigned S>
-constexpr inline bool isShiftedUInt(uint64_t x) {
+constexpr bool isShiftedUInt(uint64_t x) {
   static_assert(S < 64, "isShiftedUInt<N, S> with S >= 64 is too much.");
   static_assert(N + S <= 64,
                 "isShiftedUInt<N, S> with N + S > 64 is too wide.");
@@ -264,36 +264,36 @@ inline bool isIntN(unsigned N, int64_t x) {
 /// Return true if the argument is a non-empty sequence of ones starting at the
 /// least significant bit with the remainder zero (32 bit version).
 /// Ex. isMask_32(0x0000FFFFU) == true.
-constexpr inline bool isMask_32(uint32_t Value) {
+constexpr bool isMask_32(uint32_t Value) {
   return Value && ((Value + 1) & Value) == 0;
 }
 
 /// Return true if the argument is a non-empty sequence of ones starting at the
 /// least significant bit with the remainder zero (64 bit version).
-constexpr inline bool isMask_64(uint64_t Value) {
+constexpr bool isMask_64(uint64_t Value) {
   return Value && ((Value + 1) & Value) == 0;
 }
 
 /// Return true if the argument contains a non-empty sequence of ones with the
 /// remainder zero (32 bit version.) Ex. isShiftedMask_32(0x0000FF00U) == true.
-constexpr inline bool isShiftedMask_32(uint32_t Value) {
+constexpr bool isShiftedMask_32(uint32_t Value) {
   return Value && isMask_32((Value - 1) | Value);
 }
 
 /// Return true if the argument contains a non-empty sequence of ones with the
 /// remainder zero (64 bit version.)
-constexpr inline bool isShiftedMask_64(uint64_t Value) {
+constexpr bool isShiftedMask_64(uint64_t Value) {
   return Value && isMask_64((Value - 1) | Value);
 }
 
 /// Return true if the argument is a power of two > 0.
 /// Ex. isPowerOf2_32(0x00100000U) == true (32 bit edition.)
-constexpr inline bool isPowerOf2_32(uint32_t Value) {
+constexpr bool isPowerOf2_32(uint32_t Value) {
   return llvm::has_single_bit(Value);
 }
 
 /// Return true if the argument is a power of two > 0 (64 bit edition.)
-constexpr inline bool isPowerOf2_64(uint64_t Value) {
+constexpr bool isPowerOf2_64(uint64_t Value) {
   return llvm::has_single_bit(Value);
 }
 
@@ -326,13 +326,13 @@ inline bool isShiftedMask_64(uint64_t Value, unsigned &MaskIdx,
 
 /// Compile time Log2.
 /// Valid only for positive powers of two.
-template <size_t kValue> constexpr inline size_t CTLog2() {
+template <size_t kValue> constexpr size_t CTLog2() {
   static_assert(kValue > 0 && llvm::isPowerOf2_64(kValue),
                 "Value is not a valid power of 2");
   return 1 + CTLog2<kValue / 2>();
 }
 
-template <> constexpr inline size_t CTLog2<1>() { return 0; }
+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.)
@@ -373,13 +373,13 @@ constexpr T MinAlign(U A, V B) {
 }
 
 /// Fallback when arguments aren't integral.
-constexpr inline uint64_t MinAlign(uint64_t A, uint64_t B) {
+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 inline uint64_t NextPowerOf2(uint64_t A) {
+constexpr uint64_t NextPowerOf2(uint64_t A) {
   A |= (A >> 1);
   A |= (A >> 2);
   A |= (A >> 4);
@@ -418,14 +418,14 @@ constexpr T alignTo(U Value, V Align) {
 }
 
 /// Fallback when arguments aren't integral.
-constexpr inline uint64_t alignTo(uint64_t Value, uint64_t Align) {
+constexpr uint64_t alignTo(uint64_t Value, uint64_t Align) {
   assert(Align != 0u && "Align can't be 0.");
   uint64_t Bias = (Value != 0);
   uint64_t CeilDiv = (Value - Bias) / Align + Bias;
   return CeilDiv * Align;
 }
 
-constexpr inline uint64_t alignToPowerOf2(uint64_t Value, uint64_t 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:
@@ -478,7 +478,7 @@ constexpr T divideCeil(U Numerator, V Denominator) {
 }
 
 /// Fallback when arguments aren't integral.
-constexpr inline uint64_t divideCeil(uint64_t Numerator, uint64_t Denominator) {
+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;
@@ -544,7 +544,7 @@ constexpr T alignDown(U Value, V Align, W Skew = 0) {
 
 /// Sign-extend the number in the bottom B bits of X to a 32-bit integer.
 /// Requires B <= 32.
-template <unsigned B> constexpr inline int32_t SignExtend32(uint32_t X) {
+template <unsigned B> constexpr int32_t SignExtend32(uint32_t X) {
   static_assert(B <= 32, "Bit width out of range.");
   if constexpr (B == 0)
     return 0;
@@ -562,7 +562,7 @@ inline int32_t SignExtend32(uint32_t X, unsigned B) {
 
 /// Sign-extend the number in the bottom B bits of X to a 64-bit integer.
 /// Requires B <= 64.
-template <unsigned B> constexpr inline int64_t SignExtend64(uint64_t x) {
+template <unsigned B> constexpr int64_t SignExtend64(uint64_t x) {
   static_assert(B <= 64, "Bit width out of range.");
   if constexpr (B == 0)
     return 0;

>From f4522ebeafa379aee2ba686971b6f0bba1478f19 Mon Sep 17 00:00:00 2001
From: Ramkumar Ramachandra <ramkumar.ramachandra at codasip.com>
Date: Mon, 24 Jun 2024 12:53:48 +0100
Subject: [PATCH 3/3] MathExtras: don't re-implement divideCeil

---
 llvm/include/llvm/Support/MathExtras.h | 135 ++++++++++++-------------
 1 file changed, 66 insertions(+), 69 deletions(-)

diff --git a/llvm/include/llvm/Support/MathExtras.h b/llvm/include/llvm/Support/MathExtras.h
index ba6d697d88e95..e445d02f2612e 100644
--- a/llvm/include/llvm/Support/MathExtras.h
+++ b/llvm/include/llvm/Support/MathExtras.h
@@ -397,6 +397,69 @@ inline uint64_t PowerOf2Ceil(uint64_t A) {
   return UINT64_C(1) << Log2_64_Ceil(A);
 }
 
+/// Returns the integer ceil(Numerator / Denominator). Unsigned version.
+/// Guaranteed to never overflow.
+template <typename U, typename V, typename T = common_uint<U, V>>
+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;
+}
+
+/// Returns the integer ceil(Numerator / Denominator). Signed version.
+/// Guaranteed to never overflow.
+template <typename U, typename V, typename T = common_sint<U, V>>
+constexpr T divideCeilSigned(U Numerator, V Denominator) {
+  assert(Denominator && "Division by zero");
+  if (!Numerator)
+    return 0;
+  // C's integer division rounds towards 0.
+  T Bias = Denominator >= 0 ? 1 : -1;
+  bool SameSign = (Numerator >= 0) == (Denominator >= 0);
+  return SameSign ? (Numerator - Bias) / Denominator + 1
+                  : Numerator / Denominator;
+}
+
+/// Returns the integer floor(Numerator / Denominator). Signed version.
+/// Guaranteed to never overflow.
+template <typename U, typename V, typename T = common_sint<U, V>>
+constexpr T divideFloorSigned(U Numerator, V Denominator) {
+  assert(Denominator && "Division by zero");
+  if (!Numerator)
+    return 0;
+  // C's integer division rounds towards 0.
+  T Bias = Denominator >= 0 ? -1 : 1;
+  bool SameSign = (Numerator >= 0) == (Denominator >= 0);
+  return SameSign ? Numerator / Denominator
+                  : (Numerator - Bias) / Denominator - 1;
+}
+
+/// Returns the remainder of the Euclidean division of LHS by RHS. Result is
+/// always non-negative.
+template <typename U, typename V, typename T = common_sint<U, V>>
+constexpr T mod(U Numerator, V Denominator) {
+  assert(Denominator >= 1 && "Mod by non-positive number");
+  T Mod = Numerator % Denominator;
+  return Mod < 0 ? Mod + Denominator : Mod;
+}
+
+/// Returns (Numerator / Denominator) rounded by round-half-up. Guaranteed to
+/// never overflow.
+template <typename U, typename V, typename T = common_uint<U, V>>
+constexpr T divideNearest(U Numerator, V Denominator) {
+  assert(Denominator && "Division by zero");
+  T Mod = Numerator % Denominator;
+  return (Numerator / Denominator) +
+         (Mod > (static_cast<T>(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.
 ///
@@ -412,16 +475,14 @@ inline uint64_t PowerOf2Ceil(uint64_t A) {
 template <typename U, typename V, typename T = common_uint<U, V>>
 constexpr T alignTo(U Value, V Align) {
   assert(Align != 0u && "Align can't be 0.");
-  T Bias = (Value != 0);
-  T CeilDiv = (Value - Bias) / Align + Bias;
+  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 Bias = (Value != 0);
-  uint64_t CeilDiv = (Value - Bias) / Align + Bias;
+  uint64_t CeilDiv = divideCeil(Value, Align);
   return CeilDiv * Align;
 }
 
@@ -463,74 +524,10 @@ constexpr T alignTo(U Value, V Align, W Skew) {
 template <auto Align, typename V, typename T = common_uint<decltype(Align), V>>
 constexpr T alignTo(V Value) {
   static_assert(Align != 0u, "Align must be non-zero");
-  T Bias = (Value != 0);
-  T CeilDiv = (Value - Bias) / Align + Bias;
+  T CeilDiv = divideCeil(Value, Align);
   return CeilDiv * Align;
 }
 
-/// Returns the integer ceil(Numerator / Denominator). Unsigned version.
-/// Guaranteed to never overflow.
-template <typename U, typename V, typename T = common_uint<U, V>>
-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;
-}
-
-/// Returns the integer ceil(Numerator / Denominator). Signed version.
-/// Guaranteed to never overflow.
-template <typename U, typename V, typename T = common_sint<U, V>>
-constexpr T divideCeilSigned(U Numerator, V Denominator) {
-  assert(Denominator && "Division by zero");
-  if (!Numerator)
-    return 0;
-  // C's integer division rounds towards 0.
-  T Bias = Denominator >= 0 ? 1 : -1;
-  bool SameSign = (Numerator >= 0) == (Denominator >= 0);
-  return SameSign ? (Numerator - Bias) / Denominator + 1
-                  : Numerator / Denominator;
-}
-
-/// Returns the integer floor(Numerator / Denominator). Signed version.
-/// Guaranteed to never overflow.
-template <typename U, typename V, typename T = common_sint<U, V>>
-constexpr T divideFloorSigned(U Numerator, V Denominator) {
-  assert(Denominator && "Division by zero");
-  if (!Numerator)
-    return 0;
-  // C's integer division rounds towards 0.
-  T Bias = Denominator >= 0 ? -1 : 1;
-  bool SameSign = (Numerator >= 0) == (Denominator >= 0);
-  return SameSign ? Numerator / Denominator
-                  : (Numerator - Bias) / Denominator - 1;
-}
-
-/// Returns the remainder of the Euclidean division of LHS by RHS. Result is
-/// always non-negative.
-template <typename U, typename V, typename T = common_sint<U, V>>
-constexpr T mod(U Numerator, V Denominator) {
-  assert(Denominator >= 1 && "Mod by non-positive number");
-  T Mod = Numerator % Denominator;
-  return Mod < 0 ? Mod + Denominator : Mod;
-}
-
-/// Returns (Numerator / Denominator) rounded by round-half-up. Guaranteed to
-/// never overflow.
-template <typename U, typename V, typename T = common_uint<U, V>>
-constexpr T divideNearest(U Numerator, V Denominator) {
-  assert(Denominator && "Division by zero");
-  T Mod = Numerator % Denominator;
-  return (Numerator / Denominator) +
-         (Mod > (static_cast<T>(Denominator) - 1) / 2);
-}
-
 /// 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.



More information about the llvm-commits mailing list