Commit 053e280c authored by ahaas's avatar ahaas Committed by Commit bot

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}
parent 13d783d7
...@@ -700,6 +700,9 @@ void InstructionSelector::VisitWord32Clz(Node* node) { ...@@ -700,6 +700,9 @@ void InstructionSelector::VisitWord32Clz(Node* node) {
void InstructionSelector::VisitWord32Ctz(Node* node) { UNREACHABLE(); } void InstructionSelector::VisitWord32Ctz(Node* node) { UNREACHABLE(); }
void InstructionSelector::VisitWord32Popcnt(Node* node) { UNREACHABLE(); }
void InstructionSelector::VisitInt32Add(Node* node) { void InstructionSelector::VisitInt32Add(Node* node) {
ArmOperandGenerator g(this); ArmOperandGenerator g(this);
Int32BinopMatcher m(node); Int32BinopMatcher m(node);
......
...@@ -930,6 +930,9 @@ void InstructionSelector::VisitWord32Clz(Node* node) { ...@@ -930,6 +930,9 @@ void InstructionSelector::VisitWord32Clz(Node* node) {
void InstructionSelector::VisitWord32Ctz(Node* node) { UNREACHABLE(); } void InstructionSelector::VisitWord32Ctz(Node* node) { UNREACHABLE(); }
void InstructionSelector::VisitWord32Popcnt(Node* node) { UNREACHABLE(); }
void InstructionSelector::VisitInt32Add(Node* node) { void InstructionSelector::VisitInt32Add(Node* node) {
Arm64OperandGenerator g(this); Arm64OperandGenerator g(this);
Int32BinopMatcher m(node); Int32BinopMatcher m(node);
......
...@@ -512,6 +512,9 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) { ...@@ -512,6 +512,9 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
case kIA32Tzcnt: case kIA32Tzcnt:
__ Tzcnt(i.OutputRegister(), i.InputOperand(0)); __ Tzcnt(i.OutputRegister(), i.InputOperand(0));
break; break;
case kIA32Popcnt:
__ Popcnt(i.OutputRegister(), i.InputOperand(0));
break;
case kSSEFloat32Cmp: case kSSEFloat32Cmp:
__ ucomiss(i.InputDoubleRegister(0), i.InputOperand(1)); __ ucomiss(i.InputDoubleRegister(0), i.InputOperand(1));
break; break;
......
...@@ -32,6 +32,7 @@ namespace compiler { ...@@ -32,6 +32,7 @@ namespace compiler {
V(IA32Ror) \ V(IA32Ror) \
V(IA32Lzcnt) \ V(IA32Lzcnt) \
V(IA32Tzcnt) \ V(IA32Tzcnt) \
V(IA32Popcnt) \
V(SSEFloat32Cmp) \ V(SSEFloat32Cmp) \
V(SSEFloat32Add) \ V(SSEFloat32Add) \
V(SSEFloat32Sub) \ V(SSEFloat32Sub) \
......
...@@ -559,6 +559,12 @@ void InstructionSelector::VisitWord32Ctz(Node* node) { ...@@ -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) { void InstructionSelector::VisitInt32Add(Node* node) {
IA32OperandGenerator g(this); IA32OperandGenerator g(this);
...@@ -1365,6 +1371,9 @@ InstructionSelector::SupportedMachineOperatorFlags() { ...@@ -1365,6 +1371,9 @@ InstructionSelector::SupportedMachineOperatorFlags() {
MachineOperatorBuilder::kFloat64Min | MachineOperatorBuilder::kFloat64Min |
MachineOperatorBuilder::kWord32ShiftIsSafe | MachineOperatorBuilder::kWord32ShiftIsSafe |
MachineOperatorBuilder::kWord32Ctz; MachineOperatorBuilder::kWord32Ctz;
if (CpuFeatures::IsSupported(POPCNT)) {
flags |= MachineOperatorBuilder::kWord32Popcnt;
}
if (CpuFeatures::IsSupported(SSE4_1)) { if (CpuFeatures::IsSupported(SSE4_1)) {
flags |= MachineOperatorBuilder::kFloat64RoundDown | flags |= MachineOperatorBuilder::kFloat64RoundDown |
MachineOperatorBuilder::kFloat64RoundTruncate; MachineOperatorBuilder::kFloat64RoundTruncate;
......
...@@ -614,6 +614,8 @@ void InstructionSelector::VisitNode(Node* node) { ...@@ -614,6 +614,8 @@ void InstructionSelector::VisitNode(Node* node) {
return MarkAsWord32(node), VisitWord32Clz(node); return MarkAsWord32(node), VisitWord32Clz(node);
case IrOpcode::kWord32Ctz: case IrOpcode::kWord32Ctz:
return MarkAsWord32(node), VisitWord32Ctz(node); return MarkAsWord32(node), VisitWord32Ctz(node);
case IrOpcode::kWord32Popcnt:
return MarkAsWord32(node), VisitWord32Popcnt(node);
case IrOpcode::kWord64And: case IrOpcode::kWord64And:
return MarkAsWord64(node), VisitWord64And(node); return MarkAsWord64(node), VisitWord64And(node);
case IrOpcode::kWord64Or: case IrOpcode::kWord64Or:
......
...@@ -168,6 +168,7 @@ CheckedStoreRepresentation CheckedStoreRepresentationOf(Operator const* op) { ...@@ -168,6 +168,7 @@ CheckedStoreRepresentation CheckedStoreRepresentationOf(Operator const* op) {
#define PURE_OPTIONAL_OP_LIST(V) \ #define PURE_OPTIONAL_OP_LIST(V) \
V(Word32Ctz, Operator::kNoProperties, 1, 0, 1) \ V(Word32Ctz, Operator::kNoProperties, 1, 0, 1) \
V(Word32Popcnt, Operator::kNoProperties, 1, 0, 1) \
V(Float32Max, Operator::kNoProperties, 2, 0, 1) \ V(Float32Max, Operator::kNoProperties, 2, 0, 1) \
V(Float32Min, Operator::kNoProperties, 2, 0, 1) \ V(Float32Min, Operator::kNoProperties, 2, 0, 1) \
V(Float64Max, Operator::kNoProperties, 2, 0, 1) \ V(Float64Max, Operator::kNoProperties, 2, 0, 1) \
......
...@@ -118,9 +118,10 @@ class MachineOperatorBuilder final : public ZoneObject { ...@@ -118,9 +118,10 @@ class MachineOperatorBuilder final : public ZoneObject {
kUint32DivIsSafe = 1u << 8, kUint32DivIsSafe = 1u << 8,
kWord32ShiftIsSafe = 1u << 9, kWord32ShiftIsSafe = 1u << 9,
kWord32Ctz = 1u << 10, kWord32Ctz = 1u << 10,
kWord32Popcnt = 1u << 11,
kAllOptionalOps = kFloat32Max | kFloat32Min | kFloat64Max | kFloat64Min | kAllOptionalOps = kFloat32Max | kFloat32Min | kFloat64Max | kFloat64Min |
kFloat64RoundDown | kFloat64RoundTruncate | kFloat64RoundDown | kFloat64RoundTruncate |
kFloat64RoundTiesAway | kWord32Ctz kFloat64RoundTiesAway | kWord32Ctz | kWord32Popcnt
}; };
typedef base::Flags<Flag, unsigned> Flags; typedef base::Flags<Flag, unsigned> Flags;
...@@ -137,6 +138,7 @@ class MachineOperatorBuilder final : public ZoneObject { ...@@ -137,6 +138,7 @@ class MachineOperatorBuilder final : public ZoneObject {
const Operator* Word32Equal(); const Operator* Word32Equal();
const Operator* Word32Clz(); const Operator* Word32Clz();
const OptionalOperator Word32Ctz(); const OptionalOperator Word32Ctz();
const OptionalOperator Word32Popcnt();
bool Word32ShiftIsSafe() const { return flags_ & kWord32ShiftIsSafe; } bool Word32ShiftIsSafe() const { return flags_ & kWord32ShiftIsSafe; }
const Operator* Word64And(); const Operator* Word64And();
......
...@@ -272,6 +272,9 @@ void InstructionSelector::VisitWord32Clz(Node* node) { ...@@ -272,6 +272,9 @@ void InstructionSelector::VisitWord32Clz(Node* node) {
void InstructionSelector::VisitWord32Ctz(Node* node) { UNREACHABLE(); } void InstructionSelector::VisitWord32Ctz(Node* node) { UNREACHABLE(); }
void InstructionSelector::VisitWord32Popcnt(Node* node) { UNREACHABLE(); }
void InstructionSelector::VisitInt32Add(Node* node) { void InstructionSelector::VisitInt32Add(Node* node) {
MipsOperandGenerator g(this); MipsOperandGenerator g(this);
......
...@@ -324,6 +324,9 @@ void InstructionSelector::VisitWord32Clz(Node* node) { ...@@ -324,6 +324,9 @@ void InstructionSelector::VisitWord32Clz(Node* node) {
void InstructionSelector::VisitWord32Ctz(Node* node) { UNREACHABLE(); } void InstructionSelector::VisitWord32Ctz(Node* node) { UNREACHABLE(); }
void InstructionSelector::VisitWord32Popcnt(Node* node) { UNREACHABLE(); }
void InstructionSelector::VisitWord64Ror(Node* node) { void InstructionSelector::VisitWord64Ror(Node* node) {
VisitRRO(this, kMips64Dror, node); VisitRRO(this, kMips64Dror, node);
} }
......
...@@ -227,6 +227,7 @@ ...@@ -227,6 +227,7 @@
V(Word32Ror) \ V(Word32Ror) \
V(Word32Clz) \ V(Word32Clz) \
V(Word32Ctz) \ V(Word32Ctz) \
V(Word32Popcnt) \
V(Word64And) \ V(Word64And) \
V(Word64Or) \ V(Word64Or) \
V(Word64Xor) \ V(Word64Xor) \
......
...@@ -740,6 +740,9 @@ void InstructionSelector::VisitWord32Clz(Node* node) { ...@@ -740,6 +740,9 @@ void InstructionSelector::VisitWord32Clz(Node* node) {
void InstructionSelector::VisitWord32Ctz(Node* node) { UNREACHABLE(); } void InstructionSelector::VisitWord32Ctz(Node* node) { UNREACHABLE(); }
void InstructionSelector::VisitWord32Popcnt(Node* node) { UNREACHABLE(); }
void InstructionSelector::VisitInt32Add(Node* node) { void InstructionSelector::VisitInt32Add(Node* node) {
VisitBinop<Int32BinopMatcher>(this, node, kPPC_Add, kInt16Imm); VisitBinop<Int32BinopMatcher>(this, node, kPPC_Add, kInt16Imm);
} }
......
...@@ -1701,6 +1701,11 @@ Type* Typer::Visitor::TypeWord32Clz(Node* node) { return Type::Integral32(); } ...@@ -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::TypeWord32Ctz(Node* node) { return Type::Integral32(); }
Type* Typer::Visitor::TypeWord32Popcnt(Node* node) {
return Type::Integral32();
}
Type* Typer::Visitor::TypeWord64And(Node* node) { return Type::Internal(); } Type* Typer::Visitor::TypeWord64And(Node* node) { return Type::Internal(); }
......
...@@ -804,6 +804,7 @@ void Verifier::Visitor::Check(Node* node) { ...@@ -804,6 +804,7 @@ void Verifier::Visitor::Check(Node* node) {
case IrOpcode::kWord32Equal: case IrOpcode::kWord32Equal:
case IrOpcode::kWord32Clz: case IrOpcode::kWord32Clz:
case IrOpcode::kWord32Ctz: case IrOpcode::kWord32Ctz:
case IrOpcode::kWord32Popcnt:
case IrOpcode::kWord64And: case IrOpcode::kWord64And:
case IrOpcode::kWord64Or: case IrOpcode::kWord64Or:
case IrOpcode::kWord64Xor: case IrOpcode::kWord64Xor:
......
...@@ -777,6 +777,13 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) { ...@@ -777,6 +777,13 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
__ Tzcntl(i.OutputRegister(), i.InputOperand(0)); __ Tzcntl(i.OutputRegister(), i.InputOperand(0));
} }
break; break;
case kX64Popcnt32:
if (instr->InputAt(0)->IsRegister()) {
__ Popcntl(i.OutputRegister(), i.InputRegister(0));
} else {
__ Popcntl(i.OutputRegister(), i.InputOperand(0));
}
break;
case kSSEFloat32Cmp: case kSSEFloat32Cmp:
ASSEMBLE_SSE_BINOP(ucomiss); ASSEMBLE_SSE_BINOP(ucomiss);
break; break;
......
...@@ -48,6 +48,7 @@ namespace compiler { ...@@ -48,6 +48,7 @@ namespace compiler {
V(X64Ror32) \ V(X64Ror32) \
V(X64Lzcnt32) \ V(X64Lzcnt32) \
V(X64Tzcnt32) \ V(X64Tzcnt32) \
V(X64Popcnt32) \
V(SSEFloat32Cmp) \ V(SSEFloat32Cmp) \
V(SSEFloat32Add) \ V(SSEFloat32Add) \
V(SSEFloat32Sub) \ V(SSEFloat32Sub) \
......
...@@ -584,6 +584,12 @@ void InstructionSelector::VisitWord32Ctz(Node* node) { ...@@ -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) { void InstructionSelector::VisitInt32Add(Node* node) {
X64OperandGenerator g(this); X64OperandGenerator g(this);
...@@ -1712,6 +1718,9 @@ InstructionSelector::SupportedMachineOperatorFlags() { ...@@ -1712,6 +1718,9 @@ InstructionSelector::SupportedMachineOperatorFlags() {
MachineOperatorBuilder::kFloat64Min | MachineOperatorBuilder::kFloat64Min |
MachineOperatorBuilder::kWord32ShiftIsSafe | MachineOperatorBuilder::kWord32ShiftIsSafe |
MachineOperatorBuilder::kWord32Ctz; MachineOperatorBuilder::kWord32Ctz;
if (CpuFeatures::IsSupported(POPCNT)) {
flags |= MachineOperatorBuilder::kWord32Popcnt;
}
if (CpuFeatures::IsSupported(SSE4_1)) { if (CpuFeatures::IsSupported(SSE4_1)) {
flags |= MachineOperatorBuilder::kFloat64RoundDown | flags |= MachineOperatorBuilder::kFloat64RoundDown |
MachineOperatorBuilder::kFloat64RoundTruncate; MachineOperatorBuilder::kFloat64RoundTruncate;
......
...@@ -517,6 +517,9 @@ void InstructionSelector::VisitWord32Clz(Node* node) { ...@@ -517,6 +517,9 @@ void InstructionSelector::VisitWord32Clz(Node* node) {
void InstructionSelector::VisitWord32Ctz(Node* node) { UNREACHABLE(); } void InstructionSelector::VisitWord32Ctz(Node* node) { UNREACHABLE(); }
void InstructionSelector::VisitWord32Popcnt(Node* node) { UNREACHABLE(); }
void InstructionSelector::VisitInt32Add(Node* node) { void InstructionSelector::VisitInt32Add(Node* node) {
X87OperandGenerator g(this); X87OperandGenerator g(this);
......
...@@ -2444,6 +2444,16 @@ void MacroAssembler::Tzcnt(Register dst, const Operand& src) { ...@@ -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) { void MacroAssembler::SetCounter(StatsCounter* counter, int value) {
if (FLAG_native_code_counters && counter->Enabled()) { if (FLAG_native_code_counters && counter->Enabled()) {
mov(Operand::StaticVariable(ExternalReference(counter)), Immediate(value)); mov(Operand::StaticVariable(ExternalReference(counter)), Immediate(value));
......
...@@ -856,6 +856,9 @@ class MacroAssembler: public Assembler { ...@@ -856,6 +856,9 @@ class MacroAssembler: public Assembler {
void Tzcnt(Register dst, Register src) { Tzcnt(dst, Operand(src)); } void Tzcnt(Register dst, Register src) { Tzcnt(dst, Operand(src)); }
void Tzcnt(Register dst, const 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. // Emit call to the code we are currently generating.
void CallSelf() { void CallSelf() {
Handle<Code> self(reinterpret_cast<Code**>(CodeObject().location())); Handle<Code> self(reinterpret_cast<Code**>(CodeObject().location()));
......
...@@ -2906,6 +2906,26 @@ void MacroAssembler::Tzcntl(Register dst, const Operand& src) { ...@@ -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() { void MacroAssembler::Pushad() {
Push(rax); Push(rax);
Push(rcx); Push(rcx);
......
...@@ -947,6 +947,9 @@ class MacroAssembler: public Assembler { ...@@ -947,6 +947,9 @@ class MacroAssembler: public Assembler {
void Tzcntl(Register dst, Register src); void Tzcntl(Register dst, Register src);
void Tzcntl(Register dst, const Operand& src); void Tzcntl(Register dst, const Operand& src);
void Popcntl(Register dst, Register src);
void Popcntl(Register dst, const Operand& src);
// Non-x64 instructions. // Non-x64 instructions.
// Push/pop all general purpose registers. // Push/pop all general purpose registers.
// Does not push rsp/rbp nor any of the assembler's special purpose registers // Does not push rsp/rbp nor any of the assembler's special purpose registers
......
...@@ -120,6 +120,29 @@ TEST(RunInt32Clz) { ...@@ -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) { static Node* Int32Input(RawMachineAssemblerTester<int32_t>* m, int index) {
switch (index) { switch (index) {
case 0: case 0:
......
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