From 084db022ef7c3bfcbdab1be6a6fb434cfa511084 Mon Sep 17 00:00:00 2001 From: "marija.antic" Date: Wed, 27 Jan 2016 06:48:47 -0800 Subject: [PATCH] MIPS:[turbofan] Implement Word32Ctz, Word64Ctz, Word32Popcnt and Word64Popcnt Implement the optional turbofan operators Word32Ctz, Word64Ctz, Word32Popcnt and Word64Popcnt. BUG= Review URL: https://codereview.chromium.org/1588383002 Cr-Commit-Position: refs/heads/master@{#33555} --- src/compiler/mips/code-generator-mips.cc | 64 +++++++++ src/compiler/mips/instruction-codes-mips.h | 2 + .../mips/instruction-selector-mips.cc | 14 +- src/compiler/mips64/code-generator-mips64.cc | 136 ++++++++++++++++++ .../mips64/instruction-codes-mips64.h | 4 + .../mips64/instruction-selector-mips64.cc | 28 +++- 6 files changed, 240 insertions(+), 8 deletions(-) diff --git a/src/compiler/mips/code-generator-mips.cc b/src/compiler/mips/code-generator-mips.cc index 75e4b9e7a8..f13f7a3d38 100644 --- a/src/compiler/mips/code-generator-mips.cc +++ b/src/compiler/mips/code-generator-mips.cc @@ -688,6 +688,70 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) { case kMipsClz: __ Clz(i.OutputRegister(), i.InputRegister(0)); break; + case kMipsCtz: { + Register reg1 = kScratchReg; + Register reg2 = kScratchReg2; + Label skip_for_zero; + Label end; + // Branch if the operand is zero + __ Branch(&skip_for_zero, eq, i.InputRegister(0), Operand(zero_reg)); + // Find the number of bits before the last bit set to 1. + __ Subu(reg2, zero_reg, i.InputRegister(0)); + __ And(reg2, reg2, i.InputRegister(0)); + __ clz(reg2, reg2); + // Get the number of bits after the last bit set to 1. + __ li(reg1, 0x1F); + __ Subu(i.OutputRegister(), reg1, reg2); + __ Branch(&end); + __ bind(&skip_for_zero); + // If the operand is zero, return word length as the result. + __ li(i.OutputRegister(), 0x20); + __ bind(&end); + } break; + case kMipsPopcnt: { + Register reg1 = kScratchReg; + Register reg2 = kScratchReg2; + uint32_t m1 = 0x55555555; + uint32_t m2 = 0x33333333; + uint32_t m4 = 0x0f0f0f0f; + uint32_t m8 = 0x00ff00ff; + uint32_t m16 = 0x0000ffff; + + // Put count of ones in every 2 bits into those 2 bits. + __ li(at, m1); + __ srl(reg1, i.InputRegister(0), 1); + __ And(reg2, i.InputRegister(0), at); + __ And(reg1, reg1, at); + __ addu(reg1, reg1, reg2); + + // Put count of ones in every 4 bits into those 4 bits. + __ li(at, m2); + __ srl(reg2, reg1, 2); + __ And(reg2, reg2, at); + __ And(reg1, reg1, at); + __ addu(reg1, reg1, reg2); + + // Put count of ones in every 8 bits into those 8 bits. + __ li(at, m4); + __ srl(reg2, reg1, 4); + __ And(reg2, reg2, at); + __ And(reg1, reg1, at); + __ addu(reg1, reg1, reg2); + + // Put count of ones in every 16 bits into those 16 bits. + __ li(at, m8); + __ srl(reg2, reg1, 8); + __ And(reg2, reg2, at); + __ And(reg1, reg1, at); + __ addu(reg1, reg1, reg2); + + // Calculate total number of ones. + __ li(at, m16); + __ srl(reg2, reg1, 16); + __ And(reg2, reg2, at); + __ And(reg1, reg1, at); + __ addu(i.OutputRegister(), reg1, reg2); + } break; case kMipsShl: if (instr->InputAt(1)->IsRegister()) { __ sllv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1)); diff --git a/src/compiler/mips/instruction-codes-mips.h b/src/compiler/mips/instruction-codes-mips.h index c9381775c8..f0ea463774 100644 --- a/src/compiler/mips/instruction-codes-mips.h +++ b/src/compiler/mips/instruction-codes-mips.h @@ -28,6 +28,8 @@ namespace compiler { V(MipsNor) \ V(MipsXor) \ V(MipsClz) \ + V(MipsCtz) \ + V(MipsPopcnt) \ V(MipsShl) \ V(MipsShr) \ V(MipsSar) \ diff --git a/src/compiler/mips/instruction-selector-mips.cc b/src/compiler/mips/instruction-selector-mips.cc index 8651bbb124..fba154779d 100644 --- a/src/compiler/mips/instruction-selector-mips.cc +++ b/src/compiler/mips/instruction-selector-mips.cc @@ -401,10 +401,16 @@ void InstructionSelector::VisitWord32Clz(Node* node) { } -void InstructionSelector::VisitWord32Ctz(Node* node) { UNREACHABLE(); } +void InstructionSelector::VisitWord32Ctz(Node* node) { + MipsOperandGenerator g(this); + Emit(kMipsCtz, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0))); +} -void InstructionSelector::VisitWord32Popcnt(Node* node) { UNREACHABLE(); } +void InstructionSelector::VisitWord32Popcnt(Node* node) { + MipsOperandGenerator g(this); + Emit(kMipsPopcnt, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0))); +} void InstructionSelector::VisitInt32Add(Node* node) { @@ -1328,7 +1334,9 @@ InstructionSelector::SupportedMachineOperatorFlags() { MachineOperatorBuilder::kFloat64RoundTruncate | MachineOperatorBuilder::kFloat64RoundTiesEven; } - return flags | MachineOperatorBuilder::kInt32DivIsSafe | + return flags | MachineOperatorBuilder::kWord32Ctz | + MachineOperatorBuilder::kWord32Popcnt | + MachineOperatorBuilder::kInt32DivIsSafe | MachineOperatorBuilder::kUint32DivIsSafe | MachineOperatorBuilder::kWord32ShiftIsSafe | MachineOperatorBuilder::kFloat64Min | diff --git a/src/compiler/mips64/code-generator-mips64.cc b/src/compiler/mips64/code-generator-mips64.cc index 1b81aa5698..f30a0a0a7f 100644 --- a/src/compiler/mips64/code-generator-mips64.cc +++ b/src/compiler/mips64/code-generator-mips64.cc @@ -735,6 +735,142 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) { case kMips64Dclz: __ dclz(i.OutputRegister(), i.InputRegister(0)); break; + case kMips64Ctz: { + Register reg1 = kScratchReg; + Register reg2 = kScratchReg2; + Label skip_for_zero; + Label end; + // Branch if the operand is zero + __ Branch(&skip_for_zero, eq, i.InputRegister(0), Operand(zero_reg)); + // Find the number of bits before the last bit set to 1. + __ Subu(reg2, zero_reg, i.InputRegister(0)); + __ And(reg2, reg2, i.InputRegister(0)); + __ clz(reg2, reg2); + // Get the number of bits after the last bit set to 1. + __ li(reg1, 0x1F); + __ Subu(i.OutputRegister(), reg1, reg2); + __ Branch(&end); + __ bind(&skip_for_zero); + // If the operand is zero, return word length as the result. + __ li(i.OutputRegister(), 0x20); + __ bind(&end); + } break; + case kMips64Dctz: { + Register reg1 = kScratchReg; + Register reg2 = kScratchReg2; + Label skip_for_zero; + Label end; + // Branch if the operand is zero + __ Branch(&skip_for_zero, eq, i.InputRegister(0), Operand(zero_reg)); + // Find the number of bits before the last bit set to 1. + __ Dsubu(reg2, zero_reg, i.InputRegister(0)); + __ And(reg2, reg2, i.InputRegister(0)); + __ dclz(reg2, reg2); + // Get the number of bits after the last bit set to 1. + __ li(reg1, 0x3F); + __ Subu(i.OutputRegister(), reg1, reg2); + __ Branch(&end); + __ bind(&skip_for_zero); + // If the operand is zero, return word length as the result. + __ li(i.OutputRegister(), 0x40); + __ bind(&end); + } break; + case kMips64Popcnt: { + Register reg1 = kScratchReg; + Register reg2 = kScratchReg2; + uint32_t m1 = 0x55555555; + uint32_t m2 = 0x33333333; + uint32_t m4 = 0x0f0f0f0f; + uint32_t m8 = 0x00ff00ff; + uint32_t m16 = 0x0000ffff; + + // Put count of ones in every 2 bits into those 2 bits. + __ li(at, m1); + __ dsrl(reg1, i.InputRegister(0), 1); + __ And(reg2, i.InputRegister(0), at); + __ And(reg1, reg1, at); + __ Daddu(reg1, reg1, reg2); + + // Put count of ones in every 4 bits into those 4 bits. + __ li(at, m2); + __ dsrl(reg2, reg1, 2); + __ And(reg2, reg2, at); + __ And(reg1, reg1, at); + __ Daddu(reg1, reg1, reg2); + + // Put count of ones in every 8 bits into those 8 bits. + __ li(at, m4); + __ dsrl(reg2, reg1, 4); + __ And(reg2, reg2, at); + __ And(reg1, reg1, at); + __ Daddu(reg1, reg1, reg2); + + // Put count of ones in every 16 bits into those 16 bits. + __ li(at, m8); + __ dsrl(reg2, reg1, 8); + __ And(reg2, reg2, at); + __ And(reg1, reg1, at); + __ Daddu(reg1, reg1, reg2); + + // Calculate total number of ones. + __ li(at, m16); + __ dsrl(reg2, reg1, 16); + __ And(reg2, reg2, at); + __ And(reg1, reg1, at); + __ Daddu(i.OutputRegister(), reg1, reg2); + } break; + case kMips64Dpopcnt: { + Register reg1 = kScratchReg; + Register reg2 = kScratchReg2; + uint64_t m1 = 0x5555555555555555; + uint64_t m2 = 0x3333333333333333; + uint64_t m4 = 0x0f0f0f0f0f0f0f0f; + uint64_t m8 = 0x00ff00ff00ff00ff; + uint64_t m16 = 0x0000ffff0000ffff; + uint64_t m32 = 0x00000000ffffffff; + + // Put count of ones in every 2 bits into those 2 bits. + __ li(at, m1); + __ dsrl(reg1, i.InputRegister(0), 1); + __ and_(reg2, i.InputRegister(0), at); + __ and_(reg1, reg1, at); + __ Daddu(reg1, reg1, reg2); + + // Put count of ones in every 4 bits into those 4 bits. + __ li(at, m2); + __ dsrl(reg2, reg1, 2); + __ and_(reg2, reg2, at); + __ and_(reg1, reg1, at); + __ Daddu(reg1, reg1, reg2); + + // Put count of ones in every 8 bits into those 8 bits. + __ li(at, m4); + __ dsrl(reg2, reg1, 4); + __ and_(reg2, reg2, at); + __ and_(reg1, reg1, at); + __ Daddu(reg1, reg1, reg2); + + // Put count of ones in every 16 bits into those 16 bits. + __ li(at, m8); + __ dsrl(reg2, reg1, 8); + __ and_(reg2, reg2, at); + __ and_(reg1, reg1, at); + __ Daddu(reg1, reg1, reg2); + + // Put count of ones in every 32 bits into those 32 bits. + __ li(at, m16); + __ dsrl(reg2, reg1, 16); + __ and_(reg2, reg2, at); + __ and_(reg1, reg1, at); + __ Daddu(reg1, reg1, reg2); + + // Calculate total number of ones. + __ li(at, m32); + __ dsrl32(reg2, reg1, 0); + __ and_(reg2, reg2, at); + __ and_(reg1, reg1, at); + __ Daddu(i.OutputRegister(), reg1, reg2); + } break; case kMips64Shl: if (instr->InputAt(1)->IsRegister()) { __ sllv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1)); diff --git a/src/compiler/mips64/instruction-codes-mips64.h b/src/compiler/mips64/instruction-codes-mips64.h index 778c6add0f..fbff3d78a3 100644 --- a/src/compiler/mips64/instruction-codes-mips64.h +++ b/src/compiler/mips64/instruction-codes-mips64.h @@ -44,6 +44,10 @@ namespace compiler { V(Mips64Dext) \ V(Mips64Dins) \ V(Mips64Dclz) \ + V(Mips64Ctz) \ + V(Mips64Dctz) \ + V(Mips64Popcnt) \ + V(Mips64Dpopcnt) \ V(Mips64Dshl) \ V(Mips64Dshr) \ V(Mips64Dsar) \ diff --git a/src/compiler/mips64/instruction-selector-mips64.cc b/src/compiler/mips64/instruction-selector-mips64.cc index 2997809b5d..5bfb42eb61 100644 --- a/src/compiler/mips64/instruction-selector-mips64.cc +++ b/src/compiler/mips64/instruction-selector-mips64.cc @@ -562,16 +562,30 @@ void InstructionSelector::VisitWord32Clz(Node* node) { } -void InstructionSelector::VisitWord32Ctz(Node* node) { UNREACHABLE(); } +void InstructionSelector::VisitWord32Ctz(Node* node) { + Mips64OperandGenerator g(this); + Emit(kMips64Ctz, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0))); +} -void InstructionSelector::VisitWord64Ctz(Node* node) { UNREACHABLE(); } +void InstructionSelector::VisitWord64Ctz(Node* node) { + Mips64OperandGenerator g(this); + Emit(kMips64Dctz, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0))); +} -void InstructionSelector::VisitWord32Popcnt(Node* node) { UNREACHABLE(); } +void InstructionSelector::VisitWord32Popcnt(Node* node) { + Mips64OperandGenerator g(this); + Emit(kMips64Popcnt, g.DefineAsRegister(node), + g.UseRegister(node->InputAt(0))); +} -void InstructionSelector::VisitWord64Popcnt(Node* node) { UNREACHABLE(); } +void InstructionSelector::VisitWord64Popcnt(Node* node) { + Mips64OperandGenerator g(this); + Emit(kMips64Dpopcnt, g.DefineAsRegister(node), + g.UseRegister(node->InputAt(0))); +} void InstructionSelector::VisitWord64Ror(Node* node) { @@ -1856,7 +1870,11 @@ void InstructionSelector::VisitFloat64InsertHighWord32(Node* node) { // static MachineOperatorBuilder::Flags InstructionSelector::SupportedMachineOperatorFlags() { - return MachineOperatorBuilder::kWord32ShiftIsSafe | + return MachineOperatorBuilder::kWord32Ctz | + MachineOperatorBuilder::kWord64Ctz | + MachineOperatorBuilder::kWord32Popcnt | + MachineOperatorBuilder::kWord64Popcnt | + MachineOperatorBuilder::kWord32ShiftIsSafe | MachineOperatorBuilder::kInt32DivIsSafe | MachineOperatorBuilder::kUint32DivIsSafe | MachineOperatorBuilder::kFloat64Min |