Commit 3d97b804 authored by marija.antic's avatar marija.antic Committed by Commit bot

MIPS: [turbofan] Optimize sign-extension patterns like Sar(Shl(x, a), b)).

Port of https://crrev.com/14a5c18cc35b2c55b37de3bd0ad27941cf21cb68

BUG=

Review-Url: https://codereview.chromium.org/2355743003
Cr-Commit-Position: refs/heads/master@{#39582}
parent 65bae443
...@@ -1355,7 +1355,12 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( ...@@ -1355,7 +1355,12 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
break; break;
// ... more basic instructions ... // ... more basic instructions ...
case kMipsSeb:
__ seb(i.OutputRegister(), i.InputRegister(0));
break;
case kMipsSeh:
__ seh(i.OutputRegister(), i.InputRegister(0));
break;
case kMipsLbu: case kMipsLbu:
__ lbu(i.OutputRegister(), i.MemoryOperand()); __ lbu(i.OutputRegister(), i.MemoryOperand());
break; break;
......
...@@ -126,7 +126,9 @@ namespace compiler { ...@@ -126,7 +126,9 @@ namespace compiler {
V(MipsPush) \ V(MipsPush) \
V(MipsStoreToStackSlot) \ V(MipsStoreToStackSlot) \
V(MipsByteSwap32) \ V(MipsByteSwap32) \
V(MipsStackClaim) V(MipsStackClaim) \
V(MipsSeb) \
V(MipsSeh)
// Addressing modes represent the "shape" of inputs to an instruction. // Addressing modes represent the "shape" of inputs to an instruction.
// Many instructions support multiple addressing modes. Addressing modes // Many instructions support multiple addressing modes. Addressing modes
......
...@@ -407,6 +407,24 @@ void InstructionSelector::VisitWord32Shr(Node* node) { ...@@ -407,6 +407,24 @@ void InstructionSelector::VisitWord32Shr(Node* node) {
void InstructionSelector::VisitWord32Sar(Node* node) { void InstructionSelector::VisitWord32Sar(Node* node) {
Int32BinopMatcher m(node);
if (m.left().IsWord32Shl() && CanCover(node, m.left().node())) {
Int32BinopMatcher mleft(m.left().node());
if (m.right().HasValue() && mleft.right().HasValue()) {
MipsOperandGenerator g(this);
uint32_t sar = m.right().Value();
uint32_t shl = mleft.right().Value();
if ((sar == shl) && (sar == 16)) {
Emit(kMipsSeh, g.DefineAsRegister(node),
g.UseRegister(mleft.left().node()));
return;
} else if ((sar == shl) && (sar == 24)) {
Emit(kMipsSeb, g.DefineAsRegister(node),
g.UseRegister(mleft.left().node()));
return;
}
}
}
VisitRRO(this, kMipsSar, node); VisitRRO(this, kMipsSar, node);
} }
......
...@@ -1641,6 +1641,12 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( ...@@ -1641,6 +1641,12 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
break; break;
// ... more basic instructions ... // ... more basic instructions ...
case kMips64Seb:
__ seb(i.OutputRegister(), i.InputRegister(0));
break;
case kMips64Seh:
__ seh(i.OutputRegister(), i.InputRegister(0));
break;
case kMips64Lbu: case kMips64Lbu:
__ lbu(i.OutputRegister(), i.MemoryOperand()); __ lbu(i.OutputRegister(), i.MemoryOperand());
break; break;
......
...@@ -159,7 +159,9 @@ namespace compiler { ...@@ -159,7 +159,9 @@ namespace compiler {
V(Mips64StoreToStackSlot) \ V(Mips64StoreToStackSlot) \
V(Mips64ByteSwap64) \ V(Mips64ByteSwap64) \
V(Mips64ByteSwap32) \ V(Mips64ByteSwap32) \
V(Mips64StackClaim) V(Mips64StackClaim) \
V(Mips64Seb) \
V(Mips64Seh)
// Addressing modes represent the "shape" of inputs to an instruction. // Addressing modes represent the "shape" of inputs to an instruction.
// Many instructions support multiple addressing modes. Addressing modes // Many instructions support multiple addressing modes. Addressing modes
......
...@@ -504,6 +504,28 @@ void InstructionSelector::VisitWord32Shr(Node* node) { ...@@ -504,6 +504,28 @@ void InstructionSelector::VisitWord32Shr(Node* node) {
void InstructionSelector::VisitWord32Sar(Node* node) { void InstructionSelector::VisitWord32Sar(Node* node) {
Int32BinopMatcher m(node);
if (m.left().IsWord32Shl() && CanCover(node, m.left().node())) {
Int32BinopMatcher mleft(m.left().node());
if (m.right().HasValue() && mleft.right().HasValue()) {
Mips64OperandGenerator g(this);
uint32_t sar = m.right().Value();
uint32_t shl = mleft.right().Value();
if ((sar == shl) && (sar == 16)) {
Emit(kMips64Seh, g.DefineAsRegister(node),
g.UseRegister(mleft.left().node()));
return;
} else if ((sar == shl) && (sar == 24)) {
Emit(kMips64Seb, g.DefineAsRegister(node),
g.UseRegister(mleft.left().node()));
return;
} else if ((sar == shl) && (sar == 32)) {
Emit(kMips64Shl, g.DefineAsRegister(node),
g.UseRegister(mleft.left().node()), g.TempImmediate(0));
return;
}
}
}
VisitRRO(this, kMips64Sar, node); VisitRRO(this, kMips64Sar, node);
} }
......
...@@ -408,6 +408,36 @@ TEST_F(InstructionSelectorTest, Word32ShlWithWord32And) { ...@@ -408,6 +408,36 @@ TEST_F(InstructionSelectorTest, Word32ShlWithWord32And) {
} }
} }
TEST_F(InstructionSelectorTest, Word32SarWithWord32Shl) {
{
StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
Node* const p0 = m.Parameter(0);
Node* const r =
m.Word32Sar(m.Word32Shl(p0, m.Int32Constant(24)), m.Int32Constant(24));
m.Return(r);
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
EXPECT_EQ(kMipsSeb, s[0]->arch_opcode());
ASSERT_EQ(1U, s[0]->InputCount());
EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
ASSERT_EQ(1U, s[0]->OutputCount());
EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output()));
}
{
StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
Node* const p0 = m.Parameter(0);
Node* const r =
m.Word32Sar(m.Word32Shl(p0, m.Int32Constant(16)), m.Int32Constant(16));
m.Return(r);
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
EXPECT_EQ(kMipsSeh, s[0]->arch_opcode());
ASSERT_EQ(1U, s[0]->InputCount());
EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
ASSERT_EQ(1U, s[0]->OutputCount());
EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output()));
}
}
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Logical instructions. // Logical instructions.
......
...@@ -719,6 +719,51 @@ TEST_F(InstructionSelectorTest, Word64ShlWithWord64And) { ...@@ -719,6 +719,51 @@ TEST_F(InstructionSelectorTest, Word64ShlWithWord64And) {
} }
} }
TEST_F(InstructionSelectorTest, Word32SarWithWord32Shl) {
{
StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
Node* const p0 = m.Parameter(0);
Node* const r =
m.Word32Sar(m.Word32Shl(p0, m.Int32Constant(24)), m.Int32Constant(24));
m.Return(r);
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
EXPECT_EQ(kMips64Seb, s[0]->arch_opcode());
ASSERT_EQ(1U, s[0]->InputCount());
EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
ASSERT_EQ(1U, s[0]->OutputCount());
EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output()));
}
{
StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
Node* const p0 = m.Parameter(0);
Node* const r =
m.Word32Sar(m.Word32Shl(p0, m.Int32Constant(16)), m.Int32Constant(16));
m.Return(r);
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
EXPECT_EQ(kMips64Seh, s[0]->arch_opcode());
ASSERT_EQ(1U, s[0]->InputCount());
EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
ASSERT_EQ(1U, s[0]->OutputCount());
EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output()));
}
{
StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
Node* const p0 = m.Parameter(0);
Node* const r =
m.Word32Sar(m.Word32Shl(p0, m.Int32Constant(32)), m.Int32Constant(32));
m.Return(r);
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
EXPECT_EQ(kMips64Shl, s[0]->arch_opcode());
ASSERT_EQ(2U, s[0]->InputCount());
EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
EXPECT_EQ(0, s.ToInt32(s[0]->InputAt(1)));
ASSERT_EQ(1U, s[0]->OutputCount());
EXPECT_EQ(s.ToVreg(r), s.ToVreg(s[0]->Output()));
}
}
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// MUL/DIV instructions. // MUL/DIV 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