[llvm] [MathExtras] Optimize SaturatingAdd. Split it into two specialized parst and use reference instead pointer for owerflow flag (PR #190479)

Max Graey via llvm-commits llvm-commits at lists.llvm.org
Sat Apr 4 13:47:47 PDT 2026


https://github.com/MaxGraey updated https://github.com/llvm/llvm-project/pull/190479

>From 02d6b72373f51686a653d526d7dc31899aabb23c Mon Sep 17 00:00:00 2001
From: MaxGraey <maxgraey at gmail.com>
Date: Sat, 4 Apr 2026 21:40:23 +0300
Subject: [PATCH 1/3] Optimize SaturatingAdd

---
 llvm/include/llvm/Support/MathExtras.h    | 36 +++++++++++++----------
 llvm/lib/IR/DIExpressionOptimizer.cpp     |  2 +-
 llvm/unittests/Support/MathExtrasTest.cpp | 28 +++++++++---------
 3 files changed, 35 insertions(+), 31 deletions(-)

diff --git a/llvm/include/llvm/Support/MathExtras.h b/llvm/include/llvm/Support/MathExtras.h
index de2813094a950..bec1f4565700b 100644
--- a/llvm/include/llvm/Support/MathExtras.h
+++ b/llvm/include/llvm/Support/MathExtras.h
@@ -601,30 +601,34 @@ constexpr T AbsoluteDifference(U X, V Y) {
   return X > Y ? (X - Y) : (Y - X);
 }
 
-/// 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
+/// Add two unsigned integers, X and Y, of type T. Clamp the result to the
+/// maximum representable value of T on overflow.
+template <typename T>
+std::enable_if_t<std::is_unsigned_v<T>, T> SaturatingAdd(T X, T Y) {
+  T Z = X + Y;
+  // Z < X and Z < Y are equivalent overflow checks, so one suffices
+  return Z | -(Z < X);
+}
+
+/// Add two unsigned integers, X and Y, of type T. Clamp the result to the
+/// maximum representable value of T on overflow. Overflowed 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>
-SaturatingAdd(T X, T Y, bool *ResultOverflowed = nullptr) {
-  bool Dummy;
-  bool &Overflowed = ResultOverflowed ? *ResultOverflowed : Dummy;
-  // Hacker's Delight, p. 29
+std::enable_if_t<std::is_unsigned_v<T>, T> SaturatingAdd(T X, T Y,
+                                                         bool &Overflowed) {
   T Z = X + Y;
-  Overflowed = (Z < X || Z < Y);
-  if (Overflowed)
-    return std::numeric_limits<T>::max();
-  else
-    return Z;
+  // Z < X and Z < Y are equivalent overflow checks, so one suffices
+  Overflowed = (Z < X);
+  return Z | -Overflowed;
 }
 
-/// Add multiple unsigned integers of type T.  Clamp the result to the
+/// 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) {
   bool Overflowed = false;
-  T XY = SaturatingAdd(X, Y, &Overflowed);
+  T XY = SaturatingAdd(X, Y, Overflowed);
   if (Overflowed)
     return SaturatingAdd(std::numeric_limits<T>::max(), T(1), Args...);
   return SaturatingAdd(XY, Z, Args...);
@@ -670,7 +674,7 @@ SaturatingMultiply(T X, T Y, bool *ResultOverflowed = nullptr) {
   }
   Z <<= 1;
   if (X & 1)
-    return SaturatingAdd(Z, Y, ResultOverflowed);
+    return SaturatingAdd(Z, Y, Overflowed);
 
   return Z;
 }
@@ -689,7 +693,7 @@ SaturatingMultiplyAdd(T X, T Y, T A, bool *ResultOverflowed = nullptr) {
   if (Overflowed)
     return Product;
 
-  return SaturatingAdd(A, Product, &Overflowed);
+  return SaturatingAdd(A, Product, Overflowed);
 }
 
 /// Use this rather than HUGE_VALF; the latter causes warnings on MSVC.
diff --git a/llvm/lib/IR/DIExpressionOptimizer.cpp b/llvm/lib/IR/DIExpressionOptimizer.cpp
index be9e13a34235a..069991f60c08e 100644
--- a/llvm/lib/IR/DIExpressionOptimizer.cpp
+++ b/llvm/lib/IR/DIExpressionOptimizer.cpp
@@ -48,7 +48,7 @@ foldOperationIfPossible(uint64_t Const1, uint64_t Const2,
   bool ResultOverflowed;
   switch (Operator) {
   case dwarf::DW_OP_plus: {
-    auto Result = SaturatingAdd(Const1, Const2, &ResultOverflowed);
+    auto Result = SaturatingAdd(Const1, Const2, ResultOverflowed);
     if (ResultOverflowed)
       return std::nullopt;
     return Result;
diff --git a/llvm/unittests/Support/MathExtrasTest.cpp b/llvm/unittests/Support/MathExtrasTest.cpp
index 27e8b26e8801d..add7a7e778666 100644
--- a/llvm/unittests/Support/MathExtrasTest.cpp
+++ b/llvm/unittests/Support/MathExtrasTest.cpp
@@ -237,59 +237,59 @@ template <typename T> void SaturatingAddTestHelper() {
   bool ResultOverflowed;
 
   EXPECT_EQ(T(3), SaturatingAdd(T(1), T(2)));
-  EXPECT_EQ(T(3), SaturatingAdd(T(1), T(2), &ResultOverflowed));
+  EXPECT_EQ(T(3), SaturatingAdd(T(1), T(2), ResultOverflowed));
   EXPECT_FALSE(ResultOverflowed);
 
   EXPECT_EQ(Max, SaturatingAdd(Max, T(1)));
-  EXPECT_EQ(Max, SaturatingAdd(Max, T(1), &ResultOverflowed));
+  EXPECT_EQ(Max, SaturatingAdd(Max, T(1), ResultOverflowed));
   EXPECT_TRUE(ResultOverflowed);
 
   EXPECT_EQ(Max, SaturatingAdd(T(1), T(Max - 1)));
-  EXPECT_EQ(Max, SaturatingAdd(T(1), T(Max - 1), &ResultOverflowed));
+  EXPECT_EQ(Max, SaturatingAdd(T(1), T(Max - 1), ResultOverflowed));
   EXPECT_FALSE(ResultOverflowed);
 
   EXPECT_EQ(Max, SaturatingAdd(T(1), Max));
-  EXPECT_EQ(Max, SaturatingAdd(T(1), Max, &ResultOverflowed));
+  EXPECT_EQ(Max, SaturatingAdd(T(1), Max, ResultOverflowed));
   EXPECT_TRUE(ResultOverflowed);
 
   EXPECT_EQ(Max, SaturatingAdd(Max, Max));
-  EXPECT_EQ(Max, SaturatingAdd(Max, Max, &ResultOverflowed));
+  EXPECT_EQ(Max, SaturatingAdd(Max, Max, ResultOverflowed));
   EXPECT_TRUE(ResultOverflowed);
 
   EXPECT_EQ(T(6), SaturatingAdd(T(1), T(2), T(3)));
-  EXPECT_EQ(T(6), SaturatingAdd(T(1), T(2), T(3), &ResultOverflowed));
+  EXPECT_EQ(T(6), SaturatingAdd(T(1), T(2), T(3), ResultOverflowed));
   EXPECT_FALSE(ResultOverflowed);
 
   EXPECT_EQ(T(10), SaturatingAdd(T(1), T(2), T(3), T(4)));
-  EXPECT_EQ(T(10), SaturatingAdd(T(1), T(2), T(3), T(4), &ResultOverflowed));
+  EXPECT_EQ(T(10), SaturatingAdd(T(1), T(2), T(3), T(4), ResultOverflowed));
   EXPECT_FALSE(ResultOverflowed);
 
   EXPECT_EQ(Max, SaturatingAdd(Max, T(0), T(0)));
-  EXPECT_EQ(Max, SaturatingAdd(Max, T(0), T(0), &ResultOverflowed));
+  EXPECT_EQ(Max, SaturatingAdd(Max, T(0), T(0), ResultOverflowed));
   EXPECT_FALSE(ResultOverflowed);
 
   EXPECT_EQ(Max, SaturatingAdd(T(0), T(0), Max));
-  EXPECT_EQ(Max, SaturatingAdd(T(0), T(0), Max, &ResultOverflowed));
+  EXPECT_EQ(Max, SaturatingAdd(T(0), T(0), Max, ResultOverflowed));
   EXPECT_FALSE(ResultOverflowed);
 
   EXPECT_EQ(Max, SaturatingAdd(Max, T(0), T(1)));
-  EXPECT_EQ(Max, SaturatingAdd(Max, T(0), T(1), &ResultOverflowed));
+  EXPECT_EQ(Max, SaturatingAdd(Max, T(0), T(1), ResultOverflowed));
   EXPECT_TRUE(ResultOverflowed);
 
   EXPECT_EQ(Max, SaturatingAdd(T(0), T(1), Max));
-  EXPECT_EQ(Max, SaturatingAdd(T(0), T(1), Max, &ResultOverflowed));
+  EXPECT_EQ(Max, SaturatingAdd(T(0), T(1), Max, ResultOverflowed));
   EXPECT_TRUE(ResultOverflowed);
 
   EXPECT_EQ(Max, SaturatingAdd(T(1), T(Max - 2), T(1)));
-  EXPECT_EQ(Max, SaturatingAdd(T(1), T(Max - 2), T(1), &ResultOverflowed));
+  EXPECT_EQ(Max, SaturatingAdd(T(1), T(Max - 2), T(1), ResultOverflowed));
   EXPECT_FALSE(ResultOverflowed);
 
   EXPECT_EQ(Max, SaturatingAdd(T(1), T(1), T(Max - 2)));
-  EXPECT_EQ(Max, SaturatingAdd(T(1), T(1), T(Max - 2), &ResultOverflowed));
+  EXPECT_EQ(Max, SaturatingAdd(T(1), T(1), T(Max - 2), ResultOverflowed));
   EXPECT_FALSE(ResultOverflowed);
 
   EXPECT_EQ(Max, SaturatingAdd(Max, Max, Max));
-  EXPECT_EQ(Max, SaturatingAdd(Max, Max, Max, &ResultOverflowed));
+  EXPECT_EQ(Max, SaturatingAdd(Max, Max, Max, ResultOverflowed));
   EXPECT_TRUE(ResultOverflowed);
 }
 

>From fbe610c7efb83a3c17c95de15cc68f5d86055517 Mon Sep 17 00:00:00 2001
From: MaxGraey <maxgraey at gmail.com>
Date: Sat, 4 Apr 2026 23:44:41 +0300
Subject: [PATCH 2/3] fix

---
 llvm/include/llvm/Support/MathExtras.h | 13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/llvm/include/llvm/Support/MathExtras.h b/llvm/include/llvm/Support/MathExtras.h
index bec1f4565700b..6beaafeb53f89 100644
--- a/llvm/include/llvm/Support/MathExtras.h
+++ b/llvm/include/llvm/Support/MathExtras.h
@@ -622,13 +622,24 @@ std::enable_if_t<std::is_unsigned_v<T>, T> SaturatingAdd(T X, T Y,
   return Z | -Overflowed;
 }
 
+/// Add two unsigned integers, X and Y, of type T. Clamp the result to the
+/// maximum representable value of T on overflow. Overflowed 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> SaturatingAdd(T X, T Y,
+                                                         bool *Overflowed) {
+  bool Dummy;
+  bool &OverflowedRef = Overflowed ? *Overflowed : Dummy;
+  return SaturatingAdd(X, Y, OverflowedRef);
+}
+
 /// 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) {
   bool Overflowed = false;
-  T XY = SaturatingAdd(X, Y, Overflowed);
+  T XY = SaturatingAdd(X, Y, &Overflowed);
   if (Overflowed)
     return SaturatingAdd(std::numeric_limits<T>::max(), T(1), Args...);
   return SaturatingAdd(XY, Z, Args...);

>From cf79f0809c6fbdd4b2f098e5e2c55df63840a25f Mon Sep 17 00:00:00 2001
From: MaxGraey <maxgraey at gmail.com>
Date: Sat, 4 Apr 2026 23:47:34 +0300
Subject: [PATCH 3/3] fix tests

---
 llvm/unittests/Support/MathExtrasTest.cpp | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/llvm/unittests/Support/MathExtrasTest.cpp b/llvm/unittests/Support/MathExtrasTest.cpp
index add7a7e778666..84b00c771785d 100644
--- a/llvm/unittests/Support/MathExtrasTest.cpp
+++ b/llvm/unittests/Support/MathExtrasTest.cpp
@@ -257,39 +257,39 @@ template <typename T> void SaturatingAddTestHelper() {
   EXPECT_TRUE(ResultOverflowed);
 
   EXPECT_EQ(T(6), SaturatingAdd(T(1), T(2), T(3)));
-  EXPECT_EQ(T(6), SaturatingAdd(T(1), T(2), T(3), ResultOverflowed));
+  EXPECT_EQ(T(6), SaturatingAdd(T(1), T(2), T(3), &ResultOverflowed));
   EXPECT_FALSE(ResultOverflowed);
 
   EXPECT_EQ(T(10), SaturatingAdd(T(1), T(2), T(3), T(4)));
-  EXPECT_EQ(T(10), SaturatingAdd(T(1), T(2), T(3), T(4), ResultOverflowed));
+  EXPECT_EQ(T(10), SaturatingAdd(T(1), T(2), T(3), T(4), &ResultOverflowed));
   EXPECT_FALSE(ResultOverflowed);
 
   EXPECT_EQ(Max, SaturatingAdd(Max, T(0), T(0)));
-  EXPECT_EQ(Max, SaturatingAdd(Max, T(0), T(0), ResultOverflowed));
+  EXPECT_EQ(Max, SaturatingAdd(Max, T(0), T(0), &ResultOverflowed));
   EXPECT_FALSE(ResultOverflowed);
 
   EXPECT_EQ(Max, SaturatingAdd(T(0), T(0), Max));
-  EXPECT_EQ(Max, SaturatingAdd(T(0), T(0), Max, ResultOverflowed));
+  EXPECT_EQ(Max, SaturatingAdd(T(0), T(0), Max, &ResultOverflowed));
   EXPECT_FALSE(ResultOverflowed);
 
   EXPECT_EQ(Max, SaturatingAdd(Max, T(0), T(1)));
-  EXPECT_EQ(Max, SaturatingAdd(Max, T(0), T(1), ResultOverflowed));
+  EXPECT_EQ(Max, SaturatingAdd(Max, T(0), T(1), &ResultOverflowed));
   EXPECT_TRUE(ResultOverflowed);
 
   EXPECT_EQ(Max, SaturatingAdd(T(0), T(1), Max));
-  EXPECT_EQ(Max, SaturatingAdd(T(0), T(1), Max, ResultOverflowed));
+  EXPECT_EQ(Max, SaturatingAdd(T(0), T(1), Max, &ResultOverflowed));
   EXPECT_TRUE(ResultOverflowed);
 
   EXPECT_EQ(Max, SaturatingAdd(T(1), T(Max - 2), T(1)));
-  EXPECT_EQ(Max, SaturatingAdd(T(1), T(Max - 2), T(1), ResultOverflowed));
+  EXPECT_EQ(Max, SaturatingAdd(T(1), T(Max - 2), T(1), &ResultOverflowed));
   EXPECT_FALSE(ResultOverflowed);
 
   EXPECT_EQ(Max, SaturatingAdd(T(1), T(1), T(Max - 2)));
-  EXPECT_EQ(Max, SaturatingAdd(T(1), T(1), T(Max - 2), ResultOverflowed));
+  EXPECT_EQ(Max, SaturatingAdd(T(1), T(1), T(Max - 2), &ResultOverflowed));
   EXPECT_FALSE(ResultOverflowed);
 
   EXPECT_EQ(Max, SaturatingAdd(Max, Max, Max));
-  EXPECT_EQ(Max, SaturatingAdd(Max, Max, Max, ResultOverflowed));
+  EXPECT_EQ(Max, SaturatingAdd(Max, Max, Max, &ResultOverflowed));
   EXPECT_TRUE(ResultOverflowed);
 }
 



More information about the llvm-commits mailing list