зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1599465 - Part 5: Add fast path for BigInt multiplication with uint64 magnitude. r=jwalden
Similar to the previous part, also add a fast-path when multiplying two Bigints which fit into uint64_t. When the result also fits into uint64_t, this approach avoids allocating unused malloc memory. Differential Revision: https://phabricator.services.mozilla.com/D54761 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
0903f6d258
Коммит
ccaf2a12e3
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/Compiler.h"
|
||||
#include "mozilla/MathAlgorithms.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
@ -62,6 +63,31 @@ MOZ_MUST_USE inline bool SafeMul(int32_t one, int32_t two, int32_t* res) {
|
|||
#endif
|
||||
}
|
||||
|
||||
MOZ_MUST_USE inline bool SafeMul(uint64_t one, uint64_t two, uint64_t* res) {
|
||||
#if BUILTIN_CHECKED_ARITHMETIC_SUPPORTED(__builtin_mul_overflow)
|
||||
return !__builtin_mul_overflow(one, two, res);
|
||||
#else
|
||||
// Hacker's Delight, 2nd edition, 2-13 Overflow detection, Fig. 2-2.
|
||||
int zeroes =
|
||||
mozilla::CountLeadingZeroes64(one) + mozilla::CountLeadingZeroes64(two);
|
||||
if (zeroes <= 62) {
|
||||
return false;
|
||||
}
|
||||
uint64_t half = one * (two >> 1);
|
||||
if (int64_t(half) < 0) {
|
||||
return false;
|
||||
}
|
||||
*res = half * 2;
|
||||
if (two & 1) {
|
||||
*res += one;
|
||||
if (*res < one) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
#endif /* util_CheckedArithmetic_h */
|
||||
|
|
|
@ -101,6 +101,7 @@
|
|||
#include "js/Initialization.h"
|
||||
#include "js/StableStringChars.h"
|
||||
#include "js/Utility.h"
|
||||
#include "util/CheckedArithmetic.h"
|
||||
#include "vm/JSContext.h"
|
||||
#include "vm/SelfHosting.h"
|
||||
|
||||
|
@ -212,6 +213,28 @@ BigInt* BigInt::negativeOne(JSContext* cx) {
|
|||
return createFromDigit(cx, 1, true);
|
||||
}
|
||||
|
||||
BigInt* BigInt::createFromNonZeroRawUint64(JSContext* cx, uint64_t n,
|
||||
bool isNegative) {
|
||||
MOZ_ASSERT(n != 0);
|
||||
|
||||
size_t resultLength = 1;
|
||||
if (DigitBits == 32 && (n >> 32) != 0) {
|
||||
resultLength = 2;
|
||||
}
|
||||
|
||||
BigInt* result = createUninitialized(cx, resultLength, isNegative);
|
||||
if (!result) {
|
||||
return nullptr;
|
||||
}
|
||||
result->setDigit(0, n);
|
||||
if (DigitBits == 32 && resultLength > 1) {
|
||||
result->setDigit(1, n >> 32);
|
||||
}
|
||||
|
||||
MOZ_ASSERT(!HasLeadingZeroes(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
BigInt* BigInt::neg(JSContext* cx, HandleBigInt x) {
|
||||
if (x->isZero()) {
|
||||
return x;
|
||||
|
@ -1810,8 +1833,21 @@ BigInt* BigInt::mul(JSContext* cx, HandleBigInt x, HandleBigInt y) {
|
|||
return y;
|
||||
}
|
||||
|
||||
unsigned resultLength = x->digitLength() + y->digitLength();
|
||||
bool resultNegative = x->isNegative() != y->isNegative();
|
||||
|
||||
// Fast path for the likely-common case of up to a uint64_t of magnitude.
|
||||
if (x->absFitsInUint64() && y->absFitsInUint64()) {
|
||||
uint64_t lhs = x->uint64FromAbsNonZero();
|
||||
uint64_t rhs = y->uint64FromAbsNonZero();
|
||||
|
||||
uint64_t res;
|
||||
if (js::SafeMul(lhs, rhs, &res)) {
|
||||
MOZ_ASSERT(res != 0);
|
||||
return createFromNonZeroRawUint64(cx, res, resultNegative);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned resultLength = x->digitLength() + y->digitLength();
|
||||
RootedBigInt result(cx,
|
||||
createUninitialized(cx, resultLength, resultNegative));
|
||||
if (!result) {
|
||||
|
|
|
@ -104,6 +104,8 @@ class BigInt final
|
|||
static BigInt* createFromUint64(JSContext* cx, uint64_t n);
|
||||
static BigInt* createFromInt64(JSContext* cx, int64_t n);
|
||||
static BigInt* createFromDigit(JSContext* cx, Digit d, bool isNegative);
|
||||
static BigInt* createFromNonZeroRawUint64(JSContext* cx, uint64_t n,
|
||||
bool isNegative);
|
||||
// FIXME: Cache these values.
|
||||
static BigInt* zero(JSContext* cx);
|
||||
static BigInt* one(JSContext* cx);
|
||||
|
|
Загрузка…
Ссылка в новой задаче