Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(152)

Unified Diff: runtime/vm/assembler_arm64.cc

Issue 283513002: Adds far-branches to arm64. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « runtime/vm/assembler_arm64.h ('k') | runtime/vm/constants_arm64.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: runtime/vm/assembler_arm64.cc
===================================================================
--- runtime/vm/assembler_arm64.cc (revision 36049)
+++ 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)) {
+ // 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);
}
@@ -426,6 +490,9 @@
bool Assembler::CanLoadImmediateFromPool(int64_t imm, Register pp) {
return !Utils::IsInt(32, imm) &&
(pp != kNoPP) &&
+ // We *could* put constants in the pool in a VM isolate, but it is
+ // simpler to maintain the invariant that the object pool is not used
+ // in the VM isolate.
(Isolate::Current() != Dart::vm_isolate());
}
@@ -434,9 +501,14 @@
const ExternalLabel* label,
Patchability patchable,
Register pp) {
- const int32_t offset =
- Array::element_offset(FindExternalLabel(label, patchable));
- LoadWordFromPoolOffset(dst, pp, offset);
+ const int64_t target = static_cast<int64_t>(label->address());
+ if (CanLoadImmediateFromPool(target, pp)) {
+ const int32_t offset =
+ Array::element_offset(FindExternalLabel(label, patchable));
+ LoadWordFromPoolOffset(dst, pp, offset);
+ } else {
+ LoadImmediate(dst, target, kNoPP);
+ }
}
@@ -945,7 +1017,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));
« no previous file with comments | « runtime/vm/assembler_arm64.h ('k') | runtime/vm/constants_arm64.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698