Commit 4125ba8b authored by ivica.bogosavljevic's avatar ivica.bogosavljevic Committed by Commit bot

MIPS64: Port `ARM64: [turbofan] Avoid zero-extension after a 32-bit load`

Port f07d2cdd

Original commit message:
A load instruction will implicitely clear the top 32 bits when writing to a W
register. This patch avoids generating a `mov` instruction to zero-extend the
result in this case.

For example, this occurs in the generated code for dispatching to the next
bytecode in the interpreter:

  kind = BYTECODE_HANDLER
  name = LdaZero
  compiler = turbofan
  Instructions (size = 36)
  0x32e64c60     0  add x19, x19, #0x1 (1)
  0x32e64c64     4  ldrb w0, [x20, x19]
  0x32e64c68     8  mov w0, w0
                    ^^^^^^^^^^
  0x32e64c6c    12  lsl x0, x0, #3
  0x32e64c70    16  ldr x1, [x21, x0]
  0x32e64c74    20  movz x0, #0x0
  0x32e64c78    24  br x1

Review-Url: https://codereview.chromium.org/2469253002
Cr-Commit-Position: refs/heads/master@{#40758}
parent b7761100
...@@ -1254,6 +1254,33 @@ void InstructionSelector::VisitChangeInt32ToInt64(Node* node) { ...@@ -1254,6 +1254,33 @@ void InstructionSelector::VisitChangeInt32ToInt64(Node* node) {
void InstructionSelector::VisitChangeUint32ToUint64(Node* node) { void InstructionSelector::VisitChangeUint32ToUint64(Node* node) {
Mips64OperandGenerator g(this); Mips64OperandGenerator g(this);
Node* value = node->InputAt(0);
switch (value->opcode()) {
// 32-bit operations will write their result in a 64 bit register,
// clearing the top 32 bits of the destination register.
case IrOpcode::kUint32Div:
case IrOpcode::kUint32Mod:
case IrOpcode::kUint32MulHigh: {
Emit(kArchNop, g.DefineSameAsFirst(node), g.Use(value));
return;
}
case IrOpcode::kLoad: {
LoadRepresentation load_rep = LoadRepresentationOf(value->op());
if (load_rep.IsUnsigned()) {
switch (load_rep.representation()) {
case MachineRepresentation::kWord8:
case MachineRepresentation::kWord16:
case MachineRepresentation::kWord32:
Emit(kArchNop, g.DefineSameAsFirst(node), g.Use(value));
return;
default:
break;
}
}
}
default:
break;
}
Emit(kMips64Dext, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)), Emit(kMips64Dext, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)),
g.TempImmediate(0), g.TempImmediate(32)); g.TempImmediate(0), g.TempImmediate(32));
} }
......
...@@ -286,6 +286,15 @@ const Conversion kFloat32RoundInstructions[] = { ...@@ -286,6 +286,15 @@ const Conversion kFloat32RoundInstructions[] = {
kMips64TruncWS, MachineType::Int32()}, kMips64TruncWS, MachineType::Int32()},
MachineType::Float32()}}; MachineType::Float32()}};
// MIPS64 instructions that clear the top 32 bits of the destination.
const MachInst2 kCanElideChangeUint32ToUint64[] = {
{&RawMachineAssembler::Uint32Div, "Uint32Div", kMips64DivU,
MachineType::Uint32()},
{&RawMachineAssembler::Uint32Mod, "Uint32Mod", kMips64ModU,
MachineType::Uint32()},
{&RawMachineAssembler::Uint32MulHigh, "Uint32MulHigh", kMips64MulHighU,
MachineType::Uint32()}};
} // namespace } // namespace
...@@ -1144,6 +1153,83 @@ TEST_F(InstructionSelectorTest, ChangeInt32ToInt64AfterLoad) { ...@@ -1144,6 +1153,83 @@ TEST_F(InstructionSelectorTest, ChangeInt32ToInt64AfterLoad) {
} }
} }
typedef InstructionSelectorTestWithParam<MachInst2>
InstructionSelectorElidedChangeUint32ToUint64Test;
TEST_P(InstructionSelectorElidedChangeUint32ToUint64Test, Parameter) {
const MachInst2 binop = GetParam();
StreamBuilder m(this, MachineType::Uint64(), binop.machine_type,
binop.machine_type);
m.Return(m.ChangeUint32ToUint64(
(m.*binop.constructor)(m.Parameter(0), m.Parameter(1))));
Stream s = m.Build();
// Make sure the `ChangeUint32ToUint64` node turned into a no-op.
ASSERT_EQ(1U, s.size());
EXPECT_EQ(binop.arch_opcode, s[0]->arch_opcode());
EXPECT_EQ(2U, s[0]->InputCount());
EXPECT_EQ(1U, s[0]->OutputCount());
}
INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
InstructionSelectorElidedChangeUint32ToUint64Test,
::testing::ValuesIn(kCanElideChangeUint32ToUint64));
TEST_F(InstructionSelectorTest, ChangeUint32ToUint64AfterLoad) {
// For each case, make sure the `ChangeUint32ToUint64` node turned into a
// no-op.
// Lbu
{
StreamBuilder m(this, MachineType::Uint64(), MachineType::Pointer(),
MachineType::Int32());
m.Return(m.ChangeUint32ToUint64(
m.Load(MachineType::Uint8(), m.Parameter(0), m.Parameter(1))));
Stream s = m.Build();
ASSERT_EQ(2U, s.size());
EXPECT_EQ(kMips64Dadd, s[0]->arch_opcode());
EXPECT_EQ(kMode_None, s[0]->addressing_mode());
EXPECT_EQ(2U, s[0]->InputCount());
EXPECT_EQ(1U, s[0]->OutputCount());
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());
}
// Lhu
{
StreamBuilder m(this, MachineType::Uint64(), MachineType::Pointer(),
MachineType::Int32());
m.Return(m.ChangeUint32ToUint64(
m.Load(MachineType::Uint16(), m.Parameter(0), m.Parameter(1))));
Stream s = m.Build();
ASSERT_EQ(2U, s.size());
EXPECT_EQ(kMips64Dadd, s[0]->arch_opcode());
EXPECT_EQ(kMode_None, s[0]->addressing_mode());
EXPECT_EQ(2U, s[0]->InputCount());
EXPECT_EQ(1U, s[0]->OutputCount());
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());
}
// Lwu
{
StreamBuilder m(this, MachineType::Uint64(), MachineType::Pointer(),
MachineType::Int32());
m.Return(m.ChangeUint32ToUint64(
m.Load(MachineType::Uint32(), m.Parameter(0), m.Parameter(1))));
Stream s = m.Build();
ASSERT_EQ(2U, s.size());
EXPECT_EQ(kMips64Dadd, s[0]->arch_opcode());
EXPECT_EQ(kMode_None, s[0]->addressing_mode());
EXPECT_EQ(2U, s[0]->InputCount());
EXPECT_EQ(1U, s[0]->OutputCount());
EXPECT_EQ(kMips64Lwu, 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. // 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