Commit b36368d2 authored by Georgia Kouveli's avatar Georgia Kouveli Committed by Commit Bot

Reland "[arm64] Use root register for addressing external references."

This is a reland of 8e39af62

Original change's description:
> [arm64] Use root register for addressing external references.
> 
> This optimization is already done on x64 (7500e507).
> 
> Bug: v8:7844
> Change-Id: Iccc3bb55aa79ef1d4423576c79d9ce6f829f2828
> Reviewed-on: https://chromium-review.googlesource.com/1120343
> Commit-Queue: Georgia Kouveli <georgia.kouveli@arm.com>
> Reviewed-by: Sigurd Schneider <sigurds@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#54162}

Bug: v8:7844
Change-Id: I2eab2d753fd8e374bf7c912a107c93edc58ef4c7
Reviewed-on: https://chromium-review.googlesource.com/1126259Reviewed-by: 's avatarJakob Gruber <jgruber@chromium.org>
Reviewed-by: 's avatarSigurd Schneider <sigurds@chromium.org>
Commit-Queue: Georgia Kouveli <georgia.kouveli@arm.com>
Cr-Commit-Position: refs/heads/master@{#54257}
parent a7dce4fb
......@@ -130,6 +130,7 @@ class Arm64OperandConverter final : public InstructionOperandConverter {
return Operand(InputRegister32(index), SXTW);
case kMode_MRI:
case kMode_MRR:
case kMode_Root:
break;
}
UNREACHABLE();
......@@ -159,13 +160,13 @@ class Arm64OperandConverter final : public InstructionOperandConverter {
return Operand(InputRegister64(index), SXTW);
case kMode_MRI:
case kMode_MRR:
case kMode_Root:
break;
}
UNREACHABLE();
}
MemOperand MemoryOperand(size_t* first_index) {
const size_t index = *first_index;
MemOperand MemoryOperand(size_t index = 0) {
switch (AddressingModeField::decode(instr_->opcode())) {
case kMode_None:
case kMode_Operand2_R_LSR_I:
......@@ -177,24 +178,19 @@ class Arm64OperandConverter final : public InstructionOperandConverter {
case kMode_Operand2_R_SXTH:
case kMode_Operand2_R_SXTW:
break;
case kMode_Root:
return MemOperand(kRootRegister, InputInt64(index));
case kMode_Operand2_R_LSL_I:
*first_index += 3;
return MemOperand(InputRegister(index + 0), InputRegister(index + 1),
LSL, InputInt32(index + 2));
case kMode_MRI:
*first_index += 2;
return MemOperand(InputRegister(index + 0), InputInt32(index + 1));
case kMode_MRR:
*first_index += 2;
return MemOperand(InputRegister(index + 0), InputRegister(index + 1));
}
UNREACHABLE();
}
MemOperand MemoryOperand(size_t first_index = 0) {
return MemoryOperand(&first_index);
}
Operand ToOperand(InstructionOperand* op) {
if (op->IsRegister()) {
return Operand(ToRegister(op));
......
......@@ -362,7 +362,8 @@ namespace compiler {
V(Operand2_R_UXTH) /* %r0 UXTH (unsigned extend halfword) */ \
V(Operand2_R_SXTB) /* %r0 SXTB (signed extend byte) */ \
V(Operand2_R_SXTH) /* %r0 SXTH (signed extend halfword) */ \
V(Operand2_R_SXTW) /* %r0 SXTW (signed extend word) */
V(Operand2_R_SXTW) /* %r0 SXTW (signed extend word) */ \
V(Root) /* [%rr + K] */
} // namespace compiler
} // namespace internal
......
......@@ -560,6 +560,27 @@ void EmitLoad(InstructionSelector* selector, Node* node, InstructionCode opcode,
// If output is not nullptr, use that as the output register. This
// is used when we merge a conversion into the load.
outputs[0] = g.DefineAsRegister(output == nullptr ? node : output);
if (selector->CanAddressRelativeToRootsRegister()) {
ExternalReferenceMatcher m(base);
if (m.HasValue() && g.IsIntegerConstant(index)) {
ptrdiff_t const delta =
g.GetIntegerConstantValue(index) +
TurboAssemblerBase::RootRegisterOffsetForExternalReference(
selector->isolate(), m.Value());
input_count = 1;
// Check that the delta is a 32-bit integer due to the limitations of
// immediate operands.
if (is_int32(delta)) {
inputs[0] = g.UseImmediate(static_cast<int32_t>(delta));
opcode |= AddressingModeField::encode(kMode_Root);
selector->Emit(opcode, arraysize(outputs), outputs, input_count,
inputs);
return;
}
}
}
inputs[0] = g.UseRegister(base);
if (g.CanBeImmediate(index, immediate_mode)) {
......
......@@ -4474,6 +4474,47 @@ TEST_F(InstructionSelectorTest, StackCheck1) {
EXPECT_EQ(0U, s[1]->OutputCount());
}
TEST_F(InstructionSelectorTest, ExternalReferenceLoad1) {
// Test offsets we can use kMode_Root for.
const int64_t kOffsets[] = {0, 1, 4, INT32_MIN, INT32_MAX};
TRACED_FOREACH(int64_t, offset, kOffsets) {
StreamBuilder m(this, MachineType::Int64());
ExternalReference reference = bit_cast<ExternalReference>(
reinterpret_cast<intptr_t>(isolate()->heap()->roots_array_start()) +
offset + kRootRegisterBias);
Node* const value =
m.Load(MachineType::Int64(), m.ExternalConstant(reference));
m.Return(value);
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
EXPECT_EQ(kArm64Ldr, s[0]->arch_opcode());
EXPECT_EQ(kMode_Root, s[0]->addressing_mode());
EXPECT_EQ(1U, s[0]->InputCount());
EXPECT_EQ(s.ToInt64(s[0]->InputAt(0)), offset);
EXPECT_EQ(1U, s[0]->OutputCount());
}
}
TEST_F(InstructionSelectorTest, ExternalReferenceLoad2) {
// Offset too large, we cannot use kMode_Root.
StreamBuilder m(this, MachineType::Int64());
int64_t offset = 0x100000000;
ExternalReference reference = bit_cast<ExternalReference>(
reinterpret_cast<intptr_t>(isolate()->heap()->roots_array_start()) +
offset + kRootRegisterBias);
Node* const value =
m.Load(MachineType::Int64(), m.ExternalConstant(reference));
m.Return(value);
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
EXPECT_EQ(kArm64Ldr, s[0]->arch_opcode());
EXPECT_NE(kMode_Root, s[0]->addressing_mode());
}
} // namespace compiler
} // namespace internal
} // namespace v8
......@@ -163,7 +163,7 @@ class InstructionSelectorTest : public TestWithContext,
Operator::kNoProperties, // properties
kCalleeSaveRegisters, // callee-saved registers
kCalleeSaveFPRegisters, // callee-saved fp regs
CallDescriptor::kNoFlags, // flags
CallDescriptor::kCanUseRoots, // flags
"iselect-test-call");
}
};
......
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