Chromium Code Reviews| 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..bef7facb292ee955e1f4151ec463b02339cf80fd 100644 |
| --- a/src/a64/macro-assembler-a64.cc |
| +++ b/src/a64/macro-assembler-a64.cc |
| @@ -558,6 +558,182 @@ 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. |
| + margin += margin / 4; |
|
ulan
2014/02/18 10:17:40
Where 4 comes from?
Alexandre Rames
2014/02/18 11:59:20
Complete finger in the air guess.
With a default m
|
| + } |
| + 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))); |
|
ulan
2014/02/18 10:17:40
If the CheckVeneers below emits veneers then the p
Alexandre Rames
2014/02/18 11:59:20
Ouch. Thanks.
|
| + } |
| + CheckVeneers(true); |
| + return need_longer_range; |
| +} |
| + |
| + |
| +void MacroAssembler::B(Label* label, Condition cond) { |
| + ASSERT(allow_macro_instructions_); |
| + ASSERT((cond != al) && (cond != nv)); |
| + |
| + if (NeedExtraInstructionsOrRegisterBranch(label, CondBranchType)) { |
| + Label over; |
| + b(&over, InvertCondition(cond)); |
| + b(label); |
| + bind(&over); |
| + } else { |
| + b(label, cond); |
| + } |
| +} |
| + |
| + |
| +void MacroAssembler::Tbnz(const Register& rt, unsigned bit_pos, Label* label) { |
| + ASSERT(allow_macro_instructions_); |
| + |
| + if (NeedExtraInstructionsOrRegisterBranch(label, TestBranchType)) { |
| + Label over; |
| + tbz(rt, bit_pos, &over); |
| + b(label); |
| + bind(&over); |
| + } else { |
| + tbnz(rt, bit_pos, label); |
| + } |
| +} |
| + |
| + |
| +void MacroAssembler::Tbz(const Register& rt, unsigned bit_pos, Label* label) { |
| + ASSERT(allow_macro_instructions_); |
| + |
| + if (NeedExtraInstructionsOrRegisterBranch(label, TestBranchType)) { |
| + Label over; |
| + tbnz(rt, bit_pos, &over); |
| + b(label); |
| + bind(&over); |
| + } else { |
| + tbz(rt, bit_pos, label); |
| + } |
| +} |
| + |
| + |
| +void MacroAssembler::Cbnz(const Register& rt, Label* label) { |
| + ASSERT(allow_macro_instructions_); |
| + |
| + if (NeedExtraInstructionsOrRegisterBranch(label, CompareBranchType)) { |
| + Label over; |
| + cbz(rt, &over); |
| + b(label); |
| + bind(&over); |
| + } else { |
| + cbnz(rt, label); |
| + } |
| +} |
| + |
| + |
| +void MacroAssembler::Cbz(const Register& rt, Label* label) { |
| + ASSERT(allow_macro_instructions_); |
| + |
| + if (NeedExtraInstructionsOrRegisterBranch(label, CompareBranchType)) { |
| + Label over; |
| + cbnz(rt, &over); |
| + b(label); |
| + bind(&over); |
| + } else { |
| + cbz(rt, label); |
| + } |
| +} |
| + |
| + |
| // Pseudo-instructions. |