Reland "[base] Introduce RoundUpToPowerOfTwo64"

With fix for architectures where x<<32 != x.

Original change's description:
> [base] Introduce RoundUpToPowerOfTwo64
>
> And fix RoundUpToPowerOfTwo32 to return 1 for the input 0.
> 0 is no power of two.
> Beside being the correct value, this also avoids a special case in the
> (new) fast path using the number of leading zeros.
>
> R=​jochen@chromium.org, ahaas@chromium.org
>
> Change-Id: I87173495e13b334954bcebbb55724fb666dfa809
> Reviewed-on: https://chromium-review.googlesource.com/488143
> Reviewed-by: Jochen Eisinger <jochen@chromium.org>
> Reviewed-by: Andreas Haas <ahaas@chromium.org>
> Commit-Queue: Clemens Hammacher <clemensh@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#44925}

TBR=ahaas@chromium.org,jochen@chromium.org,clemensh@chromium.org,v8-reviews@googlegroups.com

Change-Id: I7b4719d84a419bb7b38e3b5c9d6d183275087ace
Reviewed-on: https://chromium-review.googlesource.com/488981
Commit-Queue: Clemens Hammacher <clemensh@chromium.org>
Reviewed-by: Clemens Hammacher <clemensh@chromium.org>
Cr-Commit-Position: refs/heads/master@{#44951}
This commit is contained in:
Clemens Hammacher 2017-04-27 18:16:53 +02:00 committed by Commit Bot
parent b3887f8a2c
commit a32cd1c710
4 changed files with 57 additions and 17 deletions

View File

@ -14,14 +14,36 @@ namespace base {
namespace bits {
uint32_t RoundUpToPowerOfTwo32(uint32_t value) {
DCHECK_LE(value, 0x80000000u);
value = value - 1;
value = value | (value >> 1);
value = value | (value >> 2);
value = value | (value >> 4);
value = value | (value >> 8);
value = value | (value >> 16);
DCHECK_LE(value, uint32_t{1} << 31);
if (value) --value;
// Use computation based on leading zeros if we have compiler support for that.
#if V8_HAS_BUILTIN_CLZ || V8_CC_MSVC
return 1u << (32 - CountLeadingZeros32(value));
#else
value |= value >> 1;
value |= value >> 2;
value |= value >> 4;
value |= value >> 8;
value |= value >> 16;
return value + 1;
#endif
}
uint64_t RoundUpToPowerOfTwo64(uint64_t value) {
DCHECK_LE(value, uint64_t{1} << 63);
if (value) --value;
// Use computation based on leading zeros if we have compiler support for that.
#if V8_HAS_BUILTIN_CLZ
return uint64_t{1} << (64 - CountLeadingZeros64(value));
#else
value |= value >> 1;
value |= value >> 2;
value |= value >> 4;
value |= value >> 8;
value |= value >> 16;
value |= value >> 32;
return value + 1;
#endif
}

View File

@ -168,13 +168,15 @@ inline bool IsPowerOfTwo64(uint64_t value) {
return value && !(value & (value - 1));
}
// RoundUpToPowerOfTwo32(value) returns the smallest power of two which is
// greater than or equal to |value|. If you pass in a |value| that is already a
// power of two, it is returned as is. |value| must be less than or equal to
// 0x80000000u. Implementation is from "Hacker's Delight" by Henry S. Warren,
// Jr., figure 3-3, page 48, where the function is called clp2.
// 0x80000000u. Uses computation based on leading zeros if we have compiler
// support for that. Falls back to the implementation from "Hacker's Delight" by
// Henry S. Warren, Jr., figure 3-3, page 48, where the function is called clp2.
V8_BASE_EXPORT uint32_t RoundUpToPowerOfTwo32(uint32_t value);
// Same for 64 bit integers. |value| must be <= 2^63
V8_BASE_EXPORT uint64_t RoundUpToPowerOfTwo64(uint64_t value);
// RoundDownToPowerOfTwo32(value) returns the greatest power of two which is
// less than or equal to |value|. If you pass in a |value| that is already a

View File

@ -2083,11 +2083,9 @@ class ThreadImpl {
void EnsureStackSpace(size_t size) {
if (V8_LIKELY(static_cast<size_t>(stack_limit_ - sp_) >= size)) return;
size_t old_size = stack_limit_ - stack_start_;
size_t new_size = Max(size_t{8}, 2 * old_size);
while (new_size < (sp_ - stack_start_) + size) {
DCHECK_GE(std::numeric_limits<decltype(new_size)>::max() / 4, new_size);
new_size *= 2;
}
size_t requested_size =
base::bits::RoundUpToPowerOfTwo64((sp_ - stack_start_) + size);
size_t new_size = Max(size_t{8}, Max(2 * old_size, requested_size));
WasmVal* new_stack = zone_->NewArray<WasmVal>(new_size);
memcpy(new_stack, stack_start_, old_size * sizeof(*sp_));
sp_ = new_stack + (sp_ - stack_start_);

View File

@ -117,7 +117,8 @@ TEST(Bits, RoundUpToPowerOfTwo32) {
TRACED_FORRANGE(uint32_t, shift, 0, 31) {
EXPECT_EQ(1u << shift, RoundUpToPowerOfTwo32(1u << shift));
}
EXPECT_EQ(0u, RoundUpToPowerOfTwo32(0));
EXPECT_EQ(1u, RoundUpToPowerOfTwo32(0));
EXPECT_EQ(1u, RoundUpToPowerOfTwo32(1));
EXPECT_EQ(4u, RoundUpToPowerOfTwo32(3));
EXPECT_EQ(0x80000000u, RoundUpToPowerOfTwo32(0x7fffffffu));
}
@ -125,7 +126,24 @@ TEST(Bits, RoundUpToPowerOfTwo32) {
TEST(BitsDeathTest, DISABLE_IN_RELEASE(RoundUpToPowerOfTwo32)) {
ASSERT_DEATH_IF_SUPPORTED({ RoundUpToPowerOfTwo32(0x80000001u); },
"0x80000000");
"Check failed:.* << 31");
}
TEST(Bits, RoundUpToPowerOfTwo64) {
TRACED_FORRANGE(uint64_t, shift, 0, 63) {
uint64_t value = uint64_t{1} << shift;
EXPECT_EQ(value, RoundUpToPowerOfTwo64(value));
}
EXPECT_EQ(uint64_t{1}, RoundUpToPowerOfTwo64(0));
EXPECT_EQ(uint64_t{1}, RoundUpToPowerOfTwo64(1));
EXPECT_EQ(uint64_t{4}, RoundUpToPowerOfTwo64(3));
EXPECT_EQ(uint64_t{1} << 63, RoundUpToPowerOfTwo64((uint64_t{1} << 63) - 1));
EXPECT_EQ(uint64_t{1} << 63, RoundUpToPowerOfTwo64(uint64_t{1} << 63));
}
TEST(BitsDeathTest, DISABLE_IN_RELEASE(RoundUpToPowerOfTwo64)) {
ASSERT_DEATH_IF_SUPPORTED({ RoundUpToPowerOfTwo64((uint64_t{1} << 63) + 1); },
"Check failed:.* << 63");
}