[libc] Add subtraction for UInt<N> class.
authorTue Ly <lntue@google.com>
Thu, 4 Aug 2022 20:04:14 +0000 (16:04 -0400)
committerTue Ly <lntue@google.com>
Fri, 5 Aug 2022 00:37:43 +0000 (20:37 -0400)
Add subtraction operators (-, -=) for UInt<N> class.

Reviewed By: michaelrj, orex

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

libc/src/__support/CPP/UInt.h
libc/test/src/__support/uint128_test.cpp

index ebdcb07..f2ce6ed 100644 (file)
@@ -105,6 +105,48 @@ public:
     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;
+    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];
+      }
+    }
+    return carry ? 1 : 0;
+  }
+
+  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.
+    return result;
+  }
+
+  constexpr UInt<Bits> operator-=(const UInt<Bits> &other) {
+    // TODO(lntue): Set overflow flag / errno when carry is true.
+    sub(other);
+    return *this;
+  }
+
   // Multiply this number with x and store the result in this number. It is
   // implemented using the long multiplication algorithm by splitting the
   // 64-bit words of this number and |x| in to 32-bit halves but peforming
index a5205b9..92f5408 100644 (file)
@@ -44,6 +44,35 @@ TEST(LlvmLibcUInt128ClassTest, AdditionTests) {
   EXPECT_EQ(val5 + val6, val6 + val5);
 }
 
+TEST(LlvmLibcUInt128ClassTest, SubtractionTests) {
+  LL_UInt128 val1(12345);
+  LL_UInt128 val2(54321);
+  LL_UInt128 result1({0xffffffffffff5c08, 0xffffffffffffffff});
+  LL_UInt128 result2(0xa3f8);
+  EXPECT_EQ(val1 - val2, result1);
+  EXPECT_EQ(val1, val2 + result1);
+  EXPECT_EQ(val2 - val1, result2);
+  EXPECT_EQ(val2, val1 + result2);
+
+  LL_UInt128 val3({0xf000000000000001, 0});
+  LL_UInt128 val4({0x100000000000000f, 0});
+  LL_UInt128 result3(0xdffffffffffffff2);
+  LL_UInt128 result4({0x200000000000000e, 0xffffffffffffffff});
+  EXPECT_EQ(val3 - val4, result3);
+  EXPECT_EQ(val3, val4 + result3);
+  EXPECT_EQ(val4 - val3, result4);
+  EXPECT_EQ(val4, val3 + result4);
+
+  LL_UInt128 val5({0x0123456789abcdef, 0xfedcba9876543210});
+  LL_UInt128 val6({0x1111222233334444, 0xaaaabbbbccccdddd});
+  LL_UInt128 result5({0xf0122345567889ab, 0x5431fedca9875432});
+  LL_UInt128 result6({0x0feddcbaa9877655, 0xabce01235678abcd});
+  EXPECT_EQ(val5 - val6, result5);
+  EXPECT_EQ(val5, val6 + result5);
+  EXPECT_EQ(val6 - val5, result6);
+  EXPECT_EQ(val6, val5 + result6);
+}
+
 TEST(LlvmLibcUInt128ClassTest, MultiplicationTests) {
   LL_UInt128 val1({5, 0});
   LL_UInt128 val2({10, 0});