Added Popcnt as an optional operator and implement it on x64 and ia32.
R=titzer@google.com Review URL: https://codereview.chromium.org/1407933002 Cr-Commit-Position: refs/heads/master@{#31319}
This commit is contained in:
parent
13d783d71c
commit
053e280c88
@ -700,6 +700,9 @@ void InstructionSelector::VisitWord32Clz(Node* node) {
|
||||
void InstructionSelector::VisitWord32Ctz(Node* node) { UNREACHABLE(); }
|
||||
|
||||
|
||||
void InstructionSelector::VisitWord32Popcnt(Node* node) { UNREACHABLE(); }
|
||||
|
||||
|
||||
void InstructionSelector::VisitInt32Add(Node* node) {
|
||||
ArmOperandGenerator g(this);
|
||||
Int32BinopMatcher m(node);
|
||||
|
@ -930,6 +930,9 @@ void InstructionSelector::VisitWord32Clz(Node* node) {
|
||||
void InstructionSelector::VisitWord32Ctz(Node* node) { UNREACHABLE(); }
|
||||
|
||||
|
||||
void InstructionSelector::VisitWord32Popcnt(Node* node) { UNREACHABLE(); }
|
||||
|
||||
|
||||
void InstructionSelector::VisitInt32Add(Node* node) {
|
||||
Arm64OperandGenerator g(this);
|
||||
Int32BinopMatcher m(node);
|
||||
|
@ -512,6 +512,9 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
|
||||
case kIA32Tzcnt:
|
||||
__ Tzcnt(i.OutputRegister(), i.InputOperand(0));
|
||||
break;
|
||||
case kIA32Popcnt:
|
||||
__ Popcnt(i.OutputRegister(), i.InputOperand(0));
|
||||
break;
|
||||
case kSSEFloat32Cmp:
|
||||
__ ucomiss(i.InputDoubleRegister(0), i.InputOperand(1));
|
||||
break;
|
||||
|
@ -32,6 +32,7 @@ namespace compiler {
|
||||
V(IA32Ror) \
|
||||
V(IA32Lzcnt) \
|
||||
V(IA32Tzcnt) \
|
||||
V(IA32Popcnt) \
|
||||
V(SSEFloat32Cmp) \
|
||||
V(SSEFloat32Add) \
|
||||
V(SSEFloat32Sub) \
|
||||
|
@ -559,6 +559,12 @@ void InstructionSelector::VisitWord32Ctz(Node* node) {
|
||||
}
|
||||
|
||||
|
||||
void InstructionSelector::VisitWord32Popcnt(Node* node) {
|
||||
IA32OperandGenerator g(this);
|
||||
Emit(kIA32Popcnt, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
|
||||
}
|
||||
|
||||
|
||||
void InstructionSelector::VisitInt32Add(Node* node) {
|
||||
IA32OperandGenerator g(this);
|
||||
|
||||
@ -1365,6 +1371,9 @@ InstructionSelector::SupportedMachineOperatorFlags() {
|
||||
MachineOperatorBuilder::kFloat64Min |
|
||||
MachineOperatorBuilder::kWord32ShiftIsSafe |
|
||||
MachineOperatorBuilder::kWord32Ctz;
|
||||
if (CpuFeatures::IsSupported(POPCNT)) {
|
||||
flags |= MachineOperatorBuilder::kWord32Popcnt;
|
||||
}
|
||||
if (CpuFeatures::IsSupported(SSE4_1)) {
|
||||
flags |= MachineOperatorBuilder::kFloat64RoundDown |
|
||||
MachineOperatorBuilder::kFloat64RoundTruncate;
|
||||
|
@ -614,6 +614,8 @@ void InstructionSelector::VisitNode(Node* node) {
|
||||
return MarkAsWord32(node), VisitWord32Clz(node);
|
||||
case IrOpcode::kWord32Ctz:
|
||||
return MarkAsWord32(node), VisitWord32Ctz(node);
|
||||
case IrOpcode::kWord32Popcnt:
|
||||
return MarkAsWord32(node), VisitWord32Popcnt(node);
|
||||
case IrOpcode::kWord64And:
|
||||
return MarkAsWord64(node), VisitWord64And(node);
|
||||
case IrOpcode::kWord64Or:
|
||||
|
@ -168,6 +168,7 @@ CheckedStoreRepresentation CheckedStoreRepresentationOf(Operator const* op) {
|
||||
|
||||
#define PURE_OPTIONAL_OP_LIST(V) \
|
||||
V(Word32Ctz, Operator::kNoProperties, 1, 0, 1) \
|
||||
V(Word32Popcnt, Operator::kNoProperties, 1, 0, 1) \
|
||||
V(Float32Max, Operator::kNoProperties, 2, 0, 1) \
|
||||
V(Float32Min, Operator::kNoProperties, 2, 0, 1) \
|
||||
V(Float64Max, Operator::kNoProperties, 2, 0, 1) \
|
||||
|
@ -118,9 +118,10 @@ class MachineOperatorBuilder final : public ZoneObject {
|
||||
kUint32DivIsSafe = 1u << 8,
|
||||
kWord32ShiftIsSafe = 1u << 9,
|
||||
kWord32Ctz = 1u << 10,
|
||||
kWord32Popcnt = 1u << 11,
|
||||
kAllOptionalOps = kFloat32Max | kFloat32Min | kFloat64Max | kFloat64Min |
|
||||
kFloat64RoundDown | kFloat64RoundTruncate |
|
||||
kFloat64RoundTiesAway | kWord32Ctz
|
||||
kFloat64RoundTiesAway | kWord32Ctz | kWord32Popcnt
|
||||
};
|
||||
typedef base::Flags<Flag, unsigned> Flags;
|
||||
|
||||
@ -137,6 +138,7 @@ class MachineOperatorBuilder final : public ZoneObject {
|
||||
const Operator* Word32Equal();
|
||||
const Operator* Word32Clz();
|
||||
const OptionalOperator Word32Ctz();
|
||||
const OptionalOperator Word32Popcnt();
|
||||
bool Word32ShiftIsSafe() const { return flags_ & kWord32ShiftIsSafe; }
|
||||
|
||||
const Operator* Word64And();
|
||||
|
@ -272,6 +272,9 @@ void InstructionSelector::VisitWord32Clz(Node* node) {
|
||||
void InstructionSelector::VisitWord32Ctz(Node* node) { UNREACHABLE(); }
|
||||
|
||||
|
||||
void InstructionSelector::VisitWord32Popcnt(Node* node) { UNREACHABLE(); }
|
||||
|
||||
|
||||
void InstructionSelector::VisitInt32Add(Node* node) {
|
||||
MipsOperandGenerator g(this);
|
||||
|
||||
|
@ -324,6 +324,9 @@ void InstructionSelector::VisitWord32Clz(Node* node) {
|
||||
void InstructionSelector::VisitWord32Ctz(Node* node) { UNREACHABLE(); }
|
||||
|
||||
|
||||
void InstructionSelector::VisitWord32Popcnt(Node* node) { UNREACHABLE(); }
|
||||
|
||||
|
||||
void InstructionSelector::VisitWord64Ror(Node* node) {
|
||||
VisitRRO(this, kMips64Dror, node);
|
||||
}
|
||||
|
@ -227,6 +227,7 @@
|
||||
V(Word32Ror) \
|
||||
V(Word32Clz) \
|
||||
V(Word32Ctz) \
|
||||
V(Word32Popcnt) \
|
||||
V(Word64And) \
|
||||
V(Word64Or) \
|
||||
V(Word64Xor) \
|
||||
|
@ -740,6 +740,9 @@ void InstructionSelector::VisitWord32Clz(Node* node) {
|
||||
void InstructionSelector::VisitWord32Ctz(Node* node) { UNREACHABLE(); }
|
||||
|
||||
|
||||
void InstructionSelector::VisitWord32Popcnt(Node* node) { UNREACHABLE(); }
|
||||
|
||||
|
||||
void InstructionSelector::VisitInt32Add(Node* node) {
|
||||
VisitBinop<Int32BinopMatcher>(this, node, kPPC_Add, kInt16Imm);
|
||||
}
|
||||
|
@ -1701,6 +1701,11 @@ Type* Typer::Visitor::TypeWord32Clz(Node* node) { return Type::Integral32(); }
|
||||
Type* Typer::Visitor::TypeWord32Ctz(Node* node) { return Type::Integral32(); }
|
||||
|
||||
|
||||
Type* Typer::Visitor::TypeWord32Popcnt(Node* node) {
|
||||
return Type::Integral32();
|
||||
}
|
||||
|
||||
|
||||
Type* Typer::Visitor::TypeWord64And(Node* node) { return Type::Internal(); }
|
||||
|
||||
|
||||
|
@ -804,6 +804,7 @@ void Verifier::Visitor::Check(Node* node) {
|
||||
case IrOpcode::kWord32Equal:
|
||||
case IrOpcode::kWord32Clz:
|
||||
case IrOpcode::kWord32Ctz:
|
||||
case IrOpcode::kWord32Popcnt:
|
||||
case IrOpcode::kWord64And:
|
||||
case IrOpcode::kWord64Or:
|
||||
case IrOpcode::kWord64Xor:
|
||||
|
@ -777,6 +777,13 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
|
||||
__ Tzcntl(i.OutputRegister(), i.InputOperand(0));
|
||||
}
|
||||
break;
|
||||
case kX64Popcnt32:
|
||||
if (instr->InputAt(0)->IsRegister()) {
|
||||
__ Popcntl(i.OutputRegister(), i.InputRegister(0));
|
||||
} else {
|
||||
__ Popcntl(i.OutputRegister(), i.InputOperand(0));
|
||||
}
|
||||
break;
|
||||
case kSSEFloat32Cmp:
|
||||
ASSEMBLE_SSE_BINOP(ucomiss);
|
||||
break;
|
||||
|
@ -48,6 +48,7 @@ namespace compiler {
|
||||
V(X64Ror32) \
|
||||
V(X64Lzcnt32) \
|
||||
V(X64Tzcnt32) \
|
||||
V(X64Popcnt32) \
|
||||
V(SSEFloat32Cmp) \
|
||||
V(SSEFloat32Add) \
|
||||
V(SSEFloat32Sub) \
|
||||
|
@ -584,6 +584,12 @@ void InstructionSelector::VisitWord32Ctz(Node* node) {
|
||||
}
|
||||
|
||||
|
||||
void InstructionSelector::VisitWord32Popcnt(Node* node) {
|
||||
X64OperandGenerator g(this);
|
||||
Emit(kX64Popcnt32, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
|
||||
}
|
||||
|
||||
|
||||
void InstructionSelector::VisitInt32Add(Node* node) {
|
||||
X64OperandGenerator g(this);
|
||||
|
||||
@ -1712,6 +1718,9 @@ InstructionSelector::SupportedMachineOperatorFlags() {
|
||||
MachineOperatorBuilder::kFloat64Min |
|
||||
MachineOperatorBuilder::kWord32ShiftIsSafe |
|
||||
MachineOperatorBuilder::kWord32Ctz;
|
||||
if (CpuFeatures::IsSupported(POPCNT)) {
|
||||
flags |= MachineOperatorBuilder::kWord32Popcnt;
|
||||
}
|
||||
if (CpuFeatures::IsSupported(SSE4_1)) {
|
||||
flags |= MachineOperatorBuilder::kFloat64RoundDown |
|
||||
MachineOperatorBuilder::kFloat64RoundTruncate;
|
||||
|
@ -517,6 +517,9 @@ void InstructionSelector::VisitWord32Clz(Node* node) {
|
||||
void InstructionSelector::VisitWord32Ctz(Node* node) { UNREACHABLE(); }
|
||||
|
||||
|
||||
void InstructionSelector::VisitWord32Popcnt(Node* node) { UNREACHABLE(); }
|
||||
|
||||
|
||||
void InstructionSelector::VisitInt32Add(Node* node) {
|
||||
X87OperandGenerator g(this);
|
||||
|
||||
|
@ -2444,6 +2444,16 @@ void MacroAssembler::Tzcnt(Register dst, const Operand& src) {
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::Popcnt(Register dst, const Operand& src) {
|
||||
if (CpuFeatures::IsSupported(POPCNT)) {
|
||||
CpuFeatureScope scope(this, POPCNT);
|
||||
popcnt(dst, src);
|
||||
return;
|
||||
}
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::SetCounter(StatsCounter* counter, int value) {
|
||||
if (FLAG_native_code_counters && counter->Enabled()) {
|
||||
mov(Operand::StaticVariable(ExternalReference(counter)), Immediate(value));
|
||||
|
@ -856,6 +856,9 @@ class MacroAssembler: public Assembler {
|
||||
void Tzcnt(Register dst, Register src) { Tzcnt(dst, Operand(src)); }
|
||||
void Tzcnt(Register dst, const Operand& src);
|
||||
|
||||
void Popcnt(Register dst, Register src) { Popcnt(dst, Operand(src)); }
|
||||
void Popcnt(Register dst, const Operand& src);
|
||||
|
||||
// Emit call to the code we are currently generating.
|
||||
void CallSelf() {
|
||||
Handle<Code> self(reinterpret_cast<Code**>(CodeObject().location()));
|
||||
|
@ -2906,6 +2906,26 @@ void MacroAssembler::Tzcntl(Register dst, const Operand& src) {
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::Popcntl(Register dst, Register src) {
|
||||
if (CpuFeatures::IsSupported(POPCNT)) {
|
||||
CpuFeatureScope scope(this, POPCNT);
|
||||
popcntl(dst, src);
|
||||
return;
|
||||
}
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::Popcntl(Register dst, const Operand& src) {
|
||||
if (CpuFeatures::IsSupported(POPCNT)) {
|
||||
CpuFeatureScope scope(this, POPCNT);
|
||||
popcntl(dst, src);
|
||||
return;
|
||||
}
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::Pushad() {
|
||||
Push(rax);
|
||||
Push(rcx);
|
||||
|
@ -947,6 +947,9 @@ class MacroAssembler: public Assembler {
|
||||
void Tzcntl(Register dst, Register src);
|
||||
void Tzcntl(Register dst, const Operand& src);
|
||||
|
||||
void Popcntl(Register dst, Register src);
|
||||
void Popcntl(Register dst, const Operand& src);
|
||||
|
||||
// Non-x64 instructions.
|
||||
// Push/pop all general purpose registers.
|
||||
// Does not push rsp/rbp nor any of the assembler's special purpose registers
|
||||
|
@ -120,6 +120,29 @@ TEST(RunInt32Clz) {
|
||||
}
|
||||
|
||||
|
||||
void TestWord32Popcnt(int32_t value, int32_t expected) {
|
||||
RawMachineAssemblerTester<int32_t> m;
|
||||
compiler::OptionalOperator op = m.machine()->Word32Popcnt();
|
||||
if (op.IsSupported()) {
|
||||
Node* popcnt = m.AddNode(op.op(), m.Int32Constant(value));
|
||||
m.Return(popcnt);
|
||||
CHECK_EQ(expected, m.Call());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(RunWord32Popcnt) {
|
||||
TestWord32Popcnt(0x00000000, 0);
|
||||
TestWord32Popcnt(0x00000001, 1);
|
||||
TestWord32Popcnt(0x80000000, 1);
|
||||
TestWord32Popcnt(0xffffffff, 32);
|
||||
TestWord32Popcnt(0x000dc100, 6);
|
||||
TestWord32Popcnt(0xe00dc100, 9);
|
||||
TestWord32Popcnt(0xe00dc103, 11);
|
||||
TestWord32Popcnt(0x000dc107, 9);
|
||||
}
|
||||
|
||||
|
||||
static Node* Int32Input(RawMachineAssemblerTester<int32_t>* m, int index) {
|
||||
switch (index) {
|
||||
case 0:
|
||||
|
Loading…
Reference in New Issue
Block a user