Commit 5e716333 authored by Pierre Langlois's avatar Pierre Langlois Committed by Commit Bot

[arm, arm64] Setup arguments to RecordWriteStub using `mov`.

The `TurboAssembler::CallRecordWriteStub()` method which generates out-of-line
code to call the write barrier would push and pop arguments to move them to
different registers. Let's use `mov` instructions instead, making sure we handle
overlapping registers.

Change-Id: Ideb654cd558e984ccb90c7cf44b1c2c49f1c5b50
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1499496
Commit-Queue: Jakob Gruber <jgruber@chromium.org>
Reviewed-by: 's avatarJakob Gruber <jgruber@chromium.org>
Reviewed-by: 's avatarUlan Degenbaev <ulan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#60026}
parent e00f2de6
......@@ -476,6 +476,22 @@ void TurboAssembler::Move(QwNeonRegister dst, QwNeonRegister src) {
}
}
void TurboAssembler::MovePair(Register dst0, Register src0, Register dst1,
Register src1) {
DCHECK_NE(dst0, dst1);
if (dst0 != src1) {
Move(dst0, src0);
Move(dst1, src1);
} else if (dst1 != src0) {
// Swap the order of the moves to resolve the overlap.
Move(dst1, src1);
Move(dst0, src0);
} else {
// Worse case scenario, this is a swap.
Swap(dst0, src0);
}
}
void TurboAssembler::Swap(Register srcdst0, Register srcdst1) {
DCHECK(srcdst0 != srcdst1);
UseScratchRegisterScope temps(this);
......@@ -701,11 +717,7 @@ void TurboAssembler::CallRecordWriteStub(
Register fp_mode_parameter(
descriptor.GetRegisterParameter(RecordWriteDescriptor::kFPMode));
Push(object);
Push(address);
Pop(slot_parameter);
Pop(object_parameter);
MovePair(object_parameter, object, slot_parameter, address);
Move(remembered_set_parameter, Smi::FromEnum(remembered_set_action));
Move(fp_mode_parameter, Smi::FromEnum(fp_mode));
......
......@@ -430,6 +430,9 @@ class V8_EXPORT_PRIVATE TurboAssembler : public TurboAssemblerBase {
mov(dst, src, sbit, cond);
}
}
// Move src0 to dst0 and src1 to dst1, handling possible overlaps.
void MovePair(Register dst0, Register src0, Register dst1, Register src1);
void Move(SwVfpRegister dst, SwVfpRegister src, Condition cond = al);
void Move(DwVfpRegister dst, DwVfpRegister src, Condition cond = al);
void Move(QwNeonRegister dst, QwNeonRegister src);
......
......@@ -1568,6 +1568,22 @@ void MacroAssembler::LoadObject(Register result, Handle<Object> object) {
void TurboAssembler::Move(Register dst, Smi src) { Mov(dst, src); }
void TurboAssembler::MovePair(Register dst0, Register src0, Register dst1,
Register src1) {
DCHECK_NE(dst0, dst1);
if (dst0 != src1) {
Mov(dst0, src0);
Mov(dst1, src1);
} else if (dst1 != src0) {
// Swap the order of the moves to resolve the overlap.
Mov(dst1, src1);
Mov(dst0, src0);
} else {
// Worse case scenario, this is a swap.
Swap(dst0, src0);
}
}
void TurboAssembler::Swap(Register lhs, Register rhs) {
DCHECK(lhs.IsSameSizeAndType(rhs));
DCHECK(!lhs.Is(rhs));
......@@ -3064,9 +3080,7 @@ void TurboAssembler::CallRecordWriteStub(
Register fp_mode_parameter(
descriptor.GetRegisterParameter(RecordWriteDescriptor::kFPMode));
Push(object, address);
Pop(slot_parameter, object_parameter);
MovePair(object_parameter, object, slot_parameter, address);
Mov(remembered_set_parameter, Smi::FromEnum(remembered_set_action));
Mov(fp_mode_parameter, Smi::FromEnum(fp_mode));
......
......@@ -213,6 +213,9 @@ class V8_EXPORT_PRIVATE TurboAssembler : public TurboAssemblerBase {
// Remove if not needed.
void Move(Register dst, Smi src);
// Move src0 to dst0 and src1 to dst1, handling possible overlaps.
void MovePair(Register dst0, Register src0, Register dst1, Register src1);
// Register swap. Note that the register operands should be distinct.
void Swap(Register lhs, Register rhs);
void Swap(VRegister lhs, VRegister rhs);
......
......@@ -4,7 +4,7 @@
#include "test/cctest/assembler-helper-arm.h"
#include "src/assembler-inl.h"
#include "src/macro-assembler.h"
#include "src/isolate-inl.h"
#include "src/v8.h"
#include "test/cctest/cctest.h"
......@@ -12,9 +12,9 @@
namespace v8 {
namespace internal {
Handle<Code> AssembleCodeImpl(std::function<void(Assembler&)> assemble) {
Handle<Code> AssembleCodeImpl(std::function<void(MacroAssembler&)> assemble) {
Isolate* isolate = CcTest::i_isolate();
Assembler assm(AssemblerOptions{});
MacroAssembler assm(AssemblerOptions{});
assemble(assm);
assm.bx(lr);
......
......@@ -21,11 +21,11 @@ using F_ppiii = void*(void* p0, void* p1, int p2, int p3, int p4);
using F_pppii = void*(void* p0, void* p1, void* p2, int p3, int p4);
using F_ippii = void*(int p0, void* p1, void* p2, int p3, int p4);
Handle<Code> AssembleCodeImpl(std::function<void(Assembler&)> assemble);
Handle<Code> AssembleCodeImpl(std::function<void(MacroAssembler&)> assemble);
template <typename Signature>
GeneratedCode<Signature> AssembleCode(
std::function<void(Assembler&)> assemble) {
std::function<void(MacroAssembler&)> assemble) {
return GeneratedCode<Signature>::FromCode(*AssembleCodeImpl(assemble));
}
......
......@@ -4182,6 +4182,81 @@ TEST(vneg_64) {
}
}
TEST(move_pair) {
Isolate* isolate = CcTest::i_isolate();
HandleScope scope(isolate);
auto f = AssembleCode<F_piiii>([](MacroAssembler& assm) {
RegList used_callee_saved =
r4.bit() | r5.bit() | r6.bit() | r7.bit() | r8.bit();
__ stm(db_w, sp, used_callee_saved);
// Save output register bank pointer to r8.
__ mov(r8, r0);
__ mov(r0, Operand(0xabababab));
__ mov(r1, Operand(0xbabababa));
__ mov(r2, Operand(0x12341234));
__ mov(r3, Operand(0x43214321));
// No overlap:
// r4 <- r0
// r5 <- r1
__ MovePair(r4, r0, r5, r1);
// Overlap but we can swap moves:
// r2 <- r0
// r6 <- r2
__ MovePair(r2, r0, r6, r2);
// Overlap but can be done:
// r7 <- r3
// r3 <- r0
__ MovePair(r7, r3, r3, r0);
// Swap.
// r0 <- r1
// r1 <- r0
__ MovePair(r0, r1, r1, r0);
// Fill the fake register bank.
__ str(r0, MemOperand(r8, 0 * kPointerSize));
__ str(r1, MemOperand(r8, 1 * kPointerSize));
__ str(r2, MemOperand(r8, 2 * kPointerSize));
__ str(r3, MemOperand(r8, 3 * kPointerSize));
__ str(r4, MemOperand(r8, 4 * kPointerSize));
__ str(r5, MemOperand(r8, 5 * kPointerSize));
__ str(r6, MemOperand(r8, 6 * kPointerSize));
__ str(r7, MemOperand(r8, 7 * kPointerSize));
__ ldm(ia_w, sp, used_callee_saved);
});
// Create a fake register bank.
uint32_t r[] = {0, 0, 0, 0, 0, 0, 0, 0};
f.Call(r, 0, 0, 0, 0);
// r4 <- r0
// r5 <- r1
CHECK_EQ(0xabababab, r[4]);
CHECK_EQ(0xbabababa, r[5]);
// r2 <- r0
// r6 <- r2
CHECK_EQ(0xabababab, r[2]);
CHECK_EQ(0x12341234, r[6]);
// r7 <- r3
// r3 <- r0
CHECK_EQ(0x43214321, r[7]);
CHECK_EQ(0xabababab, r[3]);
// r0 and r1 should be swapped.
CHECK_EQ(0xbabababa, r[0]);
CHECK_EQ(0xabababab, r[1]);
}
#undef __
} // namespace test_assembler_arm
......
......@@ -411,6 +411,60 @@ TEST(mov) {
CHECK_EQUAL_64(0x000000000001FFE0UL, x27);
}
TEST(move_pair) {
INIT_V8();
SETUP();
START();
__ Mov(x0, 0xabababab);
__ Mov(x1, 0xbabababa);
__ Mov(x2, 0x12341234);
__ Mov(x3, 0x43214321);
// No overlap:
// x4 <- x0
// x5 <- x1
__ MovePair(x4, x0, x5, x1);
// Overlap but we can swap moves:
// x2 <- x0
// x6 <- x2
__ MovePair(x2, x0, x6, x2);
// Overlap but can be done:
// x7 <- x3
// x3 <- x0
__ MovePair(x7, x3, x3, x0);
// Swap.
// x0 <- x1
// x1 <- x0
__ MovePair(x0, x1, x1, x0);
END();
RUN();
// x4 <- x0
// x5 <- x1
CHECK_EQUAL_64(0xabababab, x4);
CHECK_EQUAL_64(0xbabababa, x5);
// x2 <- x0
// x6 <- x2
CHECK_EQUAL_64(0xabababab, x2);
CHECK_EQUAL_64(0x12341234, x6);
// x7 <- x3
// x3 <- x0
CHECK_EQUAL_64(0x43214321, x7);
CHECK_EQUAL_64(0xabababab, x3);
// x0 and x1 should be swapped.
CHECK_EQUAL_64(0xbabababa, x0);
CHECK_EQUAL_64(0xabababab, x1);
}
TEST(mov_imm_w) {
INIT_V8();
SETUP();
......
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