| Index: src/a64/macro-assembler-a64.cc
|
| diff --git a/src/a64/macro-assembler-a64.cc b/src/a64/macro-assembler-a64.cc
|
| index c5184e891521420db1966d6a391c90d9d53401b3..8401a9defa0ef102b5178b9fbc769740c1c2ebb8 100644
|
| --- a/src/a64/macro-assembler-a64.cc
|
| +++ b/src/a64/macro-assembler-a64.cc
|
| @@ -558,6 +558,204 @@ void MacroAssembler::Store(const Register& rt,
|
| }
|
|
|
|
|
| +bool MacroAssembler::ShouldEmitVeneer(int max_reachable_pc, int margin) {
|
| + // Account for the branch around the veneers and the guard.
|
| + int protection_offset = 2 * kInstructionSize;
|
| + return pc_offset() > max_reachable_pc - margin - protection_offset -
|
| + static_cast<int>(unresolved_branches_.size() * kMaxVeneerCodeSize);
|
| +}
|
| +
|
| +
|
| +void MacroAssembler::EmitVeneers(bool need_protection) {
|
| + RecordComment("[ Veneers");
|
| +
|
| + Label end;
|
| + if (need_protection) {
|
| + B(&end);
|
| + }
|
| +
|
| + EmitVeneersGuard();
|
| +
|
| + {
|
| + InstructionAccurateScope scope(this);
|
| + Label size_check;
|
| +
|
| + std::multimap<int, FarBranchInfo>::iterator it, it_to_delete;
|
| +
|
| + it = unresolved_branches_.begin();
|
| + while (it != unresolved_branches_.end()) {
|
| + if (ShouldEmitVeneer(it->first)) {
|
| + Instruction* branch = InstructionAt(it->second.pc_offset_);
|
| + Label* label = it->second.label_;
|
| +
|
| +#ifdef DEBUG
|
| + __ bind(&size_check);
|
| +#endif
|
| + // Patch the branch to point to the current position, and emit a branch
|
| + // to the label.
|
| + Instruction* veneer = reinterpret_cast<Instruction*>(pc_);
|
| + RemoveBranchFromLabelLinkChain(branch, label, veneer);
|
| + branch->SetImmPCOffsetTarget(veneer);
|
| + b(label);
|
| +#ifdef DEBUG
|
| + ASSERT(SizeOfCodeGeneratedSince(&size_check) <= kMaxVeneerCodeSize);
|
| + size_check.Unuse();
|
| +#endif
|
| +
|
| + it_to_delete = it++;
|
| + unresolved_branches_.erase(it_to_delete);
|
| + } else {
|
| + ++it;
|
| + }
|
| + }
|
| + }
|
| +
|
| + Bind(&end);
|
| +
|
| + RecordComment("]");
|
| +}
|
| +
|
| +
|
| +void MacroAssembler::EmitVeneersGuard() {
|
| + if (emit_debug_code()) {
|
| + Unreachable();
|
| + }
|
| +}
|
| +
|
| +
|
| +void MacroAssembler::CheckVeneers(bool need_protection) {
|
| + if (unresolved_branches_.empty()) {
|
| + return;
|
| + }
|
| +
|
| + CHECK(pc_offset() < unresolved_branches_first_limit());
|
| + int margin = kVeneerDistanceMargin;
|
| + if (!need_protection) {
|
| + // Prefer emitting veneers protected by an existing instruction.
|
| + // The 4 divisor is a finger in the air guess. With a default margin of 2KB,
|
| + // that leaves 512B = 128 instructions of extra margin to avoid requiring a
|
| + // protective branch.
|
| + margin += margin / 4;
|
| + }
|
| + if (ShouldEmitVeneer(unresolved_branches_first_limit(), margin)) {
|
| + EmitVeneers(need_protection);
|
| + }
|
| +}
|
| +
|
| +
|
| +bool MacroAssembler::NeedExtraInstructionsOrRegisterBranch(
|
| + Label *label, ImmBranchType b_type) {
|
| + bool need_longer_range = false;
|
| + // There are two situations in which we care about the offset being out of
|
| + // range:
|
| + // - The label is bound but too far away.
|
| + // - The label is not bound but linked, and the previous branch
|
| + // instruction in the chain is too far away.
|
| + if (label->is_bound() || label->is_linked()) {
|
| + need_longer_range =
|
| + !Instruction::IsValidImmPCOffset(b_type, label->pos() - pc_offset());
|
| + }
|
| + if (!need_longer_range && !label->is_bound()) {
|
| + int max_reachable_pc = pc_offset() + Instruction::ImmBranchRange(b_type);
|
| + unresolved_branches_.insert(
|
| + std::pair<int, FarBranchInfo>(max_reachable_pc,
|
| + FarBranchInfo(pc_offset(), label)));
|
| + }
|
| + return need_longer_range;
|
| +}
|
| +
|
| +
|
| +void MacroAssembler::B(Label* label, Condition cond) {
|
| + ASSERT(allow_macro_instructions_);
|
| + ASSERT((cond != al) && (cond != nv));
|
| +
|
| + Label done;
|
| + bool need_extra_instructions =
|
| + NeedExtraInstructionsOrRegisterBranch(label, CondBranchType);
|
| +
|
| + if (need_extra_instructions) {
|
| + b(&done, InvertCondition(cond));
|
| + b(label);
|
| + } else {
|
| + b(label, cond);
|
| + }
|
| + CheckVeneers(!need_extra_instructions);
|
| + bind(&done);
|
| +}
|
| +
|
| +
|
| +void MacroAssembler::Tbnz(const Register& rt, unsigned bit_pos, Label* label) {
|
| + ASSERT(allow_macro_instructions_);
|
| +
|
| + Label done;
|
| + bool need_extra_instructions =
|
| + NeedExtraInstructionsOrRegisterBranch(label, TestBranchType);
|
| +
|
| + if (need_extra_instructions) {
|
| + tbz(rt, bit_pos, &done);
|
| + b(label);
|
| + } else {
|
| + tbnz(rt, bit_pos, label);
|
| + }
|
| + CheckVeneers(!need_extra_instructions);
|
| + bind(&done);
|
| +}
|
| +
|
| +
|
| +void MacroAssembler::Tbz(const Register& rt, unsigned bit_pos, Label* label) {
|
| + ASSERT(allow_macro_instructions_);
|
| +
|
| + Label done;
|
| + bool need_extra_instructions =
|
| + NeedExtraInstructionsOrRegisterBranch(label, TestBranchType);
|
| +
|
| + if (need_extra_instructions) {
|
| + tbnz(rt, bit_pos, &done);
|
| + b(label);
|
| + } else {
|
| + tbz(rt, bit_pos, label);
|
| + }
|
| + CheckVeneers(!need_extra_instructions);
|
| + bind(&done);
|
| +}
|
| +
|
| +
|
| +void MacroAssembler::Cbnz(const Register& rt, Label* label) {
|
| + ASSERT(allow_macro_instructions_);
|
| +
|
| + Label done;
|
| + bool need_extra_instructions =
|
| + NeedExtraInstructionsOrRegisterBranch(label, CompareBranchType);
|
| +
|
| + if (need_extra_instructions) {
|
| + cbz(rt, &done);
|
| + b(label);
|
| + } else {
|
| + cbnz(rt, label);
|
| + }
|
| + CheckVeneers(!need_extra_instructions);
|
| + bind(&done);
|
| +}
|
| +
|
| +
|
| +void MacroAssembler::Cbz(const Register& rt, Label* label) {
|
| + ASSERT(allow_macro_instructions_);
|
| +
|
| + Label done;
|
| + bool need_extra_instructions =
|
| + NeedExtraInstructionsOrRegisterBranch(label, CompareBranchType);
|
| +
|
| + if (need_extra_instructions) {
|
| + cbnz(rt, &done);
|
| + b(label);
|
| + } else {
|
| + cbz(rt, label);
|
| + }
|
| + CheckVeneers(!need_extra_instructions);
|
| + bind(&done);
|
| +}
|
| +
|
| +
|
| // Pseudo-instructions.
|
|
|
|
|
|
|