[turbofan] ARM: Support shifted indexes in loads and stores

This patch is a follow up to https://codereview.chromium.org/1972103002/
adding support for the `Operand_R_LSL_I` addressing mode to loads and
stores for ARM.

Just as the ARM64 implementation, the shift + load/store pattern is only
really relevant to the interpreter. For this reason, this patch does not
add support for the other addressing modes (`R_LSR_I`, `R_ASR_I` and
`R_ROR_I`) as I haven't seen those pattern being generated. Additionally,
the optimization is restricted 32 bit loads and stores.

kind = BYTECODE_HANDLER
name = Star
compiler = turbofan
Instructions (size = 40)
0x22a5f860     0  e2851001       add r1, r5, #1
0x22a5f864     4  e19610d1       ldrsb r1, [r6, +r1]
0x22a5f868     8  e1a0200b       mov r2, fp
0x22a5f86c    12  e7820101       str r0, [r2, +r1, lsl #2]
                                 ^^^^^^^^^^^^^^^^^^^^^^^^^
0x22a5f870    16  e2855002       add r5, r5, #2
0x22a5f874    20  e7d61005       ldrb r1, [r6, +r5]
0x22a5f878    24  e7981101       ldr r1, [r8, +r1, lsl #2]
                                 ^^^^^^^^^^^^^^^^^^^^^^^^^
0x22a5f87c    28  e12fff11       bx r1

BUG=

Review-Url: https://codereview.chromium.org/1974263002
Cr-Commit-Position: refs/heads/master@{#36381}
This commit is contained in:
pierre.langlois 2016-05-19 12:16:47 -07:00 committed by Commit bot
parent 4d0ea36c0d
commit 11b661f414
3 changed files with 112 additions and 38 deletions

View File

@ -125,13 +125,16 @@ class ArmOperandConverter final : public InstructionOperandConverter {
case kMode_Operand2_R:
case kMode_Operand2_R_ASR_I:
case kMode_Operand2_R_ASR_R:
case kMode_Operand2_R_LSL_I:
case kMode_Operand2_R_LSL_R:
case kMode_Operand2_R_LSR_I:
case kMode_Operand2_R_LSR_R:
case kMode_Operand2_R_ROR_I:
case kMode_Operand2_R_ROR_R:
break;
case kMode_Operand2_R_LSL_I:
*first_index += 3;
return MemOperand(InputRegister(index + 0), InputRegister(index + 1),
LSL, InputInt32(index + 2));
case kMode_Offset_RI:
*first_index += 2;
return MemOperand(InputRegister(index + 0), InputInt32(index + 1));
@ -1121,59 +1124,44 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
__ ldrsb(i.OutputRegister(), i.InputOffset());
DCHECK_EQ(LeaveCC, i.OutputSBit());
break;
case kArmStrb: {
size_t index = 0;
MemOperand operand = i.InputOffset(&index);
__ strb(i.InputRegister(index), operand);
case kArmStrb:
__ strb(i.InputRegister(0), i.InputOffset(1));
DCHECK_EQ(LeaveCC, i.OutputSBit());
break;
}
case kArmLdrh:
__ ldrh(i.OutputRegister(), i.InputOffset());
break;
case kArmLdrsh:
__ ldrsh(i.OutputRegister(), i.InputOffset());
break;
case kArmStrh: {
size_t index = 0;
MemOperand operand = i.InputOffset(&index);
__ strh(i.InputRegister(index), operand);
case kArmStrh:
__ strh(i.InputRegister(0), i.InputOffset(1));
DCHECK_EQ(LeaveCC, i.OutputSBit());
break;
}
case kArmLdr:
__ ldr(i.OutputRegister(), i.InputOffset());
break;
case kArmStr: {
size_t index = 0;
MemOperand operand = i.InputOffset(&index);
__ str(i.InputRegister(index), operand);
case kArmStr:
__ str(i.InputRegister(0), i.InputOffset(1));
DCHECK_EQ(LeaveCC, i.OutputSBit());
break;
}
case kArmVldrF32: {
__ vldr(i.OutputFloat32Register(), i.InputOffset());
DCHECK_EQ(LeaveCC, i.OutputSBit());
break;
}
case kArmVstrF32: {
size_t index = 0;
MemOperand operand = i.InputOffset(&index);
__ vstr(i.InputFloat32Register(index), operand);
case kArmVstrF32:
__ vstr(i.InputFloat32Register(0), i.InputOffset(1));
DCHECK_EQ(LeaveCC, i.OutputSBit());
break;
}
case kArmVldrF64:
__ vldr(i.OutputFloat64Register(), i.InputOffset());
DCHECK_EQ(LeaveCC, i.OutputSBit());
break;
case kArmVstrF64: {
size_t index = 0;
MemOperand operand = i.InputOffset(&index);
__ vstr(i.InputFloat64Register(index), operand);
case kArmVstrF64:
__ vstr(i.InputFloat64Register(0), i.InputOffset(1));
DCHECK_EQ(LeaveCC, i.OutputSBit());
break;
}
case kArmFloat32Max: {
CpuFeatureScope scope(masm(), ARMv8);
// (b < a) ? a : b

View File

@ -115,6 +115,24 @@ bool TryMatchShift(InstructionSelector* selector,
return false;
}
template <IrOpcode::Value kOpcode, int kImmMin, int kImmMax,
AddressingMode kImmMode>
bool TryMatchShiftImmediate(InstructionSelector* selector,
InstructionCode* opcode_return, Node* node,
InstructionOperand* value_return,
InstructionOperand* shift_return) {
ArmOperandGenerator g(selector);
if (node->opcode() == kOpcode) {
Int32BinopMatcher m(node);
if (m.right().IsInRange(kImmMin, kImmMax)) {
*opcode_return |= AddressingModeField::encode(kImmMode);
*value_return = g.UseRegister(m.left().node());
*shift_return = g.UseImmediate(m.right().node());
return true;
}
}
return false;
}
bool TryMatchROR(InstructionSelector* selector, InstructionCode* opcode_return,
Node* node, InstructionOperand* value_return,
@ -142,6 +160,14 @@ bool TryMatchLSL(InstructionSelector* selector, InstructionCode* opcode_return,
value_return, shift_return);
}
bool TryMatchLSLImmediate(InstructionSelector* selector,
InstructionCode* opcode_return, Node* node,
InstructionOperand* value_return,
InstructionOperand* shift_return) {
return TryMatchShiftImmediate<IrOpcode::kWord32Shl, 0, 31,
kMode_Operand2_R_LSL_I>(
selector, opcode_return, node, value_return, shift_return);
}
bool TryMatchLSR(InstructionSelector* selector, InstructionCode* opcode_return,
Node* node, InstructionOperand* value_return,
@ -312,8 +338,11 @@ void InstructionSelector::VisitLoad(Node* node) {
ArmOperandGenerator g(this);
Node* base = node->InputAt(0);
Node* index = node->InputAt(1);
InstructionOperand inputs[3];
size_t input_count = 0;
InstructionOperand outputs[1];
ArchOpcode opcode = kArchNop;
InstructionCode opcode = kArchNop;
switch (load_rep.representation()) {
case MachineRepresentation::kFloat32:
opcode = kArmVldrF32;
@ -339,13 +368,24 @@ void InstructionSelector::VisitLoad(Node* node) {
return;
}
outputs[0] = g.DefineAsRegister(node);
inputs[0] = g.UseRegister(base);
if (g.CanBeImmediate(index, opcode)) {
Emit(opcode | AddressingModeField::encode(kMode_Offset_RI),
g.DefineAsRegister(node), g.UseRegister(base), g.UseImmediate(index));
input_count = 2;
inputs[1] = g.UseImmediate(index);
opcode |= AddressingModeField::encode(kMode_Offset_RI);
} else if ((opcode == kArmLdr) &&
TryMatchLSLImmediate(this, &opcode, index, &inputs[1],
&inputs[2])) {
input_count = 3;
} else {
Emit(opcode | AddressingModeField::encode(kMode_Offset_RR),
g.DefineAsRegister(node), g.UseRegister(base), g.UseRegister(index));
input_count = 2;
inputs[1] = g.UseRegister(index);
opcode |= AddressingModeField::encode(kMode_Offset_RR);
}
Emit(opcode, arraysize(outputs), outputs, input_count, inputs);
}
@ -397,7 +437,10 @@ void InstructionSelector::VisitStore(Node* node) {
code |= MiscField::encode(static_cast<int>(record_write_mode));
Emit(code, 0, nullptr, input_count, inputs, temp_count, temps);
} else {
ArchOpcode opcode = kArchNop;
InstructionOperand inputs[4];
size_t input_count = 0;
InstructionCode opcode = kArchNop;
switch (rep) {
case MachineRepresentation::kFloat32:
opcode = kArmVstrF32;
@ -423,13 +466,23 @@ void InstructionSelector::VisitStore(Node* node) {
return;
}
inputs[0] = g.UseRegister(value);
inputs[1] = g.UseRegister(base);
if (g.CanBeImmediate(index, opcode)) {
Emit(opcode | AddressingModeField::encode(kMode_Offset_RI), g.NoOutput(),
g.UseRegister(base), g.UseImmediate(index), g.UseRegister(value));
input_count = 3;
inputs[2] = g.UseImmediate(index);
opcode |= AddressingModeField::encode(kMode_Offset_RI);
} else if ((opcode == kArmStr) &&
TryMatchLSLImmediate(this, &opcode, index, &inputs[2],
&inputs[3])) {
input_count = 4;
} else {
Emit(opcode | AddressingModeField::encode(kMode_Offset_RR), g.NoOutput(),
g.UseRegister(base), g.UseRegister(index), g.UseRegister(value));
input_count = 3;
inputs[2] = g.UseRegister(index);
opcode |= AddressingModeField::encode(kMode_Offset_RR);
}
Emit(opcode, 0, nullptr, input_count, inputs);
}
}

View File

@ -1392,8 +1392,8 @@ TEST_P(InstructionSelectorMemoryAccessTest, StoreWithImmediateIndex) {
EXPECT_EQ(memacc.str_opcode, s[0]->arch_opcode());
EXPECT_EQ(kMode_Offset_RI, s[0]->addressing_mode());
ASSERT_EQ(3U, s[0]->InputCount());
ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
EXPECT_EQ(index, s.ToInt32(s[0]->InputAt(1)));
ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(2)->kind());
EXPECT_EQ(index, s.ToInt32(s[0]->InputAt(2)));
EXPECT_EQ(0U, s[0]->OutputCount());
}
}
@ -1403,6 +1403,39 @@ INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
InstructionSelectorMemoryAccessTest,
::testing::ValuesIn(kMemoryAccesses));
TEST_F(InstructionSelectorMemoryAccessTest, LoadWithShiftedIndex) {
TRACED_FORRANGE(int, immediate_shift, 1, 31) {
StreamBuilder m(this, MachineType::Int32(), MachineType::Pointer(),
MachineType::Int32());
Node* const index =
m.Word32Shl(m.Parameter(1), m.Int32Constant(immediate_shift));
m.Return(m.Load(MachineType::Int32(), m.Parameter(0), index));
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
EXPECT_EQ(kArmLdr, s[0]->arch_opcode());
EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode());
EXPECT_EQ(3U, s[0]->InputCount());
EXPECT_EQ(1U, s[0]->OutputCount());
}
}
TEST_F(InstructionSelectorMemoryAccessTest, StoreWithShiftedIndex) {
TRACED_FORRANGE(int, immediate_shift, 1, 31) {
StreamBuilder m(this, MachineType::Int32(), MachineType::Pointer(),
MachineType::Int32(), MachineType::Int32());
Node* const index =
m.Word32Shl(m.Parameter(1), m.Int32Constant(immediate_shift));
m.Store(MachineRepresentation::kWord32, m.Parameter(0), index,
m.Parameter(2), kNoWriteBarrier);
m.Return(m.Int32Constant(0));
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
EXPECT_EQ(kArmStr, s[0]->arch_opcode());
EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode());
EXPECT_EQ(4U, s[0]->InputCount());
EXPECT_EQ(0U, s[0]->OutputCount());
}
}
// -----------------------------------------------------------------------------
// Conversions.