Skip to content

Commit fa056cd

Browse files
backesCommit Bot
authored andcommitted
[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/+/1903966 Reviewed-by: Yang Guo <yangguo@chromium.org> Commit-Queue: Clemens Backes <clemensb@chromium.org> Cr-Commit-Position: refs/heads/master@{#64851}
1 parent 2a32d96 commit fa056cd

15 files changed

Lines changed: 75 additions & 69 deletions

src/base/bits.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,27 @@ constexpr inline bool IsPowerOfTwo(T value) {
131131
return value > 0 && (value & (value - 1)) == 0;
132132
}
133133

134+
// Identical to {CountTrailingZeros}, but only works for powers of 2.
135+
template <typename T,
136+
typename = typename std::enable_if<std::is_integral<T>::value>::type>
137+
inline constexpr int WhichPowerOfTwo(T value) {
138+
#if V8_HAS_CXX14_CONSTEXPR
139+
DCHECK(IsPowerOfTwo(value));
140+
#endif
141+
#if V8_HAS_BUILTIN_CTZ
142+
STATIC_ASSERT(sizeof(T) <= 8);
143+
return sizeof(T) == 8 ? __builtin_ctzll(static_cast<uint64_t>(value))
144+
: __builtin_ctz(static_cast<uint32_t>(value));
145+
#else
146+
// Fall back to popcount (see "Hacker's Delight" by Henry S. Warren, Jr.),
147+
// chapter 5-4. On x64, since is faster than counting in a loop and faster
148+
// than doing binary search.
149+
using U = typename std::make_unsigned<T>::type;
150+
U u = value;
151+
return CountPopulation(static_cast<U>(u - 1));
152+
#endif
153+
}
154+
134155
// RoundUpToPowerOfTwo32(value) returns the smallest power of two which is
135156
// greater than or equal to |value|. If you pass in a |value| that is already a
136157
// power of two, it is returned as is. |value| must be less than or equal to

src/codegen/arm/macro-assembler-arm.cc

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -565,7 +565,9 @@ void MacroAssembler::And(Register dst, Register src1, const Operand& src2,
565565
base::bits::IsPowerOfTwo(src2.immediate() + 1)) {
566566
CpuFeatureScope scope(this, ARMv7);
567567
ubfx(dst, src1, 0,
568-
WhichPowerOf2(static_cast<uint32_t>(src2.immediate()) + 1), cond);
568+
base::bits::WhichPowerOfTwo(static_cast<uint32_t>(src2.immediate()) +
569+
1),
570+
cond);
569571
} else {
570572
and_(dst, src1, src2, LeaveCC, cond);
571573
}

src/codegen/ppc/macro-assembler-ppc.cc

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1076,7 +1076,8 @@ void MacroAssembler::EnterExitFrame(bool save_doubles, int stack_space,
10761076
const int frame_alignment = ActivationFrameAlignment();
10771077
if (frame_alignment > kPointerSize) {
10781078
DCHECK(base::bits::IsPowerOfTwo(frame_alignment));
1079-
ClearRightImm(sp, sp, Operand(WhichPowerOf2(frame_alignment)));
1079+
ClearRightImm(sp, sp,
1080+
Operand(base::bits::WhichPowerOfTwo(frame_alignment)));
10801081
}
10811082
li(r0, Operand::Zero());
10821083
StorePU(r0, MemOperand(sp, -kNumRequiredStackFrameSlots * kPointerSize));
@@ -1856,7 +1857,8 @@ void TurboAssembler::PrepareCallCFunction(int num_reg_arguments,
18561857
mr(scratch, sp);
18571858
addi(sp, sp, Operand(-(stack_passed_arguments + 1) * kPointerSize));
18581859
DCHECK(base::bits::IsPowerOfTwo(frame_alignment));
1859-
ClearRightImm(sp, sp, Operand(WhichPowerOf2(frame_alignment)));
1860+
ClearRightImm(sp, sp,
1861+
Operand(base::bits::WhichPowerOfTwo(frame_alignment)));
18601862
StoreP(scratch, MemOperand(sp, stack_passed_arguments * kPointerSize));
18611863
} else {
18621864
// Make room for stack arguments

src/codegen/s390/macro-assembler-s390.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1794,7 +1794,8 @@ void TurboAssembler::PrepareCallCFunction(int num_reg_arguments,
17941794
LoadRR(scratch, sp);
17951795
lay(sp, MemOperand(sp, -(stack_passed_arguments + 1) * kSystemPointerSize));
17961796
DCHECK(base::bits::IsPowerOfTwo(frame_alignment));
1797-
ClearRightImm(sp, sp, Operand(WhichPowerOf2(frame_alignment)));
1797+
ClearRightImm(sp, sp,
1798+
Operand(base::bits::WhichPowerOfTwo(frame_alignment)));
17981799
StoreP(scratch,
17991800
MemOperand(sp, (stack_passed_arguments)*kSystemPointerSize));
18001801
} else {

src/compiler/backend/arm/instruction-selector-arm.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1330,14 +1330,14 @@ void InstructionSelector::VisitInt32Mul(Node* node) {
13301330
Emit(kArmAdd | AddressingModeField::encode(kMode_Operand2_R_LSL_I),
13311331
g.DefineAsRegister(node), g.UseRegister(m.left().node()),
13321332
g.UseRegister(m.left().node()),
1333-
g.TempImmediate(WhichPowerOf2(value - 1)));
1333+
g.TempImmediate(base::bits::WhichPowerOfTwo(value - 1)));
13341334
return;
13351335
}
13361336
if (value < kMaxInt && base::bits::IsPowerOfTwo(value + 1)) {
13371337
Emit(kArmRsb | AddressingModeField::encode(kMode_Operand2_R_LSL_I),
13381338
g.DefineAsRegister(node), g.UseRegister(m.left().node()),
13391339
g.UseRegister(m.left().node()),
1340-
g.TempImmediate(WhichPowerOf2(value + 1)));
1340+
g.TempImmediate(base::bits::WhichPowerOfTwo(value + 1)));
13411341
return;
13421342
}
13431343
}

src/compiler/backend/arm64/instruction-selector-arm64.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5+
#include "src/base/bits.h"
56
#include "src/codegen/assembler-inl.h"
67
#include "src/compiler/backend/instruction-selector-impl.h"
78
#include "src/compiler/node-matchers.h"
@@ -518,7 +519,7 @@ int32_t LeftShiftForReducedMultiply(Matcher* m) {
518519
if (m->right().HasValue() && m->right().Value() >= 3) {
519520
uint64_t value_minus_one = m->right().Value() - 1;
520521
if (base::bits::IsPowerOfTwo(value_minus_one)) {
521-
return WhichPowerOf2(value_minus_one);
522+
return base::bits::WhichPowerOfTwo(value_minus_one);
522523
}
523524
}
524525
return 0;

src/compiler/backend/mips/instruction-selector-mips.cc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -847,21 +847,21 @@ void InstructionSelector::VisitInt32Mul(Node* node) {
847847
if (base::bits::IsPowerOfTwo(value)) {
848848
Emit(kMipsShl | AddressingModeField::encode(kMode_None),
849849
g.DefineAsRegister(node), g.UseRegister(m.left().node()),
850-
g.TempImmediate(WhichPowerOf2(value)));
850+
g.TempImmediate(base::bits::WhichPowerOfTwo(value)));
851851
return;
852852
}
853853
if (base::bits::IsPowerOfTwo(value - 1) && IsMipsArchVariant(kMips32r6) &&
854854
value - 1 > 0 && value - 1 <= 31) {
855855
Emit(kMipsLsa, g.DefineAsRegister(node), g.UseRegister(m.left().node()),
856856
g.UseRegister(m.left().node()),
857-
g.TempImmediate(WhichPowerOf2(value - 1)));
857+
g.TempImmediate(base::bits::WhichPowerOfTwo(value - 1)));
858858
return;
859859
}
860860
if (base::bits::IsPowerOfTwo(value + 1)) {
861861
InstructionOperand temp = g.TempRegister();
862862
Emit(kMipsShl | AddressingModeField::encode(kMode_None), temp,
863863
g.UseRegister(m.left().node()),
864-
g.TempImmediate(WhichPowerOf2(value + 1)));
864+
g.TempImmediate(base::bits::WhichPowerOfTwo(value + 1)));
865865
Emit(kMipsSub | AddressingModeField::encode(kMode_None),
866866
g.DefineAsRegister(node), temp, g.UseRegister(m.left().node()));
867867
return;

src/compiler/backend/mips64/instruction-selector-mips64.cc

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -954,21 +954,21 @@ void InstructionSelector::VisitInt32Mul(Node* node) {
954954
if (base::bits::IsPowerOfTwo(value)) {
955955
Emit(kMips64Shl | AddressingModeField::encode(kMode_None),
956956
g.DefineAsRegister(node), g.UseRegister(m.left().node()),
957-
g.TempImmediate(WhichPowerOf2(value)));
957+
g.TempImmediate(base::bits::WhichPowerOfTwo(value)));
958958
return;
959959
}
960960
if (base::bits::IsPowerOfTwo(value - 1) && kArchVariant == kMips64r6 &&
961961
value - 1 > 0 && value - 1 <= 31) {
962962
Emit(kMips64Lsa, g.DefineAsRegister(node), g.UseRegister(m.left().node()),
963963
g.UseRegister(m.left().node()),
964-
g.TempImmediate(WhichPowerOf2(value - 1)));
964+
g.TempImmediate(base::bits::WhichPowerOfTwo(value - 1)));
965965
return;
966966
}
967967
if (base::bits::IsPowerOfTwo(value + 1)) {
968968
InstructionOperand temp = g.TempRegister();
969969
Emit(kMips64Shl | AddressingModeField::encode(kMode_None), temp,
970970
g.UseRegister(m.left().node()),
971-
g.TempImmediate(WhichPowerOf2(value + 1)));
971+
g.TempImmediate(base::bits::WhichPowerOfTwo(value + 1)));
972972
Emit(kMips64Sub | AddressingModeField::encode(kMode_None),
973973
g.DefineAsRegister(node), temp, g.UseRegister(m.left().node()));
974974
return;
@@ -1009,22 +1009,22 @@ void InstructionSelector::VisitInt64Mul(Node* node) {
10091009
if (base::bits::IsPowerOfTwo(value)) {
10101010
Emit(kMips64Dshl | AddressingModeField::encode(kMode_None),
10111011
g.DefineAsRegister(node), g.UseRegister(m.left().node()),
1012-
g.TempImmediate(WhichPowerOf2(value)));
1012+
g.TempImmediate(base::bits::WhichPowerOfTwo(value)));
10131013
return;
10141014
}
10151015
if (base::bits::IsPowerOfTwo(value - 1) && kArchVariant == kMips64r6 &&
10161016
value - 1 > 0 && value - 1 <= 31) {
10171017
// Dlsa macro will handle the shifting value out of bound cases.
10181018
Emit(kMips64Dlsa, g.DefineAsRegister(node),
10191019
g.UseRegister(m.left().node()), g.UseRegister(m.left().node()),
1020-
g.TempImmediate(WhichPowerOf2(value - 1)));
1020+
g.TempImmediate(base::bits::WhichPowerOfTwo(value - 1)));
10211021
return;
10221022
}
10231023
if (base::bits::IsPowerOfTwo(value + 1)) {
10241024
InstructionOperand temp = g.TempRegister();
10251025
Emit(kMips64Dshl | AddressingModeField::encode(kMode_None), temp,
10261026
g.UseRegister(m.left().node()),
1027-
g.TempImmediate(WhichPowerOf2(value + 1)));
1027+
g.TempImmediate(base::bits::WhichPowerOfTwo(value + 1)));
10281028
Emit(kMips64Dsub | AddressingModeField::encode(kMode_None),
10291029
g.DefineAsRegister(node), temp, g.UseRegister(m.left().node()));
10301030
return;

