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

via llvm-commits llvm-commits at lists.llvm.org
Sat Apr 4 11:53:08 PDT 2026


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-ir

Author: Max Graey (MaxGraey)

<details>
<summary>Changes</summary>

Motivations:

- This improves the API and makes the code less verbose
- This significantly improves the quality of the generated code both on GCC and Clang for SaturatingAdd

**New**
--
Clang (trunk):
```asm
  add     rdi, rsi
  setb    byte ptr [rdx]
  mov     rax, -1
  cmovae  rax, rdi
  ret
```
GCC (11.4)
```asm
  add     rdi, rsi
  setc    al
  mov     BYTE PTR [rdx], al
  sal     rax, 63
  sar     rax, 63
  or      rax, rdi
  ret
```

**Old**
--
Clang (trunk):
```asm
  add     rsi, rdi
  test    rdx, rdx
  je      .LBB0_2
  cmp     rsi, rdi
  setb    byte ptr [rdx]
.LBB0_2:
  cmp     rsi, rdi
  mov     rax, -1
  cmovae  rax, rsi
  ret
```
GCC (11.4)
```asm
  lea     rax, [rsp-1]
  test    rdx, rdx
  cmove   rdx, rax
  cmp     rdi, rsi
  lea     rax, [rdi+rsi]
  cmovb   rdi, rsi
  cmp     rax, rdi
  setb    BYTE PTR [rdx]
  mov     rdx, -1
  cmovb   rax, rdx
  ret
```

See: https://godbolt.org/z/xY45ss678

---
Full diff: https://github.com/llvm/llvm-project/pull/190479.diff


3 Files Affected:

- (modified) llvm/include/llvm/Support/MathExtras.h (+20-16) 
- (modified) llvm/lib/IR/DIExpressionOptimizer.cpp (+1-1) 
- (modified) llvm/unittests/Support/MathExtrasTest.cpp (+14-14) 


``````````diff
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);
 }
 

``````````

</details>


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


More information about the llvm-commits mailing list