[libc-commits] [libc] 926dd32 - [libc][math] Improve the performance of subtraction for UInt<>.

Tue Ly via libc-commits libc-commits at lists.llvm.org
Wed Nov 30 07:51:30 PST 2022


Author: Tue Ly
Date: 2022-11-30T10:51:02-05:00
New Revision: 926dd32aab1d79dbd85639e5eaf7b4d3cd086af6

URL: https://github.com/llvm/llvm-project/commit/926dd32aab1d79dbd85639e5eaf7b4d3cd086af6
DIFF: https://github.com/llvm/llvm-project/commit/926dd32aab1d79dbd85639e5eaf7b4d3cd086af6.diff

LOG: [libc][math] Improve the performance of subtraction for UInt<>.

Use built-in sub_with_borrow to improve the performance of subtraction
for UInt<>.

Microbenchmark: https://quick-bench.com/q/UEg6Z6VK4PP2yLBtTi9C0cL9xpY

Reviewed By: sivachandra

Differential Revision: https://reviews.llvm.org/D138506

Added: 
    

Modified: 
    libc/src/__support/UInt.h

Removed: 
    


################################################################################
diff  --git a/libc/src/__support/UInt.h b/libc/src/__support/UInt.h
index 78dd8fadda0f8..cec08b3530bb6 100644
--- a/libc/src/__support/UInt.h
+++ b/libc/src/__support/UInt.h
@@ -97,9 +97,6 @@ template <size_t Bits> struct UInt {
 
   // Add x to this number and store the result in this number.
   // Returns the carry value produced by the addition operation.
-  // To prevent overflow from intermediate results, we use the following
-  // property of unsigned integers:
-  //   x + (~x) = 2^(sizeof(x)) - 1.
   constexpr uint64_t add(const UInt<Bits> &x) {
     SumCarry<uint64_t> s{0, 0};
     for (size_t i = 0; i < WordCount; ++i) {
@@ -119,48 +116,33 @@ template <size_t Bits> struct UInt {
     return result;
   }
 
-  constexpr UInt<Bits> operator+=(const UInt<Bits> &other) {
+  constexpr UInt<Bits> &operator+=(const UInt<Bits> &other) {
     add(other); // Returned carry value is ignored.
     return *this;
   }
 
   // Subtract x to this number and store the result in this number.
   // Returns the carry value produced by the subtraction operation.
-  // To prevent overflow from intermediate results, we use the following
-  // property of unsigned integers:
-  //   x + (~x) = 2^(sizeof(x)) - 1,
-  // So:
-  //   -x = ((~x) + 1) + (-2^(sizeof(x))),
-  // where 2^(sizeof(x)) is represented by the carry bit.
   constexpr uint64_t sub(const UInt<Bits> &x) {
-    bool carry = false;
+    DiffBorrow<uint64_t> d{0, 0};
     for (size_t i = 0; i < WordCount; ++i) {
-      if (!carry) {
-        if (val[i] >= x.val[i])
-          val[i] -= x.val[i];
-        else {
-          val[i] += (~x.val[i]) + 1;
-          carry = true;
-        }
-      } else {
-        if (val[i] > x.val[i]) {
-          val[i] -= x.val[i] + 1;
-          carry = false;
-        } else
-          val[i] += ~x.val[i];
-      }
+      d = sub_with_borrow(val[i], x.val[i], d.borrow);
+      val[i] = d.
diff ;
     }
-    return carry ? 1 : 0;
+    return d.borrow;
   }
 
   constexpr UInt<Bits> operator-(const UInt<Bits> &other) const {
-    UInt<Bits> result(*this);
-    result.sub(other);
-    // TODO(lntue): Set overflow flag / errno when carry is true.
+    UInt<Bits> result;
+    DiffBorrow<uint64_t> d{0, 0};
+    for (size_t i = 0; i < WordCount; ++i) {
+      d = sub_with_borrow(val[i], other.val[i], d.borrow);
+      result.val[i] = d.
diff ;
+    }
     return result;
   }
 
-  constexpr UInt<Bits> operator-=(const UInt<Bits> &other) {
+  constexpr UInt<Bits> &operator-=(const UInt<Bits> &other) {
     // TODO(lntue): Set overflow flag / errno when carry is true.
     sub(other);
     return *this;


        


More information about the libc-commits mailing list