Chromium Code Reviews| Index: runtime/vm/assembler_arm64.cc |
| =================================================================== |
| --- runtime/vm/assembler_arm64.cc (revision 36030) |
| +++ runtime/vm/assembler_arm64.cc (working copy) |
| @@ -20,6 +20,7 @@ |
| namespace dart { |
| +DEFINE_FLAG(bool, use_far_branches, false, "Always use far branches"); |
| DEFINE_FLAG(bool, print_stop_message, false, "Print stop message."); |
| DECLARE_FLAG(bool, inline_alloc); |
| @@ -123,18 +124,81 @@ |
| } |
| -// TODO(zra): Support for far branches. Requires loading large immediates. |
| void Assembler::Bind(Label* label) { |
| ASSERT(!label->IsBound()); |
| - intptr_t bound_pc = buffer_.Size(); |
| + const intptr_t bound_pc = buffer_.Size(); |
| while (label->IsLinked()) { |
| const int64_t position = label->Position(); |
| const int64_t dest = bound_pc - position; |
| - const int32_t next = buffer_.Load<int32_t>(position); |
| - const int32_t encoded = EncodeImm19BranchOffset(dest, next); |
| - buffer_.Store<int32_t>(position, encoded); |
| - label->position_ = DecodeImm19BranchOffset(next); |
| + if (use_far_branches() /*&& !CanEncodeImm19BranchOffset(dest)*/) { |
|
regis
2014/05/12 16:05:02
Left over commented code?
zra
2014/05/12 18:42:50
Ah, yah, thanks. I was testing without the optimiz
|
| + // Far branches are enabled, and we can't encode the branch offset in |
| + // 19 bits. |
| + |
| + // Grab the guarding branch instruction. |
| + const int32_t guard_branch = |
| + buffer_.Load<int32_t>(position + 0 * Instr::kInstrSize); |
| + |
| + // Grab the far branch instruction. |
| + const int32_t far_branch = |
| + buffer_.Load<int32_t>(position + 1 * Instr::kInstrSize); |
| + |
| + const Condition c = DecodeImm19BranchCondition(guard_branch); |
| + |
| + // Grab the link to the next branch. |
| + const int32_t next = DecodeImm26BranchOffset(far_branch); |
| + |
| + // dest is the offset is from the guarding branch instruction. |
| + // Correct it to be from the following instruction. |
| + const int64_t offset = dest - Instr::kInstrSize; |
| + |
| + // Encode the branch. |
| + const int32_t encoded_branch = |
| + EncodeImm26BranchOffset(offset, far_branch); |
| + |
| + // If the guard branch is conditioned on NV, replace it with a nop. |
| + if (c == NV) { |
| + buffer_.Store<int32_t>(position + 0 * Instr::kInstrSize, |
| + Instr::kNopInstruction); |
| + } |
| + |
| + // Write the far branch into the buffer and link to the next branch. |
| + buffer_.Store<int32_t>(position + 1 * Instr::kInstrSize, encoded_branch); |
| + label->position_ = next; |
| + } else if (use_far_branches() && CanEncodeImm19BranchOffset(dest)) { |
| + // We assembled a far branch, but we don't need it. Replace it with a near |
| + // branch. |
| + |
| + // Grab the guarding branch instruction. |
| + const int32_t guard_branch = |
| + buffer_.Load<int32_t>(position + 0 * Instr::kInstrSize); |
| + |
| + // Grab the far branch instruction. |
| + const int32_t far_branch = |
| + buffer_.Load<int32_t>(position + 1 * Instr::kInstrSize); |
| + |
| + // Grab the link to the next branch. |
| + const int32_t next = DecodeImm26BranchOffset(far_branch); |
| + |
| + // Re-target the guarding branch and flip the conditional sense. |
| + int32_t encoded_guard_branch = |
| + EncodeImm19BranchOffset(dest, guard_branch); |
| + const Condition c = DecodeImm19BranchCondition(encoded_guard_branch); |
| + encoded_guard_branch = EncodeImm19BranchCondition( |
| + InvertCondition(c), encoded_guard_branch); |
| + |
| + // Write back the re-encoded instructions. The far branch becomes a nop. |
| + buffer_.Store<int32_t>( |
| + position + 0 * Instr::kInstrSize, encoded_guard_branch); |
| + buffer_.Store<int32_t>( |
| + position + 1 * Instr::kInstrSize, Instr::kNopInstruction); |
| + label->position_ = next; |
| + } else { |
| + const int32_t next = buffer_.Load<int32_t>(position); |
| + const int32_t encoded = EncodeImm19BranchOffset(dest, next); |
| + buffer_.Store<int32_t>(position, encoded); |
| + label->position_ = DecodeImm19BranchOffset(next); |
| + } |
| } |
| label->BindTo(bound_pc); |
| } |
| @@ -945,7 +1009,9 @@ |
| void Assembler::ReserveAlignedFrameSpace(intptr_t frame_space) { |
| // Reserve space for arguments and align frame before entering |
| // the C++ world. |
| - AddImmediate(SP, SP, -frame_space, kNoPP); |
| + if (frame_space != 0) { |
| + AddImmediate(SP, SP, -frame_space, kNoPP); |
| + } |
| if (OS::ActivationFrameAlignment() > 1) { |
| mov(TMP, SP); // SP can't be register operand of andi. |
| andi(TMP, TMP, ~(OS::ActivationFrameAlignment() - 1)); |