Commit fa056cd0 authored by Clemens Backes's avatar Clemens Backes Committed by Commit Bot

[utils] Move {WhichPowerOf2} to base::bits

{WhichPowerOf2} is basically the same as {CountTrailingZeros}, with a
restriction to powers of two. Since it does not use or depend on any v8
internals, it can be moved to src/base/bits.h.
This CL also changes the implementation to use the CTZ builtin if
available, and falls back to popcnt otherwise.

Drive-by: Make it constexpr, and rename to {WhichPowerOfTwo}.

R=sigurds@chromium.org

Bug: v8:9810, v8:8912
Change-Id: I8368d098f9ab1247f3b9f036f1385a38de10cc6a
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1903966Reviewed-by: 's avatarYang Guo <yangguo@chromium.org>
Commit-Queue: Clemens Backes <clemensb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#64851}
parent 2a32d96b
......@@ -131,6 +131,27 @@ constexpr inline bool IsPowerOfTwo(T value) {
return value > 0 && (value & (value - 1)) == 0;
}
// Identical to {CountTrailingZeros}, but only works for powers of 2.
template <typename T,
typename = typename std::enable_if<std::is_integral<T>::value>::type>
inline constexpr int WhichPowerOfTwo(T value) {
#if V8_HAS_CXX14_CONSTEXPR
DCHECK(IsPowerOfTwo(value));
#endif
#if V8_HAS_BUILTIN_CTZ
STATIC_ASSERT(sizeof(T) <= 8);
return sizeof(T) == 8 ? __builtin_ctzll(static_cast<uint64_t>(value))
: __builtin_ctz(static_cast<uint32_t>(value));
#else
// Fall back to popcount (see "Hacker's Delight" by Henry S. Warren, Jr.),
// chapter 5-4. On x64, since is faster than counting in a loop and faster
// than doing binary search.
using U = typename std::make_unsigned<T>::type;
U u = value;
return CountPopulation(static_cast<U>(u - 1));
#endif
}
// 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
......
......@@ -565,7 +565,9 @@ void MacroAssembler::And(Register dst, Register src1, const Operand& src2,
base::bits::IsPowerOfTwo(src2.immediate() + 1)) {
CpuFeatureScope scope(this, ARMv7);
ubfx(dst, src1, 0,
WhichPowerOf2(static_cast<uint32_t>(src2.immediate()) + 1), cond);
base::bits::WhichPowerOfTwo(static_cast<uint32_t>(src2.immediate()) +
1),
cond);
} else {
and_(dst, src1, src2, LeaveCC, cond);
}
......
......@@ -1076,7 +1076,8 @@ void MacroAssembler::EnterExitFrame(bool save_doubles, int stack_space,
const int frame_alignment = ActivationFrameAlignment();
if (frame_alignment > kPointerSize) {
DCHECK(base::bits::IsPowerOfTwo(frame_alignment));
ClearRightImm(sp, sp, Operand(WhichPowerOf2(frame_alignment)));
ClearRightImm(sp, sp,
Operand(base::bits::WhichPowerOfTwo(frame_alignment)));
}
li(r0, Operand::Zero());
StorePU(r0, MemOperand(sp, -kNumRequiredStackFrameSlots * kPointerSize));
......@@ -1856,7 +1857,8 @@ void TurboAssembler::PrepareCallCFunction(int num_reg_arguments,
mr(scratch, sp);
addi(sp, sp, Operand(-(stack_passed_arguments + 1) * kPointerSize));
DCHECK(base::bits::IsPowerOfTwo(frame_alignment));
ClearRightImm(sp, sp, Operand(WhichPowerOf2(frame_alignment)));
ClearRightImm(sp, sp,
Operand(base::bits::WhichPowerOfTwo(frame_alignment)));
StoreP(scratch, MemOperand(sp, stack_passed_arguments * kPointerSize));
} else {
// Make room for stack arguments
......
......@@ -1794,7 +1794,8 @@ void TurboAssembler::PrepareCallCFunction(int num_reg_arguments,
LoadRR(scratch, sp);
lay(sp, MemOperand(sp, -(stack_passed_arguments + 1) * kSystemPointerSize));
DCHECK(base::bits::IsPowerOfTwo(frame_alignment));
ClearRightImm(sp, sp, Operand(WhichPowerOf2(frame_alignment)));
ClearRightImm(sp, sp,
Operand(base::bits::WhichPowerOfTwo(frame_alignment)));
StoreP(scratch,
MemOperand(sp, (stack_passed_arguments)*kSystemPointerSize));
} else {
......
......@@ -1330,14 +1330,14 @@ void InstructionSelector::VisitInt32Mul(Node* node) {
Emit(kArmAdd | AddressingModeField::encode(kMode_Operand2_R_LSL_I),
g.DefineAsRegister(node), g.UseRegister(m.left().node()),
g.UseRegister(m.left().node()),
g.TempImmediate(WhichPowerOf2(value - 1)));
g.TempImmediate(base::bits::WhichPowerOfTwo(value - 1)));
return;
}
if (value < kMaxInt && base::bits::IsPowerOfTwo(value + 1)) {
Emit(kArmRsb | AddressingModeField::encode(kMode_Operand2_R_LSL_I),
g.DefineAsRegister(node), g.UseRegister(m.left().node()),
g.UseRegister(m.left().node()),
g.TempImmediate(WhichPowerOf2(value + 1)));
g.TempImmediate(base::bits::WhichPowerOfTwo(value + 1)));
return;
}
}
......
......@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/base/bits.h"
#include "src/codegen/assembler-inl.h"
#include "src/compiler/backend/instruction-selector-impl.h"
#include "src/compiler/node-matchers.h"
......@@ -518,7 +519,7 @@ int32_t LeftShiftForReducedMultiply(Matcher* m) {
if (m->right().HasValue() && m->right().Value() >= 3) {
uint64_t value_minus_one = m->right().Value() - 1;
if (base::bits::IsPowerOfTwo(value_minus_one)) {
return WhichPowerOf2(value_minus_one);
return base::bits::WhichPowerOfTwo(value_minus_one);
}
}
return 0;
......
......@@ -847,21 +847,21 @@ void InstructionSelector::VisitInt32Mul(Node* node) {
if (base::bits::IsPowerOfTwo(value)) {
Emit(kMipsShl | AddressingModeField::encode(kMode_None),
g.DefineAsRegister(node), g.UseRegister(m.left().node()),
g.TempImmediate(WhichPowerOf2(value)));
g.TempImmediate(base::bits::WhichPowerOfTwo(value)));
return;
}
if (base::bits::IsPowerOfTwo(value - 1) && IsMipsArchVariant(kMips32r6) &&
value - 1 > 0 && value - 1 <= 31) {
Emit(kMipsLsa, g.DefineAsRegister(node), g.UseRegister(m.left().node()),
g.UseRegister(m.left().node()),
g.TempImmediate(WhichPowerOf2(value - 1)));
g.TempImmediate(base::bits::WhichPowerOfTwo(value - 1)));
return;
}
if (base::bits::IsPowerOfTwo(value + 1)) {
InstructionOperand temp = g.TempRegister();
Emit(kMipsShl | AddressingModeField::encode(kMode_None), temp,
g.UseRegister(m.left().node()),
g.TempImmediate(WhichPowerOf2(value + 1)));
g.TempImmediate(base::bits::WhichPowerOfTwo(value + 1)));
Emit(kMipsSub | AddressingModeField::encode(kMode_None),
g.DefineAsRegister(node), temp, g.UseRegister(m.left().node()));
return;
......
......@@ -954,21 +954,21 @@ void InstructionSelector::VisitInt32Mul(Node* node) {
if (base::bits::IsPowerOfTwo(value)) {
Emit(kMips64Shl | AddressingModeField::encode(kMode_None),
g.DefineAsRegister(node), g.UseRegister(m.left().node()),
g.TempImmediate(WhichPowerOf2(value)));
g.TempImmediate(base::bits::WhichPowerOfTwo(value)));
return;
}
if (base::bits::IsPowerOfTwo(value - 1) && kArchVariant == kMips64r6 &&
value - 1 > 0 && value - 1 <= 31) {
Emit(kMips64Lsa, g.DefineAsRegister(node), g.UseRegister(m.left().node()),
g.UseRegister(m.left().node()),
g.TempImmediate(WhichPowerOf2(value - 1)));
g.TempImmediate(base::bits::WhichPowerOfTwo(value - 1)));
return;
}
if (base::bits::IsPowerOfTwo(value + 1)) {
InstructionOperand temp = g.TempRegister();
Emit(kMips64Shl | AddressingModeField::encode(kMode_None), temp,
g.UseRegister(m.left().node()),
g.TempImmediate(WhichPowerOf2(value + 1)));
g.TempImmediate(base::bits::WhichPowerOfTwo(value + 1)));
Emit(kMips64Sub | AddressingModeField::encode(kMode_None),
g.DefineAsRegister(node), temp, g.UseRegister(m.left().node()));
return;
......@@ -1009,7 +1009,7 @@ void InstructionSelector::VisitInt64Mul(Node* node) {
if (base::bits::IsPowerOfTwo(value)) {
Emit(kMips64Dshl | AddressingModeField::encode(kMode_None),
g.DefineAsRegister(node), g.UseRegister(m.left().node()),
g.TempImmediate(WhichPowerOf2(value)));
g.TempImmediate(base::bits::WhichPowerOfTwo(value)));
return;
}
if (base::bits::IsPowerOfTwo(value - 1) && kArchVariant == kMips64r6 &&
......@@ -1017,14 +1017,14 @@ void InstructionSelector::VisitInt64Mul(Node* node) {
// Dlsa macro will handle the shifting value out of bound cases.
Emit(kMips64Dlsa, g.DefineAsRegister(node),
g.UseRegister(m.left().node()), g.UseRegister(m.left().node()),
g.TempImmediate(WhichPowerOf2(value - 1)));
g.TempImmediate(base::bits::WhichPowerOfTwo(value - 1)));
return;
}
if (base::bits::IsPowerOfTwo(value + 1)) {
InstructionOperand temp = g.TempRegister();
Emit(kMips64Dshl | AddressingModeField::encode(kMode_None), temp,
g.UseRegister(m.left().node()),
g.TempImmediate(WhichPowerOf2(value + 1)));
g.TempImmediate(base::bits::WhichPowerOfTwo(value + 1)));
Emit(kMips64Dsub | AddressingModeField::encode(kMode_None),
g.DefineAsRegister(node), temp, g.UseRegister(m.left().node()));
return;
......
......@@ -6,6 +6,7 @@
#include <ostream>
#include "src/base/bits.h"
#include "src/codegen/code-factory.h"
#include "src/codegen/interface-descriptors.h"
#include "src/codegen/machine-type.h"
......@@ -504,7 +505,7 @@ TNode<IntPtrT> CodeAssembler::IntPtrDiv(TNode<IntPtrT> left,
return IntPtrConstant(left_constant / right_constant);
}
if (base::bits::IsPowerOfTwo(right_constant)) {
return WordSar(left, WhichPowerOf2(right_constant));
return WordSar(left, base::bits::WhichPowerOfTwo(right_constant));
}
}
return UncheckedCast<IntPtrT>(raw_assembler()->IntPtrDiv(left, right));
......@@ -539,11 +540,11 @@ TNode<WordT> CodeAssembler::IntPtrMul(SloppyTNode<WordT> left,
return IntPtrConstant(left_constant * right_constant);
}
if (base::bits::IsPowerOfTwo(left_constant)) {
return WordShl(right, WhichPowerOf2(left_constant));
return WordShl(right, base::bits::WhichPowerOfTwo(left_constant));
}
} else if (is_right_constant) {
if (base::bits::IsPowerOfTwo(right_constant)) {
return WordShl(left, WhichPowerOf2(right_constant));
return WordShl(left, base::bits::WhichPowerOfTwo(right_constant));
}
}
return UncheckedCast<IntPtrT>(raw_assembler()->IntPtrMul(left, right));
......
......@@ -4,6 +4,7 @@
#include "src/compiler/effect-control-linearizer.h"
#include "src/base/bits.h"
#include "src/codegen/code-factory.h"
#include "src/codegen/machine-type.h"
#include "src/common/ptr-compr-inl.h"
......@@ -2084,7 +2085,7 @@ Node* EffectControlLinearizer::LowerCheckedInt32Div(Node* node,
// right shift on {lhs}).
int32_t divisor = m.Value();
Node* mask = __ Int32Constant(divisor - 1);
Node* shift = __ Int32Constant(WhichPowerOf2(divisor));
Node* shift = __ Int32Constant(base::bits::WhichPowerOfTwo(divisor));
Node* check = __ Word32Equal(__ Word32And(lhs, mask), zero);
__ DeoptimizeIfNot(DeoptimizeReason::kLostPrecision, FeedbackSource(),
check, frame_state);
......@@ -2277,7 +2278,7 @@ Node* EffectControlLinearizer::LowerCheckedUint32Div(Node* node,
// shift on {lhs}).
uint32_t divisor = m.Value();
Node* mask = __ Uint32Constant(divisor - 1);
Node* shift = __ Uint32Constant(WhichPowerOf2(divisor));
Node* shift = __ Uint32Constant(base::bits::WhichPowerOfTwo(divisor));
Node* check = __ Word32Equal(__ Word32And(lhs, mask), zero);
__ DeoptimizeIfNot(DeoptimizeReason::kLostPrecision, FeedbackSource(),
check, frame_state);
......
......@@ -228,7 +228,8 @@ Reduction MachineOperatorReducer::Reduce(Node* node) {
return Changed(node);
}
if (m.right().IsPowerOf2()) { // x * 2^n => x << n
node->ReplaceInput(1, Int32Constant(WhichPowerOf2(m.right().Value())));
node->ReplaceInput(
1, Int32Constant(base::bits::WhichPowerOfTwo(m.right().Value())));
NodeProperties::ChangeOp(node, machine()->Word32Shl());
Reduction reduction = ReduceWord32Shl(node);
return reduction.Changed() ? reduction : Changed(node);
......@@ -863,7 +864,7 @@ Reduction MachineOperatorReducer::ReduceInt32Div(Node* node) {
Node* const dividend = m.left().node();
Node* quotient = dividend;
if (base::bits::IsPowerOfTwo(Abs(divisor))) {
uint32_t const shift = WhichPowerOf2(Abs(divisor));
uint32_t const shift = base::bits::WhichPowerOfTwo(Abs(divisor));
DCHECK_NE(0u, shift);
if (shift > 1) {
quotient = Word32Sar(quotient, 31);
......@@ -902,7 +903,8 @@ Reduction MachineOperatorReducer::ReduceUint32Div(Node* node) {
Node* const dividend = m.left().node();
uint32_t const divisor = m.right().Value();
if (base::bits::IsPowerOfTwo(divisor)) { // x / 2^n => x >> n
node->ReplaceInput(1, Uint32Constant(WhichPowerOf2(m.right().Value())));
node->ReplaceInput(
1, Uint32Constant(base::bits::WhichPowerOfTwo(m.right().Value())));
node->TrimInputCount(2);
NodeProperties::ChangeOp(node, machine()->Word32Shr());
return Changed(node);
......
......@@ -219,7 +219,7 @@ class MachOSection : public DebugSectionBase<MachOSectionHeader> {
: name_(name), segment_(segment), align_(align), flags_(flags) {
if (align_ != 0) {
DCHECK(base::bits::IsPowerOfTwo(align));
align_ = WhichPowerOf2(align_);
align_ = base::bits::WhichPowerOfTwo(align_);
}
}
......
......@@ -1135,7 +1135,8 @@ void RegExpMacroAssemblerPPC::CallCheckStackGuardState(Register scratch) {
__ mr(scratch, sp);
__ addi(sp, sp, Operand(-(stack_passed_arguments + 1) * kPointerSize));
DCHECK(base::bits::IsPowerOfTwo(frame_alignment));
__ ClearRightImm(sp, sp, Operand(WhichPowerOf2(frame_alignment)));
__ ClearRightImm(sp, sp,
Operand(base::bits::WhichPowerOfTwo(frame_alignment)));
__ StoreP(scratch, MemOperand(sp, stack_passed_arguments * kPointerSize));
} else {
// Make room for stack arguments
......
......@@ -90,47 +90,6 @@ inline bool ClampToBounds(T index, T* length, T max) {
return !oob;
}
// X must be a power of 2. Returns the number of trailing zeros.
template <typename T,
typename = typename std::enable_if<std::is_integral<T>::value>::type>
inline int WhichPowerOf2(T x) {
DCHECK(base::bits::IsPowerOfTwo(x));
int bits = 0;
#ifdef DEBUG
const T original_x = x;
#endif
constexpr int max_bits = sizeof(T) * 8;
static_assert(max_bits <= 64, "integral types are not bigger than 64 bits");
// Avoid shifting by more than the bit width of x to avoid compiler warnings.
#define CHECK_BIGGER(s) \
if (max_bits > s && x >= T{1} << (max_bits > s ? s : 0)) { \
bits += s; \
x >>= max_bits > s ? s : 0; \
}
CHECK_BIGGER(32)
CHECK_BIGGER(16)
CHECK_BIGGER(8)
CHECK_BIGGER(4)
#undef CHECK_BIGGER
switch (x) {
default:
UNREACHABLE();
case 8:
bits++;
V8_FALLTHROUGH;
case 4:
bits++;
V8_FALLTHROUGH;
case 2:
bits++;
V8_FALLTHROUGH;
case 1:
break;
}
DCHECK_EQ(T{1} << bits, original_x);
return bits;
}
inline int MostSignificantBit(uint32_t x) {
static const int msb4[] = {0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4};
int nibble = 0;
......
......@@ -117,7 +117,6 @@ TEST(Bits, CountTrailingZeros64) {
EXPECT_EQ(36u, CountTrailingZeros(uint64_t{0xF0F0F0F000000000}));
}
TEST(Bits, IsPowerOfTwo32) {
EXPECT_FALSE(IsPowerOfTwo(0U));
TRACED_FORRANGE(uint32_t, shift, 0, 31) {
......@@ -131,7 +130,6 @@ TEST(Bits, IsPowerOfTwo32) {
EXPECT_FALSE(IsPowerOfTwo(0xFFFFFFFF));
}
TEST(Bits, IsPowerOfTwo64) {
EXPECT_FALSE(IsPowerOfTwo(uint64_t{0}));
TRACED_FORRANGE(uint32_t, shift, 0, 63) {
......@@ -145,6 +143,23 @@ TEST(Bits, IsPowerOfTwo64) {
EXPECT_FALSE(IsPowerOfTwo(uint64_t{0xFFFFFFFFFFFFFFFF}));
}
TEST(Bits, WhichPowerOfTwo32) {
TRACED_FORRANGE(int, shift, 0, 30) {
EXPECT_EQ(shift, WhichPowerOfTwo(int32_t{1} << shift));
}
TRACED_FORRANGE(int, shift, 0, 31) {
EXPECT_EQ(shift, WhichPowerOfTwo(uint32_t{1} << shift));
}
}
TEST(Bits, WhichPowerOfTwo64) {
TRACED_FORRANGE(int, shift, 0, 62) {
EXPECT_EQ(shift, WhichPowerOfTwo(int64_t{1} << shift));
}
TRACED_FORRANGE(int, shift, 0, 63) {
EXPECT_EQ(shift, WhichPowerOfTwo(uint64_t{1} << shift));
}
}
TEST(Bits, RoundUpToPowerOfTwo32) {
TRACED_FORRANGE(uint32_t, shift, 0, 31) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment