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) {
__ Ext(i.OutputRegister(), i.InputRegister(0), i.InputInt8(1),
i.InputInt8(2));
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:
__ Ror(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
break;
......
......@@ -32,6 +32,7 @@ namespace compiler {
V(MipsShr) \
V(MipsSar) \
V(MipsExt) \
V(MipsIns) \
V(MipsRor) \
V(MipsMov) \
V(MipsTst) \
......
......@@ -284,6 +284,18 @@ void InstructionSelector::VisitWord32And(Node* node) {
// 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);
}
......
......@@ -725,10 +725,26 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
__ Ext(i.OutputRegister(), i.InputRegister(0), i.InputInt8(1),
i.InputInt8(2));
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:
__ Dext(i.OutputRegister(), i.InputRegister(0), i.InputInt8(1),
i.InputInt8(2));
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:
if (instr->InputAt(1)->IsRegister()) {
__ dsllv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
......
......@@ -38,7 +38,9 @@ namespace compiler {
V(Mips64Shr) \
V(Mips64Sar) \
V(Mips64Ext) \
V(Mips64Ins) \
V(Mips64Dext) \
V(Mips64Dins) \
V(Mips64Dclz) \
V(Mips64Dshl) \
V(Mips64Dshr) \
......
......@@ -295,6 +295,19 @@ void InstructionSelector::VisitWord32And(Node* node) {
// 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);
}
......@@ -332,6 +345,20 @@ void InstructionSelector::VisitWord64And(Node* node) {
// 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);
}
......
......@@ -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) {
// Should be called via MacroAssembler::Ext.
// 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) {
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.
DCHECK(kArchVariant == kMips64r2 || kArchVariant == kMips64r6);
GenInstrRegister(SPECIAL3, rs, rt, size - 1, pos, DEXT);
......
......@@ -865,6 +865,7 @@ class Assembler : public AssemblerBase {
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 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 dbitswap(Register rd, Register rt);
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,
}
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,
Register rs,
uint16_t pos,
......
......@@ -805,6 +805,7 @@ class MacroAssembler: public Assembler {
// MIPS64 R2 instruction macro.
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 Dext(Register rt, Register rs, uint16_t pos, uint16_t size);
......
......@@ -3696,7 +3696,19 @@ void Simulator::DecodeTypeRegisterSPECIAL2() {
void Simulator::DecodeTypeRegisterSPECIAL3() {
int64_t alu_out;
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.
uint16_t msb = rd_reg();
// Interpret sa field as 5-bit lsb of insert.
......@@ -3707,7 +3719,7 @@ void Simulator::DecodeTypeRegisterSPECIAL3() {
SetResult(rt_reg(), alu_out);
break;
}
case EXT: { // Mips32r2 instruction.
case EXT: { // Mips64r2 instruction.
// Interpret rd field as 5-bit msb of extract.
uint16_t msb = rd_reg();
// Interpret sa field as 5-bit lsb of extract.
......@@ -3718,7 +3730,7 @@ void Simulator::DecodeTypeRegisterSPECIAL3() {
SetResult(rt_reg(), alu_out);
break;
}
case DEXT: { // Mips32r2 instruction.
case DEXT: { // Mips64r2 instruction.
// Interpret rd field as 5-bit msb of extract.
uint16_t msb = rd_reg();
// Interpret sa field as 5-bit lsb of extract.
......
......@@ -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.
// ----------------------------------------------------------------------------
......
......@@ -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.
// ----------------------------------------------------------------------------
......
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