diff options
-rw-r--r-- | include/llvm/ADT/APInt.h | 3 | ||||
-rw-r--r-- | lib/Support/APInt.cpp | 14 | ||||
-rw-r--r-- | unittests/ADT/APIntTest.cpp | 65 |
3 files changed, 82 insertions, 0 deletions
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 @@ public: /// 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 @@ APInt::tcIncrement(integerPart *dst, unsigned int parts) 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 @@ TEST(APIntTest, Splat) { 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); + } +} } |