[APInt] Implement tcDecrement as a counterpart to tcIncrement. This is for use in APFloat IEEE-754R 2008 nextUp/nextDown function.

rdar://13852078

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@182801 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/llvm/ADT/APInt.h b/include/llvm/ADT/APInt.h
index fc1aedb..a9df403 100644
--- a/include/llvm/ADT/APInt.h
+++ b/include/llvm/ADT/APInt.h
@@ -1642,6 +1642,9 @@
   /// Increment a bignum in-place.  Return the carry flag.
   static integerPart tcIncrement(integerPart *, unsigned int);
 
+  /// Decrement a bignum in-place.  Return the borrow flag.
+  static integerPart tcDecrement(integerPart *, unsigned int);
+
   /// Set the least significant BITS and clear the rest.
   static void tcSetLeastSignificantBits(integerPart *, unsigned int,
                                         unsigned int bits);
diff --git a/lib/Support/APInt.cpp b/lib/Support/APInt.cpp
index 71c5095..108675d 100644
--- a/lib/Support/APInt.cpp
+++ b/lib/Support/APInt.cpp
@@ -2888,6 +2888,20 @@
   return i == parts;
 }
 
+/* Decrement a bignum in-place, return the borrow flag.  */
+integerPart
+APInt::tcDecrement(integerPart *dst, unsigned int parts) {
+  for (unsigned int i = 0; i < parts; i++) {
+    // If the current word is non-zero, then the decrement has no effect on the
+    // higher-order words of the integer and no borrow can occur. Exit early.
+    if (dst[i]--)
+      return 0;
+  }
+  // If every word was zero, then there is a borrow.
+  return 1;
+}
+
+
 /* Set the least significant BITS bits of a bignum, clear the
    rest.  */
 void
diff --git a/unittests/ADT/APIntTest.cpp b/unittests/ADT/APIntTest.cpp
index f129fa7..3c0dfe1 100644
--- a/unittests/ADT/APIntTest.cpp
+++ b/unittests/ADT/APIntTest.cpp
@@ -532,4 +532,69 @@
   EXPECT_EQ(APInt(15, 0xDB6D), APInt::getSplat(15, ValB));
 }
 
+TEST(APIntTest, tcDecrement) {
+  // Test single word decrement.
+
+  // No out borrow.
+  {
+    integerPart singleWord = ~integerPart(0) << (integerPartWidth - 1);
+    integerPart carry = APInt::tcDecrement(&singleWord, 1);
+    EXPECT_EQ(carry, integerPart(0));
+    EXPECT_EQ(singleWord, ~integerPart(0) >> 1);
+  }
+
+  // With out borrow.
+  {
+    integerPart singleWord = 0;
+    integerPart carry = APInt::tcDecrement(&singleWord, 1);
+    EXPECT_EQ(carry, integerPart(1));
+    EXPECT_EQ(singleWord, ~integerPart(0));
+  }
+
+  // Test multiword decrement.
+
+  // No across word borrow, no out borrow.
+  {
+    integerPart test[4] = {0x1, 0x1, 0x1, 0x1};
+    integerPart expected[4] = {0x0, 0x1, 0x1, 0x1};
+    APInt::tcDecrement(test, 4);
+    EXPECT_EQ(APInt::tcCompare(test, expected, 4), 0);
+  }
+
+  // 1 across word borrow, no out borrow.
+  {
+    integerPart test[4] = {0x0, 0xF, 0x1, 0x1};
+    integerPart expected[4] = {~integerPart(0), 0xE, 0x1, 0x1};
+    integerPart carry = APInt::tcDecrement(test, 4);
+    EXPECT_EQ(carry, integerPart(0));
+    EXPECT_EQ(APInt::tcCompare(test, expected, 4), 0);
+  }
+
+  // 2 across word borrow, no out borrow.
+  {
+    integerPart test[4] = {0x0, 0x0, 0xC, 0x1};
+    integerPart expected[4] = {~integerPart(0), ~integerPart(0), 0xB, 0x1};
+    integerPart carry = APInt::tcDecrement(test, 4);
+    EXPECT_EQ(carry, integerPart(0));
+    EXPECT_EQ(APInt::tcCompare(test, expected, 4), 0);
+  }
+
+  // 3 across word borrow, no out borrow.
+  {
+    integerPart test[4] = {0x0, 0x0, 0x0, 0x1};
+    integerPart expected[4] = {~integerPart(0), ~integerPart(0), ~integerPart(0), 0x0};
+    integerPart carry = APInt::tcDecrement(test, 4);
+    EXPECT_EQ(carry, integerPart(0));
+    EXPECT_EQ(APInt::tcCompare(test, expected, 4), 0);
+  }
+
+  // 3 across word borrow, with out borrow.
+  {
+    integerPart test[4] = {0x0, 0x0, 0x0, 0x0};
+    integerPart expected[4] = {~integerPart(0), ~integerPart(0), ~integerPart(0), ~integerPart(0)};
+    integerPart carry = APInt::tcDecrement(test, 4);
+    EXPECT_EQ(carry, integerPart(1));
+    EXPECT_EQ(APInt::tcCompare(test, expected, 4), 0);
+  }
+}
 }