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}
This commit is contained in:
parent
bf55c87ac8
commit
084db022ef
@ -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));
|
||||
|
@ -28,6 +28,8 @@ namespace compiler {
|
||||
V(MipsNor) \
|
||||
V(MipsXor) \
|
||||
V(MipsClz) \
|
||||
V(MipsCtz) \
|
||||
V(MipsPopcnt) \
|
||||
V(MipsShl) \
|
||||
V(MipsShr) \
|
||||
V(MipsSar) \
|
||||
|
@ -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 |
|
||||
|
@ -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));
|
||||
|
@ -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) \
|
||||
|
@ -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 |
|
||||
|
Loading…
Reference in New Issue
Block a user