Commit 239f9816 authored by Miran.Karic's avatar Miran.Karic Committed by Commit bot

MIPS: [stubs,interpreter] Optimise SMI loading for 64-bit targets.

  Port 28e3467a (r38361)

  original commit message:
    Adding new methods to the code stub assembler and interpreter
    assembler to combine loading and untagging SMIs, so that on 64-bit
    architectures we can avoid loading the full 64 bits and load the
    32 interesting bits directly instead.

BUG=

Review-Url: https://codereview.chromium.org/2265043002
Cr-Commit-Position: refs/heads/master@{#38811}
parent 6ea8b4f2
......@@ -142,12 +142,29 @@ static void VisitBinop(InstructionSelector* selector, Node* node,
VisitBinop(selector, node, opcode, &cont);
}
void EmitLoad(InstructionSelector* selector, Node* node, InstructionCode opcode,
Node* output = nullptr) {
Mips64OperandGenerator g(selector);
Node* base = node->InputAt(0);
Node* index = node->InputAt(1);
if (g.CanBeImmediate(index, opcode)) {
selector->Emit(opcode | AddressingModeField::encode(kMode_MRI),
g.DefineAsRegister(output == nullptr ? node : output),
g.UseRegister(base), g.UseImmediate(index));
} else {
InstructionOperand addr_reg = g.TempRegister();
selector->Emit(kMips64Dadd | AddressingModeField::encode(kMode_None),
addr_reg, g.UseRegister(index), g.UseRegister(base));
// Emit desired load opcode, using temp addr_reg.
selector->Emit(opcode | AddressingModeField::encode(kMode_MRI),
g.DefineAsRegister(output == nullptr ? node : output),
addr_reg, g.TempImmediate(0));
}
}
void InstructionSelector::VisitLoad(Node* node) {
LoadRepresentation load_rep = LoadRepresentationOf(node->op());
Mips64OperandGenerator g(this);
Node* base = node->InputAt(0);
Node* index = node->InputAt(1);
ArchOpcode opcode = kArchNop;
switch (load_rep.representation()) {
......@@ -179,17 +196,7 @@ void InstructionSelector::VisitLoad(Node* node) {
return;
}
if (g.CanBeImmediate(index, opcode)) {
Emit(opcode | AddressingModeField::encode(kMode_MRI),
g.DefineAsRegister(node), g.UseRegister(base), g.UseImmediate(index));
} else {
InstructionOperand addr_reg = g.TempRegister();
Emit(kMips64Dadd | AddressingModeField::encode(kMode_None), addr_reg,
g.UseRegister(index), g.UseRegister(base));
// Emit desired load opcode, using temp addr_reg.
Emit(opcode | AddressingModeField::encode(kMode_MRI),
g.DefineAsRegister(node), addr_reg, g.TempImmediate(0));
}
EmitLoad(this, node, opcode);
}
......@@ -501,7 +508,7 @@ void InstructionSelector::VisitWord64Shl(Node* node) {
Mips64OperandGenerator g(this);
Int64BinopMatcher m(node);
if ((m.left().IsChangeInt32ToInt64() || m.left().IsChangeUint32ToUint64()) &&
m.right().IsInRange(32, 63)) {
m.right().IsInRange(32, 63) && CanCover(node, m.left().node())) {
// There's no need to sign/zero-extend to 64-bit if we shift out the upper
// 32 bits anyway.
Emit(kMips64Dshl, g.DefineSameAsFirst(node),
......@@ -1064,9 +1071,32 @@ void InstructionSelector::VisitTryTruncateFloat64ToUint64(Node* node) {
void InstructionSelector::VisitChangeInt32ToInt64(Node* node) {
Mips64OperandGenerator g(this);
Emit(kMips64Shl, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)),
g.TempImmediate(0));
Node* value = node->InputAt(0);
if (value->opcode() == IrOpcode::kLoad && CanCover(node, value)) {
// Generate sign-extending load.
LoadRepresentation load_rep = LoadRepresentationOf(value->op());
InstructionCode opcode = kArchNop;
switch (load_rep.representation()) {
case MachineRepresentation::kBit: // Fall through.
case MachineRepresentation::kWord8:
opcode = load_rep.IsUnsigned() ? kMips64Lbu : kMips64Lb;
break;
case MachineRepresentation::kWord16:
opcode = load_rep.IsUnsigned() ? kMips64Lhu : kMips64Lh;
break;
case MachineRepresentation::kWord32:
opcode = kMips64Lw;
break;
default:
UNREACHABLE();
return;
}
EmitLoad(this, value, opcode, node);
} else {
Mips64OperandGenerator g(this);
Emit(kMips64Shl, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)),
g.TempImmediate(0));
}
}
......
......@@ -986,6 +986,89 @@ TEST_F(InstructionSelectorTest, CombineShiftsWithDivMod) {
}
}
TEST_F(InstructionSelectorTest, ChangeInt32ToInt64AfterLoad) {
// For each case, test that the conversion is merged into the load
// operation.
// ChangeInt32ToInt64(Load_Uint8) -> Lbu
{
StreamBuilder m(this, MachineType::Int64(), MachineType::Pointer(),
MachineType::Int32());
m.Return(m.ChangeInt32ToInt64(
m.Load(MachineType::Uint8(), m.Parameter(0), m.Parameter(1))));
Stream s = m.Build();
ASSERT_EQ(2U, s.size());
EXPECT_EQ(kMips64Lbu, s[1]->arch_opcode());
EXPECT_EQ(kMode_MRI, s[1]->addressing_mode());
EXPECT_EQ(2U, s[1]->InputCount());
EXPECT_EQ(1U, s[1]->OutputCount());
}
// ChangeInt32ToInt64(Load_Int8) -> Lb
{
StreamBuilder m(this, MachineType::Int64(), MachineType::Pointer(),
MachineType::Int32());
m.Return(m.ChangeInt32ToInt64(
m.Load(MachineType::Int8(), m.Parameter(0), m.Parameter(1))));
Stream s = m.Build();
ASSERT_EQ(2U, s.size());
EXPECT_EQ(kMips64Lb, s[1]->arch_opcode());
EXPECT_EQ(kMode_MRI, s[1]->addressing_mode());
EXPECT_EQ(2U, s[1]->InputCount());
EXPECT_EQ(1U, s[1]->OutputCount());
}
// ChangeInt32ToInt64(Load_Uint16) -> Lhu
{
StreamBuilder m(this, MachineType::Int64(), MachineType::Pointer(),
MachineType::Int32());
m.Return(m.ChangeInt32ToInt64(
m.Load(MachineType::Uint16(), m.Parameter(0), m.Parameter(1))));
Stream s = m.Build();
ASSERT_EQ(2U, s.size());
EXPECT_EQ(kMips64Lhu, s[1]->arch_opcode());
EXPECT_EQ(kMode_MRI, s[1]->addressing_mode());
EXPECT_EQ(2U, s[1]->InputCount());
EXPECT_EQ(1U, s[1]->OutputCount());
}
// ChangeInt32ToInt64(Load_Int16) -> Lh
{
StreamBuilder m(this, MachineType::Int64(), MachineType::Pointer(),
MachineType::Int32());
m.Return(m.ChangeInt32ToInt64(
m.Load(MachineType::Int16(), m.Parameter(0), m.Parameter(1))));
Stream s = m.Build();
ASSERT_EQ(2U, s.size());
EXPECT_EQ(kMips64Lh, s[1]->arch_opcode());
EXPECT_EQ(kMode_MRI, s[1]->addressing_mode());
EXPECT_EQ(2U, s[1]->InputCount());
EXPECT_EQ(1U, s[1]->OutputCount());
}
// ChangeInt32ToInt64(Load_Uint32) -> Lw
{
StreamBuilder m(this, MachineType::Int64(), MachineType::Pointer(),
MachineType::Int32());
m.Return(m.ChangeInt32ToInt64(
m.Load(MachineType::Uint32(), m.Parameter(0), m.Parameter(1))));
Stream s = m.Build();
ASSERT_EQ(2U, s.size());
EXPECT_EQ(kMips64Lw, s[1]->arch_opcode());
EXPECT_EQ(kMode_MRI, s[1]->addressing_mode());
EXPECT_EQ(2U, s[1]->InputCount());
EXPECT_EQ(1U, s[1]->OutputCount());
}
// ChangeInt32ToInt64(Load_Int32) -> Lw
{
StreamBuilder m(this, MachineType::Int64(), MachineType::Pointer(),
MachineType::Int32());
m.Return(m.ChangeInt32ToInt64(
m.Load(MachineType::Int32(), m.Parameter(0), m.Parameter(1))));
Stream s = m.Build();
ASSERT_EQ(2U, s.size());
EXPECT_EQ(kMips64Lw, s[1]->arch_opcode());
EXPECT_EQ(kMode_MRI, s[1]->addressing_mode());
EXPECT_EQ(2U, s[1]->InputCount());
EXPECT_EQ(1U, s[1]->OutputCount());
}
}
// ----------------------------------------------------------------------------
// Loads and stores.
......
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