ARM64: improve Adr patching

R=ulan@chromium.org, bmeurer@chromium.org

BUG=

Review URL: https://codereview.chromium.org/363293004

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@22198 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent f3b9ece6
......@@ -3088,31 +3088,12 @@ void Assembler::PopulateConstantPool(ConstantPoolArray* constant_pool) {
}
void PatchingAssembler::MovInt64(const Register& rd, int64_t imm) {
Label start;
bind(&start);
ASSERT(rd.Is64Bits());
ASSERT(!rd.IsSP());
for (unsigned i = 0; i < (rd.SizeInBits() / 16); i++) {
uint64_t imm16 = (imm >> (16 * i)) & 0xffffL;
movk(rd, imm16, 16 * i);
}
ASSERT(SizeOfCodeGeneratedSince(&start) ==
kMovInt64NInstrs * kInstructionSize);
}
void PatchingAssembler::PatchAdrFar(Instruction* target) {
void PatchingAssembler::PatchAdrFar(ptrdiff_t target_offset) {
// The code at the current instruction should be:
// adr rd, 0
// nop (adr_far)
// nop (adr_far)
// nop (adr_far)
// movz scratch, 0
// add rd, rd, scratch
// Verify the expected code.
Instruction* expected_adr = InstructionAt(0);
......@@ -3122,39 +3103,21 @@ void PatchingAssembler::PatchAdrFar(Instruction* target) {
CHECK(InstructionAt((i + 1) * kInstructionSize)->IsNop(ADR_FAR_NOP));
}
Instruction* expected_movz =
InstructionAt((kAdrFarPatchableNInstrs - 2) * kInstructionSize);
InstructionAt((kAdrFarPatchableNInstrs - 1) * kInstructionSize);
CHECK(expected_movz->IsMovz() &&
(expected_movz->ImmMoveWide() == 0) &&
(expected_movz->ShiftMoveWide() == 0));
int scratch_code = expected_movz->Rd();
Instruction* expected_add =
InstructionAt((kAdrFarPatchableNInstrs - 1) * kInstructionSize);
CHECK(expected_add->IsAddSubShifted() &&
(expected_add->Mask(AddSubOpMask) == ADD) &&
expected_add->SixtyFourBits() &&
(expected_add->Rd() == rd_code) && (expected_add->Rn() == rd_code) &&
(expected_add->Rm() == scratch_code) &&
(static_cast<Shift>(expected_add->ShiftDP()) == LSL) &&
(expected_add->ImmDPShift() == 0));
// Patch to load the correct address.
Label start;
bind(&start);
Register rd = Register::XRegFromCode(rd_code);
// If the target is in range, we only patch the adr. Otherwise we patch the
// nops with fixup instructions.
int target_offset = expected_adr->DistanceTo(target);
if (Instruction::IsValidPCRelOffset(target_offset)) {
adr(rd, target_offset);
for (int i = 0; i < kAdrFarPatchableNInstrs - 2; ++i) {
nop(ADR_FAR_NOP);
}
} else {
Register scratch = Register::XRegFromCode(scratch_code);
adr(rd, 0);
MovInt64(scratch, target_offset);
add(rd, rd, scratch);
}
Register scratch = Register::XRegFromCode(scratch_code);
// Addresses are only 48 bits.
adr(rd, target_offset & 0xFFFF);
movz(scratch, (target_offset >> 16) & 0xFFFF, 16);
movk(scratch, (target_offset >> 32) & 0xFFFF, 32);
ASSERT((target_offset >> 48) == 0);
add(rd, rd, scratch);
}
......
......@@ -2286,13 +2286,10 @@ class PatchingAssembler : public Assembler {
CpuFeatures::FlushICache(buffer_, length);
}
static const int kMovInt64NInstrs = 4;
void MovInt64(const Register& rd, int64_t imm);
// See definition of PatchAdrFar() for details.
static const int kAdrFarPatchableNNops = kMovInt64NInstrs - 1;
static const int kAdrFarPatchableNInstrs = kAdrFarPatchableNNops + 3;
void PatchAdrFar(Instruction* target);
static const int kAdrFarPatchableNNops = 2;
static const int kAdrFarPatchableNInstrs = kAdrFarPatchableNNops + 2;
void PatchAdrFar(ptrdiff_t target_offset);
};
......
......@@ -233,7 +233,7 @@ void Instruction::SetPCRelImmTarget(Instruction* target) {
// ADRP is not supported, so 'this' must point to an ADR instruction.
ASSERT(IsAdr());
int target_offset = DistanceTo(target);
ptrdiff_t target_offset = DistanceTo(target);
Instr imm;
if (Instruction::IsValidPCRelOffset(target_offset)) {
imm = Assembler::ImmPCRelAddress(target_offset);
......@@ -241,7 +241,7 @@ void Instruction::SetPCRelImmTarget(Instruction* target) {
} else {
PatchingAssembler patcher(this,
PatchingAssembler::kAdrFarPatchableNInstrs);
patcher.PatchAdrFar(target);
patcher.PatchAdrFar(target_offset);
}
}
......
......@@ -613,10 +613,6 @@ void MacroAssembler::Adr(const Register& rd, Label* label, AdrHint hint) {
}
ASSERT(hint == kAdrFar);
UseScratchRegisterScope temps(this);
Register scratch = temps.AcquireX();
ASSERT(!AreAliased(rd, scratch));
if (label->is_bound()) {
int label_offset = label->pos() - pc_offset();
if (Instruction::IsValidPCRelOffset(label_offset)) {
......@@ -628,6 +624,9 @@ void MacroAssembler::Adr(const Register& rd, Label* label, AdrHint hint) {
Add(rd, rd, label_offset - min_adr_offset);
}
} else {
UseScratchRegisterScope temps(this);
Register scratch = temps.AcquireX();
InstructionAccurateScope scope(
this, PatchingAssembler::kAdrFarPatchableNInstrs);
adr(rd, label);
......@@ -635,7 +634,6 @@ void MacroAssembler::Adr(const Register& rd, Label* label, AdrHint hint) {
nop(ADR_FAR_NOP);
}
movz(scratch, 0);
add(rd, rd, scratch);
}
}
......
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