зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
3af8368be7
Коммит
0903f6d258
|
@ -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) {
|
||||
|
|
Загрузка…
Ссылка в новой задаче