Bug 1599465 - Part 4: Add fast path for BigInt addition with uint64 magnitude. r=jwalden

Add a fast path for uint64 BigInts to `BigInt::absoluteAdd`. This fast path
gives a substantial speed-up, because addition for uint64 BigInts no longer
needs allocate malloc memory when the result also fits into uint64_t.

Differential Revision: https://phabricator.services.mozilla.com/D54760

--HG--
extra : moz-landing-system : lando
This commit is contained in:
André Bargull 2019-12-02 17:37:06 +00:00
Родитель 3af8368be7
Коммит 0903f6d258
1 изменённых файлов: 46 добавлений и 2 удалений

Просмотреть файл

@ -128,6 +128,12 @@ static inline unsigned DigitLeadingZeroes(BigInt::Digit x) {
: mozilla::CountLeadingZeroes64(x);
}
#ifdef DEBUG
static bool HasLeadingZeroes(BigInt* bi) {
return bi->digitLength() > 0 && bi->digit(bi->digitLength() - 1) == 0;
}
#endif
BigInt* BigInt::createUninitialized(JSContext* cx, size_t digitLength,
bool isNegative) {
if (digitLength > MaxDigitLength) {
@ -447,8 +453,8 @@ void BigInt::multiplyAccumulate(BigInt* multiplicand, Digit multiplier,
}
inline int8_t BigInt::absoluteCompare(BigInt* x, BigInt* y) {
MOZ_ASSERT(!x->digitLength() || x->digit(x->digitLength() - 1));
MOZ_ASSERT(!y->digitLength() || y->digit(y->digitLength() - 1));
MOZ_ASSERT(!HasLeadingZeroes(x));
MOZ_ASSERT(!HasLeadingZeroes(y));
// Sanity checks to catch negative zeroes escaping to the wild.
MOZ_ASSERT(!x->isNegative() || !x->isZero());
@ -487,6 +493,44 @@ BigInt* BigInt::absoluteAdd(JSContext* cx, HandleBigInt x, HandleBigInt y,
return resultNegative == left->isNegative() ? left : neg(cx, left);
}
// Fast path for the likely-common case of up to a uint64_t of magnitude.
if (left->absFitsInUint64() && right->absFitsInUint64()) {
uint64_t lhs = left->uint64FromAbsNonZero();
uint64_t rhs = right->uint64FromAbsNonZero();
uint64_t res = lhs + rhs;
bool overflow = res < lhs;
MOZ_ASSERT(res != 0 || overflow);
size_t resultLength = 1;
if (DigitBits == 32) {
if (overflow) {
resultLength = 3;
} else if (res >> 32) {
resultLength = 2;
}
} else {
if (overflow) {
resultLength = 2;
}
}
BigInt* result = createUninitialized(cx, resultLength, resultNegative);
if (!result) {
return nullptr;
}
result->setDigit(0, res);
if (DigitBits == 32 && resultLength > 1) {
result->setDigit(1, res >> 32);
}
if (overflow) {
constexpr size_t overflowIndex = DigitBits == 32 ? 2 : 1;
result->setDigit(overflowIndex, 1);
}
MOZ_ASSERT(!HasLeadingZeroes(result));
return result;
}
RootedBigInt result(
cx, createUninitialized(cx, left->digitLength() + 1, resultNegative));
if (!result) {