Commit 2d0e9abe authored by dusan.m.milosavljevic's avatar dusan.m.milosavljevic Committed by Commit bot

MIPS:[turbofan] Use Ins, Dins to clear bits instead of And with inverted immediate.

TEST=unittests/InstructionSelectorTest.Word(32|64)AndToClearBits
BUG=

Review URL: https://codereview.chromium.org/1485023004

Cr-Commit-Position: refs/heads/master@{#32479}
parent 6b11cc83
...@@ -706,6 +706,14 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) { ...@@ -706,6 +706,14 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
__ Ext(i.OutputRegister(), i.InputRegister(0), i.InputInt8(1), __ Ext(i.OutputRegister(), i.InputRegister(0), i.InputInt8(1),
i.InputInt8(2)); i.InputInt8(2));
break; break;
case kMipsIns:
if (instr->InputAt(1)->IsImmediate() && i.InputInt8(1) == 0) {
__ Ins(i.OutputRegister(), zero_reg, i.InputInt8(1), i.InputInt8(2));
} else {
__ Ins(i.OutputRegister(), i.InputRegister(0), i.InputInt8(1),
i.InputInt8(2));
}
break;
case kMipsRor: case kMipsRor:
__ Ror(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1)); __ Ror(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
break; break;
......
...@@ -32,6 +32,7 @@ namespace compiler { ...@@ -32,6 +32,7 @@ namespace compiler {
V(MipsShr) \ V(MipsShr) \
V(MipsSar) \ V(MipsSar) \
V(MipsExt) \ V(MipsExt) \
V(MipsIns) \
V(MipsRor) \ V(MipsRor) \
V(MipsMov) \ V(MipsMov) \
V(MipsTst) \ V(MipsTst) \
......
...@@ -284,6 +284,18 @@ void InstructionSelector::VisitWord32And(Node* node) { ...@@ -284,6 +284,18 @@ void InstructionSelector::VisitWord32And(Node* node) {
// Other cases fall through to the normal And operation. // Other cases fall through to the normal And operation.
} }
} }
if (m.right().HasValue()) {
uint32_t mask = m.right().Value();
uint32_t shift = base::bits::CountPopulation32(~mask);
uint32_t msb = base::bits::CountLeadingZeros32(~mask);
if (shift != 0 && shift != 32 && msb + shift == 32) {
// Insert zeros for (x >> K) << K => x & ~(2^K - 1) expression reduction
// and remove constant loading of invereted mask.
Emit(kMipsIns, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()),
g.TempImmediate(0), g.TempImmediate(shift));
return;
}
}
VisitBinop(this, node, kMipsAnd); VisitBinop(this, node, kMipsAnd);
} }
......
...@@ -725,10 +725,26 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) { ...@@ -725,10 +725,26 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
__ Ext(i.OutputRegister(), i.InputRegister(0), i.InputInt8(1), __ Ext(i.OutputRegister(), i.InputRegister(0), i.InputInt8(1),
i.InputInt8(2)); i.InputInt8(2));
break; break;
case kMips64Ins:
if (instr->InputAt(1)->IsImmediate() && i.InputInt8(1) == 0) {
__ Ins(i.OutputRegister(), zero_reg, i.InputInt8(1), i.InputInt8(2));
} else {
__ Ins(i.OutputRegister(), i.InputRegister(0), i.InputInt8(1),
i.InputInt8(2));
}
break;
case kMips64Dext: case kMips64Dext:
__ Dext(i.OutputRegister(), i.InputRegister(0), i.InputInt8(1), __ Dext(i.OutputRegister(), i.InputRegister(0), i.InputInt8(1),
i.InputInt8(2)); i.InputInt8(2));
break; break;
case kMips64Dins:
if (instr->InputAt(1)->IsImmediate() && i.InputInt8(1) == 0) {
__ Dins(i.OutputRegister(), zero_reg, i.InputInt8(1), i.InputInt8(2));
} else {
__ Dins(i.OutputRegister(), i.InputRegister(0), i.InputInt8(1),
i.InputInt8(2));
}
break;
case kMips64Dshl: case kMips64Dshl:
if (instr->InputAt(1)->IsRegister()) { if (instr->InputAt(1)->IsRegister()) {
__ dsllv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1)); __ dsllv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
......
...@@ -38,7 +38,9 @@ namespace compiler { ...@@ -38,7 +38,9 @@ namespace compiler {
V(Mips64Shr) \ V(Mips64Shr) \
V(Mips64Sar) \ V(Mips64Sar) \
V(Mips64Ext) \ V(Mips64Ext) \
V(Mips64Ins) \
V(Mips64Dext) \ V(Mips64Dext) \
V(Mips64Dins) \
V(Mips64Dclz) \ V(Mips64Dclz) \
V(Mips64Dshl) \ V(Mips64Dshl) \
V(Mips64Dshr) \ V(Mips64Dshr) \
......
...@@ -295,6 +295,19 @@ void InstructionSelector::VisitWord32And(Node* node) { ...@@ -295,6 +295,19 @@ void InstructionSelector::VisitWord32And(Node* node) {
// Other cases fall through to the normal And operation. // Other cases fall through to the normal And operation.
} }
} }
if (m.right().HasValue()) {
uint32_t mask = m.right().Value();
uint32_t shift = base::bits::CountPopulation32(~mask);
uint32_t msb = base::bits::CountLeadingZeros32(~mask);
if (shift != 0 && shift != 32 && msb + shift == 32) {
// Insert zeros for (x >> K) << K => x & ~(2^K - 1) expression reduction
// and remove constant loading of inverted mask.
Emit(kMips64Ins, g.DefineSameAsFirst(node),
g.UseRegister(m.left().node()), g.TempImmediate(0),
g.TempImmediate(shift));
return;
}
}
VisitBinop(this, node, kMips64And); VisitBinop(this, node, kMips64And);
} }
...@@ -332,6 +345,20 @@ void InstructionSelector::VisitWord64And(Node* node) { ...@@ -332,6 +345,20 @@ void InstructionSelector::VisitWord64And(Node* node) {
// Other cases fall through to the normal And operation. // Other cases fall through to the normal And operation.
} }
} }
if (m.right().HasValue()) {
uint64_t mask = m.right().Value();
uint32_t shift = base::bits::CountPopulation64(~mask);
uint32_t msb = base::bits::CountLeadingZeros64(~mask);
if (shift != 0 && shift < 32 && msb + shift == 64) {
// Insert zeros for (x >> K) << K => x & ~(2^K - 1) expression reduction
// and remove constant loading of inverted mask. Dins cannot insert bits
// past word size, so shifts smaller than 32 are covered.
Emit(kMips64Dins, g.DefineSameAsFirst(node),
g.UseRegister(m.left().node()), g.TempImmediate(0),
g.TempImmediate(shift));
return;
}
}
VisitBinop(this, node, kMips64And); VisitBinop(this, node, kMips64And);
} }
......
...@@ -2312,6 +2312,14 @@ void Assembler::ins_(Register rt, Register rs, uint16_t pos, uint16_t size) { ...@@ -2312,6 +2312,14 @@ void Assembler::ins_(Register rt, Register rs, uint16_t pos, uint16_t size) {
} }
void Assembler::dins_(Register rt, Register rs, uint16_t pos, uint16_t size) {
// Should be called via MacroAssembler::Dins.
// Dext instr has 'rt' field as dest, and two uint5: msb, lsb.
DCHECK(kArchVariant == kMips64r2 || kArchVariant == kMips64r6);
GenInstrRegister(SPECIAL3, rs, rt, pos + size - 1, pos, DINS);
}
void Assembler::ext_(Register rt, Register rs, uint16_t pos, uint16_t size) { void Assembler::ext_(Register rt, Register rs, uint16_t pos, uint16_t size) {
// Should be called via MacroAssembler::Ext. // Should be called via MacroAssembler::Ext.
// Ext instr has 'rt' field as dest, and two uint5: msb, lsb. // Ext instr has 'rt' field as dest, and two uint5: msb, lsb.
...@@ -2321,7 +2329,7 @@ void Assembler::ext_(Register rt, Register rs, uint16_t pos, uint16_t size) { ...@@ -2321,7 +2329,7 @@ void Assembler::ext_(Register rt, Register rs, uint16_t pos, uint16_t size) {
void Assembler::dext_(Register rt, Register rs, uint16_t pos, uint16_t size) { void Assembler::dext_(Register rt, Register rs, uint16_t pos, uint16_t size) {
// Should be called via MacroAssembler::Ext. // Should be called via MacroAssembler::Dext.
// Dext instr has 'rt' field as dest, and two uint5: msb, lsb. // Dext instr has 'rt' field as dest, and two uint5: msb, lsb.
DCHECK(kArchVariant == kMips64r2 || kArchVariant == kMips64r6); DCHECK(kArchVariant == kMips64r2 || kArchVariant == kMips64r6);
GenInstrRegister(SPECIAL3, rs, rt, size - 1, pos, DEXT); GenInstrRegister(SPECIAL3, rs, rt, size - 1, pos, DEXT);
......
...@@ -865,6 +865,7 @@ class Assembler : public AssemblerBase { ...@@ -865,6 +865,7 @@ class Assembler : public AssemblerBase {
void ins_(Register rt, Register rs, uint16_t pos, uint16_t size); void ins_(Register rt, Register rs, uint16_t pos, uint16_t size);
void ext_(Register rt, Register rs, uint16_t pos, uint16_t size); void ext_(Register rt, Register rs, uint16_t pos, uint16_t size);
void dext_(Register rt, Register rs, uint16_t pos, uint16_t size); void dext_(Register rt, Register rs, uint16_t pos, uint16_t size);
void dins_(Register rt, Register rs, uint16_t pos, uint16_t size);
void bitswap(Register rd, Register rt); void bitswap(Register rd, Register rt);
void dbitswap(Register rd, Register rt); void dbitswap(Register rd, Register rt);
void align(Register rd, Register rs, Register rt, uint8_t bp); void align(Register rd, Register rs, Register rt, uint8_t bp);
......
...@@ -1481,6 +1481,15 @@ void MacroAssembler::Dext(Register rt, Register rs, uint16_t pos, ...@@ -1481,6 +1481,15 @@ void MacroAssembler::Dext(Register rt, Register rs, uint16_t pos,
} }
void MacroAssembler::Dins(Register rt, Register rs, uint16_t pos,
uint16_t size) {
DCHECK(pos < 32);
DCHECK(pos + size <= 32);
DCHECK(size != 0);
dins_(rt, rs, pos, size);
}
void MacroAssembler::Ins(Register rt, void MacroAssembler::Ins(Register rt,
Register rs, Register rs,
uint16_t pos, uint16_t pos,
......
...@@ -805,6 +805,7 @@ class MacroAssembler: public Assembler { ...@@ -805,6 +805,7 @@ class MacroAssembler: public Assembler {
// MIPS64 R2 instruction macro. // MIPS64 R2 instruction macro.
void Ins(Register rt, Register rs, uint16_t pos, uint16_t size); void Ins(Register rt, Register rs, uint16_t pos, uint16_t size);
void Dins(Register rt, Register rs, uint16_t pos, uint16_t size);
void Ext(Register rt, Register rs, uint16_t pos, uint16_t size); void Ext(Register rt, Register rs, uint16_t pos, uint16_t size);
void Dext(Register rt, Register rs, uint16_t pos, uint16_t size); void Dext(Register rt, Register rs, uint16_t pos, uint16_t size);
......
...@@ -3696,7 +3696,19 @@ void Simulator::DecodeTypeRegisterSPECIAL2() { ...@@ -3696,7 +3696,19 @@ void Simulator::DecodeTypeRegisterSPECIAL2() {
void Simulator::DecodeTypeRegisterSPECIAL3() { void Simulator::DecodeTypeRegisterSPECIAL3() {
int64_t alu_out; int64_t alu_out;
switch (get_instr()->FunctionFieldRaw()) { switch (get_instr()->FunctionFieldRaw()) {
case INS: { // Mips32r2 instruction. case INS: { // Mips64r2 instruction.
// Interpret rd field as 5-bit msb of insert.
uint16_t msb = rd_reg();
// Interpret sa field as 5-bit lsb of insert.
uint16_t lsb = sa();
uint16_t size = msb - lsb + 1;
uint64_t mask = (1ULL << size) - 1;
alu_out = static_cast<int32_t>((rt_u() & ~(mask << lsb)) |
((rs_u() & mask) << lsb));
SetResult(rt_reg(), alu_out);
break;
}
case DINS: { // Mips64r2 instruction.
// Interpret rd field as 5-bit msb of insert. // Interpret rd field as 5-bit msb of insert.
uint16_t msb = rd_reg(); uint16_t msb = rd_reg();
// Interpret sa field as 5-bit lsb of insert. // Interpret sa field as 5-bit lsb of insert.
...@@ -3707,7 +3719,7 @@ void Simulator::DecodeTypeRegisterSPECIAL3() { ...@@ -3707,7 +3719,7 @@ void Simulator::DecodeTypeRegisterSPECIAL3() {
SetResult(rt_reg(), alu_out); SetResult(rt_reg(), alu_out);
break; break;
} }
case EXT: { // Mips32r2 instruction. case EXT: { // Mips64r2 instruction.
// Interpret rd field as 5-bit msb of extract. // Interpret rd field as 5-bit msb of extract.
uint16_t msb = rd_reg(); uint16_t msb = rd_reg();
// Interpret sa field as 5-bit lsb of extract. // Interpret sa field as 5-bit lsb of extract.
...@@ -3718,7 +3730,7 @@ void Simulator::DecodeTypeRegisterSPECIAL3() { ...@@ -3718,7 +3730,7 @@ void Simulator::DecodeTypeRegisterSPECIAL3() {
SetResult(rt_reg(), alu_out); SetResult(rt_reg(), alu_out);
break; break;
} }
case DEXT: { // Mips32r2 instruction. case DEXT: { // Mips64r2 instruction.
// Interpret rd field as 5-bit msb of extract. // Interpret rd field as 5-bit msb of extract.
uint16_t msb = rd_reg(); uint16_t msb = rd_reg();
// Interpret sa field as 5-bit lsb of extract. // Interpret sa field as 5-bit lsb of extract.
......
...@@ -447,6 +447,32 @@ TEST_F(InstructionSelectorTest, Word32AndWithImmediateWithWord32Shr) { ...@@ -447,6 +447,32 @@ TEST_F(InstructionSelectorTest, Word32AndWithImmediateWithWord32Shr) {
} }
TEST_F(InstructionSelectorTest, Word32AndToClearBits) {
TRACED_FORRANGE(int32_t, shift, 1, 31) {
int32_t mask = ~((1 << shift) - 1);
StreamBuilder m(this, kMachInt32, kMachInt32);
m.Return(m.Word32And(m.Parameter(0), m.Int32Constant(mask)));
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
EXPECT_EQ(kMipsIns, s[0]->arch_opcode());
ASSERT_EQ(3U, s[0]->InputCount());
EXPECT_EQ(0, s.ToInt32(s[0]->InputAt(1)));
EXPECT_EQ(shift, s.ToInt32(s[0]->InputAt(2)));
}
TRACED_FORRANGE(int32_t, shift, 1, 31) {
int32_t mask = ~((1 << shift) - 1);
StreamBuilder m(this, kMachInt32, kMachInt32);
m.Return(m.Word32And(m.Int32Constant(mask), m.Parameter(0)));
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
EXPECT_EQ(kMipsIns, s[0]->arch_opcode());
ASSERT_EQ(3U, s[0]->InputCount());
EXPECT_EQ(0, s.ToInt32(s[0]->InputAt(1)));
EXPECT_EQ(shift, s.ToInt32(s[0]->InputAt(2)));
}
}
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// MUL/DIV instructions. // MUL/DIV instructions.
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
......
...@@ -377,6 +377,58 @@ TEST_F(InstructionSelectorTest, Word64ShrWithWord64AndWithImmediate) { ...@@ -377,6 +377,58 @@ TEST_F(InstructionSelectorTest, Word64ShrWithWord64AndWithImmediate) {
} }
TEST_F(InstructionSelectorTest, Word32AndToClearBits) {
TRACED_FORRANGE(int32_t, shift, 1, 31) {
int32_t mask = ~((1 << shift) - 1);
StreamBuilder m(this, kMachInt32, kMachInt32);
m.Return(m.Word32And(m.Parameter(0), m.Int32Constant(mask)));
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
EXPECT_EQ(kMips64Ins, s[0]->arch_opcode());
ASSERT_EQ(3U, s[0]->InputCount());
EXPECT_EQ(0, s.ToInt32(s[0]->InputAt(1)));
EXPECT_EQ(shift, s.ToInt32(s[0]->InputAt(2)));
}
TRACED_FORRANGE(int32_t, shift, 1, 31) {
int32_t mask = ~((1 << shift) - 1);
StreamBuilder m(this, kMachInt32, kMachInt32);
m.Return(m.Word32And(m.Int32Constant(mask), m.Parameter(0)));
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
EXPECT_EQ(kMips64Ins, s[0]->arch_opcode());
ASSERT_EQ(3U, s[0]->InputCount());
EXPECT_EQ(0, s.ToInt32(s[0]->InputAt(1)));
EXPECT_EQ(shift, s.ToInt32(s[0]->InputAt(2)));
}
}
TEST_F(InstructionSelectorTest, Word64AndToClearBits) {
TRACED_FORRANGE(int32_t, shift, 1, 31) {
int64_t mask = ~((1 << shift) - 1);
StreamBuilder m(this, kMachInt64, kMachInt64);
m.Return(m.Word64And(m.Parameter(0), m.Int64Constant(mask)));
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
EXPECT_EQ(kMips64Dins, s[0]->arch_opcode());
ASSERT_EQ(3U, s[0]->InputCount());
EXPECT_EQ(0, s.ToInt32(s[0]->InputAt(1)));
EXPECT_EQ(shift, s.ToInt32(s[0]->InputAt(2)));
}
TRACED_FORRANGE(int32_t, shift, 1, 31) {
int64_t mask = ~((1 << shift) - 1);
StreamBuilder m(this, kMachInt64, kMachInt64);
m.Return(m.Word64And(m.Int64Constant(mask), m.Parameter(0)));
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
EXPECT_EQ(kMips64Dins, s[0]->arch_opcode());
ASSERT_EQ(3U, s[0]->InputCount());
EXPECT_EQ(0, s.ToInt32(s[0]->InputAt(1)));
EXPECT_EQ(shift, s.ToInt32(s[0]->InputAt(2)));
}
}
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Logical instructions. // Logical instructions.
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
......
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