Bug 891177 - Move leading/trailing-zero-bit counting functions, ceiling/floor log2 functions, and round-up-pow2 functions into MathAlgorithms.h. r=terrence

--HG--
extra : rebase_source : 8cfbd68b8cd4a0e21185dd864c7e827ccfa6b751
This commit is contained in:
Jeff Walden 2013-07-03 15:46:51 -07:00
parent 365a106ab3
commit 9248a5e743
30 changed files with 542 additions and 246 deletions

View File

@ -7,14 +7,20 @@
/*
* PR hash table package.
*/
#include "jshash.h"
#include "mozilla/MathAlgorithms.h"
#include <stdlib.h>
#include <string.h>
#include "jstypes.h"
#include "jsutil.h"
#include "jshash.h"
using namespace js;
using mozilla::CeilingLog2Size;
/* Compute the number of buckets in ht */
#define NBUCKETS(ht) JS_BIT(JS_HASH_BITS - (ht)->shift)
@ -72,7 +78,7 @@ JS_NewHashTable(uint32_t n, JSHashFunction keyHash,
if (n <= MINBUCKETS) {
n = MINBUCKETSLOG2;
} else {
n = JS_CEILING_LOG2W(n);
n = CeilingLog2Size(n);
if (int32_t(n) < 0)
return NULL;
}
@ -352,7 +358,7 @@ out:
JS_ASSERT(ht->nentries < nlimit);
nbuckets = NBUCKETS(ht);
if (MINBUCKETS < nbuckets && ht->nentries < UNDERLOADED(nbuckets)) {
newlog2 = JS_CEILING_LOG2W(ht->nentries);
newlog2 = CeilingLog2Size(ht->nentries);
if (newlog2 < MINBUCKETSLOG2)
newlog2 = MINBUCKETSLOG2;

View File

@ -170,173 +170,6 @@ static JS_INLINE void js_free(void* p)
}
#endif/* JS_USE_CUSTOM_ALLOCATOR */
extern "C" {
/*
* Replace bit-scanning code sequences with CPU-specific instructions to
* speedup calculations of ceiling/floor log2.
*
* With GCC 3.4 or later we can use __builtin_clz for that, see bug 327129.
*
* SWS: Added MSVC intrinsic bitscan support. See bugs 349364 and 356856.
*/
#if defined(_WIN32) && (_MSC_VER >= 1300) && (defined(_M_IX86) || defined(_M_AMD64) || defined(_M_X64))
unsigned char _BitScanForward(unsigned long * Index, unsigned long Mask);
unsigned char _BitScanReverse(unsigned long * Index, unsigned long Mask);
# pragma intrinsic(_BitScanForward,_BitScanReverse)
__forceinline static int
__BitScanForward32(unsigned int val)
{
unsigned long idx;
_BitScanForward(&idx, (unsigned long)val);
return (int)idx;
}
__forceinline static int
__BitScanReverse32(unsigned int val)
{
unsigned long idx;
_BitScanReverse(&idx, (unsigned long)val);
return (int)(31-idx);
}
# define js_bitscan_ctz32(val) __BitScanForward32(val)
# define js_bitscan_clz32(val) __BitScanReverse32(val)
#if defined(_M_AMD64) || defined(_M_X64)
unsigned char _BitScanForward64(unsigned long * Index, unsigned __int64 Mask);
unsigned char _BitScanReverse64(unsigned long * Index, unsigned __int64 Mask);
# pragma intrinsic(_BitScanForward64,_BitScanReverse64)
#endif
__forceinline static int
__BitScanForward64(unsigned __int64 val)
{
#if defined(_M_AMD64) || defined(_M_X64)
unsigned long idx;
_BitScanForward64(&idx, val);
return (int)idx;
#else
uint32_t lo = (uint32_t)val;
uint32_t hi = (uint32_t)(val >> 32);
return lo != 0 ?
js_bitscan_ctz32(lo) :
32 + js_bitscan_ctz32(hi);
#endif
}
__forceinline static int
__BitScanReverse64(unsigned __int64 val)
{
#if defined(_M_AMD64) || defined(_M_X64)
unsigned long idx;
_BitScanReverse64(&idx, val);
return (int)(63-idx);
#else
uint32_t lo = (uint32_t)val;
uint32_t hi = (uint32_t)(val >> 32);
return hi != 0 ?
js_bitscan_clz32(hi) :
32 + js_bitscan_clz32(lo);
#endif
}
# define js_bitscan_ctz64(val) __BitScanForward64(val)
# define js_bitscan_clz64(val) __BitScanReverse64(val)
#elif MOZ_IS_GCC
#if MOZ_GCC_VERSION_AT_LEAST(3, 4, 0)
# define USE_BUILTIN_CTZ
#endif
#elif defined(__clang__)
#if __has_builtin(__builtin_ctz)
# define USE_BUILTIN_CTZ
#endif
#endif
#if defined(USE_BUILTIN_CTZ)
JS_STATIC_ASSERT(sizeof(unsigned int) == sizeof(uint32_t));
# define js_bitscan_ctz32(val) __builtin_ctz(val)
# define js_bitscan_clz32(val) __builtin_clz(val)
JS_STATIC_ASSERT(sizeof(unsigned long long) == sizeof(uint64_t));
# define js_bitscan_ctz64(val) __builtin_ctzll(val)
# define js_bitscan_clz64(val) __builtin_clzll(val)
# undef USE_BUILTIN_CTZ
#endif
/*
** Macro version of JS_CeilingLog2: Compute the log of the least power of
** 2 greater than or equal to _n. The result is returned in _log2.
*/
/*
* Use intrinsic function or count-leading-zeros to calculate ceil(log2(_n)).
* The macro checks for "n <= 1" and not "n != 0" as js_bitscan_clz32(0) is
* undefined.
*/
# define JS_CEILING_LOG2(_log2,_n) \
JS_BEGIN_MACRO \
unsigned int j_ = (unsigned int)(_n); \
(_log2) = (j_ <= 1 ? 0 : 32 - js_bitscan_clz32(j_ - 1)); \
JS_END_MACRO
/*
** Macro version of JS_FloorLog2: Compute the log of the greatest power of
** 2 less than or equal to _n. The result is returned in _log2.
**
** This is equivalent to finding the highest set bit in the word.
*/
/*
* Use js_bitscan_clz32 or count-leading-zeros to calculate floor(log2(_n)).
* Since js_bitscan_clz32(0) is undefined, the macro set the loweset bit to 1
* to ensure 0 result when _n == 0.
*/
# define JS_FLOOR_LOG2(_log2,_n) \
JS_BEGIN_MACRO \
(_log2) = 31 - js_bitscan_clz32(((unsigned int)(_n)) | 1); \
JS_END_MACRO
#if JS_BYTES_PER_WORD == 4
# define js_FloorLog2wImpl(n) \
((size_t)(JS_BITS_PER_WORD - 1 - js_bitscan_clz32(n)))
#elif JS_BYTES_PER_WORD == 8
# define js_FloorLog2wImpl(n) \
((size_t)(JS_BITS_PER_WORD - 1 - js_bitscan_clz64(n)))
#else
# error "NOT SUPPORTED"
#endif
} // extern "C"
/*
* Internal function.
* Compute the log of the least power of 2 greater than or equal to n. This is
* a version of JS_CeilingLog2 that operates on unsigned integers with
* CPU-dependant size.
*/
#define JS_CEILING_LOG2W(n) ((n) <= 1 ? 0 : 1 + JS_FLOOR_LOG2W((n) - 1))
/*
* Internal function.
* Compute the log of the greatest power of 2 less than or equal to n.
* This is a version of JS_FloorLog2 that operates on unsigned integers with
* CPU-dependant size and requires that n != 0.
*/
static MOZ_ALWAYS_INLINE size_t
JS_FLOOR_LOG2W(size_t n)
{
JS_ASSERT(n != 0);
return js_FloorLog2wImpl(n);
}
/*
* JS_ROTATE_LEFT32
*
@ -564,16 +397,6 @@ SCOPED_TEMPLATE(ScopedReleasePtr, ScopedReleasePtrTraits)
namespace js {
/*
* Round x up to the nearest power of 2. This function assumes that the most
* significant bit of x is not set, which would lead to overflow.
*/
JS_ALWAYS_INLINE size_t
RoundUpPow2(size_t x)
{
return size_t(1) << JS_CEILING_LOG2W(x);
}
/* Integral types for all hash functions. */
typedef uint32_t HashNumber;
const unsigned HashNumberSizeBits = 32;

View File

@ -9,6 +9,7 @@
#include "mozilla/Assertions.h"
#include "mozilla/Attributes.h"
#include "mozilla/MathAlgorithms.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/Move.h"
#include "mozilla/ReentrancyGuard.h"
@ -42,7 +43,7 @@ template <typename T>
static bool CapacityHasExcessSpace(size_t cap)
{
size_t size = cap * sizeof(T);
return RoundUpPow2(size) - size >= sizeof(T);
return mozilla::RoundUpPow2(size) - size >= sizeof(T);
}
/*
@ -694,7 +695,7 @@ Vector<T,N,AP>::growStorageBy(size_t incr)
}
size_t newMinSize = newMinCap * sizeof(T);
size_t newSize = RoundUpPow2(newMinSize);
size_t newSize = mozilla::RoundUpPow2(newMinSize);
newCap = newSize / sizeof(T);
}

View File

@ -6,8 +6,12 @@
#include "ds/LifoAlloc.h"
#include "mozilla/MathAlgorithms.h"
using namespace js;
using mozilla::RoundUpPow2;
namespace js {
namespace detail {

View File

@ -8,6 +8,7 @@
#define ds_LifoAlloc_h
#include "mozilla/DebugOnly.h"
#include "mozilla/MathAlgorithms.h"
#include "mozilla/MemoryChecking.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/PodOperations.h"
@ -175,7 +176,7 @@ class LifoAlloc
BumpChunk *getOrCreateChunk(size_t n);
void reset(size_t defaultChunkSize) {
JS_ASSERT(RoundUpPow2(defaultChunkSize) == defaultChunkSize);
JS_ASSERT(mozilla::RoundUpPow2(defaultChunkSize) == defaultChunkSize);
first = latest = last = NULL;
defaultChunkSize_ = defaultChunkSize;
markCount = 0;

View File

@ -7,6 +7,8 @@
#ifndef ion_AsmJSModule_h
#define ion_AsmJSModule_h
#include "mozilla/MathAlgorithms.h"
#ifdef JS_ION
#include "gc/Marking.h"
@ -689,8 +691,7 @@ class AsmJSModule
return;
ion::AutoFlushCache afc("patchBoundsCheck");
uint32_t bits;
JS_CEILING_LOG2(bits, heapSize);
uint32_t bits = mozilla::CeilingLog2(heapSize);
for (unsigned i = 0; i < boundsChecks_.length(); i++)
ion::Assembler::updateBoundsCheck(bits, (ion::Instruction*)(boundsChecks_[i].offset() + code_));

View File

@ -7,6 +7,8 @@
#ifndef ion_BitSet_h
#define ion_BitSet_h
#include "mozilla/MathAlgorithms.h"
#include "ion/IonAllocPolicy.h"
namespace js {
@ -150,10 +152,9 @@ class BitSet::Iterator
value_ = set_.bits_[word_];
}
// The result of js_bitscan_ctz32 is undefined if the input is 0.
JS_ASSERT(value_ != 0);
int numZeros = js_bitscan_ctz32(value_);
// Be careful: the result of CountTrailingZeroes32 is undefined if the
// input is 0.
int numZeros = mozilla::CountTrailingZeroes32(value_);
index_ += numZeros;
value_ >>= numZeros;

View File

@ -24,6 +24,7 @@ using namespace js;
using namespace js::ion;
using mozilla::Abs;
using mozilla::CountLeadingZeroes32;
using mozilla::ExponentComponent;
using mozilla::IsInfinite;
using mozilla::IsNaN;
@ -466,9 +467,9 @@ Range *
Range::or_(const Range *lhs, const Range *rhs)
{
// When one operand is always 0 or always -1, it's a special case where we
// can compute a fully precise result. Handling these up front also protects
// the code below from calling js_bitscan_clz32 with a zero operand or from
// shifting an int32_t by 32.
// can compute a fully precise result. Handling these up front also
// protects the code below from calling CountLeadingZeroes32 with a zero
// operand or from shifting an int32_t by 32.
if (lhs->lower_ == lhs->upper_) {
if (lhs->lower_ == 0)
return new Range(*rhs);
@ -482,8 +483,8 @@ Range::or_(const Range *lhs, const Range *rhs)
return new Range(*rhs);;
}
// The code below uses js_bitscan_clz32, which has undefined behavior if its
// operand is 0. We rely on the code above to protect it.
// The code below uses CountLeadingZeroes32, which has undefined behavior
// if its operand is 0. We rely on the code above to protect it.
JS_ASSERT_IF(lhs->lower_ >= 0, lhs->upper_ != 0);
JS_ASSERT_IF(rhs->lower_ >= 0, rhs->upper_ != 0);
JS_ASSERT_IF(lhs->upper_ < 0, lhs->lower_ != -1);
@ -496,17 +497,17 @@ Range::or_(const Range *lhs, const Range *rhs)
// Both operands are non-negative, so the result won't be less than either.
lower = Max(lhs->lower_, rhs->lower_);
// The result will have leading zeros where both operands have leading zeros.
upper = UINT32_MAX >> Min(js_bitscan_clz32(lhs->upper_),
js_bitscan_clz32(rhs->upper_));
upper = UINT32_MAX >> Min(CountLeadingZeroes32(lhs->upper_),
CountLeadingZeroes32(rhs->upper_));
} else {
// The result will have leading ones where either operand has leading ones.
if (lhs->upper_ < 0) {
unsigned leadingOnes = js_bitscan_clz32(~lhs->lower_);
unsigned leadingOnes = CountLeadingZeroes32(~lhs->lower_);
lower = Max(lower, int64_t(~int32_t(UINT32_MAX >> leadingOnes)));
upper = -1;
}
if (rhs->upper_ < 0) {
unsigned leadingOnes = js_bitscan_clz32(~rhs->lower_);
unsigned leadingOnes = CountLeadingZeroes32(~rhs->lower_);
lower = Max(lower, int64_t(~int32_t(UINT32_MAX >> leadingOnes)));
upper = -1;
}
@ -543,7 +544,7 @@ Range::xor_(const Range *lhs, const Range *rhs)
// Handle cases where lhs or rhs is always zero specially, because they're
// easy cases where we can be perfectly precise, and because it protects the
// js_bitscan_clz32 calls below from seeing 0 operands, which would be
// CountLeadingZeroes32 calls below from seeing 0 operands, which would be
// undefined behavior.
int32_t lower = INT32_MIN;
int32_t upper = INT32_MAX;
@ -560,8 +561,8 @@ Range::xor_(const Range *lhs, const Range *rhs)
// set all bits that don't correspond to leading zero bits in the
// other to one. For each one, this gives an upper bound for the
// result, so we can take the minimum between the two.
unsigned lhsLeadingZeros = js_bitscan_clz32(lhsUpper);
unsigned rhsLeadingZeros = js_bitscan_clz32(rhsUpper);
unsigned lhsLeadingZeros = CountLeadingZeroes32(lhsUpper);
unsigned rhsLeadingZeros = CountLeadingZeroes32(rhsUpper);
upper = Min(rhsUpper | int32_t(UINT32_MAX >> lhsLeadingZeros),
lhsUpper | int32_t(UINT32_MAX >> rhsLeadingZeros));
}

View File

@ -363,7 +363,7 @@ class Range : public TempObject {
JS_ASSERT_IF(lower() == JSVAL_INT_MIN, max == (uint32_t) JSVAL_INT_MIN);
JS_ASSERT(max <= (uint32_t) JSVAL_INT_MIN);
// The number of bits needed to encode |max| is the power of 2 plus one.
max_exponent_ = max ? js_FloorLog2wImpl(max) : max;
max_exponent_ = max ? mozilla::FloorLog2Size(max) : max;
}
const SymbolicBound *symbolicLower() const {

View File

@ -7,6 +7,8 @@
#ifndef ion_RegisterSets_h
#define ion_RegisterSets_h
#include "mozilla/MathAlgorithms.h"
#include "ion/Registers.h"
#include "ion/IonAllocPolicy.h"
@ -389,18 +391,15 @@ class TypedRegisterSet
}
T getAny() const {
JS_ASSERT(!empty());
int ireg;
JS_FLOOR_LOG2(ireg, bits_);
return T::FromCode(ireg);
return T::FromCode(mozilla::FloorLog2(bits_));
}
T getFirst() const {
JS_ASSERT(!empty());
int ireg = js_bitscan_ctz32(bits_);
return T::FromCode(ireg);
return T::FromCode(mozilla::CountTrailingZeroes32(bits_));
}
T getLast() const {
JS_ASSERT(!empty());
int ireg = 31 - js_bitscan_clz32(bits_);
int ireg = 31 - mozilla::CountLeadingZeroes32(bits_);
return T::FromCode(ireg);
}
T takeAny() {

View File

@ -5,12 +5,17 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "ion/Safepoints.h"
#include "mozilla/MathAlgorithms.h"
#include "ion/IonSpewer.h"
#include "ion/LIR.h"
using namespace js;
using namespace ion;
using mozilla::FloorLog2;
bool
SafepointWriter::init(uint32_t slotCount)
{
@ -381,8 +386,7 @@ SafepointReader::getSlotFromBitmap(uint32_t *slot)
// The current chunk still has bits in it, so get the next bit, then mask
// it out of the slot chunk.
uint32_t bit;
JS_FLOOR_LOG2(bit, currentSlotChunk_);
uint32_t bit = FloorLog2(currentSlotChunk_);
currentSlotChunk_ &= ~(1 << bit);
// Return the slot, taking care to add 1 back in since it was subtracted

View File

@ -5,6 +5,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/DebugOnly.h"
#include "mozilla/MathAlgorithms.h"
#include "ion/arm/Assembler-arm.h"
#include "ion/arm/MacroAssembler-arm.h"
@ -17,6 +18,8 @@
using namespace js;
using namespace js::ion;
using mozilla::CountLeadingZeroes32;
ABIArgGenerator::ABIArgGenerator() :
#if defined(JS_CPU_ARM_HARDFP)
intRegIndex_(0),
@ -936,7 +939,7 @@ Imm8::encodeTwoImms(uint32_t imm)
// also remember, values are rotated by multiples of two, and left,
// mid or right can have length zero
uint32_t imm1, imm2;
int left = (js_bitscan_clz32(imm)) & 0x1E;
int left = CountLeadingZeroes32(imm) & 0x1E;
uint32_t no_n1 = imm & ~(0xff << (24 - left));
// not technically needed: this case only happens if we can encode
@ -945,7 +948,7 @@ Imm8::encodeTwoImms(uint32_t imm)
if (no_n1 == 0)
return TwoImm8mData();
int mid = ((js_bitscan_clz32(no_n1)) & 0x1E);
int mid = CountLeadingZeroes32(no_n1) & 0x1E;
uint32_t no_n2 = no_n1 & ~((0xff << ((24 - mid) & 0x1f)) | 0xff >> ((8 + mid) & 0x1f));
if (no_n2 == 0) {
@ -976,7 +979,7 @@ Imm8::encodeTwoImms(uint32_t imm)
if (left >= 8)
return TwoImm8mData();
int right = 32 - (js_bitscan_clz32(no_n2) & 30);
int right = 32 - (CountLeadingZeroes32(no_n2) & 30);
// all remaining set bits *must* fit into the lower 8 bits
// the right == 8 case should be handled by the previous case.
if (right > 8)
@ -991,7 +994,7 @@ Imm8::encodeTwoImms(uint32_t imm)
// and find that we need a second op for 0x4000, and 0x1 cannot
// be included in the encoding of 0x04100000
no_n1 = imm & ~((0xff >> (8-right)) | (0xff << (24 + right)));
mid = (js_bitscan_clz32(no_n1)) & 30;
mid = CountLeadingZeroes32(no_n1) & 30;
no_n2 =
no_n1 & ~((0xff << ((24 - mid)&31)) | 0xff >> ((8 + mid)&31));
if (no_n2 != 0)

View File

@ -637,10 +637,10 @@ class Imm8 : public Operand2
{
public:
static datastore::Imm8mData encodeImm(uint32_t imm) {
// In gcc, clz is undefined if you call it with 0.
// mozilla::CountLeadingZeroes32(imm) requires imm != 0.
if (imm == 0)
return datastore::Imm8mData(0, 0);
int left = js_bitscan_clz32(imm) & 30;
int left = mozilla::CountLeadingZeroes32(imm) & 30;
// See if imm is a simple value that can be encoded with a rotate of 0.
// This is effectively imm <= 0xff, but I assume this can be optimized
// more
@ -654,7 +654,7 @@ class Imm8 : public Operand2
return datastore::Imm8mData(imm >> (24 - left), ((8+left) >> 1));
}
// Look for the most signifigant bit set, once again.
int right = 32 - (js_bitscan_clz32(no_imm) & 30);
int right = 32 - (mozilla::CountLeadingZeroes32(no_imm) & 30);
// If it is in the bottom 8 bits, there is a chance that this is a
// wraparound case.
if (right >= 8)

View File

@ -4,6 +4,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/MathAlgorithms.h"
#include "jscntxt.h"
#include "jscompartment.h"
@ -26,6 +27,8 @@
using namespace js;
using namespace js::ion;
using mozilla::FloorLog2;
// shared
CodeGeneratorARM::CodeGeneratorARM(MIRGenerator *gen, LIRGraph *graph, MacroAssembler *masm)
: CodeGeneratorShared(gen, graph, masm)
@ -406,8 +409,7 @@ CodeGeneratorARM::visitMulI(LMulI *ins)
if (!mul->canOverflow()) {
// If it cannot overflow, we can do lots of optimizations
Register src = ToRegister(lhs);
uint32_t shift;
JS_FLOOR_LOG2(shift, constant);
uint32_t shift = FloorLog2(constant);
uint32_t rest = constant - (1 << shift);
// See if the constant has one bit set, meaning it can be encoded as a bitshift
if ((1 << shift) == constant) {
@ -416,8 +418,7 @@ CodeGeneratorARM::visitMulI(LMulI *ins)
} else {
// If the constant cannot be encoded as (1<<C1), see if it can be encoded as
// (1<<C1) | (1<<C2), which can be computed using an add and a shift
uint32_t shift_rest;
JS_FLOOR_LOG2(shift_rest, rest);
uint32_t shift_rest = FloorLog2(rest);
if ((1u << shift_rest) == rest) {
masm.as_add(ToRegister(dest), src, lsl(src, shift-shift_rest));
if (shift_rest != 0)
@ -429,8 +430,7 @@ CodeGeneratorARM::visitMulI(LMulI *ins)
// To stay on the safe side, only optimize things that are a
// power of 2.
uint32_t shift;
JS_FLOOR_LOG2(shift, constant);
uint32_t shift = FloorLog2(constant);
if ((1 << shift) == constant) {
// dest = lhs * pow(2,shift)
masm.ma_lsl(Imm32(shift), ToRegister(lhs), ToRegister(dest));

View File

@ -4,6 +4,8 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/MathAlgorithms.h"
#include "ion/MIR.h"
#include "ion/Lowering.h"
#include "ion/arm/Assembler-arm.h"
@ -12,6 +14,8 @@
using namespace js;
using namespace js::ion;
using mozilla::FloorLog2;
bool
LIRGeneratorARM::useBox(LInstruction *lir, size_t n, MDefinition *mir,
LUse::Policy policy, bool useAtStart)
@ -240,8 +244,7 @@ LIRGeneratorARM::lowerDivI(MDiv *div)
// possible; division by negative powers of two can be optimized in a
// similar manner as positive powers of two, and division by other
// constants can be optimized by a reciprocal multiplication technique.
int32_t shift;
JS_FLOOR_LOG2(shift, rhs);
int32_t shift = FloorLog2(rhs);
if (rhs > 0 && 1 << shift == rhs) {
LDivPowTwoI *lir = new LDivPowTwoI(useRegisterAtStart(div->lhs()), shift);
if (div->fallible() && !assignSnapshot(lir))
@ -281,8 +284,7 @@ LIRGeneratorARM::lowerModI(MMod *mod)
if (mod->rhs()->isConstant()) {
int32_t rhs = mod->rhs()->toConstant()->value().toInt32();
int32_t shift;
JS_FLOOR_LOG2(shift, rhs);
int32_t shift = FloorLog2(rhs);
if (rhs > 0 && 1 << shift == rhs) {
LModPowTwoI *lir = new LModPowTwoI(useRegister(mod->lhs()), shift);
if (mod->fallible() && !assignSnapshot(lir))

View File

@ -5,6 +5,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/DebugOnly.h"
#include "mozilla/MathAlgorithms.h"
#include "jscntxt.h"
#include "jscompartment.h"
@ -18,6 +19,8 @@
using namespace js;
using namespace js::ion;
using mozilla::FloorLog2;
namespace js {
namespace ion {
@ -596,8 +599,7 @@ CodeGeneratorX86Shared::visitMulI(LMulI *ins)
default:
if (!mul->canOverflow() && constant > 0) {
// Use shift if cannot overflow and constant is power of 2
int32_t shift;
JS_FLOOR_LOG2(shift, constant);
int32_t shift = FloorLog2(constant);
if ((1 << shift) == constant) {
masm.shll(Imm32(shift), ToRegister(lhs));
return true;

View File

@ -4,13 +4,18 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/MathAlgorithms.h"
#include "ion/MIR.h"
#include "ion/Lowering.h"
#include "ion/shared/Lowering-x86-shared.h"
#include "ion/shared/Lowering-shared-inl.h"
using namespace js;
using namespace js::ion;
using mozilla::FloorLog2;
LTableSwitch *
LIRGeneratorX86Shared::newLTableSwitch(const LAllocation &in, const LDefinition &inputCopy,
MTableSwitch *tableswitch)
@ -138,8 +143,7 @@ LIRGeneratorX86Shared::lowerDivI(MDiv *div)
// possible; division by negative powers of two can be optimized in a
// similar manner as positive powers of two, and division by other
// constants can be optimized by a reciprocal multiplication technique.
int32_t shift;
JS_FLOOR_LOG2(shift, rhs);
int32_t shift = FloorLog2(rhs);
if (rhs > 0 && 1 << shift == rhs) {
LDivPowTwoI *lir = new LDivPowTwoI(useRegisterAtStart(div->lhs()), useRegister(div->lhs()), shift);
if (div->fallible() && !assignSnapshot(lir))
@ -162,8 +166,7 @@ LIRGeneratorX86Shared::lowerModI(MMod *mod)
if (mod->rhs()->isConstant()) {
int32_t rhs = mod->rhs()->toConstant()->value().toInt32();
int32_t shift;
JS_FLOOR_LOG2(shift, rhs);
int32_t shift = FloorLog2(rhs);
if (rhs > 0 && 1 << shift == rhs) {
LModPowTwoI *lir = new LModPowTwoI(useRegisterAtStart(mod->lhs()), shift);
if (mod->fallible() && !assignSnapshot(lir))

View File

@ -7,6 +7,7 @@
#ifndef ion_shared_MacroAssembler_x86_shared_h
#define ion_shared_MacroAssembler_x86_shared_h
#include "mozilla/Casting.h"
#include "mozilla/DebugOnly.h"
#ifdef JS_CPU_X86

View File

@ -7,6 +7,7 @@
#include "jsanalyze.h"
#include "mozilla/DebugOnly.h"
#include "mozilla/MathAlgorithms.h"
#include "mozilla/PodOperations.h"
#include "jscompartment.h"
@ -22,6 +23,7 @@ using namespace js::analyze;
using mozilla::DebugOnly;
using mozilla::PodCopy;
using mozilla::PodZero;
using mozilla::FloorLog2;
/////////////////////////////////////////////////////////////////////
// Bytecode
@ -1473,9 +1475,7 @@ PhiNodeCapacity(unsigned length)
if (length <= 4)
return 4;
unsigned log2;
JS_FLOOR_LOG2(log2, length - 1);
return 1 << (log2 + 1);
return 1 << (FloorLog2(length - 1) + 1);
}
bool

View File

@ -43,6 +43,7 @@ using namespace js::types;
using mozilla::Abs;
using mozilla::ArrayLength;
using mozilla::CeilingLog2;
using mozilla::DebugOnly;
using mozilla::IsNaN;
using mozilla::PointerRangeSize;
@ -1301,9 +1302,8 @@ NumDigitsBase10(uint32_t n)
* Algorithm taken from
* http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
*/
uint32_t log2, t;
JS_CEILING_LOG2(log2, n);
t = log2 * 1233 >> 12;
uint32_t log2 = CeilingLog2(n);
uint32_t t = log2 * 1233 >> 12;
return t - (n < powersOf10[t]) + 1;
}