src/compiler/code-assembler.cc

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
#include <ostream>
88

9+
#include "src/base/bits.h"
910
#include "src/codegen/code-factory.h"
1011
#include "src/codegen/interface-descriptors.h"
1112
#include "src/codegen/machine-type.h"
@@ -504,7 +505,7 @@ TNode<IntPtrT> CodeAssembler::IntPtrDiv(TNode<IntPtrT> left,
504505
return IntPtrConstant(left_constant / right_constant);
505506
}
506507
if (base::bits::IsPowerOfTwo(right_constant)) {
507-
return WordSar(left, WhichPowerOf2(right_constant));
508+
return WordSar(left, base::bits::WhichPowerOfTwo(right_constant));
508509
}
509510
}
510511
return UncheckedCast<IntPtrT>(raw_assembler()->IntPtrDiv(left, right));
@@ -539,11 +540,11 @@ TNode<WordT> CodeAssembler::IntPtrMul(SloppyTNode<WordT> left,
539540
return IntPtrConstant(left_constant * right_constant);
540541
}
541542
if (base::bits::IsPowerOfTwo(left_constant)) {
542-
return WordShl(right, WhichPowerOf2(left_constant));
543+
return WordShl(right, base::bits::WhichPowerOfTwo(left_constant));
543544
}
544545
} else if (is_right_constant) {
545546
if (base::bits::IsPowerOfTwo(right_constant)) {
546-
return WordShl(left, WhichPowerOf2(right_constant));
547+
return WordShl(left, base::bits::WhichPowerOfTwo(right_constant));
547548
}
548549
}
549550
return UncheckedCast<IntPtrT>(raw_assembler()->IntPtrMul(left, right));

