[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