View File

@ -9,6 +9,7 @@
#ifndef jsinferinlines_h
#define jsinferinlines_h
#include "mozilla/MathAlgorithms.h"
#include "mozilla/PodOperations.h"
#include "jsarray.h"
@ -1099,9 +1100,7 @@ HashSetCapacity(unsigned count)
if (count <= SET_ARRAY_SIZE)
return SET_ARRAY_SIZE;
unsigned log2;
JS_FLOOR_LOG2(log2, count);
return 1 << (log2 + 2);
return 1 << (mozilla::FloorLog2(count) + 2);
}
/* Compute the FNV hash for the low 32 bits of v. */

View File

@ -11,6 +11,7 @@
#include <string.h>
#include "mozilla/MathAlgorithms.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/Util.h"
@ -60,6 +61,7 @@ using namespace js::types;
using js::frontend::IsIdentifier;
using mozilla::ArrayLength;
using mozilla::DebugOnly;
using mozilla::RoundUpPow2;
JS_STATIC_ASSERT(int32_t((JSObject::NELEMENTS_LIMIT - 1) * sizeof(Value)) == int64_t((JSObject::NELEMENTS_LIMIT - 1) * sizeof(Value)));

View File

@ -9,6 +9,7 @@
#include "jsutil.h"
#include "mozilla/Assertions.h"
#include "mozilla/MathAlgorithms.h"
#include "mozilla/PodOperations.h"
#include <stdio.h>
@ -22,6 +23,7 @@
using namespace js;
using mozilla::CeilingLog2Size;
using mozilla::PodArrayZero;
#if USE_ZLIB
@ -194,7 +196,7 @@ ValToBin(unsigned logscale, uint32_t val)
bin = (logscale == 10)
? (unsigned) ceil(log10((double) val))
: (logscale == 2)
? (unsigned) JS_CEILING_LOG2W(val)
? (unsigned) CeilingLog2Size(val)
: val;
return Min(bin, 10U);
}
@ -295,7 +297,7 @@ JS_DumpHistogram(JSBasicStats *bs, FILE *fp)
if (max > 1e6 && mean > 1e3)
cnt = uint32_t(ceil(log10((double) cnt)));
else if (max > 16 && mean > 8)
cnt = JS_CEILING_LOG2W(cnt);
cnt = CeilingLog2Size(cnt);
for (unsigned i = 0; i < cnt; i++)
putc('*', fp);
}