src/compiler/effect-control-linearizer.cc

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
#include "src/compiler/effect-control-linearizer.h"
66

7+
#include "src/base/bits.h"
78
#include "src/codegen/code-factory.h"
89
#include "src/codegen/machine-type.h"
910
#include "src/common/ptr-compr-inl.h"
@@ -2084,7 +2085,7 @@ Node* EffectControlLinearizer::LowerCheckedInt32Div(Node* node,
20842085
// right shift on {lhs}).
20852086
int32_t divisor = m.Value();
20862087
Node* mask = __ Int32Constant(divisor - 1);
2087-
Node* shift = __ Int32Constant(WhichPowerOf2(divisor));
2088+
Node* shift = __ Int32Constant(base::bits::WhichPowerOfTwo(divisor));
20882089
Node* check = __ Word32Equal(__ Word32And(lhs, mask), zero);
20892090
__ DeoptimizeIfNot(DeoptimizeReason::kLostPrecision, FeedbackSource(),
20902091
check, frame_state);
@@ -2277,7 +2278,7 @@ Node* EffectControlLinearizer::LowerCheckedUint32Div(Node* node,
22772278
// shift on {lhs}).
22782279
uint32_t divisor = m.Value();
22792280
Node* mask = __ Uint32Constant(divisor - 1);
2280-
Node* shift = __ Uint32Constant(WhichPowerOf2(divisor));
2281+
Node* shift = __ Uint32Constant(base::bits::WhichPowerOfTwo(divisor));
22812282
Node* check = __ Word32Equal(__ Word32And(lhs, mask), zero);
22822283
__ DeoptimizeIfNot(DeoptimizeReason::kLostPrecision, FeedbackSource(),
22832284
check, frame_state);

0 commit comments

Comments
 (0)