View File

@ -1598,7 +1598,7 @@ class ObjectImpl : public gc::Cell
if (span <= SLOT_CAPACITY_MIN)
return SLOT_CAPACITY_MIN;
uint32_t slots = RoundUpPow2(span);
uint32_t slots = mozilla::RoundUpPow2(span);
MOZ_ASSERT(slots >= span);
return slots;
}

View File

@ -7,6 +7,7 @@
/* JS symbol tables. */
#include "mozilla/DebugOnly.h"
#include "mozilla/MathAlgorithms.h"
#include "mozilla/PodOperations.h"
#include "jsapi.h"
@ -28,6 +29,7 @@ using namespace js::gc;
using mozilla::DebugOnly;
using mozilla::PodZero;
using mozilla::CeilingLog2Size;
bool
ShapeTable::init(ExclusiveContext *cx, Shape *lastProp)
@ -39,7 +41,7 @@ ShapeTable::init(ExclusiveContext *cx, Shape *lastProp)
* event, let's try to grow, overallocating to hold at least twice the
* current population.
*/
uint32_t sizeLog2 = JS_CEILING_LOG2W(2 * entryCount);
uint32_t sizeLog2 = CeilingLog2Size(2 * entryCount);
if (sizeLog2 < MIN_SIZE_LOG2)
sizeLog2 = MIN_SIZE_LOG2;

View File

@ -6,6 +6,7 @@
#include "vm/String-inl.h"
#include "mozilla/MathAlgorithms.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/PodOperations.h"
#include "mozilla/RangedPtr.h"
@ -18,6 +19,7 @@ using namespace js;
using mozilla::PodCopy;
using mozilla::RangedPtr;
using mozilla::RoundUpPow2;
bool
JSString::isShort() const

View File

@ -142,6 +142,287 @@ Abs<long double>(const long double d)
return std::fabs(d);
}
} // namespace mozilla
#if defined(_WIN32) && (_MSC_VER >= 1300) && (defined(_M_IX86) || defined(_M_AMD64) || defined(_M_X64))
# define MOZ_BITSCAN_WINDOWS
extern "C" {
unsigned char _BitScanForward(unsigned long* Index, unsigned long mask);
unsigned char _BitScanReverse(unsigned long* Index, unsigned long mask);
# pragma intrinsic(_BitScanForward, _BitScanReverse)
# if defined(_M_AMD64) || defined(_M_X64)
# define MOZ_BITSCAN_WINDOWS64
unsigned char _BitScanForward64(unsigned long* index, unsigned __int64 mask);
unsigned char _BitScanReverse64(unsigned long* index, unsigned __int64 mask);
# pragma intrinsic(_BitScanForward64, _BitScanReverse64)
# endif
} // extern "C"
#endif
namespace mozilla {
namespace detail {
#if defined(MOZ_BITSCAN_WINDOWS)
inline uint_fast8_t
CountLeadingZeroes32(uint32_t u)
{
unsigned long index;
_BitScanReverse(&index, static_cast<unsigned long>(u));
return uint_fast8_t(31 - index);
}
inline uint_fast8_t
CountTrailingZeroes32(uint32_t u)
{
unsigned long index;
_BitScanForward(&index, static_cast<unsigned long>(u));
return uint_fast8_t(index);
}
inline uint_fast8_t
CountLeadingZeroes64(uint64_t u)
{
# if defined(MOZ_BITSCAN_WINDOWS64)
unsigned long index;
_BitScanReverse64(&index, static_cast<unsigned __int64>(u));
return uint_fast8_t(63 - index);
# else
uint32_t hi = uint32_t(u >> 32);
if (hi != 0)
return CountLeadingZeroes32(hi);
return 32 + CountLeadingZeroes32(uint32_t(u));
# endif
}
inline uint_fast8_t
CountTrailingZeroes64(uint64_t u)
{
# if defined(MOZ_BITSCAN_WINDOWS64)
unsigned long index;
_BitScanForward64(&idx, static_cast<unsigned __int64>(u));
return uint_fast8_t(index);
# else
uint32_t lo = uint32_t(u);
if (lo != 0)
return CountTrailingZeroes32(lo);
return 32 + CountTrailingZeroes32(uint32_t(u >> 32));
# endif
}
# ifdef MOZ_HAVE_BITSCAN64
# undef MOZ_HAVE_BITSCAN64
# endif
#elif defined(__clang__) || defined(__GNUC__)
# if defined(__clang__)
# if !__has_builtin(__builtin_ctz) || !__has_builtin(__builtin_clz)
# error "A clang providing __builtin_c[lt]z is required to build"
# endif
# else
// gcc has had __builtin_clz and friends since 3.4: no need to check.
# endif
inline uint_fast8_t
CountLeadingZeroes32(uint32_t u)
{
return __builtin_clz(u);
}
inline uint_fast8_t
CountTrailingZeroes32(uint32_t u)
{
return __builtin_ctz(u);
}
inline uint_fast8_t
CountLeadingZeroes64(uint64_t u)
{
return __builtin_clzll(u);
}
inline uint_fast8_t
CountTrailingZeroes64(uint64_t u)
{
return __builtin_ctzll(u);
}
#else
# error "Implement these!"
inline uint_fast8_t CountLeadingZeroes32(uint32_t u) MOZ_DELETE;
inline uint_fast8_t CountTrailingZeroes32(uint32_t u) MOZ_DELETE;
inline uint_fast8_t CountLeadingZeroes64(uint64_t u) MOZ_DELETE;
inline uint_fast8_t CountTrailingZeroes64(uint64_t u) MOZ_DELETE;
#endif
} // namespace detail
/**
* Compute the number of high-order zero bits in the NON-ZERO number |u|. That
* is, looking at the bitwise representation of the number, with the highest-
* valued bits at the start, return the number of zeroes before the first one
* is observed.
*
* CountLeadingZeroes32(0xF0FF1000) is 0;
* CountLeadingZeroes32(0x7F8F0001) is 1;
* CountLeadingZeroes32(0x3FFF0100) is 2;
* CountLeadingZeroes32(0x1FF50010) is 3; and so on.
*/
inline uint_fast8_t
CountLeadingZeroes32(uint32_t u)
{
MOZ_ASSERT(u != 0);
return detail::CountLeadingZeroes32(u);
}
/**
* Compute the number of low-order zero bits in the NON-ZERO number |u|. That
* is, looking at the bitwise representation of the number, with the lowest-
* valued bits at the start, return the number of zeroes before the first one
* is observed.
*
* CountTrailingZeroes32(0x0100FFFF) is 0;
* CountTrailingZeroes32(0x7000FFFE) is 1;
* CountTrailingZeroes32(0x0080FFFC) is 2;
* CountTrailingZeroes32(0x0080FFF8) is 3; and so on.
*/
inline uint_fast8_t
CountTrailingZeroes32(uint32_t u)
{
MOZ_ASSERT(u != 0);
return detail::CountTrailingZeroes32(u);
}
/** Analogous to CountLeadingZeroes32, but for 64-bit numbers. */
inline uint_fast8_t
CountLeadingZeroes64(uint64_t u)
{
MOZ_ASSERT(u != 0);
return detail::CountLeadingZeroes64(u);
}
/** Analogous to CountTrailingZeroes32, but for 64-bit numbers. */
inline uint_fast8_t
CountTrailingZeroes64(uint64_t u)
{
MOZ_ASSERT(u != 0);
return detail::CountTrailingZeroes64(u);
}
namespace detail {
template<typename T, size_t Size = sizeof(T)>
class CeilingLog2;
template<typename T>
class CeilingLog2<T, 4>
{
public:
static uint_fast8_t compute(const T t) {
// Check for <= 1 to avoid the == 0 undefined case.
return t <= 1 ? 0 : 32 - CountLeadingZeroes32(t - 1);
}
};
template<typename T>
class CeilingLog2<T, 8>
{
public:
static uint_fast8_t compute(const T t) {
// Check for <= 1 to avoid the == 0 undefined case.
return t <= 1 ? 0 : 64 - CountLeadingZeroes64(t - 1);
}
};
} // namespace detail
/**
* Compute the log of the least power of 2 greater than or equal to |t|.
*
* CeilingLog2(0..1) is 0;
* CeilingLog2(2) is 1;
* CeilingLog2(3..4) is 2;
* CeilingLog2(5..8) is 3;
* CeilingLog2(9..16) is 4; and so on.
*/
template<typename T>
inline uint_fast8_t
CeilingLog2(const T t)
{
return detail::CeilingLog2<T>::compute(t);
}
/** A CeilingLog2 variant that accepts only size_t. */
inline uint_fast8_t
CeilingLog2Size(size_t n)
{
return CeilingLog2(n);
}
namespace detail {
template<typename T, size_t Size = sizeof(T)>
class FloorLog2;
template<typename T>
class FloorLog2<T, 4>
{
public:
static uint_fast8_t compute(const T t) {
return 31 - CountLeadingZeroes32(t | 1);
}
};
template<typename T>
class FloorLog2<T, 8>
{
public:
static uint_fast8_t compute(const T t) {
return 63 - CountLeadingZeroes64(t | 1);
}
};
} // namespace detail
/**
* Compute the log of the greatest power of 2 less than or equal to |t|.
*
* FloorLog2(0..1) is 0;
* FloorLog2(2..3) is 1;
* FloorLog2(4..7) is 2;
* FloorLog2(8..15) is 3; and so on.
*/
template<typename T>
inline uint_fast8_t
FloorLog2(const T t)
{
return detail::FloorLog2<T>::compute(t);
}
/** A FloorLog2 variant that accepts only size_t. */
inline uint_fast8_t
FloorLog2Size(size_t n)
{
return FloorLog2(n);
}
/*
* Round x up to the nearest power of 2. This function assumes that the most
* significant bit of x is not set, which would lead to overflow.
*/
inline size_t
RoundUpPow2(size_t x)
{
MOZ_ASSERT(~x > x, "can't round up -- will overflow!");
return size_t(1) << CeilingLog2(x);
}
} /* namespace mozilla */
#endif /* mozilla_MathAlgorithms_h_ */

View File

@ -15,7 +15,9 @@ CPP_UNIT_TESTS = \
TestAtomics.cpp \
TestBloomFilter.cpp \
TestCasting.cpp \
TestCeilingFloor.cpp \
TestCheckedInt.cpp \
TestCountZeroes.cpp \
TestEndian.cpp \
TestEnumSet.cpp \
TestSHA1.cpp \

View File

@ -0,0 +1,54 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/MathAlgorithms.h"
using mozilla::CeilingLog2;
using mozilla::FloorLog2;
static void
TestCeiling()
{
for (uint32_t i = 0; i <= 1; i++)
MOZ_ASSERT(CeilingLog2(i) == 0);
for (uint32_t i = 2; i <= 2; i++)
MOZ_ASSERT(CeilingLog2(i) == 1);
for (uint32_t i = 3; i <= 4; i++)
MOZ_ASSERT(CeilingLog2(i) == 2);
for (uint32_t i = 5; i <= 8; i++)
MOZ_ASSERT(CeilingLog2(i) == 3);
for (uint32_t i = 9; i <= 16; i++)
MOZ_ASSERT(CeilingLog2(i) == 4);
}
static void
TestFloor()
{
for (uint32_t i = 0; i <= 1; i++)
MOZ_ASSERT(FloorLog2(i) == 0);
for (uint32_t i = 2; i <= 3; i++)
MOZ_ASSERT(FloorLog2(i) == 1);
for (uint32_t i = 4; i <= 7; i++)
MOZ_ASSERT(FloorLog2(i) == 2);
for (uint32_t i = 8; i <= 15; i++)
MOZ_ASSERT(FloorLog2(i) == 3);
for (uint32_t i = 16; i <= 31; i++)
MOZ_ASSERT(FloorLog2(i) == 4);
}
int main()
{
TestCeiling();
TestFloor();
return 0;
}

View File

@ -0,0 +1,100 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/MathAlgorithms.h"
using mozilla::CountLeadingZeroes32;
using mozilla::CountLeadingZeroes64;
using mozilla::CountTrailingZeroes32;
using mozilla::CountTrailingZeroes64;
static void
TestLeadingZeroes32()
{
MOZ_ASSERT(CountLeadingZeroes32(0xF0FF1000) == 0);
MOZ_ASSERT(CountLeadingZeroes32(0x7F8F0001) == 1);
MOZ_ASSERT(CountLeadingZeroes32(0x3FFF0100) == 2);
MOZ_ASSERT(CountLeadingZeroes32(0x1FF50010) == 3);
MOZ_ASSERT(CountLeadingZeroes32(0x00800000) == 8);
MOZ_ASSERT(CountLeadingZeroes32(0x00400000) == 9);
MOZ_ASSERT(CountLeadingZeroes32(0x00008000) == 16);
MOZ_ASSERT(CountLeadingZeroes32(0x00004000) == 17);
MOZ_ASSERT(CountLeadingZeroes32(0x00000080) == 24);
MOZ_ASSERT(CountLeadingZeroes32(0x00000040) == 25);
MOZ_ASSERT(CountLeadingZeroes32(0x00000001) == 31);
}
static void
TestLeadingZeroes64()
{
MOZ_ASSERT(CountLeadingZeroes64(0xF000F0F010000000) == 0);
MOZ_ASSERT(CountLeadingZeroes64(0x70F080F000000001) == 1);
MOZ_ASSERT(CountLeadingZeroes64(0x30F0F0F000100000) == 2);
MOZ_ASSERT(CountLeadingZeroes64(0x10F0F05000000100) == 3);
MOZ_ASSERT(CountLeadingZeroes64(0x0080000000000001) == 8);
MOZ_ASSERT(CountLeadingZeroes64(0x0040000010001000) == 9);
MOZ_ASSERT(CountLeadingZeroes64(0x000080F010000000) == 16);
MOZ_ASSERT(CountLeadingZeroes64(0x000040F010000000) == 17);
MOZ_ASSERT(CountLeadingZeroes64(0x0000008000100100) == 24);
MOZ_ASSERT(CountLeadingZeroes64(0x0000004100010010) == 25);
MOZ_ASSERT(CountLeadingZeroes64(0x0000000080100100) == 32);
MOZ_ASSERT(CountLeadingZeroes64(0x0000000041001010) == 33);
MOZ_ASSERT(CountLeadingZeroes64(0x0000000000800100) == 40);
MOZ_ASSERT(CountLeadingZeroes64(0x0000000000411010) == 41);
MOZ_ASSERT(CountLeadingZeroes64(0x0000000000008001) == 48);
MOZ_ASSERT(CountLeadingZeroes64(0x0000000000004010) == 49);
MOZ_ASSERT(CountLeadingZeroes64(0x0000000000000081) == 56);
MOZ_ASSERT(CountLeadingZeroes64(0x0000000000000040) == 57);
MOZ_ASSERT(CountLeadingZeroes64(0x0000000000000001) == 63);
}
static void
TestTrailingZeroes32()
{
MOZ_ASSERT(CountTrailingZeroes32(0x0100FFFF) == 0);
MOZ_ASSERT(CountTrailingZeroes32(0x7000FFFE) == 1);
MOZ_ASSERT(CountTrailingZeroes32(0x0080FFFC) == 2);
MOZ_ASSERT(CountTrailingZeroes32(0x0080FFF8) == 3);
MOZ_ASSERT(CountTrailingZeroes32(0x010FFF00) == 8);
MOZ_ASSERT(CountTrailingZeroes32(0x7000FE00) == 9);
MOZ_ASSERT(CountTrailingZeroes32(0x10CF0000) == 16);
MOZ_ASSERT(CountTrailingZeroes32(0x0BDE0000) == 17);
MOZ_ASSERT(CountTrailingZeroes32(0x0F000000) == 24);
MOZ_ASSERT(CountTrailingZeroes32(0xDE000000) == 25);
MOZ_ASSERT(CountTrailingZeroes32(0x80000000) == 31);
}
static void
TestTrailingZeroes64()
{
MOZ_ASSERT(CountTrailingZeroes64(0x000100000F0F0F0F) == 0);
MOZ_ASSERT(CountTrailingZeroes64(0x070000000F0F0F0E) == 1);
MOZ_ASSERT(CountTrailingZeroes64(0x000008000F0F0F0C) == 2);
MOZ_ASSERT(CountTrailingZeroes64(0x000008000F0F0F08) == 3);
MOZ_ASSERT(CountTrailingZeroes64(0xC001000F0F0F0F00) == 8);
MOZ_ASSERT(CountTrailingZeroes64(0x0200000F0F0F0E00) == 9);
MOZ_ASSERT(CountTrailingZeroes64(0xB0C10F0FEFDF0000) == 16);
MOZ_ASSERT(CountTrailingZeroes64(0x0AAA00F0FF0E0000) == 17);
MOZ_ASSERT(CountTrailingZeroes64(0xD010F0FEDF000000) == 24);
MOZ_ASSERT(CountTrailingZeroes64(0x7AAF0CF0BE000000) == 25);
MOZ_ASSERT(CountTrailingZeroes64(0x20F0A5D100000000) == 32);
MOZ_ASSERT(CountTrailingZeroes64(0x489BF0B200000000) == 33);
MOZ_ASSERT(CountTrailingZeroes64(0xE0F0D10000000000) == 40);
MOZ_ASSERT(CountTrailingZeroes64(0x97F0B20000000000) == 41);
MOZ_ASSERT(CountTrailingZeroes64(0x2C07000000000000) == 48);
MOZ_ASSERT(CountTrailingZeroes64(0x1FBA000000000000) == 49);
MOZ_ASSERT(CountTrailingZeroes64(0x0100000000000000) == 56);
MOZ_ASSERT(CountTrailingZeroes64(0x0200000000000000) == 57);
MOZ_ASSERT(CountTrailingZeroes64(0x8000000000000000) == 63);
}
int main()
{
TestLeadingZeroes32();
TestLeadingZeroes64();
TestTrailingZeroes32();
TestTrailingZeroes64();
return 0;